/* Opening CTF files.
- Copyright (C) 2019 Free Software Foundation, Inc.
+ Copyright (C) 2019-2021 Free Software Foundation, Inc.
This file is part of libctf.
#include <string.h>
#include <sys/types.h>
#include <elf.h>
-#include <assert.h>
#include "swap.h"
#include <bfd.h>
#include <zlib.h>
-#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},
}
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,
}
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;
/* 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;
}
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,
}
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)
{
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)
{
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)
{
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},
{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 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;
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:
}
/* 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;
+ 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
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];
}
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;
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;
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);
}
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
/* 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)
{
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;
uint32_t id, dst;
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;
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. */
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;
(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)
if (((ctf_hash_lookup_type (fp->ctf_names.ctn_readonly,
fp, name)) == 0)
- || (flag & CTF_ADD_ROOT))
+ || isroot)
{
err = ctf_hash_define_type (fp->ctf_names.ctn_readonly, fp,
LCTF_INDEX_TO_TYPE (fp, id, child),
break;
case CTF_K_FUNCTION:
+ if (!isroot)
+ break;
+
err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp,
LCTF_INDEX_TO_TYPE (fp, id, child),
tp->ctt_name);
break;
case CTF_K_STRUCT:
+ 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:
+ 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:
+ if (!isroot)
+ break;
+
err = ctf_hash_define_type (fp->ctf_enums.ctn_readonly, fp,
LCTF_INDEX_TO_TYPE (fp, id, child),
tp->ctt_name);
break;
case CTF_K_TYPEDEF:
+ if (!isroot)
+ break;
+
err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp,
LCTF_INDEX_TO_TYPE (fp, id, child),
tp->ctt_name);
case CTF_K_FORWARD:
{
ctf_names_t *np = ctf_name_table (fp, tp->ctt_type);
+
+ if (!isroot)
+ 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)
}
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)
case CTF_K_VOLATILE:
case CTF_K_CONST:
case CTF_K_RESTRICT:
+ if (!isroot)
+ break;
+
err = ctf_hash_insert_type (fp->ctf_names.ctn_readonly, fp,
LCTF_INDEX_TO_TYPE (fp, id, child),
tp->ctt_name);
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;
}
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 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)
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)
{
ctf_type_t *t = start;
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);
+ size_t vbytes = get_vbytes_v2 (fp, kind, size, vlen);
if (_libctf_unlikely_ (size == CTF_LSIZE_SENT))
{
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;
}
data, this is no real loss. */
static int
-flip_ctf (ctf_header_t *cth, unsigned char *buf)
+flip_ctf (ctf_dict_t *fp, ctf_header_t *cth, unsigned char *buf)
{
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_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);
}
-/* 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. */
/* 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,
/* 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,
}
/* 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)
{
/* 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)
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;
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;
|| 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
|| 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 exists 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))
+ {
+ ctf_err_warn (NULL, 0, ECTF_CORRUPT,
+ _("Function index section exists 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
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;
}
}
/* 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
fp->ctf_syn_ext_strtab = syn_strtab;
if (foreign_endian &&
- (err = flip_ctf (hp, fp->ctf_buf)) != 0)
+ (err = flip_ctf (fp, hp, fp->ctf_buf)) != 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. */
+ 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;
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;
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)
{
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)
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)
{
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)
{
ctf_dvd_delete (fp, dvd);
}
ctf_dynhash_destroy (fp->ctf_dvhash);
+
+ 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);
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);
}
+/* 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
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;
}
/* 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);
}
/* 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);
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. */
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));
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;
+
+ 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;
+
if (pfp != NULL)
{
int err;
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;
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;
}