From 934a437c9a607c25bfa5ee6e678ca9b74d7f9ff6 Mon Sep 17 00:00:00 2001 From: Navin P Date: Thu, 12 Nov 2020 22:12:36 +0530 Subject: [PATCH] Make elfutils compile with clang Signed-off-by: Navin P --- backends/Makefile.am | 10 +- config/eu.am | 33 +- configure.ac | 15 +- debuginfod/debuginfod-client.c | 4 +- libasm/asm_newscn.c | 6 +- libdwfl/dwfl_segment_report_module.c | 713 ++++++++++++++++----------- libdwfl/elf-from-memory.c | 122 +++-- libdwfl/link_map.c | 171 ++++--- libelf/elf.h | 1 + src/addr2line.c | 43 +- src/ar.c | 31 +- src/arlib-argp.c | 13 +- src/elfcompress.c | 350 ++++++++----- src/elflint.c | 56 +-- src/readelf.c | 152 +++--- src/strip.c | 333 +++++++------ src/unstrip.c | 150 +++--- tests/elfstrmerge.c | 108 ++-- tests/zstrptr.c | 44 +- 19 files changed, 1385 insertions(+), 970 deletions(-) diff --git a/backends/Makefile.am b/backends/Makefile.am index 62916c9c..1e3cbffd 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -34,6 +34,8 @@ endif AM_CPPFLAGS += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \ -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw + + noinst_LIBRARIES = libebl_backends.a libebl_backends_pic.a modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \ @@ -80,12 +82,7 @@ s390_SRCS = s390_init.c s390_symbol.c s390_regs.c s390_retval.c \ m68k_SRCS = m68k_init.c m68k_symbol.c m68k_regs.c \ m68k_retval.c m68k_corenote.c m68k_cfi.c m68k_initreg.c -# m68k prstatus core notes are described by a packed structure -# which has not naturally aligned fields. Since we don't access -# these fields directly, but take their offset to be used later -# to extract the data through elfxx_xlatetom/memmove, this isn't -# an issue. -m68k_corenote_no_Wpacked_not_aligned = yes + bpf_SRCS = bpf_init.c bpf_regs.c bpf_symbol.c @@ -108,3 +105,4 @@ noinst_HEADERS = libebl_CPU.h common-reloc.c linux-core-note.c x86_corenote.c EXTRA_DIST = $(modules:=_reloc.def) MOSTLYCLEANFILES = $(am_libebl_backends_pic_a_OBJECTS) + diff --git a/config/eu.am b/config/eu.am index 6c3c444f..0ed87125 100644 --- a/config/eu.am +++ b/config/eu.am @@ -29,6 +29,8 @@ ## not, see . ## + + DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DLOCALEDIR='"${localedir}"' AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_srcdir)/lib -I.. @@ -64,30 +66,51 @@ endif if HAVE_IMPLICIT_FALLTHROUGH_WARNING # Use strict fallthrough. Only __attribute__((fallthrough)) will prevent the # warning -IMPLICIT_FALLTHROUGH_WARNING=-Wimplicit-fallthrough=5 + if IS_CLANG_COMPILER + IMPLICIT_FALLTHROUGH_WARNING=-Wimplicit-fallthrough + else + IMPLICIT_FALLTHROUGH_WARNING=-Wimplicit-fallthrough=5 + endif else IMPLICIT_FALLTHROUGH_WARNING= endif +# m68k prstatus core notes are described by a packed structure +# which has not naturally aligned fields. Since we don't access +# these fields directly, but take their offset to be used later +# to extract the data through elfxx_xlatetom/memmove, this isn't +# an issue. +# + +if IS_CLANG_COMPILER + TRAMPOLINES_WARNING= + NO_XOR_USED_AS_POW=-Wno-xor-used-as-pow + m68k_corenote_no_Wpacked_not_aligned = +else + TRAMPOLINES_WARNING=-Wtrampolines + NO_XOR_USED_AS_POW= + m68k_corenote_no_Wpacked_not_aligned = yes +endif + AM_CFLAGS = -std=gnu99 -Wall -Wshadow -Wformat=2 \ - -Wold-style-definition -Wstrict-prototypes -Wtrampolines \ + -Wold-style-definition -Wstrict-prototypes $(TRAMPOLINES_WARNING) \ $(LOGICAL_OP_WARNING) $(DUPLICATED_COND_WARNING) \ $(NULL_DEREFERENCE_WARNING) $(IMPLICIT_FALLTHROUGH_WARNING) \ $(if $($(*F)_no_Werror),,-Werror) \ $(if $($(*F)_no_Wunused),,-Wunused -Wextra) \ $(if $($(*F)_no_Wstack_usage),,$(STACK_USAGE_WARNING)) \ $(if $($(*F)_no_Wpacked_not_aligned),-Wno-packed-not-aligned,) \ - $($(*F)_CFLAGS) + $($(*F)_CFLAGS) $(NO_XOR_USED_AS_POW) AM_CXXFLAGS = -std=c++11 -Wall -Wshadow \ - -Wtrampolines \ + $(TRAMPOLINES_WARNING) \ $(LOGICAL_OP_WARNING) $(DUPLICATED_COND_WARNING) \ $(NULL_DEREFERENCE_WARNING) $(IMPLICIT_FALLTHROUGH_WARNING) \ $(if $($(*F)_no_Werror),,-Werror) \ $(if $($(*F)_no_Wunused),,-Wunused -Wextra) \ $(if $($(*F)_no_Wstack_usage),,$(STACK_USAGE_WARNING)) \ $(if $($(*F)_no_Wpacked_not_aligned),-Wno-packed-not-aligned,) \ - $($(*F)_CXXFLAGS) + $($(*F)_CXXFLAGS) $(NO_XOR_USED_AS_POW) COMPILE.os = $(filter-out -fprofile-arcs -ftest-coverage, $(COMPILE)) diff --git a/configure.ac b/configure.ac index c1a6954d..eed93771 100644 --- a/configure.ac +++ b/configure.ac @@ -95,6 +95,16 @@ AM_PROG_LEX m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_CHECK_TOOL([READELF], [readelf]) AC_CHECK_TOOL([NM], [nm]) +AS_CASE([$CC],[*clang*|*clang++*], + [is_clang_compiler=yes], + [is_clang_compiler=no] +) + +AM_CONDITIONAL([IS_CLANG_COMPILER],[ test x$is_clang_compiler = xyes]) +if test "$is_clang_compiler" = "no"; then +AC_DEFINE([NOT_CLANG_COMPILER],[1],[Not a clang compiler]) +fi + # We use -std=gnu99 but have explicit checks for some language constructs # and GNU extensions since some compilers claim GNU99 support, but don't @@ -114,6 +124,7 @@ int foo (int a) for (int i = 0; i < a; ++i) if (i % 4) break; int s = a; return s; } +#ifdef NOT_CLANG_COMPILER double bar (double a, double b) { double square (double z) { return z * z; } @@ -123,7 +134,9 @@ double bar (double a, double b) void baz (int n) { struct S { int x[[n]]; }; -}])], +} +#endif +])], ac_cv_c99=yes, ac_cv_c99=no) CFLAGS="$old_CFLAGS"]) AS_IF([test "x$ac_cv_c99" != xyes], diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c index ce1d819b..4bbca2a2 100644 --- a/debuginfod/debuginfod-client.c +++ b/debuginfod/debuginfod-client.c @@ -819,7 +819,7 @@ debuginfod_query_server (debuginfod_client *c, if (curl_res == 0 && dl >= 0) pa = (dl > LONG_MAX ? LONG_MAX : (long)dl); #else - double dl; + long double dl; curl_res = curl_easy_getinfo(target_handle, CURLINFO_SIZE_DOWNLOAD, &dl); @@ -837,7 +837,7 @@ debuginfod_query_server (debuginfod_client *c, if (curl_res == 0 && cl >= 0) pb = (cl > LONG_MAX ? LONG_MAX : (long)cl); #else - double cl; + long double cl; curl_res = curl_easy_getinfo(target_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl); diff --git a/libasm/asm_newscn.c b/libasm/asm_newscn.c index 7cdf484f..778a1e59 100644 --- a/libasm/asm_newscn.c +++ b/libasm/asm_newscn.c @@ -46,15 +46,15 @@ dirty tricks here. */ static const struct { - struct FillPattern pattern; char zero; + struct FillPattern pattern; } xdefault_pattern = { + .zero = '\0', .pattern = { .len = 1 - }, - .zero = '\0' + } }; const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern; diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c index 430e13d5..85ac107c 100644 --- a/libdwfl/dwfl_segment_report_module.c +++ b/libdwfl/dwfl_segment_report_module.c @@ -232,60 +232,34 @@ invalid_elf (Elf *elf, bool disk_file_has_build_id, return false; } -int -dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, - Dwfl_Memory_Callback *memory_callback, - void *memory_callback_arg, - Dwfl_Module_Callback *read_eagerly, - void *read_eagerly_arg, - const void *note_file, size_t note_file_size, - const struct r_debug_info *r_debug_info) -{ - size_t segment = ndx; - - if (segment >= dwfl->lookup_elts) - segment = dwfl->lookup_elts - 1; - - while (segment > 0 - && (dwfl->lookup_segndx[segment] > ndx - || dwfl->lookup_segndx[segment] == -1)) - --segment; - - while (dwfl->lookup_segndx[segment] < ndx) - if (++segment == dwfl->lookup_elts) - return 0; - - GElf_Addr start = dwfl->lookup_addr[segment]; - - inline bool segment_read (int segndx, +inline static bool segment_read (int segndx, void **buffer, size_t *buffer_available, - GElf_Addr addr, size_t minread) + GElf_Addr addr, size_t minread, + Dwfl *dwfl, Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) { return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available, addr, minread, memory_callback_arg); } - inline void release_buffer (void **buffer, size_t *buffer_available) + inline static void release_buffer (void **buffer, size_t *buffer_available, + Dwfl *dwfl, Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) { if (*buffer != NULL) - (void) segment_read (-1, buffer, buffer_available, 0, 0); + (void) segment_read (-1, buffer, buffer_available, 0, 0,dwfl, + memory_callback,memory_callback_arg); } - /* First read in the file header and check its sanity. */ - - void *buffer = NULL; - size_t buffer_available = INITIAL_READ; - Elf *elf = NULL; - int fd = -1; - - /* We might have to reserve some memory for the phdrs. Set to NULL - here so we can always safely free it. */ - void *phdrsp = NULL; - - inline int finish (void) + inline static int finish (void *phdrsp,Elf *elf, + void **buffer,size_t *buffer_available, + int fd,int ndx, + Dwfl *dwfl, Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) { free (phdrsp); - release_buffer (&buffer, &buffer_available); + release_buffer (buffer, buffer_available,dwfl,memory_callback, + memory_callback_arg); if (elf != NULL) elf_end (elf); if (fd != -1) @@ -293,51 +267,358 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, return ndx; } - if (segment_read (ndx, &buffer, &buffer_available, - start, sizeof (Elf64_Ehdr)) - || memcmp (buffer, ELFMAG, SELFMAG) != 0) - return finish (); + inline static bool read_portion (void **data, size_t *data_size, + GElf_Addr vaddr, size_t filesz, + size_t *buffer_available,GElf_Addr start, + void **buffer,size_t segment, Dwfl *dwfl, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) - inline bool read_portion (void **data, size_t *data_size, - GElf_Addr vaddr, size_t filesz) { /* Check whether we will have to read the segment data, or if it can be returned from the existing buffer. */ - if (filesz > buffer_available - || vaddr - start > buffer_available - filesz + if (filesz > *buffer_available + || vaddr - start > *buffer_available - filesz /* If we're in string mode, then don't consider the buffer we have sufficient unless it contains the terminator of the string. */ - || (filesz == 0 && memchr (vaddr - start + buffer, '\0', - buffer_available - (vaddr - start)) == NULL)) + || (filesz == 0 && memchr (vaddr - start + *buffer, '\0', + *buffer_available - (vaddr - start)) == NULL)) { *data = NULL; *data_size = filesz; return segment_read (addr_segndx (dwfl, segment, vaddr, false), - data, data_size, vaddr, filesz); + data, data_size, vaddr, filesz,dwfl,memory_callback, + memory_callback_arg); } /* We already have this whole note segment from our initial read. */ - *data = vaddr - start + buffer; + *data = vaddr - start + *buffer; *data_size = 0; return false; } - inline void finish_portion (void **data, size_t *data_size) + + inline static void finish_portion (void **data, size_t *data_size, + Dwfl *dwfl, Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) + { if (*data_size != 0) - release_buffer (data, data_size); + release_buffer (data, data_size,dwfl,memory_callback,memory_callback_arg); } +union + { + Elf32_Ehdr e32; + Elf64_Ehdr e64; + } ehdr; + + + + /* Consider a PT_NOTE we've found in the image. */ + inline static void consider_notes (GElf_Addr vaddr, GElf_Xword *filesz, + GElf_Xword align,void **build_id, + size_t *buffer_available,GElf_Addr start, + void **buffer,size_t segment, + Dwfl *dwfl, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + unsigned char ei_data,Elf_Data *xlatefrom, + Elf_Data *xlateto,size_t *build_id_len, + GElf_Addr *build_id_vaddr + ) + { + /* If we have already seen a build ID, we don't care any more. */ + if ((*build_id) != NULL || *filesz == 0) + return; + + void *data; + size_t data_size; + if (read_portion (&data, &data_size, vaddr, *filesz, + buffer_available,start,buffer,segment,dwfl, + memory_callback,memory_callback_arg)) + return; + + /* data_size will be zero if we got everything from the initial + buffer, otherwise it will be the size of the new buffer that + could be read. */ + if (data_size != 0) + *filesz = data_size; + + assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); + + void *notes; + if (ei_data == MY_ELFDATA) + notes = data; + else + { + notes = malloc (*filesz); + if (unlikely (notes == NULL)) + return; + xlatefrom->d_type = xlateto->d_type = (align == 8 + ? ELF_T_NHDR8 : ELF_T_NHDR); + xlatefrom->d_buf = (void *) data; + xlatefrom->d_size = *filesz; + xlateto->d_buf = notes; + xlateto->d_size = *filesz; + if (elf32_xlatetom (xlateto, xlatefrom, + ehdr.e32.e_ident[EI_DATA]) == NULL) + goto done; + } + + const GElf_Nhdr *nh = notes; + size_t len = 0; + while (*filesz > len + sizeof (*nh)) + { + const void *note_name; + const void *note_desc; + + len += sizeof (*nh); + note_name = notes + len; + + len += nh->n_namesz; + len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len); + note_desc = notes + len; + + if (unlikely (*filesz < len + nh->n_descsz)) + break; + + if (nh->n_type == NT_GNU_BUILD_ID + && nh->n_descsz > 0 + && nh->n_namesz == sizeof "GNU" + && !memcmp (note_name, "GNU", sizeof "GNU")) + { + *build_id_vaddr = note_desc - (const void *) notes + vaddr; + *build_id_len = nh->n_descsz; + *build_id = malloc (nh->n_descsz); + if (likely (*build_id != NULL)) + memcpy (*build_id, note_desc, *build_id_len); + break; + } + + len += nh->n_descsz; + len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len); + nh = (void *) notes + len; + } + + done: + if (notes != data) + free (notes); + finish_portion (&data, &data_size,dwfl,memory_callback,memory_callback_arg); + } + + +/* Consider each of the program headers we've read from the image. */ +//should have inline + inline static void consider_phdr (GElf_Word type, + GElf_Addr vaddr, GElf_Xword memsz, + GElf_Off offset, void *ptrfilesz,size_t ptrlen, + GElf_Xword align, GElf_Addr *dyn_vaddr, + GElf_Xword *dyn_filesz,GElf_Addr start, + Dwfl *dwfl, GElf_Off *file_trimmed_end, + GElf_Off shdrs_end,GElf_Addr *module_start, + GElf_Addr *module_end, + GElf_Addr *module_address_sync,void **build_id, + size_t *buffer_available,void **buffer, + size_t segment, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg,unsigned char ei_data, + Elf_Data *xlatefrom,Elf_Data *xlateto, + size_t *build_id_len,GElf_Addr *build_id_vaddr, + GElf_Off *total_filesz,GElf_Off *file_end, + GElf_Off *contiguous , GElf_Off phoff, + uint_fast16_t phnum,uint_fast16_t phentsize, + GElf_Addr *bias,bool *found_bias + ) + { + + unsigned long filesz = 0; + memcpy(&filesz,ptrfilesz,ptrlen); + + switch (type) + { + case PT_DYNAMIC: + *dyn_vaddr = vaddr; + *dyn_filesz = filesz; + break; + + case PT_NOTE: + + /* We calculate from the p_offset of the note segment, + because we don't yet know the bias for its p_vaddr. */ + consider_notes (start + offset, &filesz, align, build_id, + buffer_available,start, + buffer,segment,dwfl, + memory_callback,memory_callback_arg,ei_data, + xlatefrom,xlateto,build_id_len,build_id_vaddr); + + break; + + case PT_LOAD: + align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1; + + GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align; + GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end; + GElf_Off filesz_offset = filesz_vaddr - vaddr + offset; + + if (*file_trimmed_end < offset + filesz) + { + *file_trimmed_end = offset + filesz; + + /* Trim the last segment so we don't bother with zeros + in the last page that are off the end of the file. + However, if the extra bit in that page includes the + section headers, keep them. */ + if (shdrs_end <= filesz_offset && shdrs_end > *file_trimmed_end) + { + filesz += shdrs_end - *file_trimmed_end; + *file_trimmed_end = shdrs_end; + } + } + + *total_filesz += filesz; + + if (*file_end < filesz_offset) + { + *file_end = filesz_offset; + if (filesz_vaddr - start == filesz_offset) + *contiguous = *file_end; + } + + if (!*found_bias && (offset & -align) == 0 + && likely (filesz_offset >= phoff + phnum * phentsize)) + { + *bias = start - vaddr; + *found_bias = true; + } + + if ((vaddr & -align) < *module_start) + { + *module_start = vaddr & -align; + *module_address_sync = vaddr + memsz; + } + + if (*module_end < vaddr_end) + *module_end = vaddr_end; + break; + } + + memcpy(ptrfilesz,&filesz,ptrlen); + } + + +inline static bool consider_dyn (GElf_Sxword tag, GElf_Xword val, + bool *execlike,GElf_Addr *soname_stroff, + GElf_Addr *dynstr_vaddr, GElf_Xword *dynstrsz) + { + switch (tag) + { + default: + return false; + + case DT_DEBUG: + *execlike = true; + break; + + case DT_SONAME: + *soname_stroff = val; + break; + + case DT_STRTAB: + *dynstr_vaddr = val; + break; + + case DT_STRSZ: + *dynstrsz = val; + break; + } + + return *soname_stroff != 0 && *dynstr_vaddr != 0 && *dynstrsz != 0; + } + +inline static void final_read (size_t offset, GElf_Addr vaddr, size_t size, + void *contents,Dwfl *dwfl,size_t segment, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) + { + void *into = contents + offset; + size_t read_size = size; + (void) segment_read (addr_segndx (dwfl, segment, vaddr, false), + &into, &read_size, vaddr, size,dwfl, + memory_callback,memory_callback_arg); + + } + + + /* We can't use the memory image verbatim as the file image. + So we'll be reading into a local image of the virtual file. */ + + inline static void read_phdr (GElf_Word type, GElf_Addr vaddr, + GElf_Off offset, GElf_Xword filesz, + GElf_Addr bias,void *contents,Dwfl *dwfl, + size_t segment, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) + { + if (type == PT_LOAD) + final_read (offset, vaddr + bias, filesz,contents,dwfl, + segment,memory_callback,memory_callback_arg); + } + + + + + + +int +dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + Dwfl_Module_Callback *read_eagerly, + void *read_eagerly_arg, + const void *note_file, size_t note_file_size, + const struct r_debug_info *r_debug_info) +{ + size_t segment = ndx; + + if (segment >= dwfl->lookup_elts) + segment = dwfl->lookup_elts - 1; + + while (segment > 0 + && (dwfl->lookup_segndx[segment] > ndx + || dwfl->lookup_segndx[segment] == -1)) + --segment; + + while (dwfl->lookup_segndx[segment] < ndx) + if (++segment == dwfl->lookup_elts) + return 0; + + GElf_Addr start = dwfl->lookup_addr[segment]; + + /* First read in the file header and check its sanity. */ + + void *buffer = NULL; + size_t buffer_available = INITIAL_READ; + Elf *elf = NULL; + int fd = -1; + + /* We might have to reserve some memory for the phdrs. Set to NULL + here so we can always safely free it. */ + void *phdrsp = NULL; + + if (segment_read (ndx, &buffer, &buffer_available,start, sizeof (Elf64_Ehdr), + dwfl,memory_callback,memory_callback_arg) + || memcmp (buffer, ELFMAG, SELFMAG) != 0) + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); + + + /* Extract the information we need from the file header. */ const unsigned char *e_ident; unsigned char ei_class; unsigned char ei_data; uint16_t e_type; - union - { - Elf32_Ehdr e32; - Elf64_Ehdr e64; - } ehdr; GElf_Off phoff; uint_fast16_t phnum; uint_fast16_t phentsize; @@ -363,13 +644,15 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, case ELFCLASS32: xlatefrom.d_size = sizeof (Elf32_Ehdr); if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); e_type = ehdr.e32.e_type; phoff = ehdr.e32.e_phoff; phnum = ehdr.e32.e_phnum; phentsize = ehdr.e32.e_phentsize; if (phentsize != sizeof (Elf32_Phdr)) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); /* NOTE if the number of sections is > 0xff00 then e_shnum is zero and the actual number would come from the section zero sh_size field. We ignore this here because getting shdrs @@ -381,19 +664,22 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, case ELFCLASS64: xlatefrom.d_size = sizeof (Elf64_Ehdr); if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); e_type = ehdr.e64.e_type; phoff = ehdr.e64.e_phoff; phnum = ehdr.e64.e_phnum; phentsize = ehdr.e64.e_phentsize; if (phentsize != sizeof (Elf64_Phdr)) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); /* See the NOTE above for shdrs_end and ehdr.e32.e_shnum. */ shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize; break; default: - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); } /* The file header tells where to find the program headers. @@ -401,7 +687,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, Without them, we don't have a module to report. */ if (phnum == 0) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; xlatefrom.d_size = phnum * phentsize; @@ -409,8 +696,11 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, void *ph_buffer = NULL; size_t ph_buffer_size = 0; if (read_portion (&ph_buffer, &ph_buffer_size, - start + phoff, xlatefrom.d_size)) - return finish (); + start + phoff, xlatefrom.d_size, + &buffer_available,start,&buffer,segment,dwfl, + memory_callback,memory_callback_arg)) + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); /* ph_buffer_size will be zero if we got everything from the initial buffer, otherwise it will be the size of the new buffer that @@ -423,11 +713,13 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, bool class32 = ei_class == ELFCLASS32; size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr); if (unlikely (phnum > SIZE_MAX / phdr_size)) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); const size_t phdrsp_bytes = phnum * phdr_size; phdrsp = malloc (phdrsp_bytes); if (unlikely (phdrsp == NULL)) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); xlateto.d_buf = phdrsp; xlateto.d_size = phdrsp_bytes; @@ -456,155 +748,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, size_t build_id_len = 0; GElf_Addr build_id_vaddr = 0; - /* Consider a PT_NOTE we've found in the image. */ - inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz, - GElf_Xword align) - { - /* If we have already seen a build ID, we don't care any more. */ - if (build_id != NULL || filesz == 0) - return; - - void *data; - size_t data_size; - if (read_portion (&data, &data_size, vaddr, filesz)) - return; - - /* data_size will be zero if we got everything from the initial - buffer, otherwise it will be the size of the new buffer that - could be read. */ - if (data_size != 0) - filesz = data_size; - - assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); - - void *notes; - if (ei_data == MY_ELFDATA) - notes = data; - else - { - notes = malloc (filesz); - if (unlikely (notes == NULL)) - return; - xlatefrom.d_type = xlateto.d_type = (align == 8 - ? ELF_T_NHDR8 : ELF_T_NHDR); - xlatefrom.d_buf = (void *) data; - xlatefrom.d_size = filesz; - xlateto.d_buf = notes; - xlateto.d_size = filesz; - if (elf32_xlatetom (&xlateto, &xlatefrom, - ehdr.e32.e_ident[EI_DATA]) == NULL) - goto done; - } - - const GElf_Nhdr *nh = notes; - size_t len = 0; - while (filesz > len + sizeof (*nh)) - { - const void *note_name; - const void *note_desc; - - len += sizeof (*nh); - note_name = notes + len; - - len += nh->n_namesz; - len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len); - note_desc = notes + len; - - if (unlikely (filesz < len + nh->n_descsz)) - break; - - if (nh->n_type == NT_GNU_BUILD_ID - && nh->n_descsz > 0 - && nh->n_namesz == sizeof "GNU" - && !memcmp (note_name, "GNU", sizeof "GNU")) - { - build_id_vaddr = note_desc - (const void *) notes + vaddr; - build_id_len = nh->n_descsz; - build_id = malloc (nh->n_descsz); - if (likely (build_id != NULL)) - memcpy (build_id, note_desc, build_id_len); - break; - } - - len += nh->n_descsz; - len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len); - nh = (void *) notes + len; - } - - done: - if (notes != data) - free (notes); - finish_portion (&data, &data_size); - } - - /* Consider each of the program headers we've read from the image. */ - inline void consider_phdr (GElf_Word type, - GElf_Addr vaddr, GElf_Xword memsz, - GElf_Off offset, GElf_Xword filesz, - GElf_Xword align) - { - switch (type) - { - case PT_DYNAMIC: - dyn_vaddr = vaddr; - dyn_filesz = filesz; - break; - - case PT_NOTE: - /* We calculate from the p_offset of the note segment, - because we don't yet know the bias for its p_vaddr. */ - consider_notes (start + offset, filesz, align); - break; - - case PT_LOAD: - align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1; - - GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align; - GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end; - GElf_Off filesz_offset = filesz_vaddr - vaddr + offset; - - if (file_trimmed_end < offset + filesz) - { - file_trimmed_end = offset + filesz; - - /* Trim the last segment so we don't bother with zeros - in the last page that are off the end of the file. - However, if the extra bit in that page includes the - section headers, keep them. */ - if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end) - { - filesz += shdrs_end - file_trimmed_end; - file_trimmed_end = shdrs_end; - } - } - - total_filesz += filesz; - - if (file_end < filesz_offset) - { - file_end = filesz_offset; - if (filesz_vaddr - start == filesz_offset) - contiguous = file_end; - } - - if (!found_bias && (offset & -align) == 0 - && likely (filesz_offset >= phoff + phnum * phentsize)) - { - bias = start - vaddr; - found_bias = true; - } - - if ((vaddr & -align) < module_start) - { - module_start = vaddr & -align; - module_address_sync = vaddr + memsz; - } - - if (module_end < vaddr_end) - module_end = vaddr_end; - break; - } - } + Elf32_Phdr (*p32)[phnum] = phdrsp; Elf64_Phdr (*p64)[phnum] = phdrsp; @@ -616,8 +760,17 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, for (uint_fast16_t i = 0; i < phnum; ++i) consider_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr, (*p32)[i].p_memsz, - (*p32)[i].p_offset, (*p32)[i].p_filesz, - (*p32)[i].p_align); + (*p32)[i].p_offset, &((*p32)[i].p_filesz), + sizeof((*p32)[i].p_filesz), + (*p32)[i].p_align, &dyn_vaddr, &dyn_filesz, + start,dwfl,&file_trimmed_end, + shdrs_end,&module_start,&module_end, + &module_address_sync,&build_id,&buffer_available, + &buffer,segment,memory_callback,memory_callback_arg, + ei_data,&xlatefrom,&xlateto,&build_id_len, + &build_id_vaddr,&total_filesz,&file_end ,&contiguous, + phoff,phnum,phentsize,&bias,&found_bias); + } else { @@ -627,18 +780,29 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, for (uint_fast16_t i = 0; i < phnum; ++i) consider_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr, (*p64)[i].p_memsz, - (*p64)[i].p_offset, (*p64)[i].p_filesz, - (*p64)[i].p_align); + (*p64)[i].p_offset, &((*p64)[i].p_filesz), + sizeof((*p64)[i].p_filesz), + (*p64)[i].p_align, &dyn_vaddr, &dyn_filesz, + start,dwfl,&file_trimmed_end, + shdrs_end,&module_start,&module_end, + &module_address_sync,&build_id,&buffer_available, + &buffer,segment,memory_callback,memory_callback_arg, + ei_data,&xlatefrom,&xlateto,&build_id_len, + &build_id_vaddr,&total_filesz,&file_end ,&contiguous, + phoff,phnum,phentsize,&bias,&found_bias); + } - finish_portion (&ph_buffer, &ph_buffer_size); + finish_portion (&ph_buffer, &ph_buffer_size,dwfl,memory_callback, + memory_callback_arg); /* We must have seen the segment covering offset 0, or else the ELF header we read at START was not produced by these program headers. */ if (unlikely (!found_bias)) { free (build_id); - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); } /* Now we know enough to report a module for sure: its bounds. */ @@ -709,7 +873,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, if (skip_this_module) { free (build_id); - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); } } @@ -755,39 +920,14 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, GElf_Addr dynstr_vaddr = 0; GElf_Xword dynstrsz = 0; bool execlike = false; - inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val) - { - switch (tag) - { - default: - return false; - - case DT_DEBUG: - execlike = true; - break; - - case DT_SONAME: - soname_stroff = val; - break; - - case DT_STRTAB: - dynstr_vaddr = val; - break; - - case DT_STRSZ: - dynstrsz = val; - break; - } - - return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0; - } - const size_t dyn_entsize = (ei_class == ELFCLASS32 ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn)); void *dyn_data = NULL; size_t dyn_data_size = 0; if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0 - && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz)) + && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz, + &buffer_available,start,&buffer,segment,dwfl,memory_callback, + memory_callback_arg)) { /* dyn_data_size will be zero if we got everything from the initial buffer, otherwise it will be the size of the new buffer that @@ -799,7 +939,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = dyns; Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = dyns; if (unlikely (dyns == NULL)) - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); xlatefrom.d_type = xlateto.d_type = ELF_T_DYN; xlatefrom.d_buf = (void *) dyn_data; @@ -811,19 +952,24 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, { if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL) for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i) - if (consider_dyn ((*d32)[i].d_tag, (*d32)[i].d_un.d_val)) + if (consider_dyn ((*d32)[i].d_tag, (*d32)[i].d_un.d_val, + &execlike,&soname_stroff, + &dynstr_vaddr, &dynstrsz)) break; } else { if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL) for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i) - if (consider_dyn ((*d64)[i].d_tag, (*d64)[i].d_un.d_val)) + if (consider_dyn ((*d64)[i].d_tag, (*d64)[i].d_un.d_val, + &execlike,&soname_stroff, + &dynstr_vaddr, &dynstrsz)) break; } free (dyns); } - finish_portion (&dyn_data, &dyn_data_size); + finish_portion (&dyn_data, &dyn_data_size,dwfl,memory_callback, + memory_callback_arg); /* We'll use the name passed in or a stupid default if not DT_SONAME. */ if (name == NULL) @@ -856,7 +1002,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, /* Try to get the DT_SONAME string. */ if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz && ! read_portion (&soname, &soname_size, - dynstr_vaddr + soname_stroff, 0)) + dynstr_vaddr + soname_stroff, 0, + &buffer_available,start,&buffer,segment, + dwfl,memory_callback, + memory_callback_arg)) name = soname; } @@ -884,12 +1033,14 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, /* At this point we do not need BUILD_ID or NAME any more. They have been copied. */ free (build_id); - finish_portion (&soname, &soname_size); + finish_portion (&soname, &soname_size,dwfl,memory_callback, + memory_callback_arg); if (unlikely (mod == NULL)) { ndx = -1; - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); } /* We have reported the module. Now let the caller decide whether we @@ -913,36 +1064,25 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, void *contents = calloc (1, file_trimmed_end); if (unlikely (contents == NULL)) - return finish (); - - inline void final_read (size_t offset, GElf_Addr vaddr, size_t size) - { - void *into = contents + offset; - size_t read_size = size; - (void) segment_read (addr_segndx (dwfl, segment, vaddr, false), - &into, &read_size, vaddr, size); - } + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); - if (contiguous < file_trimmed_end) + if (contiguous < file_trimmed_end) { - /* We can't use the memory image verbatim as the file image. - So we'll be reading into a local image of the virtual file. */ - - inline void read_phdr (GElf_Word type, GElf_Addr vaddr, - GElf_Off offset, GElf_Xword filesz) - { - if (type == PT_LOAD) - final_read (offset, vaddr + bias, filesz); - } + if (ei_class == ELFCLASS32) for (uint_fast16_t i = 0; i < phnum; ++i) read_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr, - (*p32)[i].p_offset, (*p32)[i].p_filesz); + (*p32)[i].p_offset, (*p32)[i].p_filesz, + bias,contents,dwfl,segment,memory_callback, + memory_callback_arg); else for (uint_fast16_t i = 0; i < phnum; ++i) read_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr, - (*p64)[i].p_offset, (*p64)[i].p_filesz); + (*p64)[i].p_offset, (*p64)[i].p_filesz, + bias,contents,dwfl,segment,memory_callback, + memory_callback_arg); } else { @@ -953,7 +1093,9 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, memcpy (contents, buffer, have); if (have < file_trimmed_end) - final_read (have, start + have, file_trimmed_end - have); + final_read (have, start + have, file_trimmed_end - have, + contents,dwfl,segment, + memory_callback,memory_callback_arg); } elf = elf_memory (contents, file_trimmed_end); @@ -975,5 +1117,6 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, mod->main_bias = bias; } - return finish (); + return finish (phdrsp,elf,&buffer,&buffer_available,fd,ndx,dwfl, + memory_callback,memory_callback_arg); } diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c index c54c1b99..40aea896 100644 --- a/libdwfl/elf-from-memory.c +++ b/libdwfl/elf-from-memory.c @@ -38,6 +38,63 @@ #include #include +/* Sanity checks segments and calculates segment_end, + segments_end, segments_end_mem and loadbase (if not + found_base yet). Returns true if sanity checking failed, + false otherwise. */ + inline static bool ehdr_memsz_handle_segment (GElf_Addr vaddr, GElf_Off offset, + GElf_Xword filesz, GElf_Xword memsz, + GElf_Xword pagesize, GElf_Addr ehdr_vma, + size_t *contents_size,GElf_Addr *loadbase, + bool *found_base,GElf_Off *segments_end, + GElf_Off *segments_end_mem) + { + /* Sanity check the segment load aligns with the pagesize. */ + if (((vaddr - offset) & (pagesize - 1)) != 0) + return true; + + GElf_Off segment_end = ((offset + filesz + pagesize - 1) + & -pagesize); + + if (segment_end > (GElf_Off) *contents_size) + *contents_size = segment_end; + + if (!*found_base && (offset & -pagesize) == 0) + { + *loadbase = ehdr_vma - (vaddr & -pagesize); + *found_base = true; + } + + *segments_end = offset + filesz; + *segments_end_mem = offset + memsz; + return false; + } + +/* Reads the given segment. Returns true if reading fails, + false otherwise. */ + inline static bool ehdr_filesz_handle_segment (GElf_Addr vaddr, GElf_Off offset, + GElf_Xword filesz,GElf_Xword pagesize, + size_t contents_size, ssize_t *nread, + unsigned char *buffer,GElf_Addr loadbase, + ssize_t (*read_memory) (void *arg, void *data, + GElf_Addr address, + size_t minread, + size_t maxread), + void *arg) + + { + GElf_Off start = offset & -pagesize; + GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize; + if (end > (GElf_Off) contents_size) + end = contents_size; + *nread = (*read_memory) (arg, buffer + start, + (loadbase + vaddr) & -pagesize, + end - start, end - start); + return *nread <= 0; + } + + + /* Reconstruct an ELF file by reading the segments out of remote memory based on the ELF file header at EHDR_VMA and the ELF program headers it points to. If not null, *LOADBASEP is filled in with the difference @@ -225,42 +282,16 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, Elf64_Phdr (*p64)[phnum] = phdrsp; switch (ehdr.e32.e_ident[EI_CLASS]) { - /* Sanity checks segments and calculates segment_end, - segments_end, segments_end_mem and loadbase (if not - found_base yet). Returns true if sanity checking failed, - false otherwise. */ - inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, - GElf_Xword filesz, GElf_Xword memsz) - { - /* Sanity check the segment load aligns with the pagesize. */ - if (((vaddr - offset) & (pagesize - 1)) != 0) - return true; - - GElf_Off segment_end = ((offset + filesz + pagesize - 1) - & -pagesize); - - if (segment_end > (GElf_Off) contents_size) - contents_size = segment_end; - - if (!found_base && (offset & -pagesize) == 0) - { - loadbase = ehdr_vma - (vaddr & -pagesize); - found_base = true; - } - - segments_end = offset + filesz; - segments_end_mem = offset + memsz; - return false; - } - case ELFCLASS32: if (elf32_xlatetom (&xlateto, &xlatefrom, ehdr.e32.e_ident[EI_DATA]) == NULL) goto libelf_error; for (uint_fast16_t i = 0; i < phnum; ++i) if ((*p32)[i].p_type == PT_LOAD) - if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset, - (*p32)[i].p_filesz, (*p32)[i].p_memsz)) + if (ehdr_memsz_handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset, + (*p32)[i].p_filesz, (*p32)[i].p_memsz,pagesize, + ehdr_vma,&contents_size, &loadbase,&found_base, + &segments_end,&segments_end_mem)) goto bad_elf; break; @@ -270,8 +301,10 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, goto libelf_error; for (uint_fast16_t i = 0; i < phnum; ++i) if ((*p64)[i].p_type == PT_LOAD) - if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset, - (*p64)[i].p_filesz, (*p64)[i].p_memsz)) + if (ehdr_memsz_handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset, + (*p64)[i].p_filesz, (*p64)[i].p_memsz,pagesize, + ehdr_vma,&contents_size, &loadbase,&found_base, + &segments_end,&segments_end_mem)) goto bad_elf; break; @@ -307,26 +340,12 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, switch (ehdr.e32.e_ident[EI_CLASS]) { - /* Reads the given segment. Returns true if reading fails, - false otherwise. */ - inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, - GElf_Xword filesz) - { - GElf_Off start = offset & -pagesize; - GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize; - if (end > (GElf_Off) contents_size) - end = contents_size; - nread = (*read_memory) (arg, buffer + start, - (loadbase + vaddr) & -pagesize, - end - start, end - start); - return nread <= 0; - } - case ELFCLASS32: for (uint_fast16_t i = 0; i < phnum; ++i) if ((*p32)[i].p_type == PT_LOAD) - if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset, - (*p32)[i].p_filesz)) + if (ehdr_filesz_handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset, + (*p32)[i].p_filesz,pagesize,contents_size, + &nread,buffer,loadbase,read_memory,arg)) goto read_error; /* If the segments visible in memory didn't include the section @@ -352,8 +371,9 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, case ELFCLASS64: for (uint_fast16_t i = 0; i < phnum; ++i) if ((*p64)[i].p_type == PT_LOAD) - if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset, - (*p64)[i].p_filesz)) + if (ehdr_filesz_handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset, + (*p64)[i].p_filesz,pagesize,contents_size, + &nread,buffer,loadbase,read_memory,arg)) goto read_error; /* If the segments visible in memory didn't include the section diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 29307c74..d7ca42ae 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -1,3 +1,4 @@ + /* Report modules by examining dynamic linker data structures. Copyright (C) 2008-2016 Red Hat, Inc. This file is part of elfutils. @@ -224,61 +225,42 @@ addrsize (uint_fast8_t elfclass) { return elfclass * 4; } - -/* Report a module for each struct link_map in the linked list at r_map - in the struct r_debug at R_DEBUG_VADDR. For r_debug_info description - see dwfl_link_map_report in libdwflP.h. If R_DEBUG_INFO is not NULL then no - modules get added to DWFL, caller has to add them from filled in - R_DEBUG_INFO. - - For each link_map entry, if an existing module resides at its address, - this just modifies that module's name and suggested file name. If - no such module exists, this calls dwfl_report_elf on the l_name string. - - Returns the number of modules found, or -1 for errors. */ - -static int -report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, - Dwfl *dwfl, GElf_Addr r_debug_vaddr, - Dwfl_Memory_Callback *memory_callback, - void *memory_callback_arg, - struct r_debug_info *r_debug_info) -{ - /* Skip r_version, to aligned r_map field. */ - GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass); - - void *buffer = NULL; - size_t buffer_available = 0; - inline int release_buffer (int result) +inline static int release_buffer (int result,void **buffer,size_t *buffer_available, + Dwfl *dwfl, Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) { if (buffer != NULL) - (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0, + (void) (*memory_callback) (dwfl, -1, buffer, buffer_available, 0, 0, memory_callback_arg); return result; } - GElf_Addr addrs[4]; - inline bool read_addrs (GElf_Addr vaddr, size_t n) + inline static bool read_addrs (GElf_Addr vaddr, size_t n,uint_fast8_t elfclass, + void **buffer,GElf_Addr *read_vaddr,size_t *buffer_available, + Dwfl *dwfl,Dwfl_Memory_Callback memory_callback, + void *memory_callback_arg, + uint_fast8_t elfdata, GElf_Addr addrs[] + ) { size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */ /* Read a new buffer if the old one doesn't cover these words. */ - if (buffer == NULL - || vaddr < read_vaddr - || vaddr - read_vaddr + nb > buffer_available) + if (*buffer == NULL + || vaddr < *read_vaddr + || vaddr - *read_vaddr + nb > *buffer_available) { - release_buffer (0); + release_buffer (0,buffer,buffer_available,dwfl,memory_callback,memory_callback_arg); - read_vaddr = vaddr; + *read_vaddr = vaddr; int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL); if (unlikely (segndx < 0) || unlikely (! (*memory_callback) (dwfl, segndx, - &buffer, &buffer_available, + buffer, buffer_available, vaddr, nb, memory_callback_arg))) return true; } - Elf32_Addr (*a32)[n] = vaddr - read_vaddr + buffer; + Elf32_Addr (*a32)[n] = vaddr - *read_vaddr + *buffer; Elf64_Addr (*a64)[n] = (void *) a32; if (elfclass == ELFCLASS32) @@ -303,8 +285,39 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, return false; } - if (unlikely (read_addrs (read_vaddr, 1))) - return release_buffer (-1); + +/* Report a module for each struct link_map in the linked list at r_map + in the struct r_debug at R_DEBUG_VADDR. For r_debug_info description + see dwfl_link_map_report in libdwflP.h. If R_DEBUG_INFO is not NULL then no + modules get added to DWFL, caller has to add them from filled in + R_DEBUG_INFO. + + For each link_map entry, if an existing module resides at its address, + this just modifies that module's name and suggested file name. If + no such module exists, this calls dwfl_report_elf on the l_name string. + + Returns the number of modules found, or -1 for errors. */ + +static int +report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, + Dwfl *dwfl, GElf_Addr r_debug_vaddr, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + struct r_debug_info *r_debug_info) +{ + /* Skip r_version, to aligned r_map field. */ + GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass); + + void *buffer = NULL; + size_t buffer_available = 0; + GElf_Addr addrs[4]; + if (unlikely ( + read_addrs(read_vaddr,1,elfclass,&buffer,&read_vaddr, + &buffer_available,dwfl,memory_callback,memory_callback_arg, + elfdata,addrs) + ) + ) + return release_buffer (-1,&buffer,&buffer_available,dwfl,memory_callback,memory_callback_arg); GElf_Addr next = addrs[0]; @@ -317,9 +330,13 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, there must be a loop in the pointers due to link_map clobberation. */ size_t iterations = 0; while (next != 0 && ++iterations < dwfl->lookup_elts) - { - if (read_addrs (next, 4)) - return release_buffer (-1); + { + if ( + read_addrs(next,4,elfclass,&buffer,&read_vaddr, + &buffer_available,dwfl,memory_callback,memory_callback_arg, + elfdata,addrs) + ) + return release_buffer (-1,&buffer,&buffer_available,dwfl,memory_callback,memory_callback_arg); /* Unused: l_addr is the difference between the address in memory and the ELF file when the core was created. We need to @@ -345,7 +362,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, name = l_name - read_vaddr + buffer; else { - release_buffer (0); + release_buffer (0,&buffer,&buffer_available,dwfl,memory_callback,memory_callback_arg); read_vaddr = l_name; int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL); if (likely (segndx >= 0) @@ -372,7 +389,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, r_debug_info_module = malloc (sizeof (*r_debug_info_module) + strlen (name1) + 1); if (unlikely (r_debug_info_module == NULL)) - return release_buffer (result); + return release_buffer (result,&buffer,&buffer_available,dwfl,memory_callback,memory_callback_arg); r_debug_info_module->fd = -1; r_debug_info_module->elf = NULL; r_debug_info_module->l_ld = l_ld; @@ -413,7 +430,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, GElf_Addr build_id_vaddr = (build_id_elfaddr - elf_dynamic_vaddr + l_ld); - release_buffer (0); + release_buffer (0,&buffer,&buffer_available,dwfl,memory_callback,memory_callback_arg); int segndx = INTUSE(dwfl_addrsegment) (dwfl, build_id_vaddr, NULL); @@ -432,7 +449,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, /* File has valid build-id which does not match the one in memory. */ valid = false; - release_buffer (0); + release_buffer (0,&buffer,&buffer_available,dwfl,memory_callback,memory_callback_arg); } } @@ -498,7 +515,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, } } - return release_buffer (result); + return release_buffer (result,&buffer,&buffer_available,dwfl,memory_callback,memory_callback_arg); } static GElf_Addr @@ -688,6 +705,34 @@ find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry, } + inline static bool consider_phdr (GElf_Word type, + GElf_Addr vaddr, GElf_Xword filesz, + GElf_Addr *dyn_bias,Dwfl *dwfl, + GElf_Addr phdr, GElf_Addr *dyn_vaddr, + GElf_Xword *dyn_filesz) + { + switch (type) + { + case PT_PHDR: + if (*dyn_bias == (GElf_Addr) -1 + /* Do a sanity check on the putative address. */ + && ((vaddr & (dwfl->segment_align - 1)) + == (phdr & (dwfl->segment_align - 1)))) + { + *dyn_bias = phdr - vaddr; + return *dyn_vaddr != 0; + } + break; + + case PT_DYNAMIC: + *dyn_vaddr = vaddr; + *dyn_filesz = filesz; + return *dyn_bias != (GElf_Addr) -1; + } + + return false; + } + int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, Dwfl_Memory_Callback *memory_callback, @@ -758,30 +803,6 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, GElf_Xword dyn_filesz = 0; GElf_Addr dyn_bias = (GElf_Addr) -1; - inline bool consider_phdr (GElf_Word type, - GElf_Addr vaddr, GElf_Xword filesz) - { - switch (type) - { - case PT_PHDR: - if (dyn_bias == (GElf_Addr) -1 - /* Do a sanity check on the putative address. */ - && ((vaddr & (dwfl->segment_align - 1)) - == (phdr & (dwfl->segment_align - 1)))) - { - dyn_bias = phdr - vaddr; - return dyn_vaddr != 0; - } - break; - - case PT_DYNAMIC: - dyn_vaddr = vaddr; - dyn_filesz = filesz; - return dyn_bias != (GElf_Addr) -1; - } - - return false; - } if (phdr != 0 && phnum != 0) { @@ -901,7 +922,10 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, for (size_t i = 0; i < phnum; ++i) if (consider_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr, - (*p32)[i].p_filesz)) + (*p32)[i].p_filesz, + &dyn_bias,dwfl,phdr,&dyn_vaddr, + &dyn_filesz + )) break; } else @@ -909,7 +933,10 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, for (size_t i = 0; i < phnum; ++i) if (consider_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr, - (*p64)[i].p_filesz)) + (*p64)[i].p_filesz, + &dyn_bias,dwfl,phdr,&dyn_vaddr, + &dyn_filesz + )) break; } } diff --git a/libelf/elf.h b/libelf/elf.h index 6439c1a4..26420b45 100644 --- a/libelf/elf.h +++ b/libelf/elf.h @@ -444,6 +444,7 @@ typedef struct #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_LLVM_ADDRSIG 0x6FFF4C03 /* llvm address sig */ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ diff --git a/src/addr2line.c b/src/addr2line.c index 69d8d995..038c8691 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -598,6 +598,21 @@ get_addr_width (Dwfl_Module *mod) return width; } +inline static void show (int (*get) (Dwarf_Line *, bool *), + const char *note,Dwarf_Line *info) +{ +bool flag; +if ((*get) (info, &flag) == 0 && flag) +fputs (note, stdout); +} +inline static void show_int (int (*get) (Dwarf_Line *, unsigned int *), + const char *name,Dwarf_Line *info) +{ +unsigned int val; +if ((*get) (info, &val) == 0 && val != 0) +printf (" (%s %u)", name, val); +} + static int handle_address (const char *string, Dwfl *dwfl) { @@ -692,27 +707,13 @@ handle_address (const char *string, Dwfl *dwfl) Dwarf_Line *info = dwfl_dwarf_line (line, &bias); assert (info != NULL); - inline void show (int (*get) (Dwarf_Line *, bool *), - const char *note) - { - bool flag; - if ((*get) (info, &flag) == 0 && flag) - fputs (note, stdout); - } - inline void show_int (int (*get) (Dwarf_Line *, unsigned int *), - const char *name) - { - unsigned int val; - if ((*get) (info, &val) == 0 && val != 0) - printf (" (%s %u)", name, val); - } - - show (&dwarf_linebeginstatement, " (is_stmt)"); - show (&dwarf_lineblock, " (basic_block)"); - show (&dwarf_lineprologueend, " (prologue_end)"); - show (&dwarf_lineepiloguebegin, " (epilogue_begin)"); - show_int (&dwarf_lineisa, "isa"); - show_int (&dwarf_linediscriminator, "discriminator"); + + show (&dwarf_linebeginstatement, " (is_stmt)",info); + show (&dwarf_lineblock, " (basic_block)",info); + show (&dwarf_lineprologueend, " (prologue_end)",info); + show (&dwarf_lineepiloguebegin, " (epilogue_begin)",info); + show_int (&dwarf_lineisa, "isa",info); + show_int (&dwarf_linediscriminator, "discriminator",info); } putchar ('\n'); } diff --git a/src/ar.c b/src/ar.c index 7d33d814..2beadffb 100644 --- a/src/ar.c +++ b/src/ar.c @@ -436,30 +436,31 @@ copy_content (Elf *elf, int newfd, off_t off, size_t n) return write_retry (newfd, rawfile + off, n) != (ssize_t) n; } - -static int -do_oper_extract (int oper, const char *arfname, char **argv, int argc, - long int instance) -{ - bool found[argc > 0 ? argc : 1]; - memset (found, '\0', sizeof (found)); - - size_t name_max = 0; - inline bool should_truncate_fname (void) +inline static bool should_truncate_fname (size_t *name_max) { if (errno == ENAMETOOLONG && allow_truncate_fname) { - if (name_max == 0) + if (*name_max == 0) { long int len = pathconf (".", _PC_NAME_MAX); if (len > 0) - name_max = len; + *name_max = len; } - return name_max != 0; + return *name_max != 0; } return false; } + +static int +do_oper_extract (int oper, const char *arfname, char **argv, int argc, + long int instance) +{ + bool found[argc > 0 ? argc : 1]; + memset (found, '\0', sizeof (found)); + + size_t name_max = 0; + off_t index_off = -1; size_t index_size = 0; off_t cur_off = SARMAG; @@ -615,7 +616,7 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, { int printlen = INT_MAX; - if (should_truncate_fname ()) + if (should_truncate_fname (&name_max)) { /* Try to truncate the name. First find out by how much. */ @@ -704,7 +705,7 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, { int printlen = INT_MAX; - if (should_truncate_fname ()) + if (should_truncate_fname (&name_max)) { /* Try to truncate the name. First find out by how much. */ diff --git a/src/arlib-argp.c b/src/arlib-argp.c index 1bdd8d0b..8719ec10 100644 --- a/src/arlib-argp.c +++ b/src/arlib-argp.c @@ -56,10 +56,7 @@ parse_opt (int key, char *arg __attribute__ ((unused)), return 0; } -static char * -help_filter (int key, const char *text, void *input __attribute__ ((unused))) -{ - inline char *text_for_default (void) +inline static char *text_for_default (const char *text) { char *new_text; if (unlikely (asprintf (&new_text, gettext ("%s (default)"), text) < 0)) @@ -67,15 +64,19 @@ help_filter (int key, const char *text, void *input __attribute__ ((unused))) return new_text; } +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) { case 'D': if (DEFAULT_AR_DETERMINISTIC) - return text_for_default (); + return text_for_default (text); break; case 'U': if (! DEFAULT_AR_DETERMINISTIC) - return text_for_default (); + return text_for_default (text); break; } diff --git a/src/elfcompress.c b/src/elfcompress.c index 6ba6af41..0fa10299 100644 --- a/src/elfcompress.c +++ b/src/elfcompress.c @@ -242,52 +242,19 @@ compress_section (Elf_Scn *scn, size_t orig_size, const char *name, return res; } -static int -process_file (const char *fname) -{ - if (verbose > 0) - printf ("processing: %s\n", fname); - - /* The input ELF. */ - int fd = -1; - Elf *elf = NULL; - - /* The output ELF. */ - char *fnew = NULL; - int fdnew = -1; - Elf *elfnew = NULL; - - /* Buffer for (one) new section name if necessary. */ - char *snamebuf = NULL; - - /* String table (and symbol table), if section names need adjusting. */ - Dwelf_Strtab *names = NULL; - Dwelf_Strent **scnstrents = NULL; - Dwelf_Strent **symstrents = NULL; - char **scnnames = NULL; - - /* Section data from names. */ - void *namesbuf = NULL; - - /* Which sections match and need to be (un)compressed. */ - unsigned int *sections = NULL; - - /* How many sections are we talking about? */ - size_t shnum = 0; - #define WORD_BITS (8U * sizeof (unsigned int)) - void set_section (size_t ndx) + static void set_section (size_t ndx,unsigned int *sections) { sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS)); } - bool get_section (size_t ndx) + static bool get_section (size_t ndx,unsigned int *sections) { return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0; } /* How many sections are we going to change? */ - size_t get_sections (void) + static size_t get_sections (size_t shnum,unsigned int *sections) { size_t s = 0; for (size_t i = 0; i < shnum / WORD_BITS + 1; i++) @@ -295,7 +262,10 @@ process_file (const char *fname) return s; } - int cleanup (int res) + static int cleanup (int res,Elf *elf,Elf *elfnew,int fd,int fdnew,char *fnew, + char *snamebuf,Dwelf_Strtab *names,Dwelf_Strent **scnstrents, + Dwelf_Strent **symstrents,char **scnnames,size_t shnum,void *namesbuf, + unsigned int *sections) { elf_end (elf); close (fd); @@ -329,12 +299,46 @@ process_file (const char *fname) return res; } +static int +process_file (const char *fname) +{ + if (verbose > 0) + printf ("processing: %s\n", fname); + + /* The input ELF. */ + int fd = -1; + Elf *elf = NULL; + + /* The output ELF. */ + char *fnew = NULL; + int fdnew = -1; + Elf *elfnew = NULL; + + /* Buffer for (one) new section name if necessary. */ + char *snamebuf = NULL; + + /* String table (and symbol table), if section names need adjusting. */ + Dwelf_Strtab *names = NULL; + Dwelf_Strent **scnstrents = NULL; + Dwelf_Strent **symstrents = NULL; + char **scnnames = NULL; + + /* Section data from names. */ + void *namesbuf = NULL; + + /* Which sections match and need to be (un)compressed. */ + unsigned int *sections = NULL; + + /* How many sections are we talking about? */ + size_t shnum = 0; + fd = open (fname, O_RDONLY); if (fd < 0) { error (0, errno, "Couldn't open %s\n", fname); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } elf = elf_begin (fd, ELF_C_READ, NULL); @@ -342,7 +346,8 @@ process_file (const char *fname) { error (0, 0, "Couldn't open ELF file %s for reading: %s", fname, elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } /* We dont' handle ar files (or anything else), we probably should. */ @@ -353,21 +358,24 @@ process_file (const char *fname) error (0, 0, "Cannot handle ar files: %s", fname); else error (0, 0, "Unknown file type: %s", fname); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } struct stat st; if (fstat (fd, &st) != 0) { error (0, errno, "Couldn't fstat %s", fname); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } GElf_Ehdr ehdr; if (gelf_getehdr (elf, &ehdr) == NULL) { error (0, 0, "Couldn't get ehdr for %s: %s", fname, elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } /* Get the section header string table. */ @@ -376,7 +384,8 @@ process_file (const char *fname) { error (0, 0, "Couldn't get section header string table index in %s: %s", fname, elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } /* How many sections are we talking about? */ @@ -384,13 +393,15 @@ process_file (const char *fname) { error (0, 0, "Couldn't get number of sections in %s: %s", fname, elf_errmsg (1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } if (shnum == 0) { error (0, 0, "ELF file %s has no sections", fname); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } sections = xcalloc (shnum / 8 + 1, sizeof (unsigned int)); @@ -398,8 +409,8 @@ process_file (const char *fname) size_t phnum; if (elf_getphdrnum (elf, &phnum) != 0) { - error (0, 0, "Couldn't get phdrnum: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } /* Whether we need to adjust any section names (going to/from GNU @@ -456,7 +467,8 @@ process_file (const char *fname) { error (0, 0, "Unexpected section number %zd, expected only %zd", ndx, shnum); - cleanup (-1); + cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names,scnstrents, + symstrents,scnnames,shnum,namesbuf,sections); } GElf_Shdr shdr_mem; @@ -464,14 +476,18 @@ process_file (const char *fname) if (shdr == NULL) { error (0, 0, "Couldn't get shdr for section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name); if (sname == NULL) { error (0, 0, "Couldn't get name for section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } if (section_name_matches (sname)) @@ -498,7 +514,7 @@ process_file (const char *fname) else if (shdr->sh_type != SHT_NOBITS && (shdr->sh_flags & SHF_ALLOC) == 0) { - set_section (ndx); + set_section (ndx,sections); /* Check if we might want to change this section name. */ if (! adjust_names && ((type != T_COMPRESS_GNU @@ -532,7 +548,9 @@ process_file (const char *fname) { error (0, 0, "Multiple symbol tables (%zd, %zd) using the same string table unsupported", symtabndx, ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } symtabndx = ndx; } @@ -549,12 +567,14 @@ process_file (const char *fname) } } - if (foutput == NULL && get_sections () == 0) + if (foutput == NULL && get_sections (shnum,sections) == 0) { if (verbose > 0) printf ("Nothing to do.\n"); fnew = NULL; - return cleanup (0); + return cleanup (0,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } if (adjust_names) @@ -563,7 +583,9 @@ process_file (const char *fname) if (names == NULL) { error (0, 0, "Not enough memory for new strtab"); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } scnstrents = xmalloc (shnum * sizeof (Dwelf_Strent *)); @@ -590,7 +612,9 @@ process_file (const char *fname) /* Since we didn't create it we don't want to try to unlink it. */ free (fnew); fnew = NULL; - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL); @@ -598,21 +622,27 @@ process_file (const char *fname) { error (0, 0, "Couldn't open new ELF %s for writing: %s", fnew, elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } /* Create the new ELF header and copy over all the data. */ if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0) { error (0, 0, "Couldn't create new ehdr: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } GElf_Ehdr newehdr; if (gelf_getehdr (elfnew, &newehdr) == NULL) { error (0, 0, "Couldn't get new ehdr: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA]; @@ -625,7 +655,9 @@ process_file (const char *fname) if (gelf_update_ehdr (elfnew, &newehdr) == 0) { error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } /* Copy over the phdrs as is. */ @@ -634,7 +666,9 @@ process_file (const char *fname) if (gelf_newphdr (elfnew, phnum) == 0) { error (0, 0, "Couldn't create phdrs: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } for (size_t cnt = 0; cnt < phnum; ++cnt) @@ -644,13 +678,17 @@ process_file (const char *fname) if (phdr == NULL) { error (0, 0, "Couldn't get phdr %zd: %s", cnt, elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } if (gelf_update_phdr (elfnew, cnt, phdr) == 0) { error (0, 0, "Couldn't create phdr %zd: %s", cnt, elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } } } @@ -687,14 +725,16 @@ process_file (const char *fname) /* (de)compress if section matched. */ char *sname = NULL; char *newname = NULL; - if (get_section (ndx)) + if (get_section (ndx,sections)) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); if (shdr == NULL) { error (0, 0, "Couldn't get shdr for section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } uint64_t size = shdr->sh_size; @@ -702,7 +742,9 @@ process_file (const char *fname) if (sname == NULL) { error (0, 0, "Couldn't get name for section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } /* strdup sname, the shdrstrndx section itself might be @@ -724,7 +766,9 @@ process_file (const char *fname) { if (compress_section (scn, size, sname, NULL, ndx, false, false, verbose > 0) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } else if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0) { @@ -733,7 +777,9 @@ process_file (const char *fname) newname = snamebuf; if (compress_section (scn, size, sname, newname, ndx, true, false, verbose > 0) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf,names, + scnstrents,symstrents,scnnames,shnum,namesbuf, + sections); } else if (verbose > 0) printf ("[%zd] %s already decompressed\n", ndx, sname); @@ -748,7 +794,9 @@ process_file (const char *fname) Don't report even when verbose. */ if (compress_section (scn, size, sname, NULL, ndx, false, false, false) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } snamebuf[0] = '.'; @@ -779,7 +827,9 @@ process_file (const char *fname) ndx, true, true, verbose > 0); if (res < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); if (res == 0) newname = NULL; @@ -805,7 +855,9 @@ process_file (const char *fname) Don't report even when verbose. */ if (compress_section (scn, size, sname, NULL, ndx, true, false, false) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); snamebuf[0] = '.'; strcpy (&snamebuf[1], &sname[2]); @@ -833,7 +885,9 @@ process_file (const char *fname) } else if (compress_section (scn, size, sname, newname, ndx, false, true, verbose > 0) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } else if (verbose > 0) printf ("[%zd] %s already compressed\n", ndx, sname); @@ -847,7 +901,9 @@ process_file (const char *fname) if (newscn == NULL) { error (0, 0, "Couldn't create new section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } GElf_Shdr shdr_mem; @@ -855,13 +911,17 @@ process_file (const char *fname) if (shdr == NULL) { error (0, 0, "Couldn't get shdr for section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } if (gelf_update_shdr (newscn, shdr) == 0) { error (0, 0, "Couldn't update section header %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* Except for the section header string table all data can be @@ -874,14 +934,18 @@ process_file (const char *fname) if (data == NULL) { error (0, 0, "Couldn't get data from section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } Elf_Data *newdata = elf_newdata (newscn); if (newdata == NULL) { error (0, 0, "Couldn't create new data for section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } *newdata = *data; @@ -899,7 +963,9 @@ process_file (const char *fname) if (name == NULL) { error (0, 0, "Couldn't get name for section [%zd]", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } } @@ -908,7 +974,9 @@ process_file (const char *fname) if ((scnstrents[ndx] = dwelf_strtab_add (names, name)) == NULL) { error (0, 0, "No memory to add section name string table"); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* If the symtab shares strings then add those too. */ @@ -925,7 +993,9 @@ process_file (const char *fname) /* Don't report the (internal) uncompression. */ if (compress_section (newscn, size, sname, NULL, ndx, false, false, false) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); symtab_size = size; symtab_compressed = T_COMPRESS_ZLIB; @@ -935,7 +1005,9 @@ process_file (const char *fname) /* Don't report the (internal) uncompression. */ if (compress_section (newscn, size, sname, NULL, ndx, true, false, false) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); symtab_size = size; symtab_compressed = T_COMPRESS_GNU; @@ -947,7 +1019,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get symtab data for section [%zd] %s", ndx, name); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT); size_t syms = symd->d_size / elsize; @@ -959,7 +1033,9 @@ process_file (const char *fname) if (sym == NULL) { error (0, 0, "Couldn't get symbol %zd", i); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } if (sym->st_name != 0) { @@ -971,13 +1047,17 @@ process_file (const char *fname) if (symname == NULL) { error (0, 0, "Couldn't get symbol %zd name", i); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } symstrents[i] = dwelf_strtab_add (names, symname); if (symstrents[i] == NULL) { error (0, 0, "No memory to add to symbol name"); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } } } @@ -996,19 +1076,25 @@ process_file (const char *fname) { error (0, 0, "Couldn't get new section header string table [%zd]", shdrstrndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } Elf_Data *data = elf_newdata (scn); if (data == NULL) { error (0, 0, "Couldn't create new section header string table data"); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } if (dwelf_strtab_finalize (names, data) == NULL) { error (0, 0, "Not enough memory to create string table"); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } namesbuf = data->d_buf; @@ -1018,7 +1104,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get shdr for new section strings %zd", shdrstrndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* Note that we also might have to compress and possibly set @@ -1038,7 +1126,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't update new section strings [%zd]", shdrstrndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* We might have to compress the data if the user asked us to, @@ -1054,7 +1144,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get section header string table [%zd]", shdrstrndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } shdr = gelf_getshdr (oldscn, &shdr_mem); @@ -1062,7 +1154,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get shdr for old section strings [%zd]", shdrstrndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } shstrtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name); @@ -1070,7 +1164,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get name for old section strings [%zd]", shdrstrndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } shstrtab_size = shdr->sh_size; @@ -1087,7 +1183,9 @@ process_file (const char *fname) shstrtab_newname, shdrstrndx, shstrtab_compressed == T_COMPRESS_GNU, true, verbose > 0) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } } @@ -1096,7 +1194,9 @@ process_file (const char *fname) if (gelf_getehdr (elfnew, &newehdr) == NULL) { error (0, 0, "Couldn't re-get new ehdr: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* Set this after the sections have been created, otherwise section @@ -1104,7 +1204,9 @@ process_file (const char *fname) if (setshdrstrndx (elfnew, &newehdr, shdrstrndx) != 0) { error (0, 0, "Couldn't set new shdrstrndx: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* Fixup pass. Adjust string table references, symbol table and @@ -1121,7 +1223,9 @@ process_file (const char *fname) if (shdr == NULL) { error (0, 0, "Couldn't get shdr for section %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* Keep the offset of allocated sections so they are at the @@ -1143,7 +1247,9 @@ process_file (const char *fname) if (gelf_update_shdr (scn, shdr) == 0) { error (0, 0, "Couldn't update section header %zd", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } if (adjust_names && ndx == symtabndx) @@ -1156,7 +1262,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get new symtab data section [%zd]", ndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT); size_t syms = symd->d_size / elsize; @@ -1167,7 +1275,9 @@ process_file (const char *fname) if (sym == NULL) { error (0, 0, "2 Couldn't get symbol %zd", i); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } if (sym->st_name != 0) @@ -1177,7 +1287,9 @@ process_file (const char *fname) if (gelf_update_sym (symd, i, sym) == 0) { error (0, 0, "Couldn't update symbol %zd", i); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } } } @@ -1195,7 +1307,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get symbol table [%zd]", symtabndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } shdr = gelf_getshdr (oldscn, &shdr_mem); @@ -1203,7 +1317,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get old symbol table shdr [%zd]", symtabndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } symtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name); @@ -1211,7 +1327,9 @@ process_file (const char *fname) { error (0, 0, "Couldn't get old symbol table name [%zd]", symtabndx); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } symtab_size = shdr->sh_size; @@ -1229,7 +1347,9 @@ process_file (const char *fname) symtab_newname, symtabndx, symtab_compressed == T_COMPRESS_GNU, true, verbose > 0) < 0) - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } } } @@ -1243,7 +1363,9 @@ process_file (const char *fname) if (gelf_getehdr (elfnew, &newehdr) == NULL) { error (0, 0, "Couldn't get ehdr: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* Position the shdrs after the last (unallocated) section. */ @@ -1258,7 +1380,9 @@ process_file (const char *fname) if (gelf_update_ehdr (elfnew, &newehdr) == 0) { error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } } @@ -1268,7 +1392,9 @@ process_file (const char *fname) if (elf_update (elfnew, ELF_C_WRITE) < 0) { error (0, 0, "Couldn't write %s: %s", fnew, elf_errmsg (-1)); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } elf_end (elfnew); @@ -1290,14 +1416,18 @@ process_file (const char *fname) if (rename (fnew, fname) != 0) { error (0, errno, "Couldn't rename %s to %s", fnew, fname); - return cleanup (-1); + return cleanup (-1,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } /* We are finally done with the new file, don't unlink it now. */ free (fnew); fnew = NULL; - return cleanup (0); + return cleanup (0,elf,elfnew,fd,fdnew,fnew,snamebuf, + names,scnstrents,symstrents,scnnames, + shnum,namesbuf, sections); } int diff --git a/src/elflint.c b/src/elflint.c index ef3e3732..05626084 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -3421,6 +3421,16 @@ section [%2d] '%s': unknown parent version '%s'\n"), } } + inline static size_t pos (const unsigned char *p,Elf_Data *data) + { + return p - (const unsigned char *) data->d_buf; + } + +inline static size_t left (Elf_Data *data,const unsigned char *p) + { + return (const unsigned char *) data->d_buf + data->d_size - p; + } + static void check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) { @@ -3438,12 +3448,6 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) idx, section_name (ebl, idx)); return; } - - inline size_t pos (const unsigned char *p) - { - return p - (const unsigned char *) data->d_buf; - } - const unsigned char *p = data->d_buf; if (*p++ != 'A') { @@ -3452,12 +3456,7 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) return; } - inline size_t left (void) - { - return (const unsigned char *) data->d_buf + data->d_size - p; - } - - while (left () >= 4) + while (left (data,p) >= 4) { uint32_t len; memcpy (&len, p, sizeof len); @@ -3465,16 +3464,16 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) if (len == 0) ERROR (gettext ("\ section [%2d] '%s': offset %zu: zero length field in attribute section\n"), - idx, section_name (ebl, idx), pos (p)); + idx, section_name (ebl, idx), pos (p,data)); if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) CONVERT (len); - if (len > left ()) + if (len > left (data,p)) { ERROR (gettext ("\ section [%2d] '%s': offset %zu: invalid length in attribute section\n"), - idx, section_name (ebl, idx), pos (p)); + idx, section_name (ebl, idx), pos (p,data)); break; } @@ -3486,7 +3485,7 @@ section [%2d] '%s': offset %zu: invalid length in attribute section\n"), { ERROR (gettext ("\ section [%2d] '%s': offset %zu: unterminated vendor name string\n"), - idx, section_name (ebl, idx), pos (p)); + idx, section_name (ebl, idx), pos (p,data)); break; } ++q; @@ -3503,7 +3502,7 @@ section [%2d] '%s': offset %zu: unterminated vendor name string\n"), { ERROR (gettext ("\ section [%2d] '%s': offset %zu: endless ULEB128 in attribute subsection tag\n"), - idx, section_name (ebl, idx), pos (chunk)); + idx, section_name (ebl, idx), pos (chunk,data)); break; } @@ -3512,7 +3511,7 @@ section [%2d] '%s': offset %zu: endless ULEB128 in attribute subsection tag\n"), { ERROR (gettext ("\ section [%2d] '%s': offset %zu: truncated attribute section\n"), - idx, section_name (ebl, idx), pos (q)); + idx, section_name (ebl, idx), pos (q,data)); break; } @@ -3521,7 +3520,7 @@ section [%2d] '%s': offset %zu: truncated attribute section\n"), { ERROR (gettext ("\ section [%2d] '%s': offset %zu: zero length field in attribute subsection\n"), - idx, section_name (ebl, idx), pos (q)); + idx, section_name (ebl, idx), pos (q,data)); q += sizeof subsection_len; continue; @@ -3536,7 +3535,7 @@ section [%2d] '%s': offset %zu: zero length field in attribute subsection\n"), { ERROR (gettext ("\ section [%2d] '%s': offset %zu: invalid length in attribute subsection\n"), - idx, section_name (ebl, idx), pos (q)); + idx, section_name (ebl, idx), pos (q,data)); break; } @@ -3547,7 +3546,7 @@ section [%2d] '%s': offset %zu: invalid length in attribute subsection\n"), if (subsection_tag != 1) /* Tag_File */ ERROR (gettext ("\ section [%2d] '%s': offset %zu: attribute subsection has unexpected tag %u\n"), - idx, section_name (ebl, idx), pos (chunk), subsection_tag); + idx, section_name (ebl, idx), pos (chunk,data), subsection_tag); else { chunk += sizeof subsection_len; @@ -3565,7 +3564,7 @@ section [%2d] '%s': offset %zu: attribute subsection has unexpected tag %u\n"), { ERROR (gettext ("\ section [%2d] '%s': offset %zu: endless ULEB128 in attribute tag\n"), - idx, section_name (ebl, idx), pos (chunk)); + idx, section_name (ebl, idx), pos (chunk,data)); break; } } @@ -3576,7 +3575,7 @@ section [%2d] '%s': offset %zu: endless ULEB128 in attribute tag\n"), { ERROR (gettext ("\ section [%2d] '%s': offset %zu: unterminated string in attribute\n"), - idx, section_name (ebl, idx), pos (chunk)); + idx, section_name (ebl, idx), pos (chunk,data)); break; } ++r; @@ -3589,11 +3588,11 @@ section [%2d] '%s': offset %zu: unterminated string in attribute\n"), &tag_name, &value_name)) ERROR (gettext ("\ section [%2d] '%s': offset %zu: unrecognized attribute tag %u\n"), - idx, section_name (ebl, idx), pos (chunk), tag); + idx, section_name (ebl, idx), pos (chunk,data), tag); else if ((tag & 1) == 0 && value_name == NULL) ERROR (gettext ("\ section [%2d] '%s': offset %zu: unrecognized %s attribute value %" PRIu64 "\n"), - idx, section_name (ebl, idx), pos (chunk), + idx, section_name (ebl, idx), pos (chunk,data), tag_name, value); chunk = r; @@ -3603,13 +3602,13 @@ section [%2d] '%s': offset %zu: unrecognized %s attribute value %" PRIu64 "\n"), else ERROR (gettext ("\ section [%2d] '%s': offset %zu: vendor '%s' unknown\n"), - idx, section_name (ebl, idx), pos (p), name); + idx, section_name (ebl, idx), pos (p,data), name); } - if (left () != 0) + if (left (data,p) != 0) ERROR (gettext ("\ section [%2d] '%s': offset %zu: extra bytes after last attribute section\n"), - idx, section_name (ebl, idx), pos (p)); + idx, section_name (ebl, idx), pos (p,data)); } static bool has_loadable_segment; @@ -3905,6 +3904,7 @@ section [%2zu] '%s': size not multiple of entry size\n"), && shdr->sh_type != SHT_GNU_ATTRIBUTES && shdr->sh_type != SHT_GNU_LIBLIST && shdr->sh_type != SHT_CHECKSUM + && shdr->sh_type != SHT_LLVM_ADDRSIG && shdr->sh_type != SHT_GNU_verdef && shdr->sh_type != SHT_GNU_verneed && shdr->sh_type != SHT_GNU_versym diff --git a/src/readelf.c b/src/readelf.c index f6d13afa..2bfe43bd 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -381,13 +381,7 @@ main (int argc, char *argv[]) return error_message_count != 0; } - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg, - struct argp_state *state __attribute__ ((unused))) -{ - void add_dump_section (const char *name, bool implicit) +static void add_dump_section (const char *name, bool implicit,int key) { struct section_argument *a = xmalloc (sizeof *a); a->arg = name; @@ -399,7 +393,14 @@ parse_opt (int key, char *arg, *tailp = &a->next; } - switch (key) + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) { case 'a': print_file_header = true; @@ -414,9 +415,9 @@ parse_opt (int key, char *arg, print_arch = true; print_notes = true; implicit_debug_sections |= section_exception; - add_dump_section (".strtab", true); - add_dump_section (".dynstr", true); - add_dump_section (".comment", true); + add_dump_section (".strtab", true,key); + add_dump_section (".dynstr", true,key); + add_dump_section (".comment", true,key); any_control_option = true; break; case 'A': @@ -562,7 +563,7 @@ parse_opt (int key, char *arg, } FALLTHROUGH; case 'x': - add_dump_section (arg, false); + add_dump_section (arg, false,key); any_control_option = true; break; case 'N': @@ -3567,6 +3568,11 @@ print_liblist (Ebl *ebl) } } +inline static size_t elf_left (Elf_Data *data,const unsigned char *p) + { + return (const unsigned char *) data->d_buf + data->d_size - p; + } + static void print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr) { @@ -3611,13 +3617,9 @@ print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr) fputs_unlocked (gettext (" Owner Size\n"), stdout); - inline size_t left (void) - { - return (const unsigned char *) data->d_buf + data->d_size - p; - } - + /* Loop over the sections. */ - while (left () >= 4) + while (elf_left (data,p) >= 4) { /* Section length. */ uint32_t len; @@ -3626,7 +3628,7 @@ print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr) if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) CONVERT (len); - if (unlikely (len > left ())) + if (unlikely (len > elf_left (data,p))) break; /* Section vendor name. */ @@ -6200,6 +6202,12 @@ read_encoded (unsigned int encoding, const unsigned char *readp, return readp; } +static const char *regname (unsigned int regno,Ebl *ebl,char *regnamebuf) + { + register_info (ebl, regno, NULL, regnamebuf, NULL, NULL); + return regnamebuf; + } + static void print_cfa_program (const unsigned char *readp, const unsigned char *const endp, @@ -6210,12 +6218,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, Dwarf *dbg) { char regnamebuf[REGNAMESZ]; - const char *regname (unsigned int regno) - { - register_info (ebl, regno, NULL, regnamebuf, NULL, NULL); - return regnamebuf; - } - + puts ("\n Program:"); Dwarf_Word pc = vma_base; while (readp < endp) @@ -6271,26 +6274,26 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, get_uleb128 (op2, readp, endp); printf (" offset_extended r%" PRIu64 " (%s) at cfa%+" PRId64 "\n", - op1, regname (op1), op2 * data_align); + op1, regname (op1,ebl,regnamebuf), op2 * data_align); break; case DW_CFA_restore_extended: if ((uint64_t) (endp - readp) < 1) goto invalid; get_uleb128 (op1, readp, endp); printf (" restore_extended r%" PRIu64 " (%s)\n", - op1, regname (op1)); + op1, regname (op1,ebl,regnamebuf)); break; case DW_CFA_undefined: if ((uint64_t) (endp - readp) < 1) goto invalid; get_uleb128 (op1, readp, endp); - printf (" undefined r%" PRIu64 " (%s)\n", op1, regname (op1)); + printf (" undefined r%" PRIu64 " (%s)\n", op1, regname (op1,ebl,regnamebuf)); break; case DW_CFA_same_value: if ((uint64_t) (endp - readp) < 1) goto invalid; get_uleb128 (op1, readp, endp); - printf (" same_value r%" PRIu64 " (%s)\n", op1, regname (op1)); + printf (" same_value r%" PRIu64 " (%s)\n", op1, regname (op1,ebl,regnamebuf)); break; case DW_CFA_register: if ((uint64_t) (endp - readp) < 1) @@ -6300,7 +6303,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, goto invalid; get_uleb128 (op2, readp, endp); printf (" register r%" PRIu64 " (%s) in r%" PRIu64 " (%s)\n", - op1, regname (op1), op2, regname (op2)); + op1, regname (op1,ebl,regnamebuf), op2, regname (op2,ebl,regnamebuf)); break; case DW_CFA_remember_state: puts (" remember_state"); @@ -6316,14 +6319,14 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, goto invalid; get_uleb128 (op2, readp, endp); printf (" def_cfa r%" PRIu64 " (%s) at offset %" PRIu64 "\n", - op1, regname (op1), op2); + op1, regname (op1,ebl,regnamebuf), op2); break; case DW_CFA_def_cfa_register: if ((uint64_t) (endp - readp) < 1) goto invalid; get_uleb128 (op1, readp, endp); printf (" def_cfa_register r%" PRIu64 " (%s)\n", - op1, regname (op1)); + op1, regname (op1,ebl,regnamebuf)); break; case DW_CFA_def_cfa_offset: if ((uint64_t) (endp - readp) < 1) @@ -6354,7 +6357,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, goto invalid; get_uleb128 (op2, readp, endp); /* Length of DW_FORM_block. */ printf (" expression r%" PRIu64 " (%s) \n", - op1, regname (op1)); + op1, regname (op1,ebl,regnamebuf)); if ((uint64_t) (endp - readp) < op2) goto invalid; print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, NULL, @@ -6370,7 +6373,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, get_sleb128 (sop2, readp, endp); printf (" offset_extended_sf r%" PRIu64 " (%s) at cfa%+" PRId64 "\n", - op1, regname (op1), sop2 * data_align); + op1, regname (op1,ebl,regnamebuf), sop2 * data_align); break; case DW_CFA_def_cfa_sf: if ((uint64_t) (endp - readp) < 1) @@ -6380,7 +6383,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, goto invalid; get_sleb128 (sop2, readp, endp); printf (" def_cfa_sf r%" PRIu64 " (%s) at offset %" PRId64 "\n", - op1, regname (op1), sop2 * data_align); + op1, regname (op1,ebl,regnamebuf), sop2 * data_align); break; case DW_CFA_def_cfa_offset_sf: if ((uint64_t) (endp - readp) < 1) @@ -6416,7 +6419,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, goto invalid; get_uleb128 (op2, readp, endp); /* Length of DW_FORM_block. */ printf (" val_expression r%" PRIu64 " (%s)\n", - op1, regname (op1)); + op1, regname (op1,ebl,regnamebuf)); if ((uint64_t) (endp - readp) < op2) goto invalid; print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, @@ -6456,11 +6459,11 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, goto invalid; get_uleb128 (offset, readp, endp); printf (" offset r%u (%s) at cfa%+" PRId64 "\n", - opcode & 0x3f, regname (opcode & 0x3f), offset * data_align); + opcode & 0x3f, regname (opcode & 0x3f,ebl,regnamebuf), offset * data_align); } else printf (" restore r%u (%s)\n", - opcode & 0x3f, regname (opcode & 0x3f)); + opcode & 0x3f, regname (opcode & 0x3f,ebl,regnamebuf)); } } @@ -8343,6 +8346,22 @@ print_form_data (Dwarf *dbg, int form, const unsigned char *readp, return readp; } +/* Apply the "operation advance" from a special opcode + or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */ + static inline void advance_pc (unsigned int op_advance, + unsigned int *op_addr_advance, + uint_fast8_t minimum_instr_len,unsigned int *op_index , + uint_fast8_t max_ops_per_instr, Dwarf_Word *address, + bool *show_op_index + ) + { + *op_addr_advance = minimum_instr_len * ((*op_index + op_advance) + / max_ops_per_instr); + *address += *op_addr_advance; + *show_op_index = (*op_index > 0 || + (*op_index + op_advance) % max_ops_per_instr > 0); + *op_index = (*op_index + op_advance) % max_ops_per_instr; + } static void print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, @@ -8731,20 +8750,9 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, size_t line = 1; uint_fast8_t is_stmt = default_is_stmt; - /* Apply the "operation advance" from a special opcode - or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */ unsigned int op_addr_advance; bool show_op_index; - inline void advance_pc (unsigned int op_advance) - { - op_addr_advance = minimum_instr_len * ((op_index + op_advance) - / max_ops_per_instr); - address += op_addr_advance; - show_op_index = (op_index > 0 || - (op_index + op_advance) % max_ops_per_instr > 0); - op_index = (op_index + op_advance) % max_ops_per_instr; - } - + if (max_ops_per_instr == 0) { error (0, 0, @@ -8777,10 +8785,9 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, */ int line_increment = (line_base + (opcode - opcode_base) % line_range); - - /* Perform the increments. */ + /* Perform the increments. */ line += line_increment; - advance_pc ((opcode - opcode_base) / line_range); + advance_pc ((opcode - opcode_base) / line_range,&op_addr_advance,minimum_instr_len,&op_index,max_ops_per_instr,&address,&show_op_index); printf (gettext (" special opcode %u: address+%u = "), opcode, op_addr_advance); @@ -8898,7 +8905,10 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, if (lineendp - linep < 1) goto invalid_unit; get_uleb128 (u128, linep, lineendp); - advance_pc (u128); + advance_pc (u128,&op_addr_advance,minimum_instr_len, + &op_index,max_ops_per_instr,&address, + &show_op_index + ); { printf (gettext (" advance address by %u to "), op_addr_advance); @@ -8958,8 +8968,10 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, if (unlikely (line_range == 0)) goto invalid_unit; - - advance_pc ((255 - opcode_base) / line_range); + advance_pc ((255 - opcode_base) / line_range, + &op_addr_advance,minimum_instr_len,&op_index, + max_ops_per_instr,&address, + &show_op_index); { printf (gettext (" advance address by constant %u to "), op_addr_advance); @@ -12067,7 +12079,18 @@ compare_register_sets (const void *a, const void *b) const struct register_info *const *p2 = b; return compare_sets_by_info (*p1, *p2); } - + /* Collect the unique sets and sort them. */ + inline static bool same_set (const struct register_info *a, + const struct register_info *b, + const struct register_info *regs, + ssize_t maxnreg + ) + { + return (a < ®s[maxnreg] && a->regloc != NULL + && b < ®s[maxnreg] && b->regloc != NULL + && a->bits == b->bits + && (a->set == b->set || !strcmp (a->set, b->set))); + } static unsigned int handle_core_registers (Ebl *ebl, Elf *core, const void *desc, const Ebl_Register_Location *reglocs, size_t nregloc) @@ -12105,20 +12128,13 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc, } qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers); - /* Collect the unique sets and sort them. */ - inline bool same_set (const struct register_info *a, - const struct register_info *b) - { - return (a < ®s[maxnreg] && a->regloc != NULL - && b < ®s[maxnreg] && b->regloc != NULL - && a->bits == b->bits - && (a->set == b->set || !strcmp (a->set, b->set))); - } + struct register_info *sets[maxreg + 1]; sets[0] = ®s[0]; size_t nsets = 1; for (int i = 1; i <= maxreg; ++i) - if (regs[i].regloc != NULL && !same_set (®s[i], ®s[i - 1])) + if (regs[i].regloc != NULL && + !same_set (®s[i], ®s[i - 1],regs, maxnreg)) sets[nsets++] = ®s[i]; qsort (sets, nsets, sizeof sets[0], &compare_register_sets); @@ -12129,7 +12145,7 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc, /* Find the longest name of a register in this set. */ size_t maxname = 0; const struct register_info *end; - for (end = sets[i]; same_set (sets[i], end); ++end) + for (end = sets[i]; same_set (sets[i], end,regs,maxnreg); ++end) { size_t len = strlen (end->name); if (len > maxname) diff --git a/src/strip.c b/src/strip.c index 48792a70..33e47dc0 100644 --- a/src/strip.c +++ b/src/strip.c @@ -442,85 +442,14 @@ update_shdrstrndx (Elf *elf, size_t shdrstrndx) return 0; } -/* Remove any relocations between debug sections in ET_REL - for the debug file when requested. These relocations are always - zero based between the unallocated sections. */ -static void -remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr, - const char *fname, size_t shstrndx) -{ - Elf_Scn *scn = NULL; - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - /* We need the actual section and header from the elf - not just the cached original in shdr_info because we - might want to change the size. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) - { - /* Make sure that this relocation section points to a - section to relocate with contents, that isn't - allocated and that is a debug section. */ - Elf_Scn *tscn = elf_getscn (elf, shdr->sh_info); - GElf_Shdr tshdr_mem; - GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); - if (tshdr->sh_type == SHT_NOBITS - || tshdr->sh_size == 0 - || (tshdr->sh_flags & SHF_ALLOC) != 0) - continue; - - const char *tname = elf_strptr (elf, shstrndx, - tshdr->sh_name); - if (! tname || ! ebl_debugscn_p (ebl, tname)) - continue; - - /* OK, lets relocate all trivial cross debug section - relocations. */ - Elf_Data *reldata = elf_getdata (scn, NULL); - if (reldata == NULL || reldata->d_buf == NULL) - INTERNAL_ERROR (fname); - - /* Make sure we adjust the uncompressed debug data - (and recompress if necessary at the end). */ - GElf_Chdr tchdr; - int tcompress_type = 0; - bool is_gnu_compressed = false; - if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0) - { - is_gnu_compressed = true; - if (elf_compress_gnu (tscn, 0, 0) != 1) - INTERNAL_ERROR (fname); - } - else - { - if (gelf_getchdr (tscn, &tchdr) != NULL) - { - tcompress_type = tchdr.ch_type; - if (elf_compress (tscn, 0, 0) != 1) - INTERNAL_ERROR (fname); - } - } - - Elf_Data *tdata = elf_getdata (tscn, NULL); - if (tdata == NULL || tdata->d_buf == NULL - || tdata->d_type != ELF_T_BYTE) - INTERNAL_ERROR (fname); - - /* Pick up the symbol table and shndx table to - resolve relocation symbol indexes. */ - Elf64_Word symt = shdr->sh_link; - Elf_Data *symdata, *xndxdata; - Elf_Scn * symscn = elf_getscn (elf, symt); - symdata = elf_getdata (symscn, NULL); - xndxdata = get_xndxdata (elf, symscn); - if (symdata == NULL) - INTERNAL_ERROR (fname); /* Apply one relocation. Returns true when trivial relocation actually done. */ - bool relocate (GElf_Addr offset, const GElf_Sxword addend, - bool is_rela, int rtype, int symndx) + static bool relocate (GElf_Addr offset, const GElf_Sxword addend, + bool is_rela, int rtype, int symndx, + Ebl *ebl,Elf_Data *symdata,Elf_Data *xndxdata, + Elf *elf,Elf_Data *tdata,GElf_Ehdr *ehdr, + const char *fname) { /* R_*_NONE relocs can always just be removed. */ if (rtype == 0) @@ -658,6 +587,82 @@ remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr, return false; } +/* Remove any relocations between debug sections in ET_REL + for the debug file when requested. These relocations are always + zero based between the unallocated sections. */ +static void +remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr, + const char *fname, size_t shstrndx) +{ + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + /* We need the actual section and header from the elf + not just the cached original in shdr_info because we + might want to change the size. */ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) + { + /* Make sure that this relocation section points to a + section to relocate with contents, that isn't + allocated and that is a debug section. */ + Elf_Scn *tscn = elf_getscn (elf, shdr->sh_info); + GElf_Shdr tshdr_mem; + GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); + if (tshdr->sh_type == SHT_NOBITS + || tshdr->sh_size == 0 + || (tshdr->sh_flags & SHF_ALLOC) != 0) + continue; + + const char *tname = elf_strptr (elf, shstrndx, + tshdr->sh_name); + if (! tname || ! ebl_debugscn_p (ebl, tname)) + continue; + + /* OK, lets relocate all trivial cross debug section + relocations. */ + Elf_Data *reldata = elf_getdata (scn, NULL); + if (reldata == NULL || reldata->d_buf == NULL) + INTERNAL_ERROR (fname); + + /* Make sure we adjust the uncompressed debug data + (and recompress if necessary at the end). */ + GElf_Chdr tchdr; + int tcompress_type = 0; + bool is_gnu_compressed = false; + if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0) + { + is_gnu_compressed = true; + if (elf_compress_gnu (tscn, 0, 0) != 1) + INTERNAL_ERROR (fname); + } + else + { + if (gelf_getchdr (tscn, &tchdr) != NULL) + { + tcompress_type = tchdr.ch_type; + if (elf_compress (tscn, 0, 0) != 1) + INTERNAL_ERROR (fname); + } + } + + Elf_Data *tdata = elf_getdata (tscn, NULL); + if (tdata == NULL || tdata->d_buf == NULL + || tdata->d_type != ELF_T_BYTE) + INTERNAL_ERROR (fname); + + /* Pick up the symbol table and shndx table to + resolve relocation symbol indexes. */ + Elf64_Word symt = shdr->sh_link; + Elf_Data *symdata, *xndxdata; + Elf_Scn * symscn = elf_getscn (elf, symt); + symdata = elf_getdata (symscn, NULL); + xndxdata = get_xndxdata (elf, symscn); + if (symdata == NULL) + INTERNAL_ERROR (fname); + + if (shdr->sh_entsize == 0) INTERNAL_ERROR (fname); @@ -670,7 +675,8 @@ remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr, GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem); if (! relocate (r->r_offset, 0, false, GELF_R_TYPE (r->r_info), - GELF_R_SYM (r->r_info))) + GELF_R_SYM (r->r_info),ebl,symdata,xndxdata, + elf,tdata,ehdr,fname)) { if (relidx != next) gelf_update_rel (reldata, next, r); @@ -684,7 +690,8 @@ remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr, GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem); if (! relocate (r->r_offset, r->r_addend, true, GELF_R_TYPE (r->r_info), - GELF_R_SYM (r->r_info))) + GELF_R_SYM (r->r_info),ebl,symdata,xndxdata, + elf,tdata,ehdr,fname)) { if (relidx != next) gelf_update_rela (reldata, next, r); @@ -917,6 +924,82 @@ handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf, return 0; } +struct shdr_info + { + Elf_Scn *scn; + GElf_Shdr shdr; + Elf_Data *data; + Elf_Data *debug_data; + const char *name; + Elf32_Word idx; /* Index in new file. */ + Elf32_Word old_sh_link; /* Original value of shdr.sh_link. */ + Elf32_Word symtab_idx; + Elf32_Word version_idx; + Elf32_Word group_idx; + Elf32_Word group_cnt; + Elf_Scn *newscn; + Dwelf_Strent *se; + Elf32_Word *newsymidx; + } *shdr_info = NULL; + + /* This section is being preserved in the debug file. + Sections it refers to must be preserved there too. + + In this pass we mark sections to be preserved in both + files by setting the .debug_data pointer to the original + file's .data pointer. Below, we'll copy the section + contents. */ + + inline static void check_preserved (size_t i,size_t shnum, + bool *changes, + const char *fname,size_t cnt) + { + if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0 + && shdr_info[i].debug_data == NULL) + { + if (shdr_info[i].data == NULL) + shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL); + if (shdr_info[i].data == NULL) + INTERNAL_ERROR (fname); + + shdr_info[i].debug_data = shdr_info[i].data; + *changes |= i < cnt; + } + } + + /* Update section headers when the data size has changed. + We also update the SHT_NOBITS section in the debug + file so that the section headers match in sh_size. */ + inline static void update_section_size (const Elf_Data *newdata,Elf_Scn *scn, + Elf *debugelf, const char *fname,size_t cnt) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + shdr->sh_size = newdata->d_size; + (void) gelf_update_shdr (scn, shdr); + if (debugelf != NULL) + { + /* libelf will use d_size to set sh_size. */ + Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf, + cnt), NULL); + if (debugdata == NULL) + INTERNAL_ERROR (fname); + debugdata->d_size = newdata->d_size; + } + } + +inline static bool no_symtab_updates (const Elf32_Word symtabidx,size_t cnt) + { + /* If the symbol table hasn't changed, do not do anything. */ + if (shdr_info[symtabidx].newsymidx == NULL) + return true; + + /* If the symbol table is not discarded, but additionally + duplicated in the separate debug file and this section + is discarded, don't adjust anything. */ + return (shdr_info[cnt].idx == 0 + && shdr_info[symtabidx].debug_data != NULL); + } /* Maximum size of array allocated on stack. */ #define MAX_STACK_ALLOC (400 * 1024) @@ -936,23 +1019,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, GElf_Off lastsec_offset = 0; Elf64_Xword lastsec_size = 0; size_t shstrndx; - struct shdr_info - { - Elf_Scn *scn; - GElf_Shdr shdr; - Elf_Data *data; - Elf_Data *debug_data; - const char *name; - Elf32_Word idx; /* Index in new file. */ - Elf32_Word old_sh_link; /* Original value of shdr.sh_link. */ - Elf32_Word symtab_idx; - Elf32_Word version_idx; - Elf32_Word group_idx; - Elf32_Word group_cnt; - Elf_Scn *newscn; - Dwelf_Strent *se; - Elf32_Word *newsymidx; - } *shdr_info = NULL; Elf_Scn *scn; size_t cnt; size_t idx; @@ -1528,32 +1594,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (debug_fname != NULL && (shdr_info[cnt].idx == 0 || shdr_info[cnt].debug_data != NULL)) { - /* This section is being preserved in the debug file. - Sections it refers to must be preserved there too. - - In this pass we mark sections to be preserved in both - files by setting the .debug_data pointer to the original - file's .data pointer. Below, we'll copy the section - contents. */ - - inline void check_preserved (size_t i) - { - if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0 - && shdr_info[i].debug_data == NULL) - { - if (shdr_info[i].data == NULL) - shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL); - if (shdr_info[i].data == NULL) - INTERNAL_ERROR (fname); - - shdr_info[i].debug_data = shdr_info[i].data; - changes |= i < cnt; - } - } - - check_preserved (shdr_info[cnt].shdr.sh_link); + check_preserved (shdr_info[cnt].shdr.sh_link,shnum, + &changes,fname,cnt); if (SH_INFO_LINK_P (&shdr_info[cnt].shdr)) - check_preserved (shdr_info[cnt].shdr.sh_info); + check_preserved (shdr_info[cnt].shdr.sh_info,shnum, + &changes,fname,cnt); } } } @@ -2124,25 +2169,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Find all relocation sections which use this symbol table. */ for (cnt = 1; cnt <= shdridx; ++cnt) { - /* Update section headers when the data size has changed. - We also update the SHT_NOBITS section in the debug - file so that the section headers match in sh_size. */ - inline void update_section_size (const Elf_Data *newdata) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_size = newdata->d_size; - (void) gelf_update_shdr (scn, shdr); - if (debugelf != NULL) - { - /* libelf will use d_size to set sh_size. */ - Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf, - cnt), NULL); - if (debugdata == NULL) - INTERNAL_ERROR (fname); - debugdata->d_size = newdata->d_size; - } - } + if (shdr_info[cnt].idx == 0 && debug_fname == NULL) /* Ignore sections which are discarded. When we are saving a @@ -2155,22 +2182,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx; switch (shdr_info[cnt].shdr.sh_type) { - inline bool no_symtab_updates (void) - { - /* If the symbol table hasn't changed, do not do anything. */ - if (shdr_info[symtabidx].newsymidx == NULL) - return true; - - /* If the symbol table is not discarded, but additionally - duplicated in the separate debug file and this section - is discarded, don't adjust anything. */ - return (shdr_info[cnt].idx == 0 - && shdr_info[symtabidx].debug_data != NULL); - } - + case SHT_REL: case SHT_RELA: - if (no_symtab_updates ()) + if (no_symtab_updates (symtabidx,cnt)) break; Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0 @@ -2227,7 +2242,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, break; case SHT_HASH: - if (no_symtab_updates ()) + if (no_symtab_updates (symtabidx,cnt)) break; /* We have to recompute the hash table. */ @@ -2273,7 +2288,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, * sizeof (Elf32_Word)); elf_assert (n_size <= hashd->d_size); hashd->d_size = n_size; - update_section_size (hashd); + update_section_size (hashd,scn,debugelf,fname,cnt); /* Clear the arrays. */ memset (bucket, '\0', @@ -2335,7 +2350,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, * sizeof (Elf64_Xword)); elf_assert (n_size <= hashd->d_size); hashd->d_size = n_size; - update_section_size (hashd); + update_section_size (hashd,scn,debugelf,fname,cnt); /* Clear the arrays. */ memset (bucket, '\0', @@ -2371,7 +2386,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, case SHT_GNU_versym: /* If the symbol table changed we have to adjust the entries. */ - if (no_symtab_updates ()) + if (no_symtab_updates (symtabidx,cnt)) break; elf_assert (shdr_info[cnt].idx > 0); @@ -2409,11 +2424,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, / gelf_fsize (elf, symd->d_type, 1, EV_CURRENT), EV_CURRENT); - update_section_size (verd); + update_section_size (verd,scn,debugelf,fname,cnt); break; case SHT_GROUP: - if (no_symtab_updates ()) + if (no_symtab_updates (symtabidx,cnt)) break; /* Yes, the symbol table changed. diff --git a/src/unstrip.c b/src/unstrip.c index 231b941d..f3b280f3 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -436,14 +436,7 @@ update_sh_size (Elf_Scn *outscn, const Elf_Data *data) update_shdr (outscn, newshdr); } -/* Update relocation sections using the symbol table. */ -static void -adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, - size_t map[], size_t map_size, const GElf_Shdr *symshdr) -{ - Elf_Data *data = elf_getdata (outscn, NULL); - - inline void adjust_reloc (GElf_Xword *info) +inline static void adjust_reloc (GElf_Xword *info,size_t map_size,size_t map[]) { size_t ndx = GELF_R_SYM (*info); if (ndx != STN_UNDEF) @@ -454,7 +447,15 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, } } - switch (shdr->sh_type) + +/* Update relocation sections using the symbol table. */ +static void +adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, + size_t map[], size_t map_size, const GElf_Shdr *symshdr) +{ + Elf_Data *data = elf_getdata (outscn, NULL); + + switch (shdr->sh_type) { case SHT_REL: if (shdr->sh_entsize == 0) @@ -464,7 +465,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, { GElf_Rel rel_mem; GElf_Rel *rel = gelf_getrel (data, i, &rel_mem); - adjust_reloc (&rel->r_info); + adjust_reloc (&rel->r_info,map_size,map); ELF_CHECK (gelf_update_rel (data, i, rel), _("cannot update relocation: %s")); } @@ -478,7 +479,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, { GElf_Rela rela_mem; GElf_Rela *rela = gelf_getrela (data, i, &rela_mem); - adjust_reloc (&rela->r_info); + adjust_reloc (&rela->r_info,map_size,map); ELF_CHECK (gelf_update_rela (data, i, rela), _("cannot update relocation: %s")); } @@ -1066,6 +1067,16 @@ get_group_sig (Elf *elf, GElf_Shdr *shdr) return sig; } + inline static void check_match (bool match, Elf_Scn *scn, const char *name,bool *fail) + { + if (!match) + { + *fail = true; + error (0, 0, _("cannot find matching section for [%zu] '%s'"), + elf_ndxscn (scn), name); + } + } + /* Fix things up when prelink has moved some allocated sections around and the debuginfo file's section headers no longer match up. @@ -1202,16 +1213,6 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, } bool fail = false; - inline void check_match (bool match, Elf_Scn *scn, const char *name) - { - if (!match) - { - fail = true; - error (0, 0, _("cannot find matching section for [%zu] '%s'"), - elf_ndxscn (scn), name); - } - } - Elf_Scn *scn = NULL; while ((scn = elf_nextscn (debug, scn)) != NULL) { @@ -1242,7 +1243,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, for (size_t i = 0; shdr != NULL && i < nalloc; ++i) if (sections[i].outscn == scn) shdr = NULL; - check_match (shdr == NULL, scn, name); + check_match (shdr == NULL, scn, name,&fail); } if (fail) @@ -1298,7 +1299,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, } } - check_match (undo_sec == NULL, scn, name); + check_match (undo_sec == NULL, scn, name,&fail); } free (undo_sections); @@ -1377,6 +1378,33 @@ new_shstrtab (Elf *unstripped, size_t unstripped_shnum, return strtab_data; } +/* Locate a matching unallocated section in SECTIONS. */ + inline static struct section *find_unalloc_section (const GElf_Shdr *shdr, + const char *name, + const char *sig, + size_t nalloc, + size_t stripped_shnum, + struct section *sections + ) + { + size_t l = nalloc, u = stripped_shnum - 1; + while (l < u) + { + size_t i = (l + u) / 2; + struct section *sec = §ions[i]; + int cmp = compare_unalloc_sections (shdr, &sec->shdr, + name, sec->name, + sig, sec->sig); + if (cmp < 0) + u = i; + else if (cmp > 0) + l = i + 1; + else + return sec; + } + return NULL; + } + /* Fill in any SHT_NOBITS sections in UNSTRIPPED by copying their contents and sh_type from STRIPPED. */ @@ -1450,30 +1478,7 @@ more sections in stripped file than debug file -- arguments reversed?")); stripped_symtab = §ions[nalloc]; } - /* Locate a matching unallocated section in SECTIONS. */ - inline struct section *find_unalloc_section (const GElf_Shdr *shdr, - const char *name, - const char *sig) - { - size_t l = nalloc, u = stripped_shnum - 1; - while (l < u) - { - size_t i = (l + u) / 2; - struct section *sec = §ions[i]; - int cmp = compare_unalloc_sections (shdr, &sec->shdr, - name, sec->name, - sig, sec->sig); - if (cmp < 0) - u = i; - else if (cmp > 0) - l = i + 1; - else - return sec; - } - return NULL; - } - - Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped, + Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped, unstripped_shstrndx), NULL); ELF_CHECK (shstrtab != NULL, _("cannot read section header string table: %s")); @@ -1533,10 +1538,11 @@ more sections in stripped file than debug file -- arguments reversed?")); } } else - { + { /* Look for the section that matches. */ sec = find_unalloc_section (shdr, name, - get_group_sig (unstripped, shdr)); + get_group_sig (unstripped, shdr),nalloc, + stripped_shnum,sections); if (sec == NULL) { /* An additional unallocated section is fine if not SHT_NOBITS. @@ -2227,22 +2233,22 @@ open_file (const char *file, bool writable) error (EXIT_FAILURE, errno, _("cannot open '%s'"), file); return fd; } - -/* Handle a pair of files we need to open by name. */ -static void -handle_explicit_files (const char *output_file, bool create_dirs, bool force, - const char *stripped_file, const char *unstripped_file) -{ - - /* Warn, and exit if not forced to continue, if some ELF header +/* Warn, and exit if not forced to continue, if some ELF header sanity check for the stripped and unstripped files failed. */ - void warn (const char *msg) + static void warn (const char *msg,bool force,const char *stripped_file,const char *unstripped_file) { error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.", force ? _("WARNING: ") : "", stripped_file, unstripped_file, msg, force ? "" : _(", use --force")); } +/* Handle a pair of files we need to open by name. */ +static void +handle_explicit_files (const char *output_file, bool create_dirs, bool force, + const char *stripped_file, const char *unstripped_file) +{ + + int stripped_fd = open_file (stripped_file, false); Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL); @@ -2264,16 +2270,19 @@ handle_explicit_files (const char *output_file, bool create_dirs, bool force, if (memcmp (stripped_ehdr.e_ident, unstripped_ehdr.e_ident, EI_NIDENT) != 0) - warn (_("ELF header identification (e_ident) different")); + warn (_("ELF header identification (e_ident) different"),force,stripped_file,unstripped_file); if (stripped_ehdr.e_type != unstripped_ehdr.e_type) - warn (_("ELF header type (e_type) different")); + warn (_("ELF header type (e_type) different"),force,stripped_file,unstripped_file); + +; if (stripped_ehdr.e_machine != unstripped_ehdr.e_machine) - warn (_("ELF header machine type (e_machine) different")); + warn (_("ELF header machine type (e_machine) different"),force,stripped_file,unstripped_file); if (stripped_ehdr.e_phnum < unstripped_ehdr.e_phnum) - warn (_("stripped program header (e_phnum) smaller than unstripped")); + warn (_("stripped program header (e_phnum) smaller than unstripped"),force,stripped_file,unstripped_file); + } handle_file (output_file, create_dirs, stripped, &stripped_ehdr, unstripped); @@ -2491,26 +2500,27 @@ match_module (Dwfl_Module *mod, return DWARF_CB_OK; } +inline static ptrdiff_t next (ptrdiff_t offset,const struct arg_info *info,struct match_module_info *mmi) + { + return dwfl_getmodules (info->dwfl, &match_module, mmi, offset); + } + /* Handle files opened implicitly via libdwfl. */ static void handle_implicit_modules (const struct arg_info *info) { struct match_module_info mmi = { info->args, NULL, info->match_files }; - inline ptrdiff_t next (ptrdiff_t offset) - { - return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset); - } - ptrdiff_t offset = next (0); + ptrdiff_t offset = next (0,info,&mmi); if (offset == 0) error (EXIT_FAILURE, 0, _("no matching modules found")); if (info->list) do list_module (mmi.found); - while ((offset = next (offset)) > 0); + while ((offset = next (offset,info,&mmi)) > 0); else if (info->output_dir == NULL) { - if (next (offset) != 0) + if (next (offset,info,&mmi) != 0) error (EXIT_FAILURE, 0, _("matched more than one module")); handle_dwfl_module (info->output_file, false, info->force, mmi.found, info->all, info->ignore, info->relocate); @@ -2520,7 +2530,7 @@ handle_implicit_modules (const struct arg_info *info) handle_output_dir_module (info->output_dir, mmi.found, info->force, info->all, info->ignore, info->modnames, info->relocate); - while ((offset = next (offset)) > 0); + while ((offset = next (offset,info,&mmi)) > 0); } int diff --git a/tests/elfstrmerge.c b/tests/elfstrmerge.c index ba0d68df..f5277c38 100644 --- a/tests/elfstrmerge.c +++ b/tests/elfstrmerge.c @@ -147,6 +147,50 @@ fail_elf_idx (const char *msg, const char *fname, size_t idx) abort(); } +/* section index mapping and sanity checking. */ + static size_t newsecndx (size_t secndx, const char *what, size_t widx, + const char *member, size_t midx,size_t shdrstrndx, + size_t shdrnum, + const char *fname) + { + if (unlikely (secndx == 0 || secndx == shdrstrndx || secndx >= shdrnum)) + { + /* Don't use fail... too specialized messages. Call release + outselves and then error. Ignores midx if widx is + zero. */ + release (); + if (widx == 0) + error (1, 0, "%s: bad section index %zd in %s for %s", + fname, secndx, what, member); + else if (midx == 0) + error (1, 0, "%s: bad section index %zd in %s %zd for %s", + fname, secndx, what, widx, member); + else + error (1, 0, "%s: bad section index %zd in %s %zd for %s %zd", + fname, secndx, what, widx, member, midx); + } + + return secndx < shdrstrndx ? secndx : secndx - 1; + } + + + /* Some sections need a new data buffer because they need to + manipulate the original data. Allocate and check here, so we + have a list of all data buffers we might need to release when + done. */ + static void new_data_buf (Elf_Data *d,const char *fname,size_t ndx, + size_t shdrstrndx, size_t shdrnum) + { + size_t s = d->d_size; + if (s == 0) + fail_idx ("Expected data in section", fname, ndx); + void *b = malloc (d->d_size); + if (b == NULL) + fail_idx ("Couldn't allocated buffer for section", NULL, ndx); + newscnbufs[newsecndx (ndx, "section", ndx, "d_buf", 0, + shdrstrndx, shdrnum,fname )] = d->d_buf = b; + } + int main (int argc, char **argv) { @@ -325,30 +369,6 @@ main (int argc, char **argv) if (newstrtabdata.d_size >= shdrstrshdr->sh_size + strtabshdr->sh_size) fail ("Impossible, merged string table is larger", fname); - /* section index mapping and sanity checking. */ - size_t newsecndx (size_t secndx, const char *what, size_t widx, - const char *member, size_t midx) - { - if (unlikely (secndx == 0 || secndx == shdrstrndx || secndx >= shdrnum)) - { - /* Don't use fail... too specialized messages. Call release - outselves and then error. Ignores midx if widx is - zero. */ - release (); - if (widx == 0) - error (1, 0, "%s: bad section index %zd in %s for %s", - fname, secndx, what, member); - else if (midx == 0) - error (1, 0, "%s: bad section index %zd in %s %zd for %s", - fname, secndx, what, widx, member); - else - error (1, 0, "%s: bad section index %zd in %s %zd for %s %zd", - fname, secndx, what, widx, member, midx); - } - - return secndx < shdrstrndx ? secndx : secndx - 1; - } - struct stat st; if (fstat (fd, &st) != 0) fail_errno("Couldn't fstat", fname); @@ -392,7 +412,9 @@ main (int argc, char **argv) newehdr.e_flags = ehdr.e_flags; /* The new file uses the new strtab as shstrtab. */ - size_t newstrtabndx = newsecndx (strtabndx, "ehdr", 0, "e_shstrndx", 0); + + size_t newstrtabndx = newsecndx (strtabndx, "ehdr", 0, "e_shstrndx", 0,shdrstrndx, + shdrnum,fname); if (newstrtabndx < SHN_LORESERVE) newehdr.e_shstrndx = newstrtabndx; else @@ -459,30 +481,19 @@ main (int argc, char **argv) newshdr.sh_flags = shdr->sh_flags; newshdr.sh_addr = shdr->sh_addr; newshdr.sh_size = shdr->sh_size; + if (shdr->sh_link != 0) - newshdr.sh_link = newsecndx (shdr->sh_link, "shdr", ndx, "sh_link", 0); + newshdr.sh_link = newsecndx (shdr->sh_link, "shdr", ndx, "sh_link", 0, + shdrstrndx,shdrnum,fname); else newshdr.sh_link = 0; if (SH_INFO_LINK_P (shdr) && shdr->sh_info != 0) - newshdr.sh_info = newsecndx (shdr->sh_info, "shdr", ndx, "sh_info", 0); + newshdr.sh_info = newsecndx (shdr->sh_info, "shdr", ndx, "sh_info", 0, + shdrstrndx,shdrnum,fname); else newshdr.sh_info = shdr->sh_info; newshdr.sh_entsize = shdr->sh_entsize; - /* Some sections need a new data buffer because they need to - manipulate the original data. Allocate and check here, so we - have a list of all data buffers we might need to release when - done. */ - void new_data_buf (Elf_Data *d) - { - size_t s = d->d_size; - if (s == 0) - fail_idx ("Expected data in section", fname, ndx); - void *b = malloc (d->d_size); - if (b == NULL) - fail_idx ("Couldn't allocated buffer for section", NULL, ndx); - newscnbufs[newsecndx (ndx, "section", ndx, "d_buf", 0)] = d->d_buf = b; - } Elf_Data *newdata = elf_newdata (newscn); if (newdata == NULL) @@ -510,7 +521,7 @@ main (int argc, char **argv) const bool update_name = shdr->sh_link == strtabndx; if (update_name && ndx != symtabndx) fail ("Only one symbol table using strtab expected", fname); - new_data_buf (newdata); + new_data_buf (newdata,fname,ndx,shdrstrndx,shdrnum); size_t syms = (data->d_size / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT)); for (size_t i = 0; i < syms; i++) @@ -527,7 +538,8 @@ main (int argc, char **argv) else if (sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE) sym.st_shndx = newsecndx (sym.st_shndx, "section", ndx, - "symbol", i); + "symbol", i, + shdrstrndx, shdrnum,fname ); if (update_name && sym.st_name != 0) sym.st_name = dwelf_strent_off (symstrents[i]); @@ -541,7 +553,7 @@ main (int argc, char **argv) case SHT_GROUP: { - new_data_buf (newdata); + new_data_buf (newdata,fname,ndx,shdrstrndx,shdrnum); /* A section group contains Elf32_Words. The first word is a falg value, the rest of the words are indexes of the sections belonging to the group. */ @@ -553,13 +565,14 @@ main (int argc, char **argv) newgroup[0] = group[0]; for (size_t i = 1; i < words; i++) newgroup[i] = newsecndx (group[i], "section", ndx, - "group", i); + "group", i, + shdrstrndx, shdrnum,fname ); } break; case SHT_SYMTAB_SHNDX: { - new_data_buf (newdata); + new_data_buf (newdata,fname,ndx,shdrstrndx,shdrnum); /* A SHNDX just contains an array of section indexes for the corresponding symbol table. The entry is SHN_UNDEF unless the corresponding symbol is @@ -572,7 +585,8 @@ main (int argc, char **argv) newshndx[i] = SHN_UNDEF; else newshndx[i] = newsecndx (shndx[i], "section", ndx, - "shndx", i); + "shndx", i, + shdrstrndx, shdrnum,fname ); } break; diff --git a/tests/zstrptr.c b/tests/zstrptr.c index 6d8e19f7..173c9426 100644 --- a/tests/zstrptr.c +++ b/tests/zstrptr.c @@ -30,6 +30,26 @@ #include ELFUTILS_HEADER(elf) #include +static void print_strings (Elf_Scn *scn,size_t ndx,Elf *elf) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + printf ("Strings in section %zd (%s):\n", ndx, + ((shdr->sh_flags & SHF_COMPRESSED) != 0 + ? "compressed" : "uncompressed")); + + size_t off = 0; + const char *str = elf_strptr (elf, ndx, off); + while (str != NULL) + { + printf ("[%zx] '%s'\n", off, str); + off += strlen (str) + 1; + str = elf_strptr (elf, ndx, off); + } + } + + int main (int argc, char *argv[]) { @@ -79,38 +99,20 @@ main (int argc, char *argv[]) exit (1); } - void print_strings (void) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - - printf ("Strings in section %zd (%s):\n", ndx, - ((shdr->sh_flags & SHF_COMPRESSED) != 0 - ? "compressed" : "uncompressed")); - - size_t off = 0; - const char *str = elf_strptr (elf, ndx, off); - while (str != NULL) - { - printf ("[%zx] '%s'\n", off, str); - off += strlen (str) + 1; - str = elf_strptr (elf, ndx, off); - } - } - + if (elf_compress (scn, ELFCOMPRESS_ZLIB, 0) < 0) { printf ("Couldn't compress section %zd: %s\n", ndx, elf_errmsg (-1)); exit (1); } - print_strings (); + print_strings (scn,ndx,elf); if (elf_compress (scn, 0, 0) < 0) { printf ("Couldn't decompress section %zd: %s\n", ndx, elf_errmsg (-1)); exit (1); } - print_strings (); + print_strings (scn,ndx,elf); if (elf_end (elf) != 0) { -- 2.25.1