X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/d851ecd373a3764581372b10be5b74c9ee98ae08..HEAD:/libctf/ctf-open.c diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index f4179cb78e..f0e203e0a1 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -1,5 +1,5 @@ /* Opening CTF files. - Copyright (C) 2019 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; @@ -446,7 +474,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth) number unchanged, so that LCTF_INFO_* still works on the as-yet-untranslated type info. */ - if ((ctf_base = ctf_alloc (fp->ctf_size + increase)) == NULL) + if ((ctf_base = malloc (fp->ctf_size + increase)) == NULL) return ECTF_ZALLOC; /* Start at ctf_buf, not ctf_base, to squeeze out the original header: we @@ -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 @@ -613,14 +641,14 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth) assert ((size_t) t2p - (size_t) fp->ctf_buf == cth->cth_stroff); ctf_set_version (fp, cth, CTF_VERSION_1_UPGRADED_3); - ctf_free (old_ctf_base); + free (old_ctf_base); return 0; } /* 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,24 +676,25 @@ 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; - ctf_hash_t *hp; - 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; int err; + assert (!(fp->ctf_flags & LCTF_RDWR)); + if (_libctf_unlikely_ (fp->ctf_version == CTF_VERSION_1)) { int err; @@ -691,58 +720,58 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) if (vbytes < 0) return ECTF_CORRUPT; + /* For forward declarations, ctt_type is the CTF_K_* kind for the tag, + so bump that population count too. */ if (kind == CTF_K_FORWARD) - { - /* For forward declarations, ctt_type is the CTF_K_* kind for the tag, - so bump that population count too. If ctt_type is unknown, treat - the tag as a struct. */ + pop[tp->ctt_type]++; - if (tp->ctt_type == CTF_K_UNKNOWN || tp->ctt_type >= CTF_K_MAX) - pop[CTF_K_STRUCT]++; - else - pop[tp->ctt_type]++; - } tp = (ctf_type_t *) ((uintptr_t) tp + increment + vbytes); pop[kind]++; } 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. */ - if ((fp->ctf_structs = ctf_hash_create (pop[CTF_K_STRUCT], ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_structs.ctn_readonly + = ctf_hash_create (pop[CTF_K_STRUCT], ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; - if ((fp->ctf_unions = ctf_hash_create (pop[CTF_K_UNION], ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_unions.ctn_readonly + = ctf_hash_create (pop[CTF_K_UNION], ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; - if ((fp->ctf_enums = ctf_hash_create (pop[CTF_K_ENUM], ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_enums.ctn_readonly + = ctf_hash_create (pop[CTF_K_ENUM], ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; - if ((fp->ctf_names = ctf_hash_create (pop[CTF_K_INTEGER] + - pop[CTF_K_FLOAT] + - pop[CTF_K_FUNCTION] + - pop[CTF_K_TYPEDEF] + - pop[CTF_K_POINTER] + - pop[CTF_K_VOLATILE] + - pop[CTF_K_CONST] + - pop[CTF_K_RESTRICT], - ctf_hash_string, - ctf_hash_eq_string)) == NULL) + if ((fp->ctf_names.ctn_readonly + = ctf_hash_create (pop[CTF_K_UNKNOWN] + + pop[CTF_K_INTEGER] + + pop[CTF_K_FLOAT] + + pop[CTF_K_FUNCTION] + + pop[CTF_K_TYPEDEF] + + pop[CTF_K_POINTER] + + pop[CTF_K_VOLATILE] + + pop[CTF_K_CONST] + + pop[CTF_K_RESTRICT], + ctf_hash_string, + ctf_hash_eq_string)) == NULL) return ENOMEM; - fp->ctf_txlate = ctf_alloc (sizeof (uint32_t) * (fp->ctf_typemax + 1)); - fp->ctf_ptrtab = ctf_alloc (sizeof (uint32_t) * (fp->ctf_typemax + 1)); + fp->ctf_txlate = malloc (sizeof (uint32_t) * (fp->ctf_typemax + 1)); + fp->ctf_ptrtab_len = fp->ctf_typemax + 1; + fp->ctf_ptrtab = malloc (sizeof (uint32_t) * fp->ctf_ptrtab_len); if (fp->ctf_txlate == NULL || fp->ctf_ptrtab == NULL) return ENOMEM; /* Memory allocation failed. */ @@ -759,7 +788,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) for (id = 1, tp = tbuf; tp < tend; xp++, id++) { unsigned short kind = LCTF_INFO_KIND (fp, tp->ctt_info); - unsigned short flag = LCTF_INFO_ISROOT (fp, tp->ctt_info); + unsigned short isroot = LCTF_INFO_ISROOT (fp, tp->ctt_info); unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); ssize_t size, increment, vbytes; @@ -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 @@ -779,10 +810,11 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) root-visible version so that we can be sure to find it when checking for conflicting definitions in ctf_add_type(). */ - if (((ctf_hash_lookup_type (fp->ctf_names, fp, name)) == 0) - || (flag & CTF_ADD_ROOT)) + if (((ctf_hash_lookup_type (fp->ctf_names.ctn_readonly, + fp, name)) == 0) + || isroot) { - err = ctf_hash_define_type (fp->ctf_names, fp, + err = ctf_hash_define_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) @@ -797,7 +829,10 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_FUNCTION: - err = ctf_hash_insert_type (fp->ctf_names, fp, + if (!isroot) + break; + + err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) @@ -805,31 +840,41 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_STRUCT: - err = ctf_hash_define_type (fp->ctf_structs, fp, + if (size >= CTF_LSTRUCT_THRESH) + nlstructs++; + + if (!isroot) + break; + + err = ctf_hash_define_type (fp->ctf_structs.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) return err; - if (size >= CTF_LSTRUCT_THRESH) - nlstructs++; break; case CTF_K_UNION: - err = ctf_hash_define_type (fp->ctf_unions, fp, + if (size >= CTF_LSTRUCT_THRESH) + nlunions++; + + if (!isroot) + break; + + err = ctf_hash_define_type (fp->ctf_unions.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) return err; - - if (size >= CTF_LSTRUCT_THRESH) - nlunions++; break; case CTF_K_ENUM: - err = ctf_hash_define_type (fp->ctf_enums, fp, + if (!isroot) + break; + + err = ctf_hash_define_type (fp->ctf_enums.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); @@ -838,7 +883,10 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_TYPEDEF: - err = ctf_hash_insert_type (fp->ctf_names, fp, + if (!isroot) + break; + + err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) @@ -846,37 +894,29 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) break; case CTF_K_FORWARD: - /* Only insert forward tags into the given hash if the type or tag - name is not already present. */ - switch (tp->ctt_type) - { - case CTF_K_STRUCT: - hp = fp->ctf_structs; - break; - case CTF_K_UNION: - hp = fp->ctf_unions; - break; - case CTF_K_ENUM: - hp = fp->ctf_enums; + { + ctf_names_t *np = ctf_name_table (fp, tp->ctt_type); + + if (!isroot) break; - default: - hp = fp->ctf_structs; - } - if (ctf_hash_lookup_type (hp, fp, name) == 0) - { - err = ctf_hash_insert_type (hp, fp, - LCTF_INDEX_TO_TYPE (fp, id, child), - tp->ctt_name); - if (err != 0) - return err; - } - break; + /* Only insert forward tags into the given hash if the type or tag + name is not already present. */ + if (ctf_hash_lookup_type (np->ctn_readonly, fp, name) == 0) + { + err = ctf_hash_insert_type (np->ctn_readonly, fp, + LCTF_INDEX_TO_TYPE (fp, id, child), + tp->ctt_name); + if (err != 0) + return err; + } + break; + } 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) @@ -886,15 +926,18 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: - err = ctf_hash_insert_type (fp->ctf_names, fp, + if (!isroot) + break; + + err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp, LCTF_INDEX_TO_TYPE (fp, id, child), tp->ctt_name); if (err != 0) 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; } @@ -903,31 +946,14 @@ init_types (ctf_file_t *fp, ctf_header_t *cth) } ctf_dprintf ("%lu total types processed\n", fp->ctf_typemax); - ctf_dprintf ("%u enum names hashed\n", ctf_hash_size (fp->ctf_enums)); + ctf_dprintf ("%u enum names hashed\n", + ctf_hash_size (fp->ctf_enums.ctn_readonly)); ctf_dprintf ("%u struct names hashed (%d long)\n", - ctf_hash_size (fp->ctf_structs), nlstructs); + ctf_hash_size (fp->ctf_structs.ctn_readonly), nlstructs); ctf_dprintf ("%u union names hashed (%d long)\n", - ctf_hash_size (fp->ctf_unions), nlunions); - ctf_dprintf ("%u base type names hashed\n", ctf_hash_size (fp->ctf_names)); - - /* 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; - } - } + ctf_hash_size (fp->ctf_unions.ctn_readonly), nlunions); + ctf_dprintf ("%u base type names hashed\n", + ctf_hash_size (fp->ctf_names.ctn_readonly)); return 0; } @@ -937,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); @@ -986,8 +990,9 @@ static void flip_lbls (void *start, size_t len) { ctf_lblent_t *lbl = start; + ssize_t i; - for (ssize_t i = len / sizeof (struct ctf_lblent); i > 0; lbl++, i--) + for (i = len / sizeof (struct ctf_lblent); i > 0; lbl++, i--) { swap_thing (lbl->ctl_label); swap_thing (lbl->ctl_type); @@ -995,16 +1000,15 @@ 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) { uint32_t *obj = start; + ssize_t i; - for (ssize_t i = len / sizeof (uint32_t); i > 0; obj++, i--) + for (i = len / sizeof (uint32_t); i > 0; obj++, i--) swap_thing (*obj); } @@ -1014,8 +1018,9 @@ static void flip_vars (void *start, size_t len) { ctf_varent_t *var = start; + ssize_t i; - for (ssize_t i = len / sizeof (struct ctf_varent); i > 0; var++, i--) + for (i = len / sizeof (struct ctf_varent); i > 0; var++, i--) { swap_thing (var->ctv_name); swap_thing (var->ctv_type); @@ -1026,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 @@ -1080,8 +1107,9 @@ flip_types (void *start, size_t len) /* This type has a bunch of uint32_ts. */ uint32_t *item = (uint32_t *) t; + ssize_t i; - for (ssize_t i = vlen; i > 0; item++, i--) + for (i = vlen; i > 0; item++, i--) swap_thing (*item); break; } @@ -1125,7 +1153,8 @@ flip_types (void *start, size_t len) if (_libctf_unlikely_ (size >= CTF_LSTRUCT_THRESH)) { ctf_lmember_t *lm = (ctf_lmember_t *) t; - for (ssize_t i = vlen; i > 0; i--, lm++) + ssize_t i; + for (i = vlen; i > 0; i--, lm++) { swap_thing (lm->ctlm_name); swap_thing (lm->ctlm_offsethi); @@ -1136,7 +1165,8 @@ flip_types (void *start, size_t len) else { ctf_member_t *m = (ctf_member_t *) t; - for (ssize_t i = vlen; i > 0; i--, m++) + ssize_t i; + for (i = vlen; i > 0; i--, m++) { swap_thing (m->ctm_name); swap_thing (m->ctm_offset); @@ -1151,8 +1181,9 @@ flip_types (void *start, size_t len) /* This has an array of ctf_enum_t. */ ctf_enum_t *item = (ctf_enum_t *) t; + ssize_t i; - for (ssize_t i = vlen; i > 0; item++, i--) + for (i = vlen; i > 0; item++, i--) { swap_thing (item->cte_name); swap_thing (item->cte_value); @@ -1160,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; } @@ -1172,27 +1204,55 @@ 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_dict_t. Called by both writable and + non-writable dictionary initialization. */ +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. */ + fp->ctf_lookups[0].ctl_prefix = "struct"; + fp->ctf_lookups[0].ctl_len = strlen (fp->ctf_lookups[0].ctl_prefix); + fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; + fp->ctf_lookups[1].ctl_prefix = "union"; + fp->ctf_lookups[1].ctl_len = strlen (fp->ctf_lookups[1].ctl_prefix); + fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; + fp->ctf_lookups[2].ctl_prefix = "enum"; + fp->ctf_lookups[2].ctl_len = strlen (fp->ctf_lookups[2].ctl_prefix); + fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; + fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR; + fp->ctf_lookups[3].ctl_len = strlen (fp->ctf_lookups[3].ctl_prefix); + fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; + fp->ctf_lookups[4].ctl_prefix = NULL; + fp->ctf_lookups[4].ctl_len = 0; + fp->ctf_lookups[4].ctl_hash = NULL; } /* 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, @@ -1200,17 +1260,18 @@ ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size, { return ctf_simple_open_internal (ctfsect, ctfsect_size, symsect, symsect_size, symsect_entsize, strsect, strsect_size, NULL, - errp); + 0, errp); } /* 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, - ctf_dynhash_t *syn_strtab, int *errp) + ctf_dynhash_t *syn_strtab, int writable, + int *errp) { ctf_sect_t skeleton; @@ -1247,32 +1308,33 @@ ctf_file_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size, strsectp = &str_sect; } - return ctf_bufopen_internal (ctfsectp, symsectp, strsectp, syn_strtab, errp); + return ctf_bufopen_internal (ctfsectp, symsectp, strsectp, syn_strtab, + writable, errp); } /* 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) { - return ctf_bufopen_internal (ctfsect, symsect, strsect, NULL, errp); + return ctf_bufopen_internal (ctfsect, symsect, strsect, NULL, 0, errp); } /* 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 *errp) + int writable, int *errp) { 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; @@ -1330,25 +1392,37 @@ 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 = ctf_alloc (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 ((fp->ctf_header = ctf_alloc (sizeof (struct ctf_header))) == NULL) + if (writable) + fp->ctf_flags |= LCTF_RDWR; + + if ((fp->ctf_header = malloc (sizeof (struct ctf_header))) == NULL) { - ctf_free (fp); + free (fp); return (ctf_set_open_errno (errp, ENOMEM)); } hp = fp->ctf_header; @@ -1357,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; @@ -1368,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 @@ -1377,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 @@ -1403,7 +1514,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, /* We are allocating this ourselves, so we can drop the ctf header copy in favour of ctf->ctf_header. */ - if ((fp->ctf_base = ctf_alloc (fp->ctf_size)) == NULL) + if ((fp->ctf_base = malloc (fp->ctf_size)) == NULL) { err = ECTF_ZALLOC; goto bad; @@ -1418,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 = ctf_alloc (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 @@ -1463,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)); @@ -1474,11 +1604,23 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, } if (fp->ctf_data.cts_name != NULL) - fp->ctf_data.cts_name = ctf_strdup (fp->ctf_data.cts_name); + if ((fp->ctf_data.cts_name = strdup (fp->ctf_data.cts_name)) == NULL) + { + err = ENOMEM; + goto bad; + } if (fp->ctf_symtab.cts_name != NULL) - fp->ctf_symtab.cts_name = ctf_strdup (fp->ctf_symtab.cts_name); + if ((fp->ctf_symtab.cts_name = strdup (fp->ctf_symtab.cts_name)) == NULL) + { + err = ENOMEM; + goto bad; + } if (fp->ctf_strtab.cts_name != NULL) - fp->ctf_strtab.cts_name = ctf_strdup (fp->ctf_strtab.cts_name); + if ((fp->ctf_strtab.cts_name = strdup (fp->ctf_strtab.cts_name)) == NULL) + { + err = ENOMEM; + goto bad; + } if (fp->ctf_data.cts_name == NULL) fp->ctf_data.cts_name = _CTF_NULLSTR; @@ -1495,11 +1637,11 @@ 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 - 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. */ + /* 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. */ ctf_set_base (fp, hp, fp->ctf_base); goto bad; @@ -1507,47 +1649,46 @@ 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 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; + return fp; + } + 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) { fp->ctf_nsyms = symsect->cts_size / symsect->cts_entsize; - fp->ctf_sxlate = ctf_alloc (fp->ctf_nsyms * sizeof (uint32_t)); + fp->ctf_sxlate = malloc (fp->ctf_nsyms * sizeof (uint32_t)); if (fp->ctf_sxlate == NULL) { err = ENOMEM; goto bad; } - - if ((err = init_symtab (fp, hp, symsect, strsect)) != 0) - goto bad; } - /* Initialize the ctf_lookup_by_name top-level dictionary. We keep an - array of type name prefixes and the corresponding ctf_hash to use. - NOTE: This code must be kept in sync with the code in ctf_update(). */ - fp->ctf_lookups[0].ctl_prefix = "struct"; - fp->ctf_lookups[0].ctl_len = strlen (fp->ctf_lookups[0].ctl_prefix); - fp->ctf_lookups[0].ctl_hash = fp->ctf_structs; - fp->ctf_lookups[1].ctl_prefix = "union"; - fp->ctf_lookups[1].ctl_len = strlen (fp->ctf_lookups[1].ctl_prefix); - fp->ctf_lookups[1].ctl_hash = fp->ctf_unions; - fp->ctf_lookups[2].ctl_prefix = "enum"; - fp->ctf_lookups[2].ctl_len = strlen (fp->ctf_lookups[2].ctl_prefix); - fp->ctf_lookups[2].ctl_hash = fp->ctf_enums; - fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR; - fp->ctf_lookups[3].ctl_len = strlen (fp->ctf_lookups[3].ctl_prefix); - fp->ctf_lookups[3].ctl_hash = fp->ctf_names; - fp->ctf_lookups[4].ctl_prefix = NULL; - fp->ctf_lookups[4].ctl_len = 0; - fp->ctf_lookups[4].ctl_hash = NULL; + if ((err = init_symtab (fp, hp, symsect)) != 0) + goto bad; + + ctf_set_ctl_hashes (fp); if (symsect != NULL) { @@ -1564,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) { @@ -1590,9 +1745,17 @@ ctf_file_close (ctf_file_t *fp) return; } - ctf_free (fp->ctf_dyncuname); - ctf_free (fp->ctf_dynparname); - ctf_file_close (fp->ctf_parent); + /* 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); + 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) { @@ -1600,7 +1763,20 @@ ctf_file_close (ctf_file_t *fp) ctf_dtd_delete (fp, dtd); } ctf_dynhash_destroy (fp->ctf_dthash); - ctf_dynhash_destroy (fp->ctf_dtbyname); + if (fp->ctf_flags & LCTF_RDWR) + { + ctf_dynhash_destroy (fp->ctf_structs.ctn_writable); + ctf_dynhash_destroy (fp->ctf_unions.ctn_writable); + ctf_dynhash_destroy (fp->ctf_enums.ctn_writable); + ctf_dynhash_destroy (fp->ctf_names.ctn_writable); + } + else + { + ctf_hash_destroy (fp->ctf_structs.ctn_readonly); + ctf_hash_destroy (fp->ctf_unions.ctn_readonly); + ctf_hash_destroy (fp->ctf_enums.ctn_readonly); + ctf_hash_destroy (fp->ctf_names.ctn_readonly); + } for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd) { @@ -1608,35 +1784,69 @@ 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); - ctf_free (fp->ctf_tmp_typeslice); + free (fp->ctf_tmp_typeslice); if (fp->ctf_data.cts_name != _CTF_NULLSTR) - ctf_free ((char *) fp->ctf_data.cts_name); + free ((char *) fp->ctf_data.cts_name); if (fp->ctf_symtab.cts_name != _CTF_NULLSTR) - ctf_free ((char *) fp->ctf_symtab.cts_name); + free ((char *) fp->ctf_symtab.cts_name); if (fp->ctf_strtab.cts_name != _CTF_NULLSTR) - ctf_free ((char *) fp->ctf_strtab.cts_name); + free ((char *) fp->ctf_strtab.cts_name); else if (fp->ctf_data_mmapped) ctf_munmap (fp->ctf_data_mmapped, fp->ctf_data_mmapped_len); - ctf_free (fp->ctf_dynbase); + free (fp->ctf_dynbase); ctf_dynhash_destroy (fp->ctf_syn_ext_strtab); + 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_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); + } - ctf_free (fp->ctf_sxlate); - ctf_free (fp->ctf_txlate); - ctf_free (fp->ctf_ptrtab); + free (fp->ctf_sxlate); + free (fp->ctf_txlate); + free (fp->ctf_ptrtab); + free (fp->ctf_pptrtab); - ctf_hash_destroy (fp->ctf_structs); - ctf_hash_destroy (fp->ctf_unions); - ctf_hash_destroy (fp->ctf_enums); - ctf_hash_destroy (fp->ctf_names); + free (fp->ctf_header); + free (fp); +} - ctf_free (fp->ctf_header); - ctf_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 @@ -1647,76 +1857,115 @@ 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(). */ -extern ctf_sect_t -ctf_getdatasect (const ctf_file_t *fp) + ctf_getsect()/ ctf_dict_close()/free(). */ +ctf_sect_t +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; } /* Set the parent name. It is an error to call this routine without calling ctf_import() at some point. */ -void -ctf_parent_name_set (ctf_file_t *fp, const char *name) +int +ctf_parent_name_set (ctf_dict_t *fp, const char *name) { if (fp->ctf_dynparname != NULL) - ctf_free (fp->ctf_dynparname); + free (fp->ctf_dynparname); - fp->ctf_dynparname = ctf_strdup (name); + if ((fp->ctf_dynparname = strdup (name)) == NULL) + return (ctf_set_errno (fp, ENOMEM)); fp->ctf_parname = fp->ctf_dynparname; + return 0; } /* 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. */ -void -ctf_cuname_set (ctf_file_t *fp, const char *name) +int +ctf_cuname_set (ctf_dict_t *fp, const char *name) { if (fp->ctf_dyncuname != NULL) - ctf_free (fp->ctf_dyncuname); + free (fp->ctf_dyncuname); - fp->ctf_dyncuname = ctf_strdup (name); + if ((fp->ctf_dyncuname = strdup (name)) == NULL) + return (ctf_set_errno (fp, ENOMEM)); fp->ctf_cuname = fp->ctf_dyncuname; + 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)); @@ -1724,24 +1973,72 @@ 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) - ctf_file_close (fp->ctf_parent); + 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; + + 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; if (fp->ctf_parname == NULL) - ctf_parent_name_set (fp, "PARENT"); + if ((err = ctf_parent_name_set (fp, "PARENT")) < 0) + return err; + + fp->ctf_flags |= LCTF_CHILD; + 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; @@ -1757,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; }