aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-util.c
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2020-11-23 21:17:44 +0000
committerNick Alcock <nick.alcock@oracle.com>2020-11-25 19:11:35 +0000
commit53651de80f811495262a5b17b774a486dd37b326 (patch)
tree597993b81493a294506b5b721204adebf995b0d9 /libctf/ctf-util.c
parentcbfa382abb360307c0c6b750e4c550a0d2b702d6 (diff)
downloadgdb-53651de80f811495262a5b17b774a486dd37b326.zip
gdb-53651de80f811495262a5b17b774a486dd37b326.tar.gz
gdb-53651de80f811495262a5b17b774a486dd37b326.tar.bz2
libctf, include: support foreign-endianness symtabs with CTF
The CTF symbol lookup machinery added recently has one deficit: it assumes the symtab is in the machine's native endianness. This is always true when the linker is writing out symtabs (because cross linkers byteswap symbols only after libctf has been called on them), but may be untrue in the cross case when the linker or another tool (objdump, etc) is reading them. Unfortunately the easy way to model this to the caller, as an endianness field in the ctf_sect_t, is precluded because doing so would change the size of the ctf_sect_t, which would be an ABI break. So, instead, allow the endianness of the symtab to be set after open time, by calling one of the two new API functions ctf_symsect_endianness (for ctf_dict_t's) or ctf_arc_symsect_endianness (for entire ctf_archive_t's). libctf calls these functions automatically for objects opened via any of the BFD-aware mechanisms (ctf_bfdopen, ctf_bfdopen_ctfsect, ctf_fdopen, ctf_open, or ctf_arc_open), but the various mechanisms that just take raw ctf_sect_t's will assume the symtab is in native endianness and need a later call to ctf_*symsect_endianness to adjust it if needed. (This call is basically free if the endianness is actually native: it only costs anything if the symtab endianness was previously guessed wrong, and there is a symtab, and we are using it directly rather than using symtab indexing.) Obviously, calling ctf_lookup_by_symbol or ctf_symbol_next before the symtab endianness is correctly set will probably give wrong answers -- but you can set it at any time as long as it is before then. include/ChangeLog 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. libctf/ChangeLog 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.
Diffstat (limited to 'libctf/ctf-util.c')
-rw-r--r--libctf/ctf-util.c62
1 files changed, 51 insertions, 11 deletions
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 0a15b86..ab34bc0 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -19,6 +19,7 @@
#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.
@@ -114,16 +115,35 @@ ctf_link_sym_t *
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;
}
@@ -134,22 +154,42 @@ ctf_link_sym_t *
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;
}