2019-04-23 22:45:30 +02:00
|
|
|
/* Miscellaneous utilities.
|
|
|
|
Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
This file is part of libctf.
|
|
|
|
|
|
|
|
libctf is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free
|
|
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
|
|
version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; see the file COPYING. If not see
|
|
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#include <ctf-impl.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/* Simple doubly-linked list append routine. This implementation assumes that
|
|
|
|
each list element contains an embedded ctf_list_t as the first member.
|
|
|
|
An additional ctf_list_t is used to store the head (l_next) and tail
|
|
|
|
(l_prev) pointers. The current head and tail list elements have their
|
|
|
|
previous and next pointers set to NULL, respectively. */
|
|
|
|
|
|
|
|
void
|
|
|
|
ctf_list_append (ctf_list_t *lp, void *newp)
|
|
|
|
{
|
|
|
|
ctf_list_t *p = lp->l_prev; /* p = tail list element. */
|
|
|
|
ctf_list_t *q = newp; /* q = new list element. */
|
|
|
|
|
|
|
|
lp->l_prev = q;
|
|
|
|
q->l_prev = p;
|
|
|
|
q->l_next = NULL;
|
|
|
|
|
|
|
|
if (p != NULL)
|
|
|
|
p->l_next = q;
|
|
|
|
else
|
|
|
|
lp->l_next = q;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prepend the specified existing element to the given ctf_list_t. The
|
|
|
|
existing pointer should be pointing at a struct with embedded ctf_list_t. */
|
|
|
|
|
|
|
|
void
|
|
|
|
ctf_list_prepend (ctf_list_t * lp, void *newp)
|
|
|
|
{
|
|
|
|
ctf_list_t *p = newp; /* p = new list element. */
|
|
|
|
ctf_list_t *q = lp->l_next; /* q = head list element. */
|
|
|
|
|
|
|
|
lp->l_next = p;
|
|
|
|
p->l_prev = NULL;
|
|
|
|
p->l_next = q;
|
|
|
|
|
|
|
|
if (q != NULL)
|
|
|
|
q->l_prev = p;
|
|
|
|
else
|
|
|
|
lp->l_prev = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete the specified existing element from the given ctf_list_t. The
|
|
|
|
existing pointer should be pointing at a struct with embedded ctf_list_t. */
|
|
|
|
|
|
|
|
void
|
|
|
|
ctf_list_delete (ctf_list_t *lp, void *existing)
|
|
|
|
{
|
|
|
|
ctf_list_t *p = existing;
|
|
|
|
|
|
|
|
if (p->l_prev != NULL)
|
|
|
|
p->l_prev->l_next = p->l_next;
|
|
|
|
else
|
|
|
|
lp->l_next = p->l_next;
|
|
|
|
|
|
|
|
if (p->l_next != NULL)
|
|
|
|
p->l_next->l_prev = p->l_prev;
|
|
|
|
else
|
|
|
|
lp->l_prev = p->l_prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert a 32-bit ELF symbol into Elf64 and return a pointer to it. */
|
|
|
|
|
|
|
|
Elf64_Sym *
|
|
|
|
ctf_sym_to_elf64 (const Elf32_Sym *src, Elf64_Sym *dst)
|
|
|
|
{
|
|
|
|
dst->st_name = src->st_name;
|
|
|
|
dst->st_value = src->st_value;
|
|
|
|
dst->st_size = src->st_size;
|
|
|
|
dst->st_info = src->st_info;
|
|
|
|
dst->st_other = src->st_other;
|
|
|
|
dst->st_shndx = src->st_shndx;
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Same as strdup(3C), but use ctf_alloc() to do the memory allocation. */
|
|
|
|
|
|
|
|
_libctf_malloc_ char *
|
|
|
|
ctf_strdup (const char *s1)
|
|
|
|
{
|
|
|
|
char *s2 = ctf_alloc (strlen (s1) + 1);
|
|
|
|
|
|
|
|
if (s2 != NULL)
|
|
|
|
(void) strcpy (s2, s1);
|
|
|
|
|
|
|
|
return s2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* A string appender working on dynamic strings. */
|
|
|
|
|
|
|
|
char *
|
|
|
|
ctf_str_append (char *s, const char *append)
|
|
|
|
{
|
|
|
|
size_t s_len = 0;
|
|
|
|
|
|
|
|
if (append == NULL)
|
|
|
|
return s;
|
|
|
|
|
|
|
|
if (s != NULL)
|
|
|
|
s_len = strlen (s);
|
|
|
|
|
|
|
|
size_t append_len = strlen (append);
|
|
|
|
|
|
|
|
if ((s = realloc (s, s_len + append_len + 1)) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memcpy (s + s_len, append, append_len);
|
|
|
|
s[s_len + append_len] = '\0';
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
libctf: deduplicate and sort the string table
ctf.h states:
> [...] the CTF string table does not contain any duplicated strings.
Unfortunately this is entirely untrue: libctf has before now made no
attempt whatsoever to deduplicate the string table. It computes the
string table's length on the fly as it adds new strings to the dynamic
CTF file, and ctf_update() just writes each string to the table and
notes the current write position as it traverses the dynamic CTF file's
data structures and builds the final CTF buffer. There is no global
view of the strings and no deduplication.
Fix this by erasing the ctf_dtvstrlen dead-reckoning length, and adding
a new dynhash table ctf_str_atoms that maps unique strings to a list
of references to those strings: a reference is a simple uint32_t * to
some value somewhere in the under-construction CTF buffer that needs
updating to note the string offset when the strtab is laid out.
Adding a string is now a simple matter of calling ctf_str_add_ref(),
which adds a new atom to the atoms table, if one doesn't already exist,
and adding the location of the reference to this atom to the refs list
attached to the atom: this works reliably as long as one takes care to
only call ctf_str_add_ref() once the final location of the offset is
known (so you can't call it on a temporary structure and then memcpy()
that structure into place in the CTF buffer, because the ref will still
point to the old location: ctf_update() changes accordingly).
Generating the CTF string table is a matter of calling
ctf_str_write_strtab(), which counts the length and number of elements
in the atoms table using the ctf_dynhash_iter() function we just added,
populating an array of pointers into the atoms table and sorting it into
order (to help compressors), then traversing this table and emitting it,
updating the refs to each atom as we go. The only complexity here is
arranging to keep the null string at offset zero, since a lot of code in
libctf depends on being able to leave strtab references at 0 to indicate
'no name'. Once the table is constructed and the refs updated, we know
how long it is, so we can realloc() the partial CTF buffer we allocated
earlier and can copy the table on to the end of it (and purge the refs
because they're not needed any more and have been invalidated by the
realloc() call in any case).
The net effect of all this is a reduction in uncompressed strtab sizes
of about 30% (perhaps a quarter to a half of all strings across the
Linux kernel are eliminated as duplicates). Of course, duplicated
strings are highly redundant, so the space saving after compression is
only about 20%: when the other non-strtab sections are factored in, CTF
sizes shrink by about 10%.
No change in externally-visible API or file format (other than the
reduction in pointless redundancy).
libctf/
* ctf-impl.h: (struct ctf_strs_writable): New, non-const version of
struct ctf_strs.
(struct ctf_dtdef): Note that dtd_data.ctt_name is unpopulated.
(struct ctf_str_atom): New, disambiguated single string.
(struct ctf_str_atom_ref): New, points to some other location that
references this string's offset.
(struct ctf_file): New members ctf_str_atoms and ctf_str_num_refs.
Remove member ctf_dtvstrlen: we no longer track the total strlen
as we add strings.
(ctf_str_create_atoms): Declare new function in ctf-string.c.
(ctf_str_free_atoms): Likewise.
(ctf_str_add): Likewise.
(ctf_str_add_ref): Likewise.
(ctf_str_purge_refs): Likewise.
(ctf_str_write_strtab): Likewise.
(ctf_realloc): Declare new function in ctf-util.c.
* ctf-open.c (ctf_bufopen): Create the atoms table.
(ctf_file_close): Destroy it.
* ctf-create.c (ctf_update): Copy-and-free it on update. No longer
special-case the position of the parname string. Construct the
strtab by calling ctf_str_add_ref and ctf_str_write_strtab after the
rest of each buffer element is constructed, not via open-coding:
realloc the CTF buffer and append the strtab to it. No longer
maintain ctf_dtvstrlen. Sort the variable entry table later, after
strtab construction.
(ctf_copy_membnames): Remove: integrated into ctf_copy_{s,l,e}members.
(ctf_copy_smembers): Drop the string offset: call ctf_str_add_ref
after buffer element construction instead.
(ctf_copy_lmembers): Likewise.
(ctf_copy_emembers): Likewise.
(ctf_create): No longer maintain the ctf_dtvstrlen.
(ctf_dtd_delete): Likewise.
(ctf_dvd_delete): Likewise.
(ctf_add_generic): Likewise.
(ctf_add_enumerator): Likewise.
(ctf_add_member_offset): Likewise.
(ctf_add_variable): Likewise.
(membadd): Likewise.
* ctf-util.c (ctf_realloc): New, wrapper around realloc that aborts
if there are active ctf_str_num_refs.
(ctf_strraw): Move to ctf-string.c.
(ctf_strptr): Likewise.
* ctf-string.c: New file, strtab manipulation.
* Makefile.am (libctf_a_SOURCES): Add it.
* Makefile.in: Regenerate.
2019-06-27 14:51:10 +02:00
|
|
|
/* A realloc() that fails noisily if called with any ctf_str_num_users. */
|
|
|
|
void *
|
|
|
|
ctf_realloc (ctf_file_t *fp, void *ptr, size_t size)
|
|
|
|
{
|
|
|
|
if (fp->ctf_str_num_refs > 0)
|
|
|
|
{
|
|
|
|
ctf_dprintf ("%p: attempt to realloc() string table with %lu active refs\n",
|
|
|
|
(void *) fp, (unsigned long) fp->ctf_str_num_refs);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return realloc (ptr, size);
|
|
|
|
}
|
|
|
|
|
2019-04-23 22:45:30 +02:00
|
|
|
/* Store the specified error code into errp if it is non-NULL, and then
|
|
|
|
return NULL for the benefit of the caller. */
|
|
|
|
|
|
|
|
void *
|
|
|
|
ctf_set_open_errno (int *errp, int error)
|
|
|
|
{
|
|
|
|
if (errp != NULL)
|
|
|
|
*errp = error;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the specified error code into the CTF container, and then return
|
libctf: fix a number of build problems found on Solaris and NetBSD
- Use of nonportable <endian.h>
- Use of qsort_r
- Use of zlib without appropriate magic to pull in the binutils zlib
- Use of off64_t without checking (fixed by dropping the unused fields
that need off64_t entirely)
- signedness problems due to long being too short a type on 32-bit
platforms: ctf_id_t is now 'unsigned long', and CTF_ERR must be
used only for functions that return ctf_id_t
- One lingering use of bzero() and of <sys/errno.h>
All fixed, using code from gnulib where possible.
Relatedly, set cts_size in a couple of places it was missed
(string table and symbol table loading upon ctf_bfdopen()).
binutils/
* objdump.c (make_ctfsect): Drop cts_type, cts_flags, and
cts_offset.
* readelf.c (shdr_to_ctf_sect): Likewise.
include/
* ctf-api.h (ctf_sect_t): Drop cts_type, cts_flags, and cts_offset.
(ctf_id_t): This is now an unsigned type.
(CTF_ERR): Cast it to ctf_id_t. Note that it should only be used
for ctf_id_t-returning functions.
libctf/
* Makefile.am (ZLIB): New.
(ZLIBINC): Likewise.
(AM_CFLAGS): Use them.
(libctf_a_LIBADD): New, for LIBOBJS.
* configure.ac: Check for zlib, endian.h, and qsort_r.
* ctf-endian.h: New, providing htole64 and le64toh.
* swap.h: Code style fixes.
(bswap_identity_64): New.
* qsort_r.c: New, from gnulib (with one added #include).
* ctf-decls.h: New, providing a conditional qsort_r declaration,
and unconditional definitions of MIN and MAX.
* ctf-impl.h: Use it. Do not use <sys/errno.h>.
(ctf_set_errno): Now returns unsigned long.
* ctf-util.c (ctf_set_errno): Adjust here too.
* ctf-archive.c: Use ctf-endian.h.
(ctf_arc_open_by_offset): Use memset, not bzero. Drop cts_type,
cts_flags and cts_offset.
(ctf_arc_write): Drop debugging dependent on the size of off_t.
* ctf-create.c: Provide a definition of roundup if not defined.
(ctf_create): Drop cts_type, cts_flags and cts_offset.
(ctf_add_reftype): Do not check if type IDs are below zero.
(ctf_add_slice): Likewise.
(ctf_add_typedef): Likewise.
(ctf_add_member_offset): Cast error-returning ssize_t's to size_t
when known error-free. Drop CTF_ERR usage for functions returning
int.
(ctf_add_member_encoded): Drop CTF_ERR usage for functions returning
int.
(ctf_add_variable): Likewise.
(enumcmp): Likewise.
(enumadd): Likewise.
(membcmp): Likewise.
(ctf_add_type): Likewise. Cast error-returning ssize_t's to size_t
when known error-free.
* ctf-dump.c (ctf_is_slice): Drop CTF_ERR usage for functions
returning int: use CTF_ERR for functions returning ctf_type_id.
(ctf_dump_label): Likewise.
(ctf_dump_objts): Likewise.
* ctf-labels.c (ctf_label_topmost): Likewise.
(ctf_label_iter): Likewise.
(ctf_label_info): Likewise.
* ctf-lookup.c (ctf_func_args): Likewise.
* ctf-open.c (upgrade_types): Cast to size_t where appropriate.
(ctf_bufopen): Likewise. Use zlib types as needed.
* ctf-types.c (ctf_member_iter): Drop CTF_ERR usage for functions
returning int.
(ctf_enum_iter): Likewise.
(ctf_type_size): Likewise.
(ctf_type_align): Likewise. Cast to size_t where appropriate.
(ctf_type_kind_unsliced): Likewise.
(ctf_type_kind): Likewise.
(ctf_type_encoding): Likewise.
(ctf_member_info): Likewise.
(ctf_array_info): Likewise.
(ctf_enum_value): Likewise.
(ctf_type_rvisit): Likewise.
* ctf-open-bfd.c (ctf_bfdopen): Drop cts_type, cts_flags and
cts_offset.
(ctf_simple_open): Likewise.
(ctf_bfdopen_ctfsect): Likewise. Set cts_size properly.
* Makefile.in: Regenerate.
* aclocal.m4: Likewise.
* config.h: Likewise.
* configure: Likewise.
2019-05-31 11:10:51 +02:00
|
|
|
CTF_ERR / -1 for the benefit of the caller. */
|
2019-04-23 22:45:30 +02:00
|
|
|
|
libctf: fix a number of build problems found on Solaris and NetBSD
- Use of nonportable <endian.h>
- Use of qsort_r
- Use of zlib without appropriate magic to pull in the binutils zlib
- Use of off64_t without checking (fixed by dropping the unused fields
that need off64_t entirely)
- signedness problems due to long being too short a type on 32-bit
platforms: ctf_id_t is now 'unsigned long', and CTF_ERR must be
used only for functions that return ctf_id_t
- One lingering use of bzero() and of <sys/errno.h>
All fixed, using code from gnulib where possible.
Relatedly, set cts_size in a couple of places it was missed
(string table and symbol table loading upon ctf_bfdopen()).
binutils/
* objdump.c (make_ctfsect): Drop cts_type, cts_flags, and
cts_offset.
* readelf.c (shdr_to_ctf_sect): Likewise.
include/
* ctf-api.h (ctf_sect_t): Drop cts_type, cts_flags, and cts_offset.
(ctf_id_t): This is now an unsigned type.
(CTF_ERR): Cast it to ctf_id_t. Note that it should only be used
for ctf_id_t-returning functions.
libctf/
* Makefile.am (ZLIB): New.
(ZLIBINC): Likewise.
(AM_CFLAGS): Use them.
(libctf_a_LIBADD): New, for LIBOBJS.
* configure.ac: Check for zlib, endian.h, and qsort_r.
* ctf-endian.h: New, providing htole64 and le64toh.
* swap.h: Code style fixes.
(bswap_identity_64): New.
* qsort_r.c: New, from gnulib (with one added #include).
* ctf-decls.h: New, providing a conditional qsort_r declaration,
and unconditional definitions of MIN and MAX.
* ctf-impl.h: Use it. Do not use <sys/errno.h>.
(ctf_set_errno): Now returns unsigned long.
* ctf-util.c (ctf_set_errno): Adjust here too.
* ctf-archive.c: Use ctf-endian.h.
(ctf_arc_open_by_offset): Use memset, not bzero. Drop cts_type,
cts_flags and cts_offset.
(ctf_arc_write): Drop debugging dependent on the size of off_t.
* ctf-create.c: Provide a definition of roundup if not defined.
(ctf_create): Drop cts_type, cts_flags and cts_offset.
(ctf_add_reftype): Do not check if type IDs are below zero.
(ctf_add_slice): Likewise.
(ctf_add_typedef): Likewise.
(ctf_add_member_offset): Cast error-returning ssize_t's to size_t
when known error-free. Drop CTF_ERR usage for functions returning
int.
(ctf_add_member_encoded): Drop CTF_ERR usage for functions returning
int.
(ctf_add_variable): Likewise.
(enumcmp): Likewise.
(enumadd): Likewise.
(membcmp): Likewise.
(ctf_add_type): Likewise. Cast error-returning ssize_t's to size_t
when known error-free.
* ctf-dump.c (ctf_is_slice): Drop CTF_ERR usage for functions
returning int: use CTF_ERR for functions returning ctf_type_id.
(ctf_dump_label): Likewise.
(ctf_dump_objts): Likewise.
* ctf-labels.c (ctf_label_topmost): Likewise.
(ctf_label_iter): Likewise.
(ctf_label_info): Likewise.
* ctf-lookup.c (ctf_func_args): Likewise.
* ctf-open.c (upgrade_types): Cast to size_t where appropriate.
(ctf_bufopen): Likewise. Use zlib types as needed.
* ctf-types.c (ctf_member_iter): Drop CTF_ERR usage for functions
returning int.
(ctf_enum_iter): Likewise.
(ctf_type_size): Likewise.
(ctf_type_align): Likewise. Cast to size_t where appropriate.
(ctf_type_kind_unsliced): Likewise.
(ctf_type_kind): Likewise.
(ctf_type_encoding): Likewise.
(ctf_member_info): Likewise.
(ctf_array_info): Likewise.
(ctf_enum_value): Likewise.
(ctf_type_rvisit): Likewise.
* ctf-open-bfd.c (ctf_bfdopen): Drop cts_type, cts_flags and
cts_offset.
(ctf_simple_open): Likewise.
(ctf_bfdopen_ctfsect): Likewise. Set cts_size properly.
* Makefile.in: Regenerate.
* aclocal.m4: Likewise.
* config.h: Likewise.
* configure: Likewise.
2019-05-31 11:10:51 +02:00
|
|
|
unsigned long
|
2019-04-23 22:45:30 +02:00
|
|
|
ctf_set_errno (ctf_file_t * fp, int err)
|
|
|
|
{
|
|
|
|
fp->ctf_errno = err;
|
|
|
|
return CTF_ERR;
|
|
|
|
}
|