diff options
author | Chih-hung Hsieh <chh@google.com> | 2016-01-05 17:44:12 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2016-01-05 17:44:12 +0000 |
commit | 97c644e689be3b7b3b7898513a38ead399d2285a (patch) | |
tree | bcd20af43068df2ab3c279089461ef1c69ca6ff6 | |
parent | 611603536be3a6caaafb4289e2713cd117c70048 (diff) | |
parent | 645a828a7aef8113f07efae9b48e742bb65b712e (diff) | |
download | android_external_elfutils-97c644e689be3b7b3b7898513a38ead399d2285a.tar.gz android_external_elfutils-97c644e689be3b7b3b7898513a38ead399d2285a.tar.bz2 android_external_elfutils-97c644e689be3b7b3b7898513a38ead399d2285a.zip |
Merge "Merge upstream SHA '9d1e236'"
51 files changed, 1407 insertions, 578 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog index 7f0d1c00..4b604fd2 100644 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@ -1,3 +1,19 @@ +2015-12-08 Jose E. Marchesi <jose.marchesi@oracle.com> + + * sparc_init.c (sparc_init): Hook sparc_set_initial_registers_tid. + * sparc_initreg.c: New file. + * Makefile.am (sparc_SRCS): Added sparc_initreg.c. + +2015-12-08 Jose E. Marchesi <jose.marchesi@oracle.com> + + * sparc_corenote.c: Header comment typo fixed. + (PRSTATUS_REGSET_ITEMS): Defined, so the PC can be fetched from + core files. + * Makefile.am (sparc_SRCS): Added sparc_cfi.c + * sparc_cfi.c: New file. + * sparc_init.c (sparc_init): Set eh->frame_nregs, eh->ra_offset + and hook sparc_abi_cfi. + 2015-10-21 Chih-Hung Hsieh <chh@google.com> * ia64_retval.c (hfa_type): Move nested function 'hfa' to file scope. diff --git a/backends/Makefile.am b/backends/Makefile.am index f7002fb5..b16f9486 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -84,7 +84,8 @@ libebl_aarch64_pic_a_SOURCES = $(aarch64_SRCS) am_libebl_aarch64_pic_a_OBJECTS = $(aarch64_SRCS:.c=.os) sparc_SRCS = sparc_init.c sparc_symbol.c sparc_regs.c sparc_retval.c \ - sparc_corenote.c sparc64_corenote.c sparc_auxv.c sparc_attrs.c + sparc_corenote.c sparc64_corenote.c sparc_auxv.c sparc_attrs.c \ + sparc_cfi.c sparc_initreg.c libebl_sparc_pic_a_SOURCES = $(sparc_SRCS) am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os) diff --git a/backends/sparc_cfi.c b/backends/sparc_cfi.c new file mode 100644 index 00000000..dcc17bd6 --- /dev/null +++ b/backends/sparc_cfi.c @@ -0,0 +1,83 @@ +/* SPARC defaults for DWARF CFI. + Copyright (C) 2015 Oracle Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +int +sparc_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + /* %g0 .. %g7 */ + SV (0), SV (1), SV (2), SV (3), SV (4), SV (5), SV (6), SV (7), + /* %o0 .. %o7 */ + SV (8), SV (9), SV (10), SV (11), SV (12), SV (13), SV (14), SV (15), + /* %l0 .. %l7 */ + SV (16), SV (17), SV (18), SV (19), SV (20), SV (21), SV (22), SV (23), + /* %i0 .. %i7 */ + SV (24), SV (25), SV (26), SV (27), SV (28), SV (29), SV (30), SV (31), + /* %f0 .. %f32 */ + SV (32), SV (33), SV (34), SV (35), SV (36), SV (37), SV (38), SV (39), + SV (40), SV (41), SV (42), SV (43), SV (44), SV (45), SV (46), SV (47), + SV (48), SV (49), SV (50), SV (51), SV (52), SV (53), SV (54), SV (55), + SV (56), SV (57), SV (58), SV (59), SV (60), SV (61), SV (52), SV (63), + /* %f33 .. %63 + Note that there are DWARF columns for the odd registers, even + if they don't exist in hardware) */ + SV (64), SV (65), SV (66), SV (67), SV (68), SV (69), SV (70), SV (71), + SV (72), SV (73), SV (74), SV (75), SV (76), SV (77), SV (78), SV (79), + SV (80), SV (81), SV (82), SV (83), SV (84), SV (85), SV (86), SV (87), + SV (88), SV (89), SV (90), SV (91), SV (92), SV (93), SV (94), SV (95), + /* %fcc[0123] */ + SV (96), SV (97), SV (98), SV (99), + /* %icc/%xcc */ + SV (100), + /* Soft frame-pointer */ + SV (101), + /* %gsr */ + SV (102) +#undef SV + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = 4; + + abi_info->return_address_register = 31; /* %i7 */ + + return 0; +} + diff --git a/backends/sparc_corenote.c b/backends/sparc_corenote.c index 7912539b..c9b6ff3d 100644 --- a/backends/sparc_corenote.c +++ b/backends/sparc_corenote.c @@ -1,5 +1,6 @@ -/* PowerPC specific core note handling. +/* SPARC specific core note handling. Copyright (C) 2007 Red Hat, Inc. + Copyright (C) 2015 Oracle, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -109,4 +110,11 @@ static const Ebl_Register_Location fpregset_regs[] = #define ALIGN_PID_T 4 #define TYPE_PID_T ELF_T_SWORD +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "pc", .type = ELF_T_ADDR, .format = 'x', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[33]), \ + .group = "register", .pc_register = true \ + } + #include "linux-core-note.c" diff --git a/backends/sparc_init.c b/backends/sparc_init.c index f8a7cfbd..8e946fb2 100644 --- a/backends/sparc_init.c +++ b/backends/sparc_init.c @@ -76,6 +76,14 @@ sparc_init (Elf *elf __attribute__ ((unused)), HOOK (eh, register_info); HOOK (eh, return_value_location); HOOK (eh, check_object_attribute); + HOOK (eh, abi_cfi); + /* gcc/config/sparc.h define FIRST_PSEUDO_REGISTER */ + eh->frame_nregs = 103; + /* The CFI Dwarf register with the "return address" in sparc + actually contains the call address. The return address is + located 8 bytes after it. */ + eh->ra_offset = 8; + HOOK (eh, set_initial_registers_tid); return MODVERSION; } diff --git a/backends/sparc_initreg.c b/backends/sparc_initreg.c new file mode 100644 index 00000000..c2a9b32a --- /dev/null +++ b/backends/sparc_initreg.c @@ -0,0 +1,129 @@ +/* Fetch live process registers from TID. + Copyright (C) 2015 Oracle, In + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <stdlib.h> +#ifdef __sparc__ +# include <asm/ptrace.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +bool +EBLHOOK (set_initial_registers_tid) (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __sparc__ + return false; +#else /* __sparc__ */ + + + /* The pt_regs structure filled in by PTRACE_GETREGS provides the + PC, the global registers and the output registers. Note how the + %g0 register is not explicitly provided in the structure (it's + value is always 0) and the resulting weird packing in the u_regs + array: the last element is not used. */ + + struct pt_regs regs; + if (ptrace (PTRACE_GETREGS, tid, ®s, 0) == -1) + return false; + + /* PC: no DWARF number */ + if (!setfunc (-1, 1, (Dwarf_Word *) ®s.tpc, arg)) + return false; + + /* Global registers: DWARF 0 .. 7 */ + Dwarf_Word zero = 0; + if (!setfunc (0, 1, &zero, arg)) + return false; + if (!setfunc (1, 7, (Dwarf_Word *) ®s.u_regs[0], arg)) + return false; + + /* Output registers: DWARF 8 .. 15 */ + if (!setfunc (8, 8, (Dwarf_Word *) ®s.u_regs[7], arg)) + return false; + + /* Local and input registers must be read from the stack. They are + saved in the previous stack frame. The stack pointer is %o6, + read above. */ + + Dwarf_Word locals_outs[16]; + Dwarf_Word sp = regs.u_regs[13]; + + if (sp & 1) + { + /* Registers are 64 bits, and we need to apply the 2047 stack + bias in order to get the real stack pointer. */ + + sp += 2047; + + for (unsigned i = 0; i < 16; i++) + { + locals_outs[i] = ptrace (PTRACE_PEEKDATA, tid, + (void *) (uintptr_t) (sp + (i * 8)), + NULL); + if (errno != 0) + return false; + } + } + else + { + /* Registers are 32 bits. */ + + for (unsigned i = 0; i < 8; i++) + { + Dwarf_Word tuple = ptrace (PTRACE_PEEKDATA, tid, + (void *) (uintptr_t) (sp + (i * 8)), + NULL); + if (errno != 0) + return false; + + locals_outs[2*i] = (tuple >> 32) & 0xffffffff; + locals_outs[2*i+1] = tuple & 0xffffffff; + } + } + + + /* Local registers: DWARF 16 .. 23 */ + if (!setfunc (16, 8, &locals_outs[0], arg)) + return false; + + /* Input registers: DWARF 24 .. 31 */ + if (!setfunc (24, 8, &locals_outs[8], arg)) + return false; + + return true; +#endif +} diff --git a/libdw/Android.mk b/libdw/Android.mk index 55a04dc9..5558a1ad 100755 --- a/libdw/Android.mk +++ b/libdw/Android.mk @@ -143,9 +143,6 @@ ifeq ($(HOST_OS),linux) include $(CLEAR_VARS) -# Clang has no nested functions. -LOCAL_CLANG := false - LOCAL_SRC_FILES := $(LIBDW_SRC_FILES) LOCAL_C_INCLUDES := \ @@ -175,9 +172,6 @@ endif # linux include $(CLEAR_VARS) -# Clang has no nested functions. -LOCAL_CLANG := false - # b/25642296, local __thread variable does not work with arm64 clang/llvm. LOCAL_CLANG_arm64 := false diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 5218145e..d0e97f3c 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,32 @@ +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * fde.c (intern_fde): Don't leak duplicate FDEs. + +2015-12-01 Mark Wielaard <mjw@redhat.com> + + * fde.c (intern_fde): Don't intern an fde that doesn't cover a + valid code range. + +2015-12-01 Mark Wielaard <mjw@redhat.com> + + * dwarf_end.c (dwarf_end): Call cu_free on fake_loc_cu if it exists. + +2015-10-14 Chih-Hung Hsieh <chh@google.com> + + * dwarf_entry_breakpoints.c (dwarf_entry_breakpoints): Move recursive + functions 'add_bkpt', 'entrypc_bkpt', and 'search_range' to file scope. + +2015-10-14 Chih-Hung Hsieh <chh@google.com> + + * libdw_visit_scopes.c (__libdw_visit_scopes): Move recursive nested + function 'walk_children' to file scope; inline 'recurse' at its call + site. + +2015-10-19 Mark Wielaard <mjw@redhat.com> + + * frame-cache.c (__libdw_destroy_frame_cache): Call ebl_closebackend + if necessary. + 2015-10-16 Dmitry V. Levin <ldv@altlinux.org> * dwarf_getsrclines.c (read_srclines): Initialize state early. diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index 32b551df..2108063d 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -117,7 +117,11 @@ dwarf_end (Dwarf *dwarf) elf_end (dwarf->elf); /* Free the fake location list CU. */ - free (dwarf->fake_loc_cu); + if (dwarf->fake_loc_cu != NULL) + { + cu_free (dwarf->fake_loc_cu); + free (dwarf->fake_loc_cu); + } /* Free the context descriptor. */ free (dwarf); diff --git a/libdw/dwarf_entry_breakpoints.c b/libdw/dwarf_entry_breakpoints.c index abfee73c..c3c0f399 100644 --- a/libdw/dwarf_entry_breakpoints.c +++ b/libdw/dwarf_entry_breakpoints.c @@ -34,54 +34,40 @@ #include <stdlib.h> -int -dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts) +/* Add one breakpoint location to the result vector. */ +static inline int +add_bkpt (Dwarf_Addr pc, Dwarf_Addr **bkpts, int *pnbkpts) { - int nbkpts = 0; - *bkpts = NULL; - - /* Add one breakpoint location to the result vector. */ - inline int add_bkpt (Dwarf_Addr pc) - { - Dwarf_Addr *newlist = realloc (*bkpts, ++nbkpts * sizeof newlist[0]); - if (newlist == NULL) - { - free (*bkpts); - *bkpts = NULL; - __libdw_seterrno (DWARF_E_NOMEM); - return -1; - } - newlist[nbkpts - 1] = pc; - *bkpts = newlist; - return nbkpts; - } - - /* Fallback result, break at the entrypc/lowpc value. */ - inline int entrypc_bkpt (void) + Dwarf_Addr *newlist = realloc (*bkpts, ++(*pnbkpts) * sizeof newlist[0]); + if (newlist == NULL) { - Dwarf_Addr pc; - return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc); - } - - /* Fetch the CU's line records to look for this DIE's addresses. */ - Dwarf_Die cudie = CUDIE (die->cu); - Dwarf_Lines *lines; - size_t nlines; - if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0) - { - int error = INTUSE (dwarf_errno) (); - if (error == 0) /* CU has no DW_AT_stmt_list. */ - return entrypc_bkpt (); - __libdw_seterrno (error); + free (*bkpts); + *bkpts = NULL; + __libdw_seterrno (DWARF_E_NOMEM); return -1; } + newlist[*pnbkpts - 1] = pc; + *bkpts = newlist; + return *pnbkpts; +} - /* Search a contiguous PC range for prologue-end markers. - If DWARF, look for proper markers. - Failing that, if ADHOC, look for the ad hoc convention. */ - inline int search_range (Dwarf_Addr low, Dwarf_Addr high, - bool dwarf, bool adhoc) - { +/* Fallback result, break at the entrypc/lowpc value. */ +static inline int +entrypc_bkpt (Dwarf_Die *die, Dwarf_Addr **bkpts, int *pnbkpts) +{ + Dwarf_Addr pc; + return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc, bkpts, pnbkpts); +} + +/* Search a contiguous PC range for prologue-end markers. + If DWARF, look for proper markers. + Failing that, if ADHOC, look for the ad hoc convention. */ +static inline int +search_range (Dwarf_Addr low, Dwarf_Addr high, + bool dwarf, bool adhoc, + Dwarf_Lines *lines, size_t nlines, + Dwarf_Addr **bkpts, int *pnbkpts) +{ size_t l = 0, u = nlines; while (l < u) { @@ -103,16 +89,35 @@ dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts) if (dwarf) for (size_t i = l; i < u && lines->info[i].addr < high; ++i) if (lines->info[i].prologue_end - && add_bkpt (lines->info[i].addr) < 0) + && add_bkpt (lines->info[i].addr, bkpts, pnbkpts) < 0) return -1; - if (adhoc && nbkpts == 0) + if (adhoc && *pnbkpts == 0) while (++l < nlines && lines->info[l].addr < high) if (!lines->info[l].end_sequence) - return add_bkpt (lines->info[l].addr); - return nbkpts; + return add_bkpt (lines->info[l].addr, bkpts, pnbkpts); + return *pnbkpts; } __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; +} + +int +dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts) +{ + int nbkpts = 0; + *bkpts = NULL; + + /* Fetch the CU's line records to look for this DIE's addresses. */ + Dwarf_Die cudie = CUDIE (die->cu); + Dwarf_Lines *lines; + size_t nlines; + if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0) + { + int error = INTUSE (dwarf_errno) (); + if (error == 0) /* CU has no DW_AT_stmt_list. */ + return entrypc_bkpt (die, bkpts, &nbkpts); + __libdw_seterrno (error); + return -1; } /* Search each contiguous address range for DWARF prologue_end markers. */ @@ -126,14 +131,16 @@ dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts) /* Most often there is a single contiguous PC range for the DIE. */ if (offset == 1) - return search_range (begin, end, true, true) ?: entrypc_bkpt (); + return search_range (begin, end, true, true, lines, nlines, bkpts, &nbkpts) + ?: entrypc_bkpt (die, bkpts, &nbkpts); Dwarf_Addr lowpc = (Dwarf_Addr) -1l; Dwarf_Addr highpc = (Dwarf_Addr) -1l; while (offset > 0) { /* We have an address range entry. */ - if (search_range (begin, end, true, false) < 0) + if (search_range (begin, end, true, false, + lines, nlines, bkpts, &nbkpts) < 0) return -1; if (begin < lowpc) @@ -150,6 +157,7 @@ dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts) fall back to just using the entrypc value. */ return (nbkpts ?: (lowpc == (Dwarf_Addr) -1l ? 0 - : search_range (lowpc, highpc, false, true)) - ?: entrypc_bkpt ()); + : search_range (lowpc, highpc, false, true, + lines, nlines, bkpts, &nbkpts)) + ?: entrypc_bkpt (die, bkpts, &nbkpts)); } diff --git a/libdw/fde.c b/libdw/fde.c index c8475f3e..f5f6fbe1 100644 --- a/libdw/fde.c +++ b/libdw/fde.c @@ -90,6 +90,13 @@ intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry) } fde->end += fde->start; + /* Make sure the fde actually covers a real code range. */ + if (fde->start >= fde->end) + { + free (fde); + return (void *) -1; + } + fde->cie = cie; if (cie->sized_augmentation_data) @@ -112,12 +119,21 @@ intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry) fde->instructions += cie->fde_augmentation_data_size; /* Add the new entry to the search tree. */ - if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL) + struct dwarf_fde **tres = tsearch (fde, &cache->fde_tree, &compare_fde); + if (tres == NULL) { free (fde); __libdw_seterrno (DWARF_E_NOMEM); return NULL; } + else if (*tres != fde) + { + /* There is already an FDE in the cache that covers the same + address range. That is odd. Ignore this FDE. And just use + the one in the cache for consistency. */ + free (fde); + return *tres; + } return fde; } diff --git a/libdw/frame-cache.c b/libdw/frame-cache.c index 54a1cc9a..5b6afb5d 100644 --- a/libdw/frame-cache.c +++ b/libdw/frame-cache.c @@ -1,5 +1,5 @@ /* Frame cache handling. - Copyright (C) 2009 Red Hat, Inc. + Copyright (C) 2009, 2015 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -30,6 +30,7 @@ # include <config.h> #endif +#include "../libebl/libebl.h" #include "cfi.h" #include <search.h> #include <stdlib.h> @@ -63,4 +64,7 @@ __libdw_destroy_frame_cache (Dwarf_CFI *cache) tdestroy (cache->fde_tree, free_fde); tdestroy (cache->cie_tree, free_cie); tdestroy (cache->expr_tree, free_expr); + + if (cache->ebl != NULL && cache->ebl != (void *) -1l) + ebl_closebackend (cache->ebl); } diff --git a/libdw/libdw_visit_scopes.c b/libdw/libdw_visit_scopes.c index 5e5c26fd..eb892e10 100644 --- a/libdw/libdw_visit_scopes.c +++ b/libdw/libdw_visit_scopes.c @@ -64,6 +64,21 @@ may_have_scopes (Dwarf_Die *die) return false; } +struct walk_children_state +{ + /* Parameters of __libdw_visit_scopes. */ + unsigned int depth; + struct Dwarf_Die_Chain *imports; + int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *); + int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *); + void *arg; + /* Extra local variables for the walker. */ + struct Dwarf_Die_Chain child; +}; + +static inline int +walk_children (struct walk_children_state *state); + int internal_function __libdw_visit_scopes (unsigned int depth, struct Dwarf_Die_Chain *root, @@ -76,95 +91,98 @@ __libdw_visit_scopes (unsigned int depth, struct Dwarf_Die_Chain *root, void *), void *arg) { - struct Dwarf_Die_Chain child; + struct walk_children_state state = + { + .depth = depth, + .imports = imports, + .previsit = previsit, + .postvisit = postvisit, + .arg = arg + }; + + state.child.parent = root; int ret; - - child.parent = root; - if ((ret = INTUSE(dwarf_child) (&root->die, &child.die)) != 0) + if ((ret = INTUSE(dwarf_child) (&root->die, &state.child.die)) != 0) return ret < 0 ? -1 : 0; // Having zero children is legal. - inline int recurse (void) - { - return __libdw_visit_scopes (depth + 1, &child, imports, - previsit, postvisit, arg); - } - - /* Checks the given DIE hasn't been imported yet to prevent cycles. */ - inline bool imports_contains (Dwarf_Die *die) - { - for (struct Dwarf_Die_Chain *import = imports; import != NULL; - import = import->parent) - if (import->die.addr == die->addr) - return true; - - return false; - } + return walk_children (&state); +} - inline int walk_children (void) +static inline int +walk_children (struct walk_children_state *state) { - do - { - /* For an imported unit, it is logically as if the children of - that unit are siblings of the other children. So don't do - a full recursion into the imported unit, but just walk the - children in place before moving to the next real child. */ - while (INTUSE(dwarf_tag) (&child.die) == DW_TAG_imported_unit) - { - Dwarf_Die orig_child_die = child.die; - Dwarf_Attribute attr_mem; - Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child.die, - DW_AT_import, - &attr_mem); - if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL - && INTUSE(dwarf_child) (&child.die, &child.die) == 0) - { - if (imports_contains (&orig_child_die)) - { - __libdw_seterrno (DWARF_E_INVALID_DWARF); - return -1; - } - struct Dwarf_Die_Chain *orig_imports = imports; - struct Dwarf_Die_Chain import = { .die = orig_child_die, - .parent = orig_imports }; - imports = &import; - int result = walk_children (); - imports = orig_imports; - if (result != DWARF_CB_OK) - return result; - } - - /* Any "real" children left? */ - if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die, - &child.die)) != 0) - return ret < 0 ? -1 : 0; - }; - - child.prune = false; + int ret; + do + { + /* For an imported unit, it is logically as if the children of + that unit are siblings of the other children. So don't do + a full recursion into the imported unit, but just walk the + children in place before moving to the next real child. */ + while (INTUSE(dwarf_tag) (&state->child.die) == DW_TAG_imported_unit) + { + Dwarf_Die orig_child_die = state->child.die; + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&state->child.die, + DW_AT_import, + &attr_mem); + if (INTUSE(dwarf_formref_die) (attr, &state->child.die) != NULL + && INTUSE(dwarf_child) (&state->child.die, &state->child.die) == 0) + { + /* Checks the given DIE hasn't been imported yet + to prevent cycles. */ + bool imported = false; + for (struct Dwarf_Die_Chain *import = state->imports; import != NULL; + import = import->parent) + if (import->die.addr == orig_child_die.addr) + { + imported = true; + break; + } + if (imported) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + struct Dwarf_Die_Chain *orig_imports = state->imports; + struct Dwarf_Die_Chain import = { .die = orig_child_die, + .parent = orig_imports }; + state->imports = &import; + int result = walk_children (state); + state->imports = orig_imports; + if (result != DWARF_CB_OK) + return result; + } + + /* Any "real" children left? */ + if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die, + &state->child.die)) != 0) + return ret < 0 ? -1 : 0; + }; + + state->child.prune = false; /* previsit is declared NN */ - int result = (*previsit) (depth + 1, &child, arg); + int result = (*state->previsit) (state->depth + 1, &state->child, state->arg); if (result != DWARF_CB_OK) return result; - if (!child.prune && may_have_scopes (&child.die) - && INTUSE(dwarf_haschildren) (&child.die)) + if (!state->child.prune && may_have_scopes (&state->child.die) + && INTUSE(dwarf_haschildren) (&state->child.die)) { - result = recurse (); + result = __libdw_visit_scopes (state->depth + 1, &state->child, state->imports, + state->previsit, state->postvisit, state->arg); if (result != DWARF_CB_OK) return result; } - if (postvisit != NULL) + if (state->postvisit != NULL) { - result = (*postvisit) (depth + 1, &child, arg); + result = (*state->postvisit) (state->depth + 1, &state->child, state->arg); if (result != DWARF_CB_OK) return result; } - } - while ((ret = INTUSE(dwarf_siblingof) (&child.die, &child.die)) == 0); - - return ret < 0 ? -1 : 0; - } + } + while ((ret = INTUSE(dwarf_siblingof) (&state->child.die, &state->child.die)) == 0); - return walk_children (); + return ret < 0 ? -1 : 0; } diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 163a6f1e..06b8469d 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,65 @@ +2015-11-18 Chih-Hung Hsieh <chh@google.com> + + * linux-proc-maps.c (proc_maps_report): Move nested function + 'report' to file scope. + +2015-11-18 Chih-Hung Hsieh <chh@google.com> + + * core-file.c (elf_begin_rand): Move nested function 'fail' to file + scope. + * core-file.c (dwfl_elf_phdr_memory_callback): Move nested functions + 'update_end' and 'more' to file scope. + +2015-11-17 Chih-Hung Hsieh <chh@google.com> + + * link_map.c (auxv_format_probe): Move nested functions + check64 and check32 to file scope. + +2015-12-08 Jose E. Marchesi <jose.marchesi@oracle.com> + + * dwfl_frame.c (state_fetch_pc): Add a backend-defined offset to + the value of the return address register as defined by the CFI + abi. + * frame_unwind.c (handle_cfi): Likewise. + +2015-12-01 Mark Wielaard <mjw@redhat.com> + + * link_map.c (dwfl_link_map_report): Track whether in.d_buf comes + from exec or memory_callback, free as appropriate. + +2015-12-01 Mark Wielaard <mjw@redhat.com> + + * libdwflP.h (struct Dwfl_User_Core): New. + (struct DWfl): Replace executable_for_core with user_core. + * argp-std.c (parse_opt): Store core and fd in Dwfl user_core. + * core-file.c (dwfl_core_file_report): Check and store + executable_for_core in Dwfl user_core. + * dwfl_build_id_find_elf.c (dwfl_build_id_find_elf): Check and use + executable_for_core in Dwfl user_core. + * dwfl_end.c (dwfl_end): Release resources held in Dwfl user_core. + * link-map.c (report_r_debug): Check executable_for_core in Dwfl + user_core. + (dwfl_link_map_report): Likewise. + +2015-11-16 Chih-Hung Hsieh <chh@google.com> + + * dwfl_module_getdwarf.c (find_prelink_address_sync): Move nested + function 'consider_shdr' to file scope. + * dwfl_module_getdwarf.c (find_dynsym): Move nested function + 'translate_offs' to file scope. + +2015-11-16 Chih-Hung Hsieh <chh@google.com> + + * dwfl_module_addrsym.c (__libdwfl_addrsym): Move nested functions + 'same_section', 'binding_value', 'try_sym_value', and 'search_table' + to file scope. + +2015-11-19 Mark Wielaard <mjw@redhat.com> + + * dwfl_module.c (__libdwfl_module_free): Remove Dwfl_Module Ebl from + eh_cfi and dwarf_cfi cache if necessary before calling dwarf_end and + dwarf_cfi_end. + 2015-11-13 Chih-Hung Hsieh <chh@google.com> * gzip.c (unzip): Move nested functions to file scope. diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c index 2bbf74fc..501530a5 100644 --- a/libdwfl/argp-std.c +++ b/libdwfl/argp-std.c @@ -1,5 +1,5 @@ /* Standard argp argument parsers for tools using libdwfl. - Copyright (C) 2005-2010, 2012 Red Hat, Inc. + Copyright (C) 2005-2010, 2012, 2015 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -303,7 +303,19 @@ parse_opt (int key, char *arg, struct argp_state *state) /* Non-fatal to not be able to attach to core, ignore error. */ INTUSE(dwfl_core_file_attach) (dwfl, core); - /* From now we leak FD and CORE. */ + /* Store core Elf and fd in Dwfl to expose with dwfl_end. */ + if (dwfl->user_core == NULL) + { + dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core)); + if (dwfl->user_core == NULL) + { + argp_failure (state, EXIT_FAILURE, 0, + _("Not enough memory")); + return ENOMEM; + } + } + dwfl->user_core->core = core; + dwfl->user_core->fd = fd; if (result == 0) { diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c index b317ecaa..67684c9a 100644 --- a/libdwfl/core-file.c +++ b/libdwfl/core-file.c @@ -39,6 +39,19 @@ #include "system.h" +/* On failure return, we update *NEXT to point back at OFFSET. */ +static inline Elf * +do_fail (int error, off_t *next, off_t offset) +{ + if (next != NULL) + *next = offset; + //__libelf_seterrno (error); + __libdwfl_seterrno (DWFL_E (LIBELF, error)); + return NULL; +} + +#define fail(error) do_fail (error, next, offset) + /* This is a prototype of what a new libelf interface might be. This implementation is pessimal for non-mmap cases and should be replaced by more diddling inside libelf internals. */ @@ -48,16 +61,6 @@ elf_begin_rand (Elf *parent, off_t offset, off_t size, off_t *next) if (parent == NULL) return NULL; - /* On failure return, we update *NEXT to point back at OFFSET. */ - inline Elf *fail (int error) - { - if (next != NULL) - *next = offset; - //__libelf_seterrno (error); - __libdwfl_seterrno (DWFL_E (LIBELF, error)); - return NULL; - } - off_t min = (parent->kind == ELF_K_ELF ? (parent->class == ELFCLASS32 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)) @@ -238,6 +241,44 @@ core_file_read_eagerly (Dwfl_Module *mod, return cost <= MAX_EAGER_COST; } +static inline void +update_end (GElf_Phdr *pphdr, const GElf_Off align, + GElf_Off *pend, GElf_Addr *pend_vaddr) +{ + *pend = (pphdr->p_offset + pphdr->p_filesz + align - 1) & -align; + *pend_vaddr = (pphdr->p_vaddr + pphdr->p_memsz + align - 1) & -align; +} + +/* Use following contiguous segments to get towards SIZE. */ +static inline bool +do_more (size_t size, GElf_Phdr *pphdr, const GElf_Off align, + Elf *elf, GElf_Off start, int *pndx, + GElf_Off *pend, GElf_Addr *pend_vaddr) +{ + while (*pend <= start || *pend - start < size) + { + if (pphdr->p_filesz < pphdr->p_memsz) + /* This segment is truncated, so no following one helps us. */ + return false; + + if (unlikely (gelf_getphdr (elf, (*pndx)++, pphdr) == NULL)) + return false; + + if (pphdr->p_type == PT_LOAD) + { + if (pphdr->p_offset > *pend + || pphdr->p_vaddr > *pend_vaddr) + /* It's discontiguous! */ + return false; + + update_end (pphdr, align, pend, pend_vaddr); + } + } + return true; +} + +#define more(size) do_more (size, &phdr, align, elf, start, &ndx, &end, &end_vaddr) + bool dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, void **buffer, size_t *buffer_available, @@ -270,38 +311,7 @@ dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, GElf_Off end; GElf_Addr end_vaddr; - inline void update_end (void) -{ - end = (phdr.p_offset + phdr.p_filesz + align - 1) & -align; - end_vaddr = (phdr.p_vaddr + phdr.p_memsz + align - 1) & -align; - } - - update_end (); - - /* Use following contiguous segments to get towards SIZE. */ - inline bool more (size_t size) - { - while (end <= start || end - start < size) - { - if (phdr.p_filesz < phdr.p_memsz) - /* This segment is truncated, so no following one helps us. */ - return false; - - if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL)) - return false; - - if (phdr.p_type == PT_LOAD) - { - if (phdr.p_offset > end - || phdr.p_vaddr > end_vaddr) - /* It's discontiguous! */ - return false; - - update_end (); - } - } - return true; - } + update_end (&phdr, align, &end, &end_vaddr); /* We need at least this much. */ if (! more (minread)) @@ -441,13 +451,27 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) return -1; } - free (dwfl->executable_for_core); + if (dwfl->user_core != NULL) + free (dwfl->user_core->executable_for_core); if (executable == NULL) - dwfl->executable_for_core = NULL; + { + if (dwfl->user_core != NULL) + dwfl->user_core->executable_for_core = NULL; + } else { - dwfl->executable_for_core = strdup (executable); - if (dwfl->executable_for_core == NULL) + if (dwfl->user_core == NULL) + { + dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core)); + if (dwfl->user_core == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + dwfl->user_core->fd = -1; + } + dwfl->user_core->executable_for_core = strdup (executable); + if (dwfl->user_core->executable_for_core == NULL) { __libdwfl_seterrno (DWFL_E_NOMEM); return -1; diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c index 2e30b7ab..903e1931 100644 --- a/libdwfl/dwfl_build_id_find_elf.c +++ b/libdwfl/dwfl_build_id_find_elf.c @@ -140,16 +140,19 @@ dwfl_build_id_find_elf (Dwfl_Module *mod, char **file_name, Elf **elfp) { *elfp = NULL; - if (mod->is_executable && mod->dwfl->executable_for_core != NULL) + if (mod->is_executable + && mod->dwfl->user_core != NULL + && mod->dwfl->user_core->executable_for_core != NULL) { /* When dwfl_core_file_report was called with a non-NULL executable file name this callback will replace the Dwfl_Module main.name with the recorded executable file when MOD was identified as main executable (which then triggers opening and reporting of the executable). */ - int fd = open (mod->dwfl->executable_for_core, O_RDONLY); + const char *executable = mod->dwfl->user_core->executable_for_core; + int fd = open (executable, O_RDONLY); if (fd >= 0) { - *file_name = strdup (mod->dwfl->executable_for_core); + *file_name = strdup (executable); if (*file_name != NULL) return fd; else diff --git a/libdwfl/dwfl_end.c b/libdwfl/dwfl_end.c index 33cae48c..0b35bd28 100644 --- a/libdwfl/dwfl_end.c +++ b/libdwfl/dwfl_end.c @@ -1,5 +1,5 @@ /* Finish a session using libdwfl. - Copyright (C) 2005, 2008, 2012-2013 Red Hat, Inc. + Copyright (C) 2005, 2008, 2012-2013, 2015 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -27,6 +27,7 @@ not, see <http://www.gnu.org/licenses/>. */ #include "libdwflP.h" +#include <unistd.h> void dwfl_end (Dwfl *dwfl) @@ -49,6 +50,13 @@ dwfl_end (Dwfl *dwfl) __libdwfl_module_free (dead); } - free (dwfl->executable_for_core); + if (dwfl->user_core != NULL) + { + free (dwfl->user_core->executable_for_core); + elf_end (dwfl->user_core->core); + if (dwfl->user_core->fd != -1) + close (dwfl->user_core->fd); + free (dwfl->user_core); + } free (dwfl); } diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c index a91a1d68..d6399398 100644 --- a/libdwfl/dwfl_frame.c +++ b/libdwfl/dwfl_frame.c @@ -57,7 +57,7 @@ state_fetch_pc (Dwfl_Frame *state) __libdwfl_seterrno (DWFL_E_LIBEBL_BAD); return false; } - state->pc = state->regs[ra]; + state->pc = state->regs[ra] + ebl_ra_offset (ebl); state->pc_state = DWFL_FRAME_STATE_PC_SET; } return true; diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c index 76d45a83..515092f3 100644 --- a/libdwfl/dwfl_module.c +++ b/libdwfl/dwfl_module.c @@ -1,5 +1,5 @@ /* Maintenance of module list in libdwfl. - Copyright (C) 2005, 2006, 2007, 2008, 2014 Red Hat, Inc. + Copyright (C) 2005, 2006, 2007, 2008, 2014, 2015 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -27,6 +27,7 @@ not, see <http://www.gnu.org/licenses/>. */ #include "libdwflP.h" +#include "../libdw/cfi.h" #include <search.h> #include <unistd.h> @@ -70,6 +71,23 @@ __libdwfl_module_free (Dwfl_Module *mod) free (mod->cu); } + /* We might have primed the Dwarf_CFI ebl cache with our own ebl + in __libdwfl_set_cfi. Make sure we don't free it twice. */ + if (mod->eh_cfi != NULL) + { + if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl) + mod->eh_cfi->ebl = NULL; + dwarf_cfi_end (mod->eh_cfi); + } + + if (mod->dwarf_cfi != NULL) + { + if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl) + mod->dwarf_cfi->ebl = NULL; + /* We don't need to explicitly destroy the dwarf_cfi. + That will be done by dwarf_end. */ + } + if (mod->dw != NULL) { INTUSE(dwarf_end) (mod->dw); @@ -97,9 +115,6 @@ __libdwfl_module_free (Dwfl_Module *mod) if (mod->reloc_info != NULL) free (mod->reloc_info); - if (mod->eh_cfi != NULL) - dwarf_cfi_end (mod->eh_cfi); - free (mod->name); free (mod); } diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c index d205832c..5a7bf714 100644 --- a/libdwfl/dwfl_module_addrsym.c +++ b/libdwfl/dwfl_module_addrsym.c @@ -28,141 +28,144 @@ #include "libdwflP.h" -/* Returns the name of the symbol "closest" to ADDR. - Never returns symbols at addresses above ADDR. */ - -const char * -internal_function -__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, - GElf_Sym *closest_sym, GElf_Word *shndxp, - Elf **elfp, Dwarf_Addr *biasp, bool adjust_st_value) +struct search_state { - int syments = INTUSE(dwfl_module_getsymtab) (mod); - if (syments < 0) - return NULL; + Dwfl_Module *mod; + GElf_Addr addr; - /* Return true iff we consider ADDR to lie in the same section as SYM. */ - GElf_Word addr_shndx = SHN_UNDEF; - Elf *addr_symelf = NULL; - inline bool same_section (GElf_Addr value, Elf *symelf, GElf_Word shndx) - { - /* For absolute symbols and the like, only match exactly. */ - if (shndx >= SHN_LORESERVE) - return value == addr; + GElf_Sym *closest_sym; + bool adjust_st_value; + GElf_Word addr_shndx; + Elf *addr_symelf; - /* If value might not be st_value, the shndx of the symbol might - not match the section of the value. Explicitly look both up. */ - if (! adjust_st_value) - { - Dwarf_Addr v; - if (addr_shndx == SHN_UNDEF) - { - v = addr; - addr_shndx = __libdwfl_find_section_ndx (mod, &v); - } + /* Keep track of the closest symbol we have seen so far. + Here we store only symbols with nonzero st_size. */ + const char *closest_name; + GElf_Addr closest_value; + GElf_Word closest_shndx; + Elf *closest_elf; - v = value; - return addr_shndx == __libdwfl_find_section_ndx (mod, &v); - } + /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ + const char *sizeless_name; + GElf_Sym sizeless_sym; + GElf_Addr sizeless_value; + GElf_Word sizeless_shndx; + Elf *sizeless_elf; - /* Figure out what section ADDR lies in. */ - if (addr_shndx == SHN_UNDEF || addr_symelf != symelf) - { - GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, symelf, addr); - Elf_Scn *scn = NULL; - addr_shndx = SHN_ABS; - addr_symelf = symelf; - while ((scn = elf_nextscn (symelf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (likely (shdr != NULL) - && mod_addr >= shdr->sh_addr - && mod_addr < shdr->sh_addr + shdr->sh_size) - { - addr_shndx = elf_ndxscn (scn); - break; - } - } - } + /* Keep track of the lowest address a relevant sizeless symbol could have. */ + GElf_Addr min_label; +}; - return shndx == addr_shndx && addr_symelf == symelf; +/* Return true iff we consider ADDR to lie in the same section as SYM. */ +static inline bool +same_section (struct search_state *state, + GElf_Addr value, Elf *symelf, GElf_Word shndx) +{ + /* For absolute symbols and the like, only match exactly. */ + if (shndx >= SHN_LORESERVE) + return value == state->addr; + + /* If value might not be st_value, the shndx of the symbol might + not match the section of the value. Explicitly look both up. */ + if (! state->adjust_st_value) + { + Dwarf_Addr v; + if (state->addr_shndx == SHN_UNDEF) + { + v = state->addr; + state->addr_shndx = __libdwfl_find_section_ndx (state->mod, &v); + } + + v = value; + return state->addr_shndx == __libdwfl_find_section_ndx (state->mod, &v); } - /* Keep track of the closest symbol we have seen so far. - Here we store only symbols with nonzero st_size. */ - const char *closest_name = NULL; - GElf_Addr closest_value = 0; - GElf_Word closest_shndx = SHN_UNDEF; - Elf *closest_elf = NULL; + /* Figure out what section ADDR lies in. */ + if (state->addr_shndx == SHN_UNDEF || state->addr_symelf != symelf) + { + GElf_Addr mod_addr = dwfl_deadjust_st_value (state->mod, symelf, + state->addr); + Elf_Scn *scn = NULL; + state->addr_shndx = SHN_ABS; + state->addr_symelf = symelf; + while ((scn = elf_nextscn (symelf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (likely (shdr != NULL) + && mod_addr >= shdr->sh_addr + && mod_addr < shdr->sh_addr + shdr->sh_size) + { + state->addr_shndx = elf_ndxscn (scn); + break; + } + } + } - /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ - const char *sizeless_name = NULL; - GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }; - GElf_Addr sizeless_value = 0; - GElf_Word sizeless_shndx = SHN_UNDEF; - Elf *sizeless_elf = NULL; + return shndx == state->addr_shndx && state->addr_symelf == symelf; +} - /* Keep track of the lowest address a relevant sizeless symbol could have. */ - GElf_Addr min_label = 0; +/* Return GELF_ST_BIND as higher-is-better integer. */ +static inline int +binding_value (const GElf_Sym *symp) +{ + switch (GELF_ST_BIND (symp->st_info)) + { + case STB_GLOBAL: + return 3; + case STB_WEAK: + return 2; + case STB_LOCAL: + return 1; + default: + return 0; + } +} - /* Try one symbol and associated value from the search table. */ - inline void try_sym_value (GElf_Addr value, GElf_Sym *sym, - const char *name, GElf_Word shndx, - Elf *elf, bool resolved) - { +/* Try one symbol and associated value from the search table. */ +static inline void +try_sym_value (struct search_state *state, + GElf_Addr value, GElf_Sym *sym, + const char *name, GElf_Word shndx, + Elf *elf, bool resolved) +{ /* Even if we don't choose this symbol, its existence excludes any sizeless symbol (assembly label) that is below its upper bound. */ - if (value + sym->st_size > min_label) - min_label = value + sym->st_size; + if (value + sym->st_size > state->min_label) + state->min_label = value + sym->st_size; - if (sym->st_size == 0 || addr - value < sym->st_size) + if (sym->st_size == 0 || state->addr - value < sym->st_size) { - /* Return GELF_ST_BIND as higher-is-better integer. */ - inline int binding_value (const GElf_Sym *symp) - { - switch (GELF_ST_BIND (symp->st_info)) - { - case STB_GLOBAL: - return 3; - case STB_WEAK: - return 2; - case STB_LOCAL: - return 1; - default: - return 0; - } - } - /* This symbol is a better candidate than the current one if it's closer to ADDR or is global when it was local. */ - if (closest_name == NULL - || closest_value < value - || binding_value (closest_sym) < binding_value (sym)) + if (state->closest_name == NULL + || state->closest_value < value + || binding_value (state->closest_sym) < binding_value (sym)) { if (sym->st_size != 0) { - *closest_sym = *sym; - closest_value = value; - closest_shndx = shndx; - closest_elf = elf; - closest_name = name; + *state->closest_sym = *sym; + state->closest_value = value; + state->closest_shndx = shndx; + state->closest_elf = elf; + state->closest_name = name; } - else if (closest_name == NULL - && value >= min_label - && same_section (value, - resolved ? mod->main.elf : elf, shndx)) + else if (state->closest_name == NULL + && value >= state->min_label + && same_section (state, value, + resolved ? state->mod->main.elf : elf, + shndx)) { /* Handwritten assembly symbols sometimes have no st_size. If no symbol with proper size includes the address, we'll use the closest one that is in the same section as ADDR. */ - sizeless_sym = *sym; - sizeless_value = value; - sizeless_shndx = shndx; - sizeless_elf = elf; - sizeless_name = name; + state->sizeless_sym = *sym; + state->sizeless_value = value; + state->sizeless_shndx = shndx; + state->sizeless_elf = elf; + state->sizeless_name = name; } } /* When the beginning of its range is no closer, @@ -170,26 +173,27 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, GELF_ST_BIND preference. If all are equal prefer the first symbol found. */ else if (sym->st_size != 0 - && closest_value == value - && ((closest_sym->st_size > sym->st_size - && (binding_value (closest_sym) + && state->closest_value == value + && ((state->closest_sym->st_size > sym->st_size + && (binding_value (state->closest_sym) <= binding_value (sym))) - || (closest_sym->st_size >= sym->st_size - && (binding_value (closest_sym) + || (state->closest_sym->st_size >= sym->st_size + && (binding_value (state->closest_sym) < binding_value (sym))))) { - *closest_sym = *sym; - closest_value = value; - closest_shndx = shndx; - closest_elf = elf; - closest_name = name; + *state->closest_sym = *sym; + state->closest_value = value; + state->closest_shndx = shndx; + state->closest_elf = elf; + state->closest_name = name; } } - } +} - /* Look through the symbol table for a matching symbol. */ - inline void search_table (int start, int end) - { +/* Look through the symbol table for a matching symbol. */ +static inline void +search_table (struct search_state *state, int start, int end) +{ for (int i = start; i < end; ++i) { GElf_Sym sym; @@ -197,32 +201,66 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, GElf_Word shndx; Elf *elf; bool resolved; - const char *name = __libdwfl_getsym (mod, i, &sym, &value, + const char *name = __libdwfl_getsym (state->mod, i, &sym, &value, &shndx, &elf, NULL, - &resolved, adjust_st_value); + &resolved, + state->adjust_st_value); if (name != NULL && name[0] != '\0' && sym.st_shndx != SHN_UNDEF - && value <= addr + && value <= state->addr && GELF_ST_TYPE (sym.st_info) != STT_SECTION && GELF_ST_TYPE (sym.st_info) != STT_FILE && GELF_ST_TYPE (sym.st_info) != STT_TLS) { - try_sym_value (value, &sym, name, shndx, elf, resolved); + try_sym_value (state, value, &sym, name, shndx, elf, resolved); /* If this is an addrinfo variant and the value could be resolved then also try matching the (adjusted) st_value. */ - if (resolved && mod->e_type != ET_REL) + if (resolved && state->mod->e_type != ET_REL) { GElf_Addr adjusted_st_value; - adjusted_st_value = dwfl_adjusted_st_value (mod, elf, + adjusted_st_value = dwfl_adjusted_st_value (state->mod, elf, sym.st_value); - if (value != adjusted_st_value && adjusted_st_value <= addr) - try_sym_value (adjusted_st_value, &sym, name, shndx, + if (value != adjusted_st_value + && adjusted_st_value <= state->addr) + try_sym_value (state, adjusted_st_value, &sym, name, shndx, elf, false); } } } - } +} + +/* Returns the name of the symbol "closest" to ADDR. + Never returns symbols at addresses above ADDR. */ +const char * +internal_function +__libdwfl_addrsym (Dwfl_Module *_mod, GElf_Addr _addr, GElf_Off *off, + GElf_Sym *_closest_sym, GElf_Word *shndxp, + Elf **elfp, Dwarf_Addr *biasp, bool _adjust_st_value) +{ + int syments = INTUSE(dwfl_module_getsymtab) (_mod); + if (syments < 0) + return NULL; + + struct search_state state = + { + .addr = _addr, + .mod = _mod, + .closest_sym = _closest_sym, + .adjust_st_value = _adjust_st_value, + .addr_shndx = SHN_UNDEF, + .addr_symelf = NULL, + .closest_name = NULL, + .closest_value = 0, + .closest_shndx = SHN_UNDEF, + .closest_elf = NULL, + .sizeless_name = NULL, + .sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }, + .sizeless_value = 0, + .sizeless_shndx = SHN_UNDEF, + .sizeless_elf = NULL, + .min_label = 0 + }; /* First go through global symbols. mod->first_global and mod->aux_first_global are setup by dwfl_module_getsymtab to the @@ -233,38 +271,39 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, come first in the symbol table, then all globals. The zeroth, null entry, in the auxiliary table is skipped if there is a main table. */ - int first_global = INTUSE (dwfl_module_getsymtab_first_global) (mod); + int first_global = INTUSE (dwfl_module_getsymtab_first_global) (state.mod); if (first_global < 0) return NULL; - search_table (first_global == 0 ? 1 : first_global, syments); + search_table (&state, first_global == 0 ? 1 : first_global, syments); /* If we found nothing searching the global symbols, then try the locals. Unless we have a global sizeless symbol that matches exactly. */ - if (closest_name == NULL && first_global > 1 - && (sizeless_name == NULL || sizeless_value != addr)) - search_table (1, first_global); + if (state.closest_name == NULL && first_global > 1 + && (state.sizeless_name == NULL || state.sizeless_value != state.addr)) + search_table (&state, 1, first_global); /* If we found no proper sized symbol to use, fall back to the best candidate sizeless symbol we found, if any. */ - if (closest_name == NULL - && sizeless_name != NULL && sizeless_value >= min_label) + if (state.closest_name == NULL + && state.sizeless_name != NULL + && state.sizeless_value >= state.min_label) { - *closest_sym = sizeless_sym; - closest_value = sizeless_value; - closest_shndx = sizeless_shndx; - closest_elf = sizeless_elf; - closest_name = sizeless_name; + *state.closest_sym = state.sizeless_sym; + state.closest_value = state.sizeless_value; + state.closest_shndx = state.sizeless_shndx; + state.closest_elf = state.sizeless_elf; + state.closest_name = state.sizeless_name; } - *off = addr - closest_value; + *off = state.addr - state.closest_value; if (shndxp != NULL) - *shndxp = closest_shndx; + *shndxp = state.closest_shndx; if (elfp != NULL) - *elfp = closest_elf; + *elfp = state.closest_elf; if (biasp != NULL) - *biasp = dwfl_adjusted_st_value (mod, closest_elf, 0); - return closest_name; + *biasp = dwfl_adjusted_st_value (state.mod, state.closest_elf, 0); + return state.closest_name; } diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 8483fa21..e9589b3f 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -231,6 +231,24 @@ __libdwfl_getelf (Dwfl_Module *mod) mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr; } +static inline void +consider_shdr (GElf_Addr interp, + GElf_Word sh_type, + GElf_Xword sh_flags, + GElf_Addr sh_addr, + GElf_Xword sh_size, + GElf_Addr *phighest) +{ + if ((sh_flags & SHF_ALLOC) + && ((sh_type == SHT_PROGBITS && sh_addr != interp) + || sh_type == SHT_NOBITS)) + { + const GElf_Addr sh_end = sh_addr + sh_size; + if (sh_end > *phighest) + *phighest = sh_end; + } +} + /* If the main file might have been prelinked, then we need to discover the correct synchronization address between the main and debug files. Because of prelink's section juggling, we cannot rely @@ -448,22 +466,6 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) GElf_Addr highest; - inline void consider_shdr (GElf_Addr interp, - GElf_Word sh_type, - GElf_Xword sh_flags, - GElf_Addr sh_addr, - GElf_Xword sh_size) - { - if ((sh_flags & SHF_ALLOC) - && ((sh_type == SHT_PROGBITS && sh_addr != interp) - || sh_type == SHT_NOBITS)) - { - const GElf_Addr sh_end = sh_addr + sh_size; - if (sh_end > highest) - highest = sh_end; - } - } - highest = 0; scn = NULL; while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) @@ -476,7 +478,7 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) return DWFL_E_LIBELF; } consider_shdr (main_interp, sh->sh_type, sh->sh_flags, - sh->sh_addr, sh->sh_size); + sh->sh_addr, sh->sh_size, &highest); } if (highest > mod->main.vaddr) { @@ -489,7 +491,7 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) for (size_t i = 0; i < shnum - 1; ++i) consider_shdr (undo_interp, (*s32)[i].sh_type, (*s32)[i].sh_flags, (*s32)[i].sh_addr, - (*s32)[i].sh_size); + (*s32)[i].sh_size, &highest); } else { @@ -497,7 +499,7 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) for (size_t i = 0; i < shnum - 1; ++i) consider_shdr (undo_interp, (*s64)[i].sh_type, (*s64)[i].sh_flags, (*s64)[i].sh_addr, - (*s64)[i].sh_size); + (*s64)[i].sh_size, &highest); } if (highest > file->vaddr) @@ -676,6 +678,141 @@ find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n, } } +/* Various addresses we might want to pull from the dynamic segment. */ +enum +{ + i_symtab, + i_strtab, + i_hash, + i_gnu_hash, + i_max +}; + +/* Translate pointers into file offsets. ADJUST is either zero + in case the dynamic segment wasn't adjusted or mod->main_bias. + Will set mod->symfile if the translated offsets can be used as + symbol table. */ +static void +translate_offs (GElf_Addr adjust, + Dwfl_Module *mod, size_t phnum, + GElf_Addr addrs[i_max], GElf_Xword strsz, + GElf_Ehdr *ehdr) +{ + GElf_Off offs[i_max] = { 0, }; + find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs); + + /* Figure out the size of the symbol table. */ + if (offs[i_hash] != 0) + { + /* In the original format, .hash says the size of .dynsym. */ + + size_t entsz = SH_ENTSIZE_HASH (ehdr); + Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, + offs[i_hash] + entsz, entsz, + (entsz == 4 + ? ELF_T_WORD : ELF_T_XWORD)); + if (data != NULL) + mod->syments = (entsz == 4 + ? *(const GElf_Word *) data->d_buf + : *(const GElf_Xword *) data->d_buf); + } + if (offs[i_gnu_hash] != 0 && mod->syments == 0) + { + /* In the new format, we can derive it with some work. */ + + const struct + { + Elf32_Word nbuckets; + Elf32_Word symndx; + Elf32_Word maskwords; + Elf32_Word shift2; + } *header; + + Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash], + sizeof *header, ELF_T_WORD); + if (data != NULL) + { + header = data->d_buf; + Elf32_Word nbuckets = header->nbuckets; + Elf32_Word symndx = header->symndx; + GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header + + (gelf_getclass (mod->main.elf) + * sizeof (Elf32_Word) + * header->maskwords)); + + // elf_getdata_rawchunk takes a size_t, make sure it + // doesn't overflow. +#if SIZE_MAX <= UINT32_MAX + if (nbuckets > SIZE_MAX / sizeof (Elf32_Word)) + data = NULL; + else +#endif + data = elf_getdata_rawchunk (mod->main.elf, buckets_at, + nbuckets * sizeof (Elf32_Word), + ELF_T_WORD); + if (data != NULL && symndx < nbuckets) + { + const Elf32_Word *const buckets = data->d_buf; + Elf32_Word maxndx = symndx; + for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) + if (buckets[bucket] > maxndx) + maxndx = buckets[bucket]; + + GElf_Off hasharr_at = (buckets_at + + nbuckets * sizeof (Elf32_Word)); + hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); + do + { + data = elf_getdata_rawchunk (mod->main.elf, + hasharr_at, + sizeof (Elf32_Word), + ELF_T_WORD); + if (data != NULL + && (*(const Elf32_Word *) data->d_buf & 1u)) + { + mod->syments = maxndx + 1; + break; + } + ++maxndx; + hasharr_at += sizeof (Elf32_Word); + } + while (data != NULL); + } + } + } + if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0) + mod->syments = ((offs[i_strtab] - offs[i_symtab]) + / gelf_fsize (mod->main.elf, + ELF_T_SYM, 1, EV_CURRENT)); + + if (mod->syments > 0) + { + mod->symdata = elf_getdata_rawchunk (mod->main.elf, + offs[i_symtab], + gelf_fsize (mod->main.elf, + ELF_T_SYM, + mod->syments, + EV_CURRENT), + ELF_T_SYM); + if (mod->symdata != NULL) + { + mod->symstrdata = elf_getdata_rawchunk (mod->main.elf, + offs[i_strtab], + strsz, + ELF_T_BYTE); + if (mod->symstrdata == NULL) + mod->symdata = NULL; + } + if (mod->symdata == NULL) + mod->symerr = DWFL_E (LIBELF, elf_errno ()); + else + { + mod->symfile = &mod->main; + mod->symerr = DWFL_E_NOERROR; + } + } +} + /* Try to find a dynamic symbol table via phdrs. */ static void find_dynsym (Dwfl_Module *mod) @@ -704,14 +841,6 @@ find_dynsym (Dwfl_Module *mod) if (data == NULL) continue; - enum - { - i_symtab, - i_strtab, - i_hash, - i_gnu_hash, - i_max - }; GElf_Addr addrs[i_max] = { 0, }; GElf_Xword strsz = 0; size_t n = data->d_size / gelf_fsize (mod->main.elf, @@ -752,131 +881,12 @@ find_dynsym (Dwfl_Module *mod) break; } - /* Translate pointers into file offsets. ADJUST is either zero - in case the dynamic segment wasn't adjusted or mod->main_bias. */ - void translate_offs (GElf_Addr adjust) - { - GElf_Off offs[i_max] = { 0, }; - find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs); - - /* Figure out the size of the symbol table. */ - if (offs[i_hash] != 0) - { - /* In the original format, .hash says the size of .dynsym. */ - - size_t entsz = SH_ENTSIZE_HASH (ehdr); - data = elf_getdata_rawchunk (mod->main.elf, - offs[i_hash] + entsz, entsz, - entsz == 4 ? ELF_T_WORD - : ELF_T_XWORD); - if (data != NULL) - mod->syments = (entsz == 4 - ? *(const GElf_Word *) data->d_buf - : *(const GElf_Xword *) data->d_buf); - } - if (offs[i_gnu_hash] != 0 && mod->syments == 0) - { - /* In the new format, we can derive it with some work. */ - - const struct - { - Elf32_Word nbuckets; - Elf32_Word symndx; - Elf32_Word maskwords; - Elf32_Word shift2; - } *header; - - data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash], - sizeof *header, ELF_T_WORD); - if (data != NULL) - { - header = data->d_buf; - Elf32_Word nbuckets = header->nbuckets; - Elf32_Word symndx = header->symndx; - GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header - + (gelf_getclass (mod->main.elf) - * sizeof (Elf32_Word) - * header->maskwords)); - - // elf_getdata_rawchunk takes a size_t, make sure it - // doesn't overflow. -#if SIZE_MAX <= UINT32_MAX - if (nbuckets > SIZE_MAX / sizeof (Elf32_Word)) - data = NULL; - else -#endif - data - = elf_getdata_rawchunk (mod->main.elf, buckets_at, - nbuckets * sizeof (Elf32_Word), - ELF_T_WORD); - if (data != NULL && symndx < nbuckets) - { - const Elf32_Word *const buckets = data->d_buf; - Elf32_Word maxndx = symndx; - for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) - if (buckets[bucket] > maxndx) - maxndx = buckets[bucket]; - - GElf_Off hasharr_at = (buckets_at - + nbuckets * sizeof (Elf32_Word)); - hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); - do - { - data = elf_getdata_rawchunk (mod->main.elf, - hasharr_at, - sizeof (Elf32_Word), - ELF_T_WORD); - if (data != NULL - && (*(const Elf32_Word *) data->d_buf & 1u)) - { - mod->syments = maxndx + 1; - break; - } - ++maxndx; - hasharr_at += sizeof (Elf32_Word); - } while (data != NULL); - } - } - } - if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0) - mod->syments = ((offs[i_strtab] - offs[i_symtab]) - / gelf_fsize (mod->main.elf, - ELF_T_SYM, 1, EV_CURRENT)); - - if (mod->syments > 0) - { - mod->symdata = elf_getdata_rawchunk (mod->main.elf, - offs[i_symtab], - gelf_fsize (mod->main.elf, - ELF_T_SYM, - mod->syments, - EV_CURRENT), - ELF_T_SYM); - if (mod->symdata != NULL) - { - mod->symstrdata = elf_getdata_rawchunk (mod->main.elf, - offs[i_strtab], - strsz, - ELF_T_BYTE); - if (mod->symstrdata == NULL) - mod->symdata = NULL; - } - if (mod->symdata == NULL) - mod->symerr = DWFL_E (LIBELF, elf_errno ()); - else - { - mod->symfile = &mod->main; - mod->symerr = DWFL_E_NOERROR; - } - } - } - /* First try unadjusted, like ELF files from disk, vdso. Then try for already adjusted dynamic section, like ELF from remote memory. */ - translate_offs (0); + translate_offs (0, mod, phnum, addrs, strsz, ehdr); if (mod->symfile == NULL) - translate_offs (mod->main_bias); + translate_offs (mod->main_bias, mod, phnum, addrs, strsz, ehdr); return; } diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c index 39509b70..0e470b97 100644 --- a/libdwfl/frame_unwind.c +++ b/libdwfl/frame_unwind.c @@ -637,7 +637,14 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) if (unwound->pc == 0) unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; else - unwound->pc_state = DWFL_FRAME_STATE_PC_SET; + { + unwound->pc_state = DWFL_FRAME_STATE_PC_SET; + /* In SPARC the return address register actually contains + the address of the call instruction instead of the return + address. Therefore we add here an offset defined by the + backend. Most likely 0. */ + unwound->pc += ebl_ra_offset (ebl); + } } free (frame); } diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 63556d51..2a83646e 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -1,5 +1,5 @@ /* Internal definitions for libdwfl. - Copyright (C) 2005-2014 Red Hat, Inc. + Copyright (C) 2005-2015 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -104,6 +104,16 @@ typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error; extern int __libdwfl_canon_error (Dwfl_Error) internal_function; extern void __libdwfl_seterrno (Dwfl_Error) internal_function; +/* Resources we might keep for the user about the core file that the + Dwfl might have been created from. Can currently only be set + through std-argp. */ +struct Dwfl_User_Core +{ + char *executable_for_core; /* --executable if --core was specified. */ + Elf *core; /* non-NULL if we need to free it. */ + int fd; /* close if >= 0. */ +}; + struct Dwfl { const Dwfl_Callbacks *callbacks; @@ -130,7 +140,7 @@ struct Dwfl GElf_Off lookup_tail_offset; int lookup_tail_ndx; - char *executable_for_core; /* --executable if --core was specified. */ + struct Dwfl_User_Core *user_core; }; #define OFFLINE_REDZONE 0x10000 diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 13cac529..28d7382f 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -42,64 +42,70 @@ #define PROBE_VAL64 sizeof (Elf64_Phdr) -/* Examine an auxv data block and determine its format. - Return true iff we figured it out. */ -static bool -auxv_format_probe (const void *auxv, size_t size, - uint_fast8_t *elfclass, uint_fast8_t *elfdata) +static inline bool +do_check64 (size_t i, const Elf64_auxv_t (*a64)[], uint_fast8_t *elfdata) { - const Elf32_auxv_t (*a32)[size / sizeof (Elf32_auxv_t)] = (void *) auxv; - const Elf64_auxv_t (*a64)[size / sizeof (Elf64_auxv_t)] = (void *) auxv; + /* The AUXV pointer might not even be naturally aligned for 64-bit + data, because note payloads in a core file are not aligned. */ - inline bool check64 (size_t i) - { - /* The AUXV pointer might not even be naturally aligned for 64-bit - data, because note payloads in a core file are not aligned. */ + uint64_t type = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_type); + uint64_t val = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_un.a_val); - uint64_t type = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_type); - uint64_t val = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_un.a_val); + if (type == BE64 (PROBE_TYPE) + && val == BE64 (PROBE_VAL64)) + { + *elfdata = ELFDATA2MSB; + return true; + } - if (type == BE64 (PROBE_TYPE) - && val == BE64 (PROBE_VAL64)) - { - *elfdata = ELFDATA2MSB; - return true; - } + if (type == LE64 (PROBE_TYPE) + && val == LE64 (PROBE_VAL64)) + { + *elfdata = ELFDATA2LSB; + return true; + } - if (type == LE64 (PROBE_TYPE) - && val == LE64 (PROBE_VAL64)) - { - *elfdata = ELFDATA2LSB; - return true; - } + return false; +} - return false; - } +#define check64(n) do_check64 (n, a64, elfdata) - inline bool check32 (size_t i) - { - /* The AUXV pointer might not even be naturally aligned for 32-bit - data, because note payloads in a core file are not aligned. */ +static inline bool +do_check32 (size_t i, const Elf32_auxv_t (*a32)[], uint_fast8_t *elfdata) +{ + /* The AUXV pointer might not even be naturally aligned for 32-bit + data, because note payloads in a core file are not aligned. */ - uint32_t type = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_type); - uint32_t val = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_un.a_val); + uint32_t type = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_type); + uint32_t val = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_un.a_val); - if (type == BE32 (PROBE_TYPE) - && val == BE32 (PROBE_VAL32)) - { - *elfdata = ELFDATA2MSB; - return true; - } + if (type == BE32 (PROBE_TYPE) + && val == BE32 (PROBE_VAL32)) + { + *elfdata = ELFDATA2MSB; + return true; + } - if (type == LE32 (PROBE_TYPE) - && val == LE32 (PROBE_VAL32)) - { - *elfdata = ELFDATA2LSB; - return true; - } + if (type == LE32 (PROBE_TYPE) + && val == LE32 (PROBE_VAL32)) + { + *elfdata = ELFDATA2LSB; + return true; + } - return false; - } + return false; +} + +#define check32(n) do_check32 (n, a32, elfdata) + +/* Examine an auxv data block and determine its format. + Return true iff we figured it out. */ +static bool +auxv_format_probe (const void *auxv, size_t size, + uint_fast8_t *elfclass, uint_fast8_t *elfdata) +{ + const Elf32_auxv_t (*a32)[size / sizeof (Elf32_auxv_t)] = (void *) auxv; + const Elf64_auxv_t (*a64)[size / sizeof (Elf64_auxv_t)] = (void *) auxv; for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i) { @@ -356,8 +362,10 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, if (name != NULL && name[0] == '\0') name = NULL; - if (iterations == 1 && dwfl->executable_for_core != NULL) - name = dwfl->executable_for_core; + if (iterations == 1 + && dwfl->user_core != NULL + && dwfl->user_core->executable_for_core != NULL) + name = dwfl->user_core->executable_for_core; struct r_debug_info_module *r_debug_info_module = NULL; if (r_debug_info != NULL) @@ -789,7 +797,10 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf, &in.d_size, phdr, phnum * phent, memory_callback_arg); - if (! in_ok && dwfl->executable_for_core != NULL) + bool in_from_exec = false; + if (! in_ok + && dwfl->user_core != NULL + && dwfl->user_core->executable_for_core != NULL) { /* AUXV -> PHDR -> DYNAMIC Both AUXV and DYNAMIC should be always present in a core file. @@ -797,7 +808,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the core file. */ - int fd = open (dwfl->executable_for_core, O_RDONLY); + int fd = open (dwfl->user_core->executable_for_core, O_RDONLY); Elf *elf; Dwfl_Error error = DWFL_E_ERRNO; if (fd != -1) @@ -851,6 +862,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, return false; } in_ok = true; + in_from_exec = true; } if (in_ok) { @@ -899,8 +911,11 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, } } - (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0, - memory_callback_arg); + if (in_from_exec) + free (in.d_buf); + else + (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0, + memory_callback_arg); free (buf); } else diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c index 2e2c8f92..9e7b2a21 100644 --- a/libdwfl/linux-proc-maps.c +++ b/libdwfl/linux-proc-maps.c @@ -175,6 +175,23 @@ grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr) return ENOEXEC; } +static inline bool +do_report (Dwfl *dwfl, char **plast_file, Dwarf_Addr low, Dwarf_Addr high) +{ + if (*plast_file != NULL) + { + Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, *plast_file, + low, high); + free (*plast_file); + *plast_file = NULL; + if (unlikely (mod == NULL)) + return true; + } + return false; +} + +#define report() do_report(dwfl, &last_file, low, high) + static int proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid) { @@ -183,20 +200,6 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid) char *last_file = NULL; Dwarf_Addr low = 0, high = 0; - inline bool report (void) - { - if (last_file != NULL) - { - Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file, - low, high); - free (last_file); - last_file = NULL; - if (unlikely (mod == NULL)) - return true; - } - return false; - } - char *line = NULL; size_t linesz; ssize_t len; diff --git a/libebl/ChangeLog b/libebl/ChangeLog index d040c08f..a1a10224 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,9 @@ +2015-12-08 Jose E. Marchesi <jose.marchesi@oracle.com> + + * libebl.h: Prototype for ebl_ra_offset. + * eblabicfi.c (ebl_ra_offset): New function. + * libeblP.h (struct ebl): new field ra_offset; + 2015-09-24 Jose E. Marchesi <jose.marchesi@oracle.com> * Makefile.am (AM_CFLAGS): Use -fPIC instead of -fpic to avoid diff --git a/libebl/eblabicfi.c b/libebl/eblabicfi.c index 6b0e18e4..8bf189f1 100644 --- a/libebl/eblabicfi.c +++ b/libebl/eblabicfi.c @@ -38,3 +38,9 @@ ebl_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info) { return ebl == NULL ? -1 : ebl->abi_cfi (ebl, abi_info); } + +int +ebl_ra_offset (Ebl *ebl) +{ + return ebl->ra_offset; +} diff --git a/libebl/libebl.h b/libebl/libebl.h index 7dbf4608..efcb6d60 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -422,6 +422,12 @@ extern bool ebl_set_initial_registers_tid (Ebl *ebl, extern size_t ebl_frame_nregs (Ebl *ebl) __nonnull_attribute__ (1); +/* Offset to apply to the value of the return_address_register, as + fetched from a Dwarf CFI. This is used by some backends, where the + return_address_register actually contains the call address. */ +extern int ebl_ra_offset (Ebl *ebl) + __nonnull_attribute__ (1); + /* Mask to use for function symbol or unwind return addresses in case the architecture adds some extra non-address bits to it. This is different from ebl_resolve_sym_value which only works for actual diff --git a/libebl/libeblP.h b/libebl/libeblP.h index dbd67f3e..5b339b31 100644 --- a/libebl/libeblP.h +++ b/libebl/libeblP.h @@ -64,6 +64,12 @@ struct ebl Ebl architecture can unwind iff FRAME_NREGS > 0. */ size_t frame_nregs; + /* Offset to apply to the value of the return_address_register, as + fetched from a Dwarf CFI. This is used by some backends, where + the return_address_register actually contains the call + address. */ + int ra_offset; + /* Mask to use to turn a function value into a real function address in case the architecture adds some extra non-address bits to it. If not initialized (0) then ebl_func_addr_mask will return ~0, diff --git a/src/ChangeLog b/src/ChangeLog index d6d2936e..b5b5e4a4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,31 @@ +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * nm.c (process_file): Accept fd and pass it on. + (handle_elf): Likewise. + (find_no_debuginfo): New. + (struct getdbg): Likewise. + (getdbg_dwflmod): Likewise. + (show_symbols): Take fd. If the file is ET_REL use libdwfl to get + the relocated Dwarf. + +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * nm.c (get_local_names): Check for duplicates in local_root tree. + +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * unstrip.c (struct data_list): New. + (new_data_list): Likewise. + (record_new_data): Likewise. + (free_new_data): Likewise. + (adjust_relocs): Call record_new_data. + (add_new_section_symbols): Likewise. + (copy_elided_sections): Call free_new_data. + +2015-12-01 Mark Wielaard <mjw@redhat.com> + + * elfcmp.c (main): Close ebl1 and ebl2 backends. + 2015-10-16 Mark Wielaard <mjw@redhat.com> * Makefile.am [BUILD_STATIC](libdw): Add -lz. diff --git a/src/elfcmp.c b/src/elfcmp.c index 0250fbe3..852b92f5 100644 --- a/src/elfcmp.c +++ b/src/elfcmp.c @@ -655,6 +655,8 @@ cannot read note section [%zu] '%s' in '%s': %s"), out: elf_end (elf1); elf_end (elf2); + ebl_closebackend (ebl1); + ebl_closebackend (ebl2); close (fd1); close (fd2); @@ -45,6 +45,7 @@ #include <system.h> #include "../libebl/libeblP.h" +#include "../libdwfl/libdwflP.h" /* Name and version of program. */ @@ -131,7 +132,7 @@ static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, const char *suffix); /* Handle ELF file. */ -static int handle_elf (Elf *elf, const char *prefix, const char *fname, +static int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const char *suffix); @@ -384,7 +385,7 @@ process_file (const char *fname, bool more_than_one) { if (elf_kind (elf) == ELF_K_ELF) { - int result = handle_elf (elf, more_than_one ? "" : NULL, + int result = handle_elf (fd, elf, more_than_one ? "" : NULL, fname, NULL); if (elf_end (elf) != 0) @@ -493,7 +494,7 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, && strcmp (arhdr->ar_name, "/SYM64/") != 0) { if (elf_kind (subelf) == ELF_K_ELF) - result |= handle_elf (subelf, new_prefix, arhdr->ar_name, + result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, new_suffix); else if (elf_kind (subelf) == ELF_K_AR) result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, @@ -708,11 +709,16 @@ get_local_names (Dwarf *dbg) newp->lowpc = lowpc; newp->highpc = highpc; - /* Since we cannot deallocate individual memory we do not test - for duplicates in the tree. This should not happen anyway. */ - if (tsearch (newp, &local_root, local_compare) == NULL) - error (EXIT_FAILURE, errno, - gettext ("cannot create search tree")); + /* Check whether a similar local_name is already in the + cache. That should not happen. But if it does, we + don't want to leak memory. */ + struct local_name **tres = tsearch (newp, &local_root, + local_compare); + if (tres == NULL) + error (EXIT_FAILURE, errno, + gettext ("cannot create search tree")); + else if (*tres != newp) + free (newp); } while (dwarf_siblingof (die, die) == 0); } @@ -1148,8 +1154,63 @@ sort_by_name (const void *p1, const void *p2) return reverse_sort ? -result : result; } +/* Stub libdwfl callback, only the ELF handle already open is ever + used. Only used for finding the alternate debug file if the Dwarf + comes from the main file. We are not interested in separate + debuginfo. */ +static int +find_no_debuginfo (Dwfl_Module *mod, + void **userdata, + const char *modname, + Dwarf_Addr base, + const char *file_name, + const char *debuglink_file, + GElf_Word debuglink_crc, + char **debuginfo_file_name) +{ + Dwarf_Addr dwbias; + dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL); + + /* We are only interested if the Dwarf has been setup on the main + elf file but is only missing the alternate debug link. If dwbias + hasn't even been setup, this is searching for separate debuginfo + for the main elf. We don't care in that case. */ + if (dwbias == (Dwarf_Addr) -1) + return -1; + + return dwfl_standard_find_debuginfo (mod, userdata, modname, base, + file_name, debuglink_file, + debuglink_crc, debuginfo_file_name); +} + +/* Get the Dwarf for the module/file we want. */ +struct getdbg +{ + const char *name; + Dwarf **dbg; +}; + +static int +getdbg_dwflmod (Dwfl_Module *dwflmod, + void **userdata __attribute__ ((unused)), + const char *name, + Dwarf_Addr base __attribute__ ((unused)), + void *arg) +{ + struct getdbg *get = (struct getdbg *) arg; + if (get != NULL && get->name != NULL && strcmp (get->name, name) == 0) + { + Dwarf_Addr bias; + *get->dbg = dwfl_module_getdwarf (dwflmod, &bias); + return DWARF_CB_ABORT; + } + + return DWARF_CB_OK; +} + static void -show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, +show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr, + Elf_Scn *scn, Elf_Scn *xndxscn, GElf_Shdr *shdr, const char *prefix, const char *fname, const char *fullname) { @@ -1189,9 +1250,48 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, /* Get a DWARF debugging descriptor. It's no problem if this isn't possible. We just won't print any line number information. */ Dwarf *dbg = NULL; + Dwfl *dwfl = NULL; if (format == format_sysv) { - dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); + if (ehdr->e_type != ET_REL) + dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); + else + { + /* Abuse libdwfl to do the relocations for us. This is just + for the ET_REL file containing Dwarf, so no need for + fancy lookups. */ + + /* Duplicate an fd for dwfl_report_offline to swallow. */ + int dwfl_fd = dup (fd); + if (likely (dwfl_fd >= 0)) + { + static const Dwfl_Callbacks callbacks = + { + .section_address = dwfl_offline_section_address, + .find_debuginfo = find_no_debuginfo + }; + dwfl = dwfl_begin (&callbacks); + if (likely (dwfl != NULL)) + { + /* Let 0 be the logical address of the file (or + first in archive). */ + dwfl->offline_next_address = 0; + if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) + == NULL) + { + /* Consumed on success, not on failure. */ + close (dwfl_fd); + } + else + { + dwfl_report_end (dwfl, NULL, NULL); + + struct getdbg get = { .name = fname, .dbg = &dbg }; + dwfl_getmodules (dwfl, &getdbg_dwflmod, &get, 0); + } + } + } + } if (dbg != NULL) { (void) dwarf_getpubnames (dbg, get_global, NULL, 0); @@ -1396,13 +1496,16 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, tdestroy (local_root, free); local_root = NULL; - (void) dwarf_end (dbg); + if (dwfl == NULL) + (void) dwarf_end (dbg); } + if (dwfl != NULL) + dwfl_end (dwfl); } static int -handle_elf (Elf *elf, const char *prefix, const char *fname, +handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const char *suffix) { size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); @@ -1481,7 +1584,7 @@ handle_elf (Elf *elf, const char *prefix, const char *fname, } } - show_symbols (ebl, ehdr, scn, xndxscn, shdr, prefix, fname, + show_symbols (fd, ebl, ehdr, scn, xndxscn, shdr, prefix, fname, fullname); } } diff --git a/src/unstrip.c b/src/unstrip.c index bc8ed503..85e0a1da 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -311,6 +311,38 @@ make_directories (const char *path) error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir); } +/* Keep track of new section data we are creating, so we can free it + when done. */ +struct data_list +{ + void *data; + struct data_list *next; +}; + +struct data_list *new_data_list; + +static void +record_new_data (void *data) +{ + struct data_list *next = new_data_list; + new_data_list = xmalloc (sizeof (struct data_list)); + new_data_list->data = data; + new_data_list->next = next; +} + +static void +free_new_data (void) +{ + struct data_list *list = new_data_list; + while (list != NULL) + { + struct data_list *next = list->next; + free (list->data); + free (list); + list = next; + } + new_data_list = NULL; +} /* The binutils linker leaves gratuitous section symbols in .symtab that strip has to remove. Older linkers likewise include a @@ -472,6 +504,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, if (old_chain[i] != STN_UNDEF) \ new_chain[map[i - 1]] = map[old_chain[i] - 1]; \ \ + record_new_data (new_hash); \ data->d_buf = new_hash; \ data->d_size = nent * sizeof new_hash[0]; \ } @@ -514,6 +547,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, ELF_CHECK (v != NULL, _("cannot get symbol version: %s")); } + record_new_data (versym); data->d_buf = versym; data->d_size = nent * shdr->sh_entsize; elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY); @@ -571,6 +605,7 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum, symdata->d_size = shdr->sh_size; symdata->d_buf = xmalloc (symdata->d_size); + record_new_data (symdata->d_buf); /* Copy the existing section symbols. */ Elf_Data *old_symdata = elf_getdata (old_symscn, NULL); @@ -1762,6 +1797,7 @@ more sections in stripped file than debug file -- arguments reversed?")); shdr->sh_size = symdata->d_size = (1 + nsym) * shdr->sh_entsize; symdata->d_buf = xmalloc (symdata->d_size); + record_new_data (symdata->d_buf); GElf_Sym sym; memset (&sym, 0, sizeof sym); @@ -1927,13 +1963,12 @@ more sections in stripped file than debug file -- arguments reversed?")); free (strtab_data->d_buf); } - if (symdata != NULL) - free (symdata->d_buf); if (symstrtab != NULL) { ebl_strtabfree (symstrtab); free (symstrdata->d_buf); } + free_new_data (); } /* Process one pair of files, already opened. */ diff --git a/tests/ChangeLog b/tests/ChangeLog index 69a25fc6..b8d1d954 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,31 @@ +2015-12-08 Jose E. Marchesi <jose.marchesi@oracle.com> + + * run-backtrace-core-sparc.sh: New file. + * backtrace.sparc.core.bz2: New file. + * backtrace.sparc.exec.bz2: New file. + * Makefile.am (EXTRA_DIST): ... and added all here. + (TESTS): Added run-backtrace-core-sparc.sh. + +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (valgrind_cmd): Use --leak-check=full. + * run-backtrace-demangle.sh: Disable valgrind. + * run-stack-demangled-test.sh: Likewise. + * run-stack-d-test.sh: Likewise. + * run-stack-i-test.sh: Likewise. + +2015-12-01 Mark Wielaard <mjw@redhat.com> + + * test-flag-nobits.c (main): Call elf_end. + * rerequest_tag.c (main): Call dwarf_end. + * funcscopes.c (handle_function): Free scopes. + * dwarf-getstring.c (main): Call dwarf_end. + * allregs.c (main): Free state.info. + * alldts.c (main): Free dyn. + * addrcfi.c (handle_address): Free stuff.frame between handle_cfi + calls. + * addrscopes.c (handle_address): Free scopes. + 2015-10-16 Mark Wielaard <mjw@redhat.com> * Makefile.am [BUILD_STATIC] (libdw): Add -lz. diff --git a/tests/Makefile.am b/tests/Makefile.am index 30cf137c..8fca8014 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -114,7 +114,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ run-backtrace-core-x32.sh \ run-backtrace-core-i386.sh run-backtrace-core-ppc.sh \ run-backtrace-core-s390x.sh run-backtrace-core-s390.sh \ - run-backtrace-core-aarch64.sh \ + run-backtrace-core-aarch64.sh run-backtrace-core-sparc.sh \ run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh \ run-stack-demangled-test.sh \ run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh \ @@ -287,6 +287,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ run-backtrace-core-s390x.sh run-backtrace-core-s390.sh \ run-backtrace-core-aarch64.sh \ backtrace.aarch64.core.bz2 backtrace.aarch64.exec.bz2 \ + run-backtrace-core-sparc.sh \ + backtrace.sparc.core.bz2 backtrace.sparc.exec.bz2 \ run-backtrace-demangle.sh testfile-backtrace-demangle.bz2 \ testfile-backtrace-demangle.cc \ testfile-backtrace-demangle.core.bz2 \ @@ -307,7 +309,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ run-lfs-symbols.sh lfs-symbols testfile-nolfs.bz2 if USE_VALGRIND -valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no' +valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1' endif diff --git a/tests/addrcfi.c b/tests/addrcfi.c index eb950c0b..589b8513 100644 --- a/tests/addrcfi.c +++ b/tests/addrcfi.c @@ -160,10 +160,19 @@ handle_address (GElf_Addr pc, Dwfl *dwfl) Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc); struct stuff stuff; - return (handle_cfi (dwfl, ".eh_frame", - dwfl_module_eh_cfi (mod, &stuff.bias), pc, &stuff) - & handle_cfi (dwfl, ".debug_frame", - dwfl_module_dwarf_cfi (mod, &stuff.bias), pc, &stuff)); + stuff.frame = NULL; + stuff.bias = 0; + int res = handle_cfi (dwfl, ".eh_frame", + dwfl_module_eh_cfi (mod, &stuff.bias), pc, &stuff); + free (stuff.frame); + + stuff.frame = NULL; + stuff.bias = 0; + res &= handle_cfi (dwfl, ".debug_frame", + dwfl_module_dwarf_cfi (mod, &stuff.bias), pc, &stuff); + free (stuff.frame); + + return res; } int diff --git a/tests/addrscopes.c b/tests/addrscopes.c index 2285d2ca..791569f5 100644 --- a/tests/addrscopes.c +++ b/tests/addrscopes.c @@ -134,6 +134,7 @@ handle_address (GElf_Addr pc, Dwfl *dwfl) print_vars (indent + INDENT, die); } + free (scopes); } } diff --git a/tests/alldts.c b/tests/alldts.c index c39b8fb6..eaecaf57 100644 --- a/tests/alldts.c +++ b/tests/alldts.c @@ -256,6 +256,9 @@ main (void) /* And the data allocated in the .shstrtab section. */ free (data->d_buf); + /* And the dynamic entries. */ + free (dyn); + /* All done. */ if (elf_end (elf) != 0) { diff --git a/tests/allregs.c b/tests/allregs.c index 901d4e88..286f7e3c 100644 --- a/tests/allregs.c +++ b/tests/allregs.c @@ -184,6 +184,7 @@ main (int argc, char **argv) dwarf_encoding_string (state.info[i].type), state.info[i].bits); } + free (state.info); } else do diff --git a/tests/backtrace.sparc.core.bz2 b/tests/backtrace.sparc.core.bz2 Binary files differnew file mode 100644 index 00000000..ad37f75c --- /dev/null +++ b/tests/backtrace.sparc.core.bz2 diff --git a/tests/backtrace.sparc.exec.bz2 b/tests/backtrace.sparc.exec.bz2 Binary files differnew file mode 100755 index 00000000..b049ec50 --- /dev/null +++ b/tests/backtrace.sparc.exec.bz2 diff --git a/tests/dwarf-getstring.c b/tests/dwarf-getstring.c index 824edef8..ffa3e375 100644 --- a/tests/dwarf-getstring.c +++ b/tests/dwarf-getstring.c @@ -70,6 +70,7 @@ main (int argc, char *argv[]) offset += len + 1; } + dwarf_end (dbg); close (fd); } diff --git a/tests/funcscopes.c b/tests/funcscopes.c index 55cb4fac..9c901858 100644 --- a/tests/funcscopes.c +++ b/tests/funcscopes.c @@ -162,6 +162,7 @@ handle_function (Dwarf_Die *funcdie, void *arg) print_vars (indent + INDENT, die); } + free (scopes); } return 0; diff --git a/tests/rerequest_tag.c b/tests/rerequest_tag.c index d0bf5f24..b4d46271 100644 --- a/tests/rerequest_tag.c +++ b/tests/rerequest_tag.c @@ -42,5 +42,6 @@ main (int argc, char **argv) assert (die == &die_mem); assert (dwarf_tag (die) == 0); + dwarf_end (dw); return 0; } diff --git a/tests/run-backtrace-core-sparc.sh b/tests/run-backtrace-core-sparc.sh new file mode 100755 index 00000000..60399baa --- /dev/null +++ b/tests/run-backtrace-core-sparc.sh @@ -0,0 +1,20 @@ +#! /bin/bash +# Copyright (C) 2015 Oracle, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. $srcdir/backtrace-subr.sh + +check_core sparc diff --git a/tests/run-backtrace-demangle.sh b/tests/run-backtrace-demangle.sh index 71a73518..2d253240 100755 --- a/tests/run-backtrace-demangle.sh +++ b/tests/run-backtrace-demangle.sh @@ -26,6 +26,11 @@ child=testfile-backtrace-demangle testfiles $child{,.core} tempfiles $child.{bt,err} +# Disable valgrind while dumping because of a bug unmapping libc.so. +# https://bugs.kde.org/show_bug.cgi?id=327427 +SAVED_VALGRIND_CMD="$VALGRIND_CMD" +unset VALGRIND_CMD + # There can be more than 3 frames, but depending on the system/installed # glibc we might not be able to unwind fully till the end. # cxxfunc -> f -> main @@ -33,6 +38,12 @@ tempfiles $child.{bt,err} # (exit code 1) testrun ${abs_top_builddir}/src/stack -n 2 -e $child --core $child.core >$child.bt 2>$child.err || exitcode=$? cat $child.{bt,err} + +if [ "x$SAVED_VALGRIND_CMD" != "x" ]; then + VALGRIND_CMD="$SAVED_VALGRIND_CMD" + export VALGRIND_CMD +fi + if test $exitcode != 1 || ! grep "shown max number of frames" $child.err; then echo >&2 $2: expected more than 2 frames false diff --git a/tests/run-stack-d-test.sh b/tests/run-stack-d-test.sh index 41982014..a9f03806 100755 --- a/tests/run-stack-d-test.sh +++ b/tests/run-stack-d-test.sh @@ -68,6 +68,11 @@ else STACKCMD=${abs_top_builddir}/src/stack fi +# Disable valgrind while dumping because of a bug unmapping libc.so. +# https://bugs.kde.org/show_bug.cgi?id=327427 +SAVED_VALGRIND_CMD="$VALGRIND_CMD" +unset VALGRIND_CMD + # Without -d the top function comes out as fu. Use --raw to not demangle. testrun_compare ${abs_top_builddir}/src/stack -r -n 2 -e testfiledwarfinlines --core testfiledwarfinlines.core<<EOF PID 13654 - core @@ -109,4 +114,9 @@ TID 13654: $STACKCMD: tid 13654: shown max number of frames (2, use -n 0 for unlimited) EOF +if [ "x$SAVED_VALGRIND_CMD" != "x" ]; then + VALGRIND_CMD="$SAVED_VALGRIND_CMD" + export VALGRIND_CMD +fi + exit 0 diff --git a/tests/run-stack-demangled-test.sh b/tests/run-stack-demangled-test.sh index 98f8ff8e..c26918f9 100755 --- a/tests/run-stack-demangled-test.sh +++ b/tests/run-stack-demangled-test.sh @@ -37,6 +37,11 @@ else STACKCMD=${abs_top_builddir}/src/stack fi +# Disable valgrind while dumping because of a bug unmapping libc.so. +# https://bugs.kde.org/show_bug.cgi?id=327427 +SAVED_VALGRIND_CMD="$VALGRIND_CMD" +unset VALGRIND_CMD + # Without -d the top function comes out as fu. testrun_compare ${abs_top_builddir}/src/stack -n 2 -e testfiledwarfinlines --core testfiledwarfinlines.core<<EOF PID 13654 - core @@ -92,4 +97,9 @@ TID 13654: $STACKCMD: tid 13654: shown max number of frames (6, use -n 0 for unlimited) EOF +if [ "x$SAVED_VALGRIND_CMD" != "x" ]; then + VALGRIND_CMD="$SAVED_VALGRIND_CMD" + export VALGRIND_CMD +fi + exit 0 diff --git a/tests/run-stack-i-test.sh b/tests/run-stack-i-test.sh index ffab85f9..3722ab09 100755 --- a/tests/run-stack-i-test.sh +++ b/tests/run-stack-i-test.sh @@ -29,6 +29,11 @@ else STACKCMD=${abs_top_builddir}/src/stack fi +# Disable valgrind while dumping because of a bug unmapping libc.so. +# https://bugs.kde.org/show_bug.cgi?id=327427 +SAVED_VALGRIND_CMD="$VALGRIND_CMD" +unset VALGRIND_CMD + # Compare with run-stack-d-test.sh to see the output without --inlines. # Only two call frames are visible (there is a jump from main to fu or # fubar). Explicitly use --raw so demangler support being configured in @@ -68,4 +73,9 @@ TID 13654: $STACKCMD: tid 13654: shown max number of frames (6, use -n 0 for unlimited) EOF +if [ "x$SAVED_VALGRIND_CMD" != "x" ]; then + VALGRIND_CMD="$SAVED_VALGRIND_CMD" + export VALGRIND_CMD +fi + exit 0 diff --git a/tests/test-flag-nobits.c b/tests/test-flag-nobits.c index ff19ce20..15d44ea8 100644 --- a/tests/test-flag-nobits.c +++ b/tests/test-flag-nobits.c @@ -36,4 +36,7 @@ main (int argc, char **argv) Elf_Scn *scn = NULL; while ((scn = elf_nextscn (stripped, scn)) != NULL) elf_flagdata (elf_getdata (scn, NULL), ELF_C_SET, ELF_F_DIRTY); + + elf_end (stripped); + return 0; } |