+2020-11-23 Nick Alcock <nick.alcock@oracle.com>
+
+ * ctf-api.h: Style nit: remove () on function names in comments.
+ (ctf_sect_t): Mention endianness concerns.
+ (ctf_symsect_endianness): New declaration.
+ (ctf_arc_symsect_endianness): Likewise.
+
2020-11-20 Nick Alcock <nick.alcock@oracle.com>
* ctf-api.h (ctf_getsymsect): New.
/* If the debugger needs to provide the CTF library with a set of raw buffers
for use as the CTF data, symbol table, and string table, it can do so by
- filling in ctf_sect_t structures and passing them to ctf_bufopen().
+ filling in ctf_sect_t structures and passing them to ctf_bufopen.
- The contents of this structure must always be in native endianness (no
- byteswapping is performed). */
+ The contents of this structure must always be in native endianness. At read
+ time, the symbol table endianness is derived from the BFD target (if BFD is
+ in use): if a BFD target is not in use, please call ctf_symsect_endianness or
+ ctf_arc_symsect_endianness. */
typedef struct ctf_sect
{
/* A minimal symbol extracted from a linker's internal symbol table
representation. The symbol name can be given either via st_name or via a
strtab offset in st_nameidx, which corresponds to one of the string offsets
- communicated via the ctf_link_add_strtab callback. */
+ communicated via the ctf_link_add_strtab callback. */
typedef struct ctf_link_sym
{
/* The st_name and st_nameidx will not be accessed outside the call to
- ctf_link_shuffle_syms(). If you set st_nameidx to offset zero, make sure
+ ctf_link_shuffle_syms. If you set st_nameidx to offset zero, make sure
to set st_nameidx_set as well. */
const char *st_name;
} ctf_sect_names_t;
/* Encoding information for integers, floating-point values, and certain other
- intrinsics can be obtained by calling ctf_type_encoding(), below. The flags
+ intrinsics can be obtained by calling ctf_type_encoding, below. The flags
field will contain values appropriate for the type defined in <ctf.h>. */
typedef struct ctf_encoding
#define CTF_FUNC_VARARG 0x1 /* Function arguments end with varargs. */
/* Functions that return a ctf_id_t use the following value to indicate failure.
- ctf_errno() can be used to obtain an error code. Functions that return
- a straight integral -1 also use ctf_errno(). */
+ ctf_errno can be used to obtain an error code. Functions that return
+ a straight integral -1 also use ctf_errno. */
#define CTF_ERR ((ctf_id_t) -1L)
/* This macro holds information about all the available ctf errors.
#define ECTF_NERR (ECTF_NEEDSBFD - ECTF_BASE + 1) /* Count of CTF errors. */
/* The CTF data model is inferred to be the caller's data model or the data
- model of the given object, unless ctf_setmodel() is explicitly called. */
+ model of the given object, unless ctf_setmodel is explicitly called. */
#define CTF_MODEL_ILP32 1 /* Object data model is ILP32. */
#define CTF_MODEL_LP64 2 /* Object data model is LP64. */
#ifdef _LP64
# define CTF_MODEL_NATIVE CTF_MODEL_ILP32
#endif
-/* Dynamic CTF containers can be created using ctf_create(). The ctf_add_*
+/* Dynamic CTF containers can be created using ctf_create. The ctf_add_*
routines can be used to add new definitions to the dynamic container.
New types are labeled as root or non-root to determine whether they are
visible at the top-level program scope when subsequently doing a lookup. */
typedef struct ctf_dump_state ctf_dump_state_t;
-/* Iteration state for the _next() functions, and allocators/copiers/freers for
+/* Iteration state for the _next functions, and allocators/copiers/freers for
it. (None of these are needed for the simple case of iterating to the end:
- the _next() function allocate and free the iterators for you.) */
+ the _next function allocate and free the iterators for you.) */
typedef struct ctf_next ctf_next_t;
extern ctf_next_t *ctf_next_create (void);
/* Opening. These mostly return an abstraction over both CTF files and CTF
archives: so they can be used to open both. CTF files will appear to be an
archive with one member named '.ctf'. The low-level functions
- ctf_simple_open() and ctf_bufopen() return ctf_dict_t's directly, and cannot
+ ctf_simple_open and ctf_bufopen return ctf_dict_t's directly, and cannot
be used on CTF archives. */
extern ctf_archive_t *ctf_bfdopen (struct bfd *, int *);
extern ctf_sect_t ctf_getdatasect (const ctf_dict_t *);
extern ctf_sect_t ctf_getsymsect (const ctf_dict_t *);
extern ctf_sect_t ctf_getstrsect (const ctf_dict_t *);
+extern void ctf_symsect_endianness (ctf_dict_t *, int little_endian);
extern ctf_archive_t *ctf_get_arc (const ctf_dict_t *);
extern ctf_archive_t *ctf_arc_open (const char *, int *);
extern ctf_archive_t *ctf_arc_bufopen (const ctf_sect_t *,
const ctf_sect_t *,
const ctf_sect_t *,
int *);
+extern void ctf_arc_symsect_endianness (ctf_archive_t *, int little_endian);
extern void ctf_arc_close (ctf_archive_t *);
extern ctf_dict_t *ctf_arc_lookup_symbol (ctf_archive_t *,
unsigned long symidx,
+2020-11-23 Nick Alcock <nick.alcock@oracle.com>
+
+ * ctf-impl.h (ctf_dict_t) <ctf_symtab_little_endian>: New.
+ (struct ctf_archive_internal) <ctfi_symsect_little_endian>: Likewise.
+ * ctf-create.c (ctf_serialize): Adjust for new field.
+ * ctf-open.c (init_symtab): Note the semantics of repeated calls.
+ (ctf_symsect_endianness): New.
+ (ctf_bufopen_internal): Set ctf_symtab_little_endian suitably for
+ the native endianness.
+ (_Static_assert): Moved...
+ (swap_thing): ... with this...
+ * swap.h: ... to here.
+ * ctf-util.c (ctf_elf32_to_link_sym): Use it, byteswapping the
+ Elf32_Sym if the ctf_symtab_little_endian demands it.
+ (ctf_elf64_to_link_sym): Likewise swap the Elf64_Sym if needed.
+ * ctf-archive.c (ctf_arc_symsect_endianness): New, set the
+ endianness of the symtab used by the dicts in an archive.
+ (ctf_archive_iter_internal): Initialize to unknown (assumed native,
+ do not call ctf_symsect_endianness).
+ (ctf_dict_open_by_offset): Call ctf_symsect_endianness if need be.
+ (ctf_dict_open_internal): Propagate the endianness down.
+ (ctf_dict_open_sections): Likewise.
+ * ctf-open-bfd.c (ctf_bfdopen_ctfsect): Get the endianness from the
+ struct bfd and pass it down to the archive.
+ * libctf.ver: Add ctf_symsect_endianness and
+ ctf_arc_symsect_endianness.
+
2020-11-20 Nick Alcock <nick.alcock@oracle.com>
* ctf-link.c (ctf_link_deduplicating): Clean up the ctf_link_outputs
static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive *arc,
const ctf_sect_t *symsect,
const ctf_sect_t *strsect,
- size_t offset, int *errp);
+ size_t offset, int little_endian,
+ int *errp);
static int sort_modent_by_name (const void *one, const void *two, void *n);
static void *arc_mmap_header (int fd, size_t headersz);
static void *arc_mmap_file (int fd, size_t size);
arci->ctfi_free_symsect = 0;
arci->ctfi_free_strsect = 0;
arci->ctfi_unmap_on_close = unmap_on_close;
+ arci->ctfi_symsect_little_endian = -1;
return arci;
}
+/* Set the symbol-table endianness of an archive (defaulting the symtab
+ endianness of all ctf_file_t's opened from that archive). */
+void
+ctf_arc_symsect_endianness (ctf_archive_t *arc, int little_endian)
+{
+ arc->ctfi_symsect_little_endian = !!little_endian;
+ if (!arc->ctfi_is_archive)
+ ctf_symsect_endianness (arc->ctfi_dict, arc->ctfi_symsect_little_endian);
+}
+
/* Get the CTF preamble from data in a buffer, which may be either an archive or
a CTF dict. If multiple dicts are present in an archive, the preamble comes
from an arbitrary dict. The preamble is a pointer into the ctfsect passed
ctf_dict_open_internal (const struct ctf_archive *arc,
const ctf_sect_t *symsect,
const ctf_sect_t *strsect,
- const char *name, int *errp)
+ const char *name, int little_endian,
+ int *errp)
{
struct ctf_archive_modent *modent;
const char *search_nametbl;
}
return ctf_dict_open_by_offset (arc, symsect, strsect,
- le64toh (modent->ctf_offset), errp);
+ le64toh (modent->ctf_offset),
+ little_endian, errp);
}
/* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
{
ctf_dict_t *ret;
ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect,
- name, errp);
+ name, arc->ctfi_symsect_little_endian,
+ errp);
if (ret)
{
ret->ctf_archive = (ctf_archive_t *) arc;
ctf_dict_open_by_offset (const struct ctf_archive *arc,
const ctf_sect_t *symsect,
const ctf_sect_t *strsect, size_t offset,
- int *errp)
+ int little_endian, int *errp)
{
ctf_sect_t ctfsect;
ctf_dict_t *fp;
ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
fp = ctf_bufopen (&ctfsect, symsect, strsect, errp);
if (fp)
- ctf_setmodel (fp, le64toh (arc->ctfa_model));
+ {
+ ctf_setmodel (fp, le64toh (arc->ctfa_model));
+ if (little_endian >= 0)
+ ctf_symsect_endianness (fp, little_endian);
+ }
return fp;
}
name = &nametbl[le64toh (modent[i].name_offset)];
if ((f = ctf_dict_open_internal (arc, symsect, strsect,
- name, &rc)) == NULL)
+ name,
+ wrapper->ctfi_symsect_little_endian,
+ &rc)) == NULL)
return rc;
f->ctf_archive = (ctf_archive_t *) wrapper;
nfp->ctf_link_memb_name_changer_arg = fp->ctf_link_memb_name_changer_arg;
nfp->ctf_link_variable_filter = fp->ctf_link_variable_filter;
nfp->ctf_link_variable_filter_arg = fp->ctf_link_variable_filter_arg;
+ nfp->ctf_symsect_little_endian = fp->ctf_symsect_little_endian;
nfp->ctf_link_flags = fp->ctf_link_flags;
nfp->ctf_dedup_atoms = fp->ctf_dedup_atoms;
nfp->ctf_dedup_atoms_alloc = fp->ctf_dedup_atoms_alloc;
ctf_sect_t ctf_data; /* CTF data from object file. */
ctf_sect_t ctf_symtab; /* Symbol table from object file. */
ctf_sect_t ctf_strtab; /* String table from object file. */
+ int ctf_symsect_little_endian; /* Endianness of the ctf_symtab. */
ctf_dynhash_t *ctf_prov_strtab; /* Maps provisional-strtab offsets
to names. */
ctf_dynhash_t *ctf_syn_ext_strtab; /* Maps ext-strtab offsets to names. */
ctf_dict_t **ctfi_symdicts; /* Array of index -> ctf_dict_t *. */
ctf_id_t *ctfi_syms; /* Array of index -> ctf_id_t. */
ctf_sect_t ctfi_symsect;
+ int ctfi_symsect_little_endian; /* -1 for unknown / do not set. */
ctf_sect_t ctfi_strsect;
int ctfi_free_symsect;
int ctfi_free_strsect;
ctf_sect_t *strsectp = NULL;
const char *bfderrstr = NULL;
char *strtab_alloc = NULL;
+ int symsect_endianness = -1;
#ifdef HAVE_BFD_ELF
ctf_sect_t symsect, strsect;
symsect.cts_data = symtab;
symsectp = &symsect;
}
+
+ symsect_endianness = bfd_little_endian (abfd);
#endif
arci = ctf_arc_bufopen (ctfsect, symsectp, strsectp, errp);
arci->ctfi_free_symsect = 1;
if (strtab_alloc)
arci->ctfi_free_strsect = 1;
+
+ /* Get the endianness right. */
+ if (symsect_endianness > -1)
+ ctf_arc_symsect_endianness (arci, symsect_endianness);
return arci;
}
#ifdef HAVE_BFD_ELF
#include <string.h>
#include <sys/types.h>
#include <elf.h>
-#include <assert.h>
#include "swap.h"
#include <bfd.h>
#include <zlib.h>
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. */
+ 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_dict_t *fp, const ctf_header_t *hp, const ctf_sect_t *sp)
return ECTF_SYMTAB;
}
+ /* 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;
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
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. */
+ 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)
{
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 *
#include <ctf-impl.h>
#include <string.h>
+#include "ctf-endian.h"
/* Simple doubly-linked list append routine. This implementation assumes that
each list element contains an embedded ctf_list_t as the first member.
ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf32_Sym *src,
uint32_t symidx)
{
+ Elf32_Sym tmp;
+ int needs_flipping = 0;
+
+#ifdef WORDS_BIGENDIAN
+ if (fp->ctf_symsect_little_endian)
+ needs_flipping = 1;
+#else
+ if (!fp->ctf_symsect_little_endian)
+ needs_flipping = 1;
+#endif
+
+ memcpy (&tmp, src, sizeof (Elf32_Sym));
+ if (needs_flipping)
+ {
+ swap_thing (tmp.st_name);
+ swap_thing (tmp.st_size);
+ swap_thing (tmp.st_shndx);
+ swap_thing (tmp.st_value);
+ }
/* The name must be in the external string table. */
- if (src->st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
- dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + src->st_name;
+ if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
+ dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name;
else
dst->st_name = _CTF_NULLSTR;
dst->st_nameidx_set = 0;
dst->st_symidx = symidx;
- dst->st_shndx = src->st_shndx;
- dst->st_type = ELF32_ST_TYPE (src->st_info);
- dst->st_value = src->st_value;
+ dst->st_shndx = tmp.st_shndx;
+ dst->st_type = ELF32_ST_TYPE (tmp.st_info);
+ dst->st_value = tmp.st_value;
return dst;
}
ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src,
uint32_t symidx)
{
+ Elf64_Sym tmp;
+ int needs_flipping = 0;
+
+#ifdef WORDS_BIGENDIAN
+ if (fp->ctf_symsect_little_endian)
+ needs_flipping = 1;
+#else
+ if (!fp->ctf_symsect_little_endian)
+ needs_flipping = 1;
+#endif
+
+ memcpy (&tmp, src, sizeof (Elf64_Sym));
+ if (needs_flipping)
+ {
+ swap_thing (tmp.st_name);
+ swap_thing (tmp.st_size);
+ swap_thing (tmp.st_shndx);
+ swap_thing (tmp.st_value);
+ }
+
/* The name must be in the external string table. */
- if (src->st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
- dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + src->st_name;
+ if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
+ dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name;
else
dst->st_name = _CTF_NULLSTR;
dst->st_nameidx_set = 0;
dst->st_symidx = symidx;
- dst->st_shndx = src->st_shndx;
- dst->st_type = ELF32_ST_TYPE (src->st_info);
+ dst->st_shndx = tmp.st_shndx;
+ dst->st_type = ELF32_ST_TYPE (tmp.st_info);
/* We only care if the value is zero, so avoid nonzeroes turning into
zeroes. */
- if (_libctf_unlikely_ (src->st_value != 0 && ((uint32_t) src->st_value == 0)))
+ if (_libctf_unlikely_ (tmp.st_value != 0 && ((uint32_t) tmp.st_value == 0)))
dst->st_value = 1;
else
- dst->st_value = (uint32_t) src->st_value;
+ dst->st_value = (uint32_t) tmp.st_value;
return dst;
}
ctf_getsymsect;
ctf_getstrsect;
+ ctf_symsect_endianness;
+ ctf_arc_symsect_endianness;
} LIBCTF_1.0;
#include "config.h"
#include <stdint.h>
+#include <assert.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
}
#endif /* !HAVE_DECL_BSWAP64 */
+/* < 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);
+
+
#endif /* !defined(_CTF_SWAP_H) */