X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/2484ca436ac68716636a7aca3826bca3cda243a4..HEAD:/libctf/ctf-open.c diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 05672f3649..f0e203e0a1 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -1,5 +1,5 @@ /* Opening CTF files. - Copyright (C) 2019-2020 Free Software Foundation, Inc. + Copyright (C) 2019-2022 Free Software Foundation, Inc. This file is part of libctf. @@ -22,13 +22,10 @@ #include #include #include -#include #include "swap.h" #include #include -#include "elf-bfd.h" - static const ctf_dmodel_t _libctf_models[] = { {"ILP32", CTF_MODEL_ILP32, 4, 1, 2, 4, 4}, {"LP64", CTF_MODEL_LP64, 8, 1, 2, 4, 8}, @@ -77,7 +74,7 @@ get_vlen_v2 (uint32_t info) } static inline ssize_t -get_ctt_size_common (const ctf_file_t *fp _libctf_unused_, +get_ctt_size_common (const ctf_dict_t *fp _libctf_unused_, const ctf_type_t *tp _libctf_unused_, ssize_t *sizep, ssize_t *incrementp, size_t lsize, size_t csize, size_t ctf_type_size, @@ -105,7 +102,7 @@ get_ctt_size_common (const ctf_file_t *fp _libctf_unused_, } static ssize_t -get_ctt_size_v1 (const ctf_file_t *fp, const ctf_type_t *tp, +get_ctt_size_v1 (const ctf_dict_t *fp, const ctf_type_t *tp, ssize_t *sizep, ssize_t *incrementp) { ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp; @@ -119,7 +116,7 @@ get_ctt_size_v1 (const ctf_file_t *fp, const ctf_type_t *tp, /* Return the size that a v1 will be once it is converted to v2. */ static ssize_t -get_ctt_size_v2_unconverted (const ctf_file_t *fp, const ctf_type_t *tp, +get_ctt_size_v2_unconverted (const ctf_dict_t *fp, const ctf_type_t *tp, ssize_t *sizep, ssize_t *incrementp) { ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp; @@ -131,7 +128,7 @@ get_ctt_size_v2_unconverted (const ctf_file_t *fp, const ctf_type_t *tp, } static ssize_t -get_ctt_size_v2 (const ctf_file_t *fp, const ctf_type_t *tp, +get_ctt_size_v2 (const ctf_dict_t *fp, const ctf_type_t *tp, ssize_t *sizep, ssize_t *incrementp) { return (get_ctt_size_common (fp, tp, sizep, incrementp, @@ -141,8 +138,8 @@ get_ctt_size_v2 (const ctf_file_t *fp, const ctf_type_t *tp, } static ssize_t -get_vbytes_common (unsigned short kind, ssize_t size _libctf_unused_, - size_t vlen) +get_vbytes_common (ctf_dict_t *fp, unsigned short kind, + ssize_t size _libctf_unused_, size_t vlen) { switch (kind) { @@ -162,13 +159,14 @@ get_vbytes_common (unsigned short kind, ssize_t size _libctf_unused_, case CTF_K_RESTRICT: return 0; default: - ctf_dprintf ("detected invalid CTF kind -- %x\n", kind); - return ECTF_CORRUPT; + ctf_set_errno (fp, ECTF_CORRUPT); + ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind); + return -1; } } static ssize_t -get_vbytes_v1 (unsigned short kind, ssize_t size, size_t vlen) +get_vbytes_v1 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen) { switch (kind) { @@ -184,11 +182,11 @@ get_vbytes_v1 (unsigned short kind, ssize_t size, size_t vlen) return (sizeof (ctf_lmember_v1_t) * vlen); } - return (get_vbytes_common (kind, size, vlen)); + return (get_vbytes_common (fp, kind, size, vlen)); } static ssize_t -get_vbytes_v2 (unsigned short kind, ssize_t size, size_t vlen) +get_vbytes_v2 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen) { switch (kind) { @@ -204,10 +202,10 @@ get_vbytes_v2 (unsigned short kind, ssize_t size, size_t vlen) return (sizeof (ctf_lmember_t) * vlen); } - return (get_vbytes_common (kind, size, vlen)); + return (get_vbytes_common (fp, kind, size, vlen)); } -static const ctf_fileops_t ctf_fileops[] = { +static const ctf_dictops_t ctf_dictops[] = { {NULL, NULL, NULL, NULL, NULL}, /* CTF_VERSION_1 */ {get_kind_v1, get_root_v1, get_vlen_v1, get_ctt_size_v1, get_vbytes_v1}, @@ -219,55 +217,95 @@ static const ctf_fileops_t ctf_fileops[] = { {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, }; -/* Initialize the symtab translation table by filling each entry with the - offset of the CTF type or function data corresponding to each STT_FUNC or - STT_OBJECT entry in the symbol table. */ +/* Initialize the symtab translation table as appropriate for its indexing + state. For unindexed symtypetabs, fill each entry with the offset of the CTF + type or function data corresponding to each STT_FUNC or STT_OBJECT entry in + the symbol table. For indexed symtypetabs, do nothing: the needed + initialization for indexed lookups may be quite expensive, so it is done only + as needed, when lookups happen. (In particular, the majority of indexed + symtypetabs come from the compiler, and all the linker does is iteration over + all entries, which doesn't need this initialization.) + + The SP symbol table section may be NULL if there is no symtab. + + If init_symtab works on one call, it cannot fail on future calls to the same + fp: ctf_symsect_endianness relies on this. */ static int -init_symtab (ctf_file_t *fp, const ctf_header_t *hp, - const ctf_sect_t *sp, const ctf_sect_t *strp) +init_symtab (ctf_dict_t *fp, const ctf_header_t *hp, const ctf_sect_t *sp) { - const unsigned char *symp = sp->cts_data; + const unsigned char *symp; + int skip_func_info = 0; + int i; uint32_t *xp = fp->ctf_sxlate; - uint32_t *xend = xp + fp->ctf_nsyms; + uint32_t *xend = PTR_ADD (xp, fp->ctf_nsyms); uint32_t objtoff = hp->cth_objtoff; uint32_t funcoff = hp->cth_funcoff; - uint32_t info, vlen; - Elf64_Sym sym, *gsp; - const char *name; - - /* The CTF data object and function type sections are ordered to match - the relative order of the respective symbol types in the symtab. - If no type information is available for a symbol table entry, a - pad is inserted in the CTF section. As a further optimization, - anonymous or undefined symbols are omitted from the CTF data. */ - - for (; xp < xend; xp++, symp += sp->cts_entsize) + /* If the CTF_F_NEWFUNCINFO flag is not set, pretend the func info section + is empty: this compiler is too old to emit a function info section we + understand. */ + + if (!(hp->cth_flags & CTF_F_NEWFUNCINFO)) + skip_func_info = 1; + + if (hp->cth_objtidxoff < hp->cth_funcidxoff) + fp->ctf_objtidx_names = (uint32_t *) (fp->ctf_buf + hp->cth_objtidxoff); + if (hp->cth_funcidxoff < hp->cth_varoff && !skip_func_info) + fp->ctf_funcidx_names = (uint32_t *) (fp->ctf_buf + hp->cth_funcidxoff); + + /* Don't bother doing the rest if everything is indexed, or if we don't have a + symbol table: we will never use it. */ + if ((fp->ctf_objtidx_names && fp->ctf_funcidx_names) || !sp || !sp->cts_data) + return 0; + + /* The CTF data object and function type sections are ordered to match the + relative order of the respective symbol types in the symtab, unless there + is an index section, in which case the order is arbitrary and the index + gives the mapping. If no type information is available for a symbol table + entry, a pad is inserted in the CTF section. As a further optimization, + anonymous or undefined symbols are omitted from the CTF data. If an + index is available for function symbols but not object symbols, or vice + versa, we populate the xslate table for the unindexed symbols only. */ + + for (i = 0, symp = sp->cts_data; xp < xend; xp++, symp += sp->cts_entsize, + i++) { - if (sp->cts_entsize == sizeof (Elf32_Sym)) - gsp = ctf_sym_to_elf64 ((Elf32_Sym *) (uintptr_t) symp, &sym); - else - gsp = (Elf64_Sym *) (uintptr_t) symp; + ctf_link_sym_t sym; - if (gsp->st_name < strp->cts_size) - name = (const char *) strp->cts_data + gsp->st_name; - else - name = _CTF_NULLSTR; + switch (sp->cts_entsize) + { + case sizeof (Elf64_Sym): + { + const Elf64_Sym *symp64 = (Elf64_Sym *) (uintptr_t) symp; + ctf_elf64_to_link_sym (fp, &sym, symp64, i); + } + break; + case sizeof (Elf32_Sym): + { + const Elf32_Sym *symp32 = (Elf32_Sym *) (uintptr_t) symp; + ctf_elf32_to_link_sym (fp, &sym, symp32, i); + } + break; + default: + return ECTF_SYMTAB; + } - if (gsp->st_name == 0 || gsp->st_shndx == SHN_UNDEF - || strcmp (name, "_START_") == 0 || strcmp (name, "_END_") == 0) + /* This call may be led astray if our idea of the symtab's endianness is + wrong, but when this is fixed by a call to ctf_symsect_endianness, + init_symtab will be called again with the right endianness in + force. */ + if (ctf_symtab_skippable (&sym)) { *xp = -1u; continue; } - switch (ELF64_ST_TYPE (gsp->st_info)) + switch (sym.st_type) { case STT_OBJECT: - if (objtoff >= hp->cth_funcoff - || (gsp->st_shndx == SHN_EXTABS && gsp->st_value == 0)) + if (fp->ctf_objtidx_names || objtoff >= hp->cth_funcoff) { *xp = -1u; break; @@ -278,25 +316,15 @@ init_symtab (ctf_file_t *fp, const ctf_header_t *hp, break; case STT_FUNC: - if (funcoff >= hp->cth_objtidxoff) + if (fp->ctf_funcidx_names || funcoff >= hp->cth_objtidxoff + || skip_func_info) { *xp = -1u; break; } *xp = funcoff; - - info = *(uint32_t *) ((uintptr_t) fp->ctf_buf + funcoff); - vlen = LCTF_INFO_VLEN (fp, info); - - /* If we encounter a zero pad at the end, just skip it. Otherwise - skip over the function and its return type (+2) and the argument - list (vlen). - */ - if (LCTF_INFO_KIND (fp, info) == CTF_K_UNKNOWN && vlen == 0) - funcoff += sizeof (uint32_t); /* Skip pad. */ - else - funcoff += sizeof (uint32_t) * (vlen + 2); + funcoff += sizeof (uint32_t); break; default: @@ -310,14 +338,14 @@ init_symtab (ctf_file_t *fp, const ctf_header_t *hp, } /* Reset the CTF base pointer and derive the buf pointer from it, initializing - everything in the ctf_file that depends on the base or buf pointers. + everything in the ctf_dict that depends on the base or buf pointers. The original gap between the buf and base pointers, if any -- the original, unconverted CTF header -- is kept, but its contents are not specified and are never used. */ static void -ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, unsigned char *base) +ctf_set_base (ctf_dict_t *fp, const ctf_header_t *hp, unsigned char *base) { fp->ctf_buf = base + (fp->ctf_buf - fp->ctf_base); fp->ctf_base = base; @@ -329,8 +357,8 @@ ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, unsigned char *base) + hp->cth_stroff; fp->ctf_str[CTF_STRTAB_0].cts_len = hp->cth_strlen; - /* If we have a parent container name and label, store the relocated - string pointers in the CTF container for easy access later. */ + /* If we have a parent dict name and label, store the relocated string + pointers in the CTF dict for easy access later. */ /* Note: before conversion, these will be set to values that will be immediately invalidated by the conversion process, but the conversion @@ -358,11 +386,11 @@ ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, unsigned char *base) caller must ensure this has been done in advance. */ static void -ctf_set_version (ctf_file_t *fp, ctf_header_t *cth, int ctf_version) +ctf_set_version (ctf_dict_t *fp, ctf_header_t *cth, int ctf_version) { fp->ctf_version = ctf_version; cth->cth_version = ctf_version; - fp->ctf_fileops = &ctf_fileops[ctf_version]; + fp->ctf_dictops = &ctf_dictops[ctf_version]; } @@ -396,7 +424,7 @@ upgrade_header (ctf_header_t *hp) Type kinds not checked here due to nonexistence in older formats: CTF_K_SLICE. */ static int -upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth) +upgrade_types_v1 (ctf_dict_t *fp, ctf_header_t *cth) { const ctf_type_v1_t *tbuf; const ctf_type_v1_t *tend; @@ -428,11 +456,11 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth) unsigned long vlen = CTF_V1_INFO_VLEN (tp->ctt_info); size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment); - vbytes = get_vbytes_v1 (kind, size, vlen); + vbytes = get_vbytes_v1 (fp, kind, size, vlen); get_ctt_size_v2_unconverted (fp, (const ctf_type_t *) tp, NULL, &v2increment); - v2bytes = get_vbytes_v2 (kind, size, vlen); + v2bytes = get_vbytes_v2 (fp, kind, size, vlen); if ((vbytes < 0) || (size < 0)) return ECTF_CORRUPT; @@ -485,7 +513,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth) void *vdata, *v2data; size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment); - vbytes = get_vbytes_v1 (kind, size, vlen); + vbytes = get_vbytes_v1 (fp, kind, size, vlen); t2p->ctt_name = tp->ctt_name; t2p->ctt_info = CTF_TYPE_INFO (kind, isroot, vlen); @@ -519,7 +547,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth) } v2size = get_ctt_size_v2 (fp, t2p, NULL, &v2increment); - v2bytes = get_vbytes_v2 (kind, v2size, vlen); + v2bytes = get_vbytes_v2 (fp, kind, v2size, vlen); /* Catch out-of-sync get_ctt_size_*(). The count goes wrong if these are not identical (and having them different makes no @@ -620,7 +648,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth) /* Upgrade from any earlier version. */ static int -upgrade_types (ctf_file_t *fp, ctf_header_t *cth) +upgrade_types (ctf_dict_t *fp, ctf_header_t *cth) { switch (cth->cth_version) { @@ -648,18 +676,18 @@ upgrade_types (ctf_file_t *fp, ctf_header_t *cth) recension of libctf supports upgrading. */ static int -init_types (ctf_file_t *fp, ctf_header_t *cth) +init_types (ctf_dict_t *fp, ctf_header_t *cth) { const ctf_type_t *tbuf; const ctf_type_t *tend; unsigned long pop[CTF_K_MAX + 1] = { 0 }; const ctf_type_t *tp; - uint32_t id, dst; + uint32_t id; uint32_t *xp; - /* We determine whether the container is a child or a parent based on - the value of cth_parname. */ + /* We determine whether the dict is a child or a parent based on the value of + cth_parname. */ int child = cth->cth_parname != 0; int nlstructs = 0, nlunions = 0; @@ -703,11 +731,11 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) if (child) { - ctf_dprintf ("CTF container %p is a child\n", (void *) fp); + ctf_dprintf ("CTF dict %p is a child\n", (void *) fp); fp->ctf_flags |= LCTF_CHILD; } else - ctf_dprintf ("CTF container %p is a parent\n", (void *) fp); + ctf_dprintf ("CTF dict %p is a parent\n", (void *) fp); /* Now that we've counted up the number of each type, we can allocate the hash tables, type translation table, and pointer table. */ @@ -728,7 +756,8 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) return ENOMEM; if ((fp->ctf_names.ctn_readonly - = ctf_hash_create (pop[CTF_K_INTEGER] + + = ctf_hash_create (pop[CTF_K_UNKNOWN] + + pop[CTF_K_INTEGER] + pop[CTF_K_FLOAT] + pop[CTF_K_FUNCTION] + pop[CTF_K_TYPEDEF] + @@ -767,10 +796,12 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) (void) ctf_get_ctt_size (fp, tp, &size, &increment); name = ctf_strptr (fp, tp->ctt_name); + /* Cannot fail: shielded by call in loop above. */ vbytes = LCTF_VBYTES (fp, kind, size, vlen); switch (kind) { + case CTF_K_UNKNOWN: case CTF_K_INTEGER: case CTF_K_FLOAT: /* Names are reused by bit-fields, which are differentiated by their @@ -883,9 +914,9 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) } case CTF_K_POINTER: - /* If the type referenced by the pointer is in this CTF container, - then store the index of the pointer type in - fp->ctf_ptrtab[ index of referenced type ]. */ + /* If the type referenced by the pointer is in this CTF dict, then + store the index of the pointer type in fp->ctf_ptrtab[ index of + referenced type ]. */ if (LCTF_TYPE_ISCHILD (fp, tp->ctt_type) == child && LCTF_TYPE_TO_INDEX (fp, tp->ctt_type) <= fp->ctf_typemax) @@ -905,8 +936,8 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) return err; break; default: - ctf_dprintf ("unhandled CTF kind in endianness conversion -- %x\n", - kind); + ctf_err_warn (fp, 0, ECTF_CORRUPT, + _("init_types(): unhandled CTF kind: %x"), kind); return ECTF_CORRUPT; } @@ -924,25 +955,6 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) ctf_dprintf ("%u base type names hashed\n", ctf_hash_size (fp->ctf_names.ctn_readonly)); - /* Make an additional pass through the pointer table to find pointers that - point to anonymous typedef nodes. If we find one, modify the pointer table - so that the pointer is also known to point to the node that is referenced - by the anonymous typedef node. */ - - for (id = 1; id <= fp->ctf_typemax; id++) - { - if ((dst = fp->ctf_ptrtab[id]) != 0) - { - tp = LCTF_INDEX_TO_TYPEPTR (fp, id); - - if (LCTF_INFO_KIND (fp, tp->ctt_info) == CTF_K_TYPEDEF - && strcmp (ctf_strptr (fp, tp->ctt_name), "") == 0 - && LCTF_TYPE_ISCHILD (fp, tp->ctt_type) == child - && LCTF_TYPE_TO_INDEX (fp, tp->ctt_type) <= fp->ctf_typemax) - fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, tp->ctt_type)] = dst; - } - } - return 0; } @@ -951,32 +963,10 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) We flip everything, mindlessly, even 1-byte entities, so that future expansions do not require changes to this code. */ -/* < C11? define away static assertions. */ - -#if !defined (__STDC_VERSION__) || __STDC_VERSION__ < 201112L -#define _Static_assert(cond, err) -#endif - -/* Swap the endianness of something. */ - -#define swap_thing(x) \ - do { \ - _Static_assert (sizeof (x) == 1 || (sizeof (x) % 2 == 0 \ - && sizeof (x) <= 8), \ - "Invalid size, update endianness code"); \ - switch (sizeof (x)) { \ - case 2: x = bswap_16 (x); break; \ - case 4: x = bswap_32 (x); break; \ - case 8: x = bswap_64 (x); break; \ - case 1: /* Nothing needs doing */ \ - break; \ - } \ - } while (0); - /* Flip the endianness of the CTF header. */ -static void -flip_header (ctf_header_t *cth) +void +ctf_flip_header (ctf_header_t *cth) { swap_thing (cth->cth_preamble.ctp_magic); swap_thing (cth->cth_preamble.ctp_version); @@ -1010,9 +1000,7 @@ flip_lbls (void *start, size_t len) } /* Flip the endianness of the data-object or function sections or their indexes, - all arrays of uint32_t. (The function section has more internal structure, - but that structure is an array of uint32_t, so can be treated as one big - array for byte-swapping.) */ + all arrays of uint32_t. */ static void flip_objts (void *start, size_t len) @@ -1043,26 +1031,48 @@ flip_vars (void *start, size_t len) ctf_stype followed by variable data. */ static int -flip_types (void *start, size_t len) +flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign) { ctf_type_t *t = start; while ((uintptr_t) t < ((uintptr_t) start) + len) { + uint32_t kind; + size_t size; + uint32_t vlen; + size_t vbytes; + + if (to_foreign) + { + kind = CTF_V2_INFO_KIND (t->ctt_info); + size = t->ctt_size; + vlen = CTF_V2_INFO_VLEN (t->ctt_info); + vbytes = get_vbytes_v2 (fp, kind, size, vlen); + } + swap_thing (t->ctt_name); swap_thing (t->ctt_info); swap_thing (t->ctt_size); - uint32_t kind = CTF_V2_INFO_KIND (t->ctt_info); - size_t size = t->ctt_size; - uint32_t vlen = CTF_V2_INFO_VLEN (t->ctt_info); - size_t vbytes = get_vbytes_v2 (kind, size, vlen); + if (!to_foreign) + { + kind = CTF_V2_INFO_KIND (t->ctt_info); + size = t->ctt_size; + vlen = CTF_V2_INFO_VLEN (t->ctt_info); + vbytes = get_vbytes_v2 (fp, kind, size, vlen); + } if (_libctf_unlikely_ (size == CTF_LSIZE_SENT)) { + if (to_foreign) + size = CTF_TYPE_LSIZE (t); + swap_thing (t->ctt_lsizehi); swap_thing (t->ctt_lsizelo); - size = CTF_TYPE_LSIZE (t); + + if (!to_foreign) + size = CTF_TYPE_LSIZE (t); + t = (ctf_type_t *) ((uintptr_t) t + sizeof (ctf_type_t)); } else @@ -1181,8 +1191,9 @@ flip_types (void *start, size_t len) break; } default: - ctf_dprintf ("unhandled CTF kind in endianness conversion -- %x\n", - kind); + ctf_err_warn (fp, 0, ECTF_CORRUPT, + _("unhandled CTF kind in endianness conversion: %x"), + kind); return ECTF_CORRUPT; } @@ -1193,27 +1204,32 @@ flip_types (void *start, size_t len) } /* Flip the endianness of BUF, given the offsets in the (already endian- - converted) CTH. + converted) CTH. If TO_FOREIGN is set, flip to foreign-endianness; if not, + flip away. All of this stuff happens before the header is fully initialized, so the LCTF_*() macros cannot be used yet. Since we do not try to endian-convert v1 data, this is no real loss. */ -static int -flip_ctf (ctf_header_t *cth, unsigned char *buf) +int +ctf_flip (ctf_dict_t *fp, ctf_header_t *cth, unsigned char *buf, + int to_foreign) { + ctf_dprintf("flipping endianness\n"); + flip_lbls (buf + cth->cth_lbloff, cth->cth_objtoff - cth->cth_lbloff); flip_objts (buf + cth->cth_objtoff, cth->cth_funcoff - cth->cth_objtoff); flip_objts (buf + cth->cth_funcoff, cth->cth_objtidxoff - cth->cth_funcoff); flip_objts (buf + cth->cth_objtidxoff, cth->cth_funcidxoff - cth->cth_objtidxoff); flip_objts (buf + cth->cth_funcidxoff, cth->cth_varoff - cth->cth_funcidxoff); flip_vars (buf + cth->cth_varoff, cth->cth_typeoff - cth->cth_varoff); - return flip_types (buf + cth->cth_typeoff, cth->cth_stroff - cth->cth_typeoff); + return flip_types (fp, buf + cth->cth_typeoff, + cth->cth_stroff - cth->cth_typeoff, to_foreign); } -/* Set up the ctl hashes in a ctf_file_t. Called by both writable and +/* Set up the ctl hashes in a ctf_dict_t. Called by both writable and non-writable dictionary initialization. */ -void ctf_set_ctl_hashes (ctf_file_t *fp) +void ctf_set_ctl_hashes (ctf_dict_t *fp) { /* Initialize the ctf_lookup_by_name top-level dictionary. We keep an array of type name prefixes and the corresponding ctf_hash to use. */ @@ -1236,7 +1252,7 @@ void ctf_set_ctl_hashes (ctf_file_t *fp) /* Open a CTF file, mocking up a suitable ctf_sect. */ -ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size, +ctf_dict_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size, const char *symsect, size_t symsect_size, size_t symsect_entsize, const char *strsect, size_t strsect_size, @@ -1250,7 +1266,7 @@ ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size, /* Open a CTF file, mocking up a suitable ctf_sect and overriding the external strtab with a synthetic one. */ -ctf_file_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size, +ctf_dict_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size, const char *symsect, size_t symsect_size, size_t symsect_entsize, const char *strsect, size_t strsect_size, @@ -1297,11 +1313,11 @@ ctf_file_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size, } /* Decode the specified CTF buffer and optional symbol table, and create a new - CTF container representing the symbolic debugging information. This code can + CTF dict representing the symbolic debugging information. This code can be used directly by the debugger, or it can be used as the engine for ctf_fdopen() or ctf_open(), below. */ -ctf_file_t * +ctf_dict_t * ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, const ctf_sect_t *strsect, int *errp) { @@ -1310,7 +1326,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, /* Like ctf_bufopen, but overriding the external strtab with a synthetic one. */ -ctf_file_t * +ctf_dict_t * ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, const ctf_sect_t *strsect, ctf_dynhash_t *syn_strtab, int writable, int *errp) @@ -1318,7 +1334,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, const ctf_preamble_t *pp; size_t hdrsz = sizeof (ctf_header_t); ctf_header_t *hp; - ctf_file_t *fp; + ctf_dict_t *fp; int foreign_endian = 0; int err; @@ -1376,21 +1392,30 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, info. We do not support dynamically upgrading such entries (none should exist in any case, since dwarf2ctf does not create them). */ - ctf_dprintf ("ctf_bufopen: CTF version %d symsect not " - "supported\n", pp->ctp_version); + ctf_err_warn (NULL, 0, ECTF_NOTSUP, _("ctf_bufopen: CTF version %d " + "symsect not supported"), + pp->ctp_version); return (ctf_set_open_errno (errp, ECTF_NOTSUP)); } if (pp->ctp_version < CTF_VERSION_3) hdrsz = sizeof (ctf_header_v2_t); + if (_libctf_unlikely_ (pp->ctp_flags > CTF_F_MAX)) + { + ctf_err_warn (NULL, 0, ECTF_FLAGS, _("ctf_bufopen: invalid header " + "flags: %x"), + (unsigned int) pp->ctp_flags); + return (ctf_set_open_errno (errp, ECTF_FLAGS)); + } + if (ctfsect->cts_size < hdrsz) return (ctf_set_open_errno (errp, ECTF_NOCTFBUF)); - if ((fp = malloc (sizeof (ctf_file_t))) == NULL) + if ((fp = malloc (sizeof (ctf_dict_t))) == NULL) return (ctf_set_open_errno (errp, ENOMEM)); - memset (fp, 0, sizeof (ctf_file_t)); + memset (fp, 0, sizeof (ctf_dict_t)); if (writable) fp->ctf_flags |= LCTF_RDWR; @@ -1406,7 +1431,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, upgrade_header (hp); if (foreign_endian) - flip_header (hp); + ctf_flip_header (hp); fp->ctf_openflags = hp->cth_flags; fp->ctf_size = hp->cth_stroff + hp->cth_strlen; @@ -1417,7 +1442,10 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, || hp->cth_funcoff > fp->ctf_size || hp->cth_objtidxoff > fp->ctf_size || hp->cth_funcidxoff > fp->ctf_size || hp->cth_typeoff > fp->ctf_size || hp->cth_stroff > fp->ctf_size) - return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + { + ctf_err_warn (NULL, 0, ECTF_CORRUPT, _("header offset exceeds CTF size")); + return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + } if (hp->cth_lbloff > hp->cth_objtoff || hp->cth_objtoff > hp->cth_funcoff @@ -1426,13 +1454,47 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, || hp->cth_objtidxoff > hp->cth_funcidxoff || hp->cth_funcidxoff > hp->cth_varoff || hp->cth_varoff > hp->cth_typeoff || hp->cth_typeoff > hp->cth_stroff) - return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + { + ctf_err_warn (NULL, 0, ECTF_CORRUPT, _("overlapping CTF sections")); + return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + } if ((hp->cth_lbloff & 3) || (hp->cth_objtoff & 2) || (hp->cth_funcoff & 2) || (hp->cth_objtidxoff & 2) || (hp->cth_funcidxoff & 2) || (hp->cth_varoff & 3) || (hp->cth_typeoff & 3)) - return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + { + ctf_err_warn (NULL, 0, ECTF_CORRUPT, + _("CTF sections not properly aligned")); + return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + } + + /* This invariant will be lifted in v4, but for now it is true. */ + + if ((hp->cth_funcidxoff - hp->cth_objtidxoff != 0) && + (hp->cth_funcidxoff - hp->cth_objtidxoff + != hp->cth_funcoff - hp->cth_objtoff)) + { + ctf_err_warn (NULL, 0, ECTF_CORRUPT, + _("Object index section is neither empty nor the " + "same length as the object section: %u versus %u " + "bytes"), hp->cth_funcoff - hp->cth_objtoff, + hp->cth_funcidxoff - hp->cth_objtidxoff); + return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + } + + if ((hp->cth_varoff - hp->cth_funcidxoff != 0) && + (hp->cth_varoff - hp->cth_funcidxoff + != hp->cth_objtidxoff - hp->cth_funcoff) && + (hp->cth_flags & CTF_F_NEWFUNCINFO)) + { + ctf_err_warn (NULL, 0, ECTF_CORRUPT, + _("Function index section is neither empty nor the " + "same length as the function section: %u versus %u " + "bytes"), hp->cth_objtidxoff - hp->cth_funcoff, + hp->cth_varoff - hp->cth_funcidxoff); + return (ctf_set_open_errno (errp, ECTF_CORRUPT)); + } /* Once everything is determined to be valid, attempt to decompress the CTF data buffer if it is compressed, or copy it into new storage if it is not @@ -1467,44 +1529,58 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, if ((rc = uncompress (fp->ctf_base, &dstlen, src, srclen)) != Z_OK) { - ctf_dprintf ("zlib inflate err: %s\n", zError (rc)); + ctf_err_warn (NULL, 0, ECTF_DECOMPRESS, _("zlib inflate err: %s"), + zError (rc)); err = ECTF_DECOMPRESS; goto bad; } if ((size_t) dstlen != fp->ctf_size) { - ctf_dprintf ("zlib inflate short -- got %lu of %lu " - "bytes\n", (unsigned long) dstlen, - (unsigned long) fp->ctf_size); + ctf_err_warn (NULL, 0, ECTF_CORRUPT, + _("zlib inflate short: got %lu of %lu bytes"), + (unsigned long) dstlen, (unsigned long) fp->ctf_size); err = ECTF_CORRUPT; goto bad; } } - else if (foreign_endian) + else { - if ((fp->ctf_base = malloc (fp->ctf_size)) == NULL) + if (_libctf_unlikely_ (ctfsect->cts_size < hdrsz + fp->ctf_size)) { - err = ECTF_ZALLOC; + ctf_err_warn (NULL, 0, ECTF_CORRUPT, + _("%lu byte long CTF dictionary overruns %lu byte long CTF section"), + (unsigned long) ctfsect->cts_size, + (unsigned long) (hdrsz + fp->ctf_size)); + err = ECTF_CORRUPT; goto bad; } - fp->ctf_dynbase = fp->ctf_base; - memcpy (fp->ctf_base, ((unsigned char *) ctfsect->cts_data) + hdrsz, - fp->ctf_size); - fp->ctf_buf = fp->ctf_base; - } - else - { - /* We are just using the section passed in -- but its header may be an old - version. Point ctf_buf past the old header, and never touch it - again. */ - fp->ctf_base = (unsigned char *) ctfsect->cts_data; - fp->ctf_dynbase = NULL; - fp->ctf_buf = fp->ctf_base + hdrsz; + + if (foreign_endian) + { + if ((fp->ctf_base = malloc (fp->ctf_size)) == NULL) + { + err = ECTF_ZALLOC; + goto bad; + } + fp->ctf_dynbase = fp->ctf_base; + memcpy (fp->ctf_base, ((unsigned char *) ctfsect->cts_data) + hdrsz, + fp->ctf_size); + fp->ctf_buf = fp->ctf_base; + } + else + { + /* We are just using the section passed in -- but its header may + be an old version. Point ctf_buf past the old header, and + never touch it again. */ + fp->ctf_base = (unsigned char *) ctfsect->cts_data; + fp->ctf_dynbase = NULL; + fp->ctf_buf = fp->ctf_base + hdrsz; + } } /* Once we have uncompressed and validated the CTF data buffer, we can - proceed with initializing the ctf_file_t we allocated above. + proceed with initializing the ctf_dict_t we allocated above. Nothing that depends on buf or base should be set directly in this function before the init_types() call, because it may be reallocated during @@ -1512,7 +1588,12 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, ctf_set_base(). */ ctf_set_version (fp, hp, hp->cth_version); - ctf_str_create_atoms (fp); + if (ctf_str_create_atoms (fp) < 0) + { + err = ENOMEM; + goto bad; + } + fp->ctf_parmax = CTF_MAX_PTYPE; memcpy (&fp->ctf_data, ctfsect, sizeof (ctf_sect_t)); @@ -1556,9 +1637,9 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, fp->ctf_syn_ext_strtab = syn_strtab; if (foreign_endian && - (err = flip_ctf (hp, fp->ctf_buf)) != 0) + (err = ctf_flip (fp, hp, fp->ctf_buf, 0)) != 0) { - /* We can be certain that flip_ctf() will have endian-flipped everything + /* We can be certain that ctf_flip() will have endian-flipped everything other than the types table when we return. In particular the header is fine, so set it, to allow freeing to use the usual code path. */ @@ -1568,8 +1649,8 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, ctf_set_base (fp, hp, fp->ctf_base); - /* No need to do anything else for dynamic containers: they do not support - symbol lookups, and the type table is maintained in the dthashes. */ + /* No need to do anything else for dynamic dicts: they do not support symbol + lookups, and the type table is maintained in the dthashes. */ if (fp->ctf_flags & LCTF_RDWR) { fp->ctf_refcnt = 1; @@ -1579,10 +1660,18 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, if ((err = init_types (fp, hp)) != 0) goto bad; - /* If we have a symbol table section, allocate and initialize - the symtab translation table, pointed to by ctf_sxlate. This table may be - too large for the actual size of the object and function info sections: if - so, ctf_nsyms will be adjusted and the excess will never be used. */ + /* Allocate and initialize the symtab translation table, pointed to by + ctf_sxlate, and the corresponding index sections. This table may be too + large for the actual size of the object and function info sections: if so, + ctf_nsyms will be adjusted and the excess will never be used. It's + possible to do indexed symbol lookups even without a symbol table, so check + even in that case. Initially, we assume the symtab is native-endian: if it + isn't, the caller will inform us later by calling ctf_symsect_endianness. */ +#ifdef WORDS_BIGENDIAN + fp->ctf_symsect_little_endian = 0; +#else + fp->ctf_symsect_little_endian = 1; +#endif if (symsect != NULL) { @@ -1594,11 +1683,11 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, err = ENOMEM; goto bad; } - - if ((err = init_symtab (fp, hp, symsect, strsect)) != 0) - goto bad; } + if ((err = init_symtab (fp, hp, symsect)) != 0) + goto bad; + ctf_set_ctl_hashes (fp); if (symsect != NULL) @@ -1616,25 +1705,39 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, bad: ctf_set_open_errno (errp, err); - ctf_file_close (fp); + ctf_err_warn_to_open (fp); + ctf_dict_close (fp); return NULL; } -/* Close the specified CTF container and free associated data structures. Note - that ctf_file_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. */ +/* Bump the refcount on the specified CTF dict, to allow export of ctf_dict_t's + from iterators that open and close the ctf_dict_t around the loop. (This + does not extend their lifetime beyond that of the ctf_archive_t in which they + are contained.) */ void -ctf_file_close (ctf_file_t *fp) +ctf_ref (ctf_dict_t *fp) +{ + fp->ctf_refcnt++; +} + +/* Close the specified CTF dict and free associated data structures. Note that + ctf_dict_close() is a reference counted operation: if the specified file is + the parent of other active dict, its reference count will be greater than one + and it will be freed later when no active children exist. */ + +void +ctf_dict_close (ctf_dict_t *fp) { ctf_dtdef_t *dtd, *ntd; ctf_dvdef_t *dvd, *nvd; + ctf_in_flight_dynsym_t *did, *nid; + ctf_err_warning_t *err, *nerr; if (fp == NULL) - return; /* Allow ctf_file_close(NULL) to simplify caller code. */ + return; /* Allow ctf_dict_close(NULL) to simplify caller code. */ - ctf_dprintf ("ctf_file_close(%p) refcnt=%u\n", (void *) fp, fp->ctf_refcnt); + ctf_dprintf ("ctf_dict_close(%p) refcnt=%u\n", (void *) fp, fp->ctf_refcnt); if (fp->ctf_refcnt > 1) { @@ -1642,9 +1745,17 @@ ctf_file_close (ctf_file_t *fp) return; } + /* It is possible to recurse back in here, notably if dicts in the + ctf_link_inputs or ctf_link_outputs cite this dict as a parent without + using ctf_import_unref. Do nothing in that case. */ + if (fp->ctf_refcnt == 0) + return; + + fp->ctf_refcnt--; free (fp->ctf_dyncuname); free (fp->ctf_dynparname); - ctf_file_close (fp->ctf_parent); + if (fp->ctf_parent && !fp->ctf_parent_unreffed) + ctf_dict_close (fp->ctf_parent); for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { @@ -1673,6 +1784,21 @@ ctf_file_close (ctf_file_t *fp) ctf_dvd_delete (fp, dvd); } ctf_dynhash_destroy (fp->ctf_dvhash); + + ctf_dynhash_destroy (fp->ctf_symhash); + free (fp->ctf_funcidx_sxlate); + free (fp->ctf_objtidx_sxlate); + ctf_dynhash_destroy (fp->ctf_objthash); + ctf_dynhash_destroy (fp->ctf_funchash); + free (fp->ctf_dynsymidx); + ctf_dynhash_destroy (fp->ctf_dynsyms); + for (did = ctf_list_next (&fp->ctf_in_flight_dynsyms); did != NULL; did = nid) + { + nid = ctf_list_next (did); + ctf_list_delete (&fp->ctf_in_flight_dynsyms, did); + free (did); + } + ctf_str_free_atoms (fp); free (fp->ctf_tmp_typeslice); @@ -1693,17 +1819,36 @@ ctf_file_close (ctf_file_t *fp) ctf_dynhash_destroy (fp->ctf_link_inputs); ctf_dynhash_destroy (fp->ctf_link_outputs); ctf_dynhash_destroy (fp->ctf_link_type_mapping); - ctf_dynhash_destroy (fp->ctf_link_cu_mapping); + ctf_dynhash_destroy (fp->ctf_link_in_cu_mapping); + ctf_dynhash_destroy (fp->ctf_link_out_cu_mapping); ctf_dynhash_destroy (fp->ctf_add_processing); + ctf_dedup_fini (fp, NULL, 0); + ctf_dynset_destroy (fp->ctf_dedup_atoms_alloc); + + for (err = ctf_list_next (&fp->ctf_errs_warnings); err != NULL; err = nerr) + { + nerr = ctf_list_next (err); + ctf_list_delete (&fp->ctf_errs_warnings, err); + free (err->cew_text); + free (err); + } free (fp->ctf_sxlate); free (fp->ctf_txlate); free (fp->ctf_ptrtab); + free (fp->ctf_pptrtab); free (fp->ctf_header); free (fp); } +/* Backward compatibility. */ +void +ctf_file_close (ctf_file_t *fp) +{ + ctf_dict_close (fp); +} + /* The converse of ctf_open(). ctf_open() disguises whatever it opens as an archive, so closing one is just like closing an archive. */ void @@ -1712,36 +1857,70 @@ ctf_close (ctf_archive_t *arc) ctf_arc_close (arc); } -/* Get the CTF archive from which this ctf_file_t is derived. */ +/* Get the CTF archive from which this ctf_dict_t is derived. */ ctf_archive_t * -ctf_get_arc (const ctf_file_t *fp) +ctf_get_arc (const ctf_dict_t *fp) { return fp->ctf_archive; } /* Return the ctfsect out of the core ctf_impl. Useful for freeing the - ctfsect's data * after ctf_file_close(), which is why we return the actual + ctfsect's data * after ctf_dict_close(), which is why we return the actual structure, not a pointer to it, since that is likely to become a pointer to freed data before the return value is used under the expected use case of - ctf_getsect()/ ctf_file_close()/free(). */ + ctf_getsect()/ ctf_dict_close()/free(). */ ctf_sect_t -ctf_getdatasect (const ctf_file_t *fp) +ctf_getdatasect (const ctf_dict_t *fp) { return fp->ctf_data; } -/* Return the CTF handle for the parent CTF container, if one exists. - Otherwise return NULL to indicate this container has no imported parent. */ -ctf_file_t * -ctf_parent_file (ctf_file_t *fp) +ctf_sect_t +ctf_getsymsect (const ctf_dict_t *fp) +{ + return fp->ctf_symtab; +} + +ctf_sect_t +ctf_getstrsect (const ctf_dict_t *fp) +{ + return fp->ctf_strtab; +} + +/* Set the endianness of the symbol table attached to FP. */ +void +ctf_symsect_endianness (ctf_dict_t *fp, int little_endian) +{ + int old_endianness = fp->ctf_symsect_little_endian; + + fp->ctf_symsect_little_endian = !!little_endian; + + /* If we already have a symtab translation table, we need to repopulate it if + our idea of the endianness has changed. */ + + if (old_endianness != fp->ctf_symsect_little_endian + && fp->ctf_sxlate != NULL && fp->ctf_symtab.cts_data != NULL) + assert (init_symtab (fp, fp->ctf_header, &fp->ctf_symtab) == 0); +} + +/* Return the CTF handle for the parent CTF dict, if one exists. Otherwise + return NULL to indicate this dict has no imported parent. */ +ctf_dict_t * +ctf_parent_dict (ctf_dict_t *fp) { return fp->ctf_parent; } -/* Return the name of the parent CTF container, if one exists. Otherwise - return NULL to indicate this container is a root container. */ +/* Backward compatibility. */ +ctf_dict_t * +ctf_parent_file (ctf_dict_t *fp) +{ + return ctf_parent_dict (fp); +} + +/* Return the name of the parent CTF dict, if one exists, or NULL otherwise. */ const char * -ctf_parent_name (ctf_file_t *fp) +ctf_parent_name (ctf_dict_t *fp) { return fp->ctf_parname; } @@ -1749,7 +1928,7 @@ ctf_parent_name (ctf_file_t *fp) /* Set the parent name. It is an error to call this routine without calling ctf_import() at some point. */ int -ctf_parent_name_set (ctf_file_t *fp, const char *name) +ctf_parent_name_set (ctf_dict_t *fp, const char *name) { if (fp->ctf_dynparname != NULL) free (fp->ctf_dynparname); @@ -1761,16 +1940,16 @@ ctf_parent_name_set (ctf_file_t *fp, const char *name) } /* Return the name of the compilation unit this CTF file applies to. Usually - non-NULL only for non-parent containers. */ + non-NULL only for non-parent dicts. */ const char * -ctf_cuname (ctf_file_t *fp) +ctf_cuname (ctf_dict_t *fp) { return fp->ctf_cuname; } /* Set the compilation unit name. */ int -ctf_cuname_set (ctf_file_t *fp, const char *name) +ctf_cuname_set (ctf_dict_t *fp, const char *name) { if (fp->ctf_dyncuname != NULL) free (fp->ctf_dyncuname); @@ -1781,11 +1960,12 @@ ctf_cuname_set (ctf_file_t *fp, const char *name) return 0; } -/* Import the types from the specified parent container by storing a pointer - to it in ctf_parent and incrementing its reference count. Only one parent - is allowed: if a parent already exists, it is replaced by the new parent. */ +/* Import the types from the specified parent dict by storing a pointer to it in + ctf_parent and incrementing its reference count. Only one parent is allowed: + if a parent already exists, it is replaced by the new parent. The pptrtab + is wiped, and will be refreshed by the next ctf_lookup_by_name call. */ int -ctf_import (ctf_file_t *fp, ctf_file_t *pfp) +ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp) { if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0)) return (ctf_set_errno (fp, EINVAL)); @@ -1793,13 +1973,53 @@ ctf_import (ctf_file_t *fp, ctf_file_t *pfp) if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel) return (ctf_set_errno (fp, ECTF_DMODEL)); - if (fp->ctf_parent != NULL) + if (fp->ctf_parent && !fp->ctf_parent_unreffed) + ctf_dict_close (fp->ctf_parent); + fp->ctf_parent = NULL; + + free (fp->ctf_pptrtab); + fp->ctf_pptrtab = NULL; + fp->ctf_pptrtab_len = 0; + fp->ctf_pptrtab_typemax = 0; + + if (pfp != NULL) { - fp->ctf_parent->ctf_refcnt--; - ctf_file_close (fp->ctf_parent); - fp->ctf_parent = NULL; + int err; + + if (fp->ctf_parname == NULL) + if ((err = ctf_parent_name_set (fp, "PARENT")) < 0) + return err; + + fp->ctf_flags |= LCTF_CHILD; + pfp->ctf_refcnt++; + fp->ctf_parent_unreffed = 0; } + fp->ctf_parent = pfp; + return 0; +} + +/* Like ctf_import, but does not increment the refcount on the imported parent + or close it at any point: as a result it can go away at any time and the + caller must do all freeing itself. Used internally to avoid refcount + loops. */ +int +ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp) +{ + if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0)) + return (ctf_set_errno (fp, EINVAL)); + + if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel) + return (ctf_set_errno (fp, ECTF_DMODEL)); + + if (fp->ctf_parent && !fp->ctf_parent_unreffed) + ctf_dict_close (fp->ctf_parent); + fp->ctf_parent = NULL; + + free (fp->ctf_pptrtab); + fp->ctf_pptrtab = NULL; + fp->ctf_pptrtab_len = 0; + fp->ctf_pptrtab_typemax = 0; if (pfp != NULL) { int err; @@ -1809,16 +2029,16 @@ ctf_import (ctf_file_t *fp, ctf_file_t *pfp) return err; fp->ctf_flags |= LCTF_CHILD; - pfp->ctf_refcnt++; + fp->ctf_parent_unreffed = 1; } fp->ctf_parent = pfp; return 0; } -/* Set the data model constant for the CTF container. */ +/* Set the data model constant for the CTF dict. */ int -ctf_setmodel (ctf_file_t *fp, int model) +ctf_setmodel (ctf_dict_t *fp, int model) { const ctf_dmodel_t *dp; @@ -1834,24 +2054,24 @@ ctf_setmodel (ctf_file_t *fp, int model) return (ctf_set_errno (fp, EINVAL)); } -/* Return the data model constant for the CTF container. */ +/* Return the data model constant for the CTF dict. */ int -ctf_getmodel (ctf_file_t *fp) +ctf_getmodel (ctf_dict_t *fp) { return fp->ctf_dmodel->ctd_code; } -/* The caller can hang an arbitrary pointer off each ctf_file_t using this +/* The caller can hang an arbitrary pointer off each ctf_dict_t using this function. */ void -ctf_setspecific (ctf_file_t *fp, void *data) +ctf_setspecific (ctf_dict_t *fp, void *data) { fp->ctf_specific = data; } /* Retrieve the arbitrary pointer again. */ void * -ctf_getspecific (ctf_file_t *fp) +ctf_getspecific (ctf_dict_t *fp) { return fp->ctf_specific; }