/* * Close the specified CTF container and free associated data structures. Note * that ctf_close() is a reference counted operation: if the specified file is * the parent of other active containers, its reference count will be greater * than one and it will be freed later when no active children exist. */ void ctf_close(ctf_file_t *fp) { ctf_dtdef_t *dtd, *ntd; if (fp == NULL) return; /* allow ctf_close(NULL) to simplify caller code */ ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt); if (fp->ctf_refcnt > 1) { fp->ctf_refcnt--; return; } if (fp->ctf_parent != NULL) ctf_close(fp->ctf_parent); for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { ntd = ctf_list_next(dtd); ctf_dtd_delete(fp, dtd); } ctf_free(fp->ctf_dthash, fp->ctf_dthashlen * sizeof (ctf_dtdef_t *)); if (fp->ctf_flags & LCTF_MMAP) { if (fp->ctf_data.cts_data != NULL) ctf_sect_munmap(&fp->ctf_data); if (fp->ctf_symtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_symtab); if (fp->ctf_strtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_strtab); } if (fp->ctf_data.cts_name != _CTF_NULLSTR && fp->ctf_data.cts_name != NULL) { ctf_free((char *)fp->ctf_data.cts_name, strlen(fp->ctf_data.cts_name) + 1); } if (fp->ctf_symtab.cts_name != _CTF_NULLSTR && fp->ctf_symtab.cts_name != NULL) { ctf_free((char *)fp->ctf_symtab.cts_name, strlen(fp->ctf_symtab.cts_name) + 1); } if (fp->ctf_strtab.cts_name != _CTF_NULLSTR && fp->ctf_strtab.cts_name != NULL) { ctf_free((char *)fp->ctf_strtab.cts_name, strlen(fp->ctf_strtab.cts_name) + 1); } if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL) ctf_data_free((void *)fp->ctf_base, fp->ctf_size); if (fp->ctf_sxlate != NULL) ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms); if (fp->ctf_txlate != NULL) { ctf_free(fp->ctf_txlate, sizeof (uint_t) * (fp->ctf_typemax + 1)); } if (fp->ctf_ptrtab != NULL) { ctf_free(fp->ctf_ptrtab, sizeof (ushort_t) * (fp->ctf_typemax + 1)); } ctf_hash_destroy(&fp->ctf_structs); ctf_hash_destroy(&fp->ctf_unions); ctf_hash_destroy(&fp->ctf_enums); ctf_hash_destroy(&fp->ctf_names); ctf_free(fp, sizeof (ctf_file_t)); }
/* * Open the specified file descriptor and return a pointer to a CTF container. * The file can be either an ELF file or raw CTF file. The caller is * responsible for closing the file descriptor when it is no longer needed. */ ctf_file_t * ctf_fdopen(int fd, int *errp) { ctf_sect_t ctfsect, symsect, strsect; ctf_file_t *fp = NULL; struct stat64 st; ssize_t nbytes; union { ctf_preamble_t ctf; Elf32_Ehdr e32; GElf_Ehdr e64; } hdr; bzero(&ctfsect, sizeof (ctf_sect_t)); bzero(&symsect, sizeof (ctf_sect_t)); bzero(&strsect, sizeof (ctf_sect_t)); bzero(&hdr.ctf, sizeof (hdr)); if (fstat64(fd, &st) == -1) return (ctf_set_open_errno(errp, errno)); if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0) return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT)); /* * If we have read enough bytes to form a CTF header and the magic * string matches, attempt to interpret the file as raw CTF. */ if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) && hdr.ctf.ctp_magic == CTF_MAGIC) { if (hdr.ctf.ctp_version > CTF_VERSION) return (ctf_set_open_errno(errp, ECTF_CTFVERS)); ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (ctfsect.cts_data == MAP_FAILED) return (ctf_set_open_errno(errp, errno)); ctfsect.cts_name = _CTF_SECTION; ctfsect.cts_type = SHT_PROGBITS; ctfsect.cts_flags = SHF_ALLOC; ctfsect.cts_size = (size_t)st.st_size; ctfsect.cts_entsize = 1; ctfsect.cts_offset = 0; if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL) ctf_sect_munmap(&ctfsect); return (fp); } /* * If we have read enough bytes to form an ELF header and the magic * string matches, attempt to interpret the file as an ELF file. We * do our own largefile ELF processing, and convert everything to * GElf structures so that clients can operate on any data model. */ if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) && bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) { #ifdef _BIG_ENDIAN uchar_t order = ELFDATA2MSB; #else uchar_t order = ELFDATA2LSB; #endif GElf_Half i, n; GElf_Shdr *sp; void *strs_map; size_t strs_mapsz; char *strs; if (hdr.e32.e_ident[EI_DATA] != order) return (ctf_set_open_errno(errp, ECTF_ENDIAN)); if (hdr.e32.e_version != EV_CURRENT) return (ctf_set_open_errno(errp, ECTF_ELFVERS)); if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) { if (nbytes < (ssize_t) sizeof (GElf_Ehdr)) return (ctf_set_open_errno(errp, ECTF_FMT)); } else { Elf32_Ehdr e32 = hdr.e32; ehdr_to_gelf(&e32, &hdr.e64); } if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum) return (ctf_set_open_errno(errp, ECTF_CORRUPT)); n = hdr.e64.e_shnum; nbytes = sizeof (GElf_Shdr) * n; if ((sp = malloc(nbytes)) == NULL) return (ctf_set_open_errno(errp, errno)); /* * Read in and convert to GElf the array of Shdr structures * from e_shoff so we can locate sections of interest. */ if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { Elf32_Shdr *sp32; nbytes = sizeof (Elf32_Shdr) * n; if ((sp32 = malloc(nbytes)) == NULL || pread64(fd, sp32, nbytes, hdr.e64.e_shoff) != nbytes) { free(sp); return (ctf_set_open_errno(errp, errno)); } for (i = 0; i < n; i++) shdr_to_gelf(&sp32[i], &sp[i]); free(sp32); } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) { free(sp); return (ctf_set_open_errno(errp, errno)); } /* * Now mmap the section header strings section so that we can * perform string comparison on the section names. */ strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size + (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK); strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE, fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK); strs = (char *)strs_map + (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK); if (strs_map == MAP_FAILED) { free(sp); return (ctf_set_open_errno(errp, ECTF_MMAP)); } /* * Iterate over the section header array looking for the CTF * section and symbol table. The strtab is linked to symtab. */ for (i = 0; i < n; i++) { const GElf_Shdr *shp = &sp[i]; const GElf_Shdr *lhp = &sp[shp->sh_link]; if (shp->sh_link >= hdr.e64.e_shnum) continue; /* corrupt sh_link field */ if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size || lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size) continue; /* corrupt sh_name field */ if (shp->sh_type == SHT_PROGBITS && strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) { ctfsect.cts_name = strs + shp->sh_name; ctfsect.cts_type = shp->sh_type; ctfsect.cts_flags = shp->sh_flags; ctfsect.cts_size = shp->sh_size; ctfsect.cts_entsize = shp->sh_entsize; ctfsect.cts_offset = (off64_t)shp->sh_offset; } else if (shp->sh_type == SHT_SYMTAB) { symsect.cts_name = strs + shp->sh_name; symsect.cts_type = shp->sh_type; symsect.cts_flags = shp->sh_flags; symsect.cts_size = shp->sh_size; symsect.cts_entsize = shp->sh_entsize; symsect.cts_offset = (off64_t)shp->sh_offset; strsect.cts_name = strs + lhp->sh_name; strsect.cts_type = lhp->sh_type; strsect.cts_flags = lhp->sh_flags; strsect.cts_size = lhp->sh_size; strsect.cts_entsize = lhp->sh_entsize; strsect.cts_offset = (off64_t)lhp->sh_offset; } } free(sp); /* free section header array */ if (ctfsect.cts_type == SHT_NULL) { (void) munmap(strs_map, strs_mapsz); return (ctf_set_open_errno(errp, ECTF_NOCTFDATA)); } /* * Now mmap the CTF data, symtab, and strtab sections and * call ctf_bufopen() to do the rest of the work. */ if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) { (void) munmap(strs_map, strs_mapsz); return (ctf_set_open_errno(errp, ECTF_MMAP)); } if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) { if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED || ctf_sect_mmap(&strsect, fd) == MAP_FAILED) { (void) ctf_set_open_errno(errp, ECTF_MMAP); goto bad; /* unmap all and abort */ } fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp); } else fp = ctf_bufopen(&ctfsect, NULL, NULL, errp); bad: if (fp == NULL) { ctf_sect_munmap(&ctfsect); ctf_sect_munmap(&symsect); ctf_sect_munmap(&strsect); } else fp->ctf_flags |= LCTF_MMAP; (void) munmap(strs_map, strs_mapsz); return (fp); } return (ctf_set_open_errno(errp, ECTF_FMT)); }
/* * Close the specified CTF container and free associated data structures. Note * that ctf_close() is a reference counted operation: if the specified file is * the parent of other active containers, its reference count will be greater * than one and it will be freed later when no active children exist. */ void ctf_close(ctf_file_t *fp) { ctf_dtdef_t *dtd, *ntd; ctf_dmdef_t *dmd, *nmd; if (fp == NULL) return; /* allow ctf_close(NULL) to simplify caller code */ ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt); if (fp->ctf_refcnt > 1) { fp->ctf_refcnt--; return; } for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) { case CTF_K_STRUCT: case CTF_K_UNION: case CTF_K_ENUM: for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = nmd) { if (dmd->dmd_name != NULL) { ctf_free(dmd->dmd_name, strlen(dmd->dmd_name) + 1); } nmd = ctf_list_next(dmd); ctf_free(dmd, sizeof (ctf_dmdef_t)); } break; case CTF_K_FUNCTION: ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) * CTF_INFO_VLEN(dtd->dtd_data.ctt_info)); break; } if (dtd->dtd_name != NULL) ctf_free(dtd->dtd_name, strlen(dtd->dtd_name) + 1); ntd = ctf_list_next(dtd); ctf_free(dtd, sizeof (ctf_dtdef_t)); } if (fp->ctf_parent != NULL) ctf_close(fp->ctf_parent); if (fp->ctf_flags & LCTF_MMAP) { if (fp->ctf_data.cts_data != NULL) ctf_sect_munmap(&fp->ctf_data); if (fp->ctf_symtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_symtab); if (fp->ctf_strtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_strtab); } if (fp->ctf_data.cts_name != _CTF_NULLSTR && fp->ctf_data.cts_name != NULL) { ctf_free((char *)fp->ctf_data.cts_name, strlen(fp->ctf_data.cts_name) + 1); } if (fp->ctf_symtab.cts_name != _CTF_NULLSTR && fp->ctf_symtab.cts_name != NULL) { ctf_free((char *)fp->ctf_symtab.cts_name, strlen(fp->ctf_symtab.cts_name) + 1); } if (fp->ctf_strtab.cts_name != _CTF_NULLSTR && fp->ctf_strtab.cts_name != NULL) { ctf_free((char *)fp->ctf_strtab.cts_name, strlen(fp->ctf_strtab.cts_name) + 1); } if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL) ctf_data_free((void *)fp->ctf_base, fp->ctf_size); if (fp->ctf_sxlate != NULL) ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms); if (fp->ctf_txlate != NULL) { ctf_free(fp->ctf_txlate, sizeof (uint_t) * (fp->ctf_typemax + 1)); } if (fp->ctf_ptrtab != NULL) { ctf_free(fp->ctf_ptrtab, sizeof (ushort_t) * (fp->ctf_typemax + 1)); } ctf_hash_destroy(&fp->ctf_structs); ctf_hash_destroy(&fp->ctf_unions); ctf_hash_destroy(&fp->ctf_enums); ctf_hash_destroy(&fp->ctf_names); ctf_free(fp, sizeof (ctf_file_t)); }
/* * Close the specified CTF container and free associated data structures. Note * that ctf_close() is a reference counted operation: if the specified file is * the parent of other active containers, its reference count will be greater * than one and it will be freed later when no active children exist. */ void ctf_close(ctf_file_t *fp) { ctf_dtdef_t *dtd, *ntd; if (fp == NULL) return; /* allow ctf_close(NULL) to simplify caller code */ ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt); if (fp->ctf_refcnt > 1) { fp->ctf_refcnt--; return; } if (fp->ctf_parent != NULL) ctf_close(fp->ctf_parent); /* * Note, to work properly with reference counting on the dynamic * section, we must delete the list in reverse. */ for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { ntd = ctf_list_prev(dtd); ctf_dtd_delete(fp, dtd); } ctf_free(fp->ctf_dthash, fp->ctf_dthashlen * sizeof (ctf_dtdef_t *)); if (fp->ctf_flags & LCTF_MMAP) { if (fp->ctf_data.cts_data != NULL) ctf_sect_munmap(&fp->ctf_data); if (fp->ctf_symtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_symtab); if (fp->ctf_strtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_strtab); } if (fp->ctf_data.cts_name != _CTF_NULLSTR && fp->ctf_data.cts_name != NULL) { ctf_free(__UNCONST(fp->ctf_data.cts_name), strlen(fp->ctf_data.cts_name) + 1); } if (fp->ctf_symtab.cts_name != _CTF_NULLSTR && fp->ctf_symtab.cts_name != NULL) { ctf_free(__UNCONST(fp->ctf_symtab.cts_name), strlen(fp->ctf_symtab.cts_name) + 1); } if (fp->ctf_strtab.cts_name != _CTF_NULLSTR && fp->ctf_strtab.cts_name != NULL) { ctf_free(__UNCONST(fp->ctf_strtab.cts_name), strlen(fp->ctf_strtab.cts_name) + 1); } if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL) ctf_data_free(__UNCONST(fp->ctf_base), fp->ctf_size); if (fp->ctf_sxlate != NULL) ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms); if (fp->ctf_txlate != NULL) { ctf_free(fp->ctf_txlate, sizeof (uint_t) * (fp->ctf_typemax + 1)); } if (fp->ctf_ptrtab != NULL) { ctf_free(fp->ctf_ptrtab, sizeof (ushort_t) * (fp->ctf_typemax + 1)); } ctf_hash_destroy(&fp->ctf_structs); ctf_hash_destroy(&fp->ctf_unions); ctf_hash_destroy(&fp->ctf_enums); ctf_hash_destroy(&fp->ctf_names); ctf_free(fp, sizeof (ctf_file_t)); }