* Clang has Blocks like closures that can serve similar purpose as the nested functions in gnu99. Syntax of Blocks is similar to nested functions that *NESTED_FUNC macro can be used for the function/block declarations. See spec in http://clang.llvm.org/docs/BlockLanguageSpec.html * Local variables used in a closure should have __BLOCK attribute unless they are constants. * Formal parameters used in a closure should be copied to local variable and declared as __BLOCK. * Cannot goto and jump over __BLOCK variables, so these variables have been moved to be declared before goto. * Clang Blocks cannot copy an array to a closure, and gcc complains about unbounded stack usage from alloca.
Signed-off-by: Chih-Hung Hsieh <c...@google.com> --- backends/aarch64_regs.c | 10 +- backends/ia64_retval.c | 6 +- lib/nested_func.h | 85 ++++++++++++++++ libdw/cfi.c | 13 +-- libdw/dwarf_entry_breakpoints.c | 18 ++-- libdw/dwarf_getscopevar.c | 8 +- libdw/dwarf_getsrclines.c | 60 +++++++----- libdw/libdw_visit_scopes.c | 22 +++-- libdwelf/dwelf_elf_gnu_build_id.c | 7 +- libdwfl/argp-std.c | 13 ++- libdwfl/core-file.c | 28 +++--- libdwfl/dwfl_module.c | 7 +- libdwfl/dwfl_module_addrsym.c | 55 ++++++----- libdwfl/dwfl_module_getdwarf.c | 73 ++++++++------ libdwfl/dwfl_module_getsrc_file.c | 29 +++--- libdwfl/dwfl_segment_report_module.c | 185 ++++++++++++++++++++--------------- libdwfl/elf-from-memory.c | 125 ++++++++++++----------- libdwfl/frame_unwind.c | 17 ++-- libdwfl/gzip.c | 35 +++---- libdwfl/link_map.c | 59 ++++++----- libdwfl/linux-kernel-modules.c | 37 +++---- libdwfl/linux-proc-maps.c | 13 +-- libdwfl/relocate.c | 41 ++++---- libelf/elf32_updatefile.c | 5 +- libelf/elf_begin.c | 5 +- src/addr2line.c | 19 ++-- src/ar.c | 7 +- src/arlib-argp.c | 5 +- src/elflint.c | 14 +-- src/ld.c | 5 +- src/readelf.c | 48 +++++---- src/strip.c | 74 +++++++------- src/unstrip.c | 40 ++++---- 33 files changed, 693 insertions(+), 475 deletions(-) create mode 100644 lib/nested_func.h diff --git a/backends/aarch64_regs.c b/backends/aarch64_regs.c index 7a8a678..053c99e 100644 --- a/backends/aarch64_regs.c +++ b/backends/aarch64_regs.c @@ -37,6 +37,7 @@ #define BACKEND aarch64_ #include "libebl_CPU.h" +#include "nested_func.h" ssize_t aarch64_register_info (Ebl *ebl __attribute__ ((unused)), @@ -47,9 +48,10 @@ aarch64_register_info (Ebl *ebl __attribute__ ((unused)), if (name == NULL) return 128; - __attribute__ ((format (printf, 3, 4))) - ssize_t - regtype (const char *setname, int type, const char *fmt, ...) + NESTED_FUNC (__attribute__ ((format (printf, 3, 4))) ssize_t, + regtype, + (const char *, int, const char *, ...), + (const char *setname, int type, const char *fmt, ...)) { *setnamep = setname; *typep = type; @@ -62,7 +64,7 @@ aarch64_register_info (Ebl *ebl __attribute__ ((unused)), if (s < 0 || (unsigned) s >= namelen) return -1; return s + 1; - } + }; *prefix = ""; *bits = 64; diff --git a/backends/ia64_retval.c b/backends/ia64_retval.c index b5928c5..339f092 100644 --- a/backends/ia64_retval.c +++ b/backends/ia64_retval.c @@ -35,6 +35,7 @@ #define BACKEND ia64_ #include "libebl_CPU.h" +#include "nested_func.h" /* r8, or pair r8, r9, or aggregate up to r8-r11. */ @@ -100,14 +101,15 @@ hfa_type (Dwarf_Die *typedie, Dwarf_Word size, If we find a datum that's not the same FP type as the first datum, punt. If we count more than eight total homogeneous FP data, punt. */ - inline int hfa (const Dwarf_Op *loc, int nregs) + INLINE_NESTED_FUNC (int, hfa, (const Dwarf_Op *, int), + (const Dwarf_Op *loc, int nregs)) { if (fpregs_used == 0) *locp = loc; else if (*locp != loc) return 9; return fpregs_used + nregs; - } + }; int tag = DWARF_TAG_OR_RETURN (typedie); switch (tag) diff --git a/lib/nested_func.h b/lib/nested_func.h new file mode 100644 index 0000000..be44a31 --- /dev/null +++ b/lib/nested_func.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2015 Red Hat, Inc. + This file is part of elfutils. + Written by Chih-Hung Hsieh <c...@google.com>, 2015. + + 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/>. */ + +#ifndef _NESTED_FUNC_H +#define _NESTED_FUNC_H 1 + +#if __clang__ + + #define __BLOCK __block + + #define NESTED_FUNC(return_type, function_name, \ + arg_types, arg_types_and_names) \ + return_type (^function_name) arg_types = \ + ^ return_type arg_types_and_names + + /* Clang does not like inline keyword before a block variable. */ + #define INLINE_NESTED_FUNC(r, f, t, a) \ + NESTED_FUNC (r, f, t, a) + + #define INLINE_INTUSE_NESTED_FUNC(r, f, t, a) \ + NESTED_FUNC (r, INTUSE(f), t, a) + + /* Recrusive blocks need to be declared before used. */ + #define RECURSIVE_NESTED_FUNC(return_type, function_name, \ + arg_types, arg_types_and_names) \ + __BLOCK return_type (^function_name) arg_types; \ + function_name = ^ return_type arg_types_and_names + + #define INLINE_RECURSIVE_NESTED_FUNC(r, f, t, a) \ + RECURSIVE_NESTED_FUNC (r, f, t, a) + + #define INLINE_INTUSE_RECURSIVE_NESTED_FUNC(r, f, t, a) \ + RECURSIVE_NESTED_FUNC (r, INTUSE(f), t, a) + +#else /* gcc nested function */ + + #define __BLOCK + + #define NESTED_FUNC(return_type, function_name, \ + arg_types, arg_types_and_names) \ + return_type function_name arg_types_and_names + + #define INLINE_NESTED_FUNC(r, f, t, a) \ + inline NESTED_FUNC (r, f, t, a) + + #define INLINE_INTUSE_NESTED_FUNC(r, f, t, a) \ + inline NESTED_FUNC (r, INTUSE(f), t, a) + + #define RECURSIVE_NESTED_FUNC(r, f, t, a) \ + NESTED_FUNC (r, f, t, a) + + #define INLINE_RECURSIVE_NESTED_FUNC(r, f, t, a) \ + inline RECURSIVE_NESTED_FUNC (r, f, t, a) + + #define INLINE_INTUSE_RECURSIVE_NESTED_FUNC(r, f, t, a) \ + INLINE_RECURSIVE_NESTED_FUNC (r, INTUSE(f), t, a) + +#endif + +#endif /* _NESTED_FUNC_H */ diff --git a/libdw/cfi.c b/libdw/cfi.c index 5a6f956..fccf2c5 100644 --- a/libdw/cfi.c +++ b/libdw/cfi.c @@ -34,6 +34,7 @@ #include "../libebl/libebl.h" #include "cfi.h" #include "memory-access.h" +#include "nested_func.h" #include "encoded-value.h" #include "system.h" #include <assert.h> @@ -68,7 +69,7 @@ execute_cfi (Dwarf_CFI *cache, /* The caller should not give us anything out of range. */ assert (loc <= find_pc); - int result = DWARF_E_NOERROR; + __BLOCK int result = DWARF_E_NOERROR; #define cfi_assert(ok) do { \ if (likely (ok)) break; \ @@ -76,8 +77,8 @@ execute_cfi (Dwarf_CFI *cache, goto out; \ } while (0) - Dwarf_Frame *fs = *state; - inline bool enough_registers (Dwarf_Word reg) + __BLOCK Dwarf_Frame *fs = *state; + INLINE_NESTED_FUNC (bool, enough_registers, (Dwarf_Word), (Dwarf_Word reg)) { /* Don't allow insanely large register numbers. 268435456 registers should be enough for anybody. And very large values might overflow @@ -107,13 +108,13 @@ execute_cfi (Dwarf_CFI *cache, } } return true; - } + }; - inline void require_cfa_offset (void) + INLINE_NESTED_FUNC (void, require_cfa_offset, (void), (void)) { if (unlikely (fs->cfa_rule != cfa_offset)) fs->cfa_rule = cfa_invalid; - } + }; #define register_rule(regno, r_rule, r_value) do { \ if (unlikely (! enough_registers (regno))) \ diff --git a/libdw/dwarf_entry_breakpoints.c b/libdw/dwarf_entry_breakpoints.c index ffd5169..65484ce 100644 --- a/libdw/dwarf_entry_breakpoints.c +++ b/libdw/dwarf_entry_breakpoints.c @@ -30,6 +30,7 @@ # include <config.h> #endif #include "libdwP.h" +#include "nested_func.h" #include <dwarf.h> #include <stdlib.h> @@ -39,11 +40,11 @@ dwarf_entry_breakpoints (die, bkpts) Dwarf_Die *die; Dwarf_Addr **bkpts; { - int nbkpts = 0; + __BLOCK int nbkpts = 0; *bkpts = NULL; /* Add one breakpoint location to the result vector. */ - inline int add_bkpt (Dwarf_Addr pc) + INLINE_NESTED_FUNC (int, add_bkpt, (Dwarf_Addr), (Dwarf_Addr pc)) { Dwarf_Addr *newlist = realloc (*bkpts, ++nbkpts * sizeof newlist[0]); if (newlist == NULL) @@ -56,14 +57,14 @@ dwarf_entry_breakpoints (die, bkpts) newlist[nbkpts - 1] = pc; *bkpts = newlist; return nbkpts; - } + }; /* Fallback result, break at the entrypc/lowpc value. */ - inline int entrypc_bkpt (void) + INLINE_NESTED_FUNC (int, entrypc_bkpt, (void), (void)) { 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); @@ -81,8 +82,9 @@ dwarf_entry_breakpoints (die, bkpts) /* 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) + INLINE_NESTED_FUNC (int, search_range, + (Dwarf_Addr, Dwarf_Addr, bool, bool), + (Dwarf_Addr low, Dwarf_Addr high, bool dwarf, bool adhoc)) { size_t l = 0, u = nlines; while (l < u) @@ -115,7 +117,7 @@ dwarf_entry_breakpoints (die, bkpts) } __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; - } + }; /* Search each contiguous address range for DWARF prologue_end markers. */ diff --git a/libdw/dwarf_getscopevar.c b/libdw/dwarf_getscopevar.c index eb50c0a..73c9475 100644 --- a/libdw/dwarf_getscopevar.c +++ b/libdw/dwarf_getscopevar.c @@ -33,6 +33,7 @@ #include <stdbool.h> #include <string.h> #include "libdwP.h" +#include "nested_func.h" #include <dwarf.h> @@ -70,9 +71,10 @@ dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, { /* Match against the given file name. */ size_t match_file_len = match_file == NULL ? 0 : strlen (match_file); - bool lastfile_matches = false; + __BLOCK bool lastfile_matches = false; const char *lastfile = NULL; - inline bool file_matches (Dwarf_Files *files, size_t idx) + INLINE_NESTED_FUNC (bool, file_matches, + (Dwarf_Files *, size_t), (Dwarf_Files *files, size_t idx)) { if (idx >= files->nfiles) return false; @@ -87,7 +89,7 @@ dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, || file[len - match_file_len - 1] == '/')); } return lastfile_matches; - } + }; /* Start with the innermost scope and move out. */ for (int out = 0; out < nscopes; ++out) diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index 389c824..f200d70 100644 --- a/libdw/dwarf_getsrclines.c +++ b/libdw/dwarf_getsrclines.c @@ -38,6 +38,7 @@ #include "dwarf.h" #include "libdwP.h" +#include "nested_func.h" struct filelist @@ -86,10 +87,29 @@ read_srclines (Dwarf *dbg, { int res = -1; - struct linelist *linelist = NULL; - size_t nlinelist = 0; - size_t nfilelist = 0; - unsigned int ndirlist = 0; + __BLOCK struct linelist *linelist = NULL; + __BLOCK size_t nlinelist = 0; + __BLOCK size_t nfilelist = 0; + __BLOCK unsigned int ndirlist = 0; + /* We are about to process the statement program. Initialize the + state machine registers (see 6.2.2 in the v2.1 specification). */ + __BLOCK Dwarf_Word addr = 0; + __BLOCK unsigned int op_index = 0; + __BLOCK unsigned int file = 1; + /* We only store an int, but want to check for overflow (see SET below). */ + __BLOCK int64_t line = 1; + __BLOCK unsigned int column = 0; + __BLOCK uint_fast8_t is_stmt = 0; + __BLOCK bool basic_block = false; + __BLOCK bool prologue_end = false; + __BLOCK bool epilogue_begin = false; + __BLOCK unsigned int isa = 0; + __BLOCK unsigned int discriminator = 0; + /* Next the minimum instruction length. */ + __BLOCK uint_fast8_t minimum_instr_len = 0; + /* Next the maximum operations per instruction, in version 4 format. */ + __BLOCK uint_fast8_t max_ops_per_instr = 1; + struct filelist null_file = { @@ -159,10 +179,8 @@ read_srclines (Dwarf *dbg, const unsigned char *header_start = linep; /* Next the minimum instruction length. */ - uint_fast8_t minimum_instr_len = *linep++; + minimum_instr_len = *linep++; - /* Next the maximum operations per instruction, in version 4 format. */ - uint_fast8_t max_ops_per_instr = 1; if (version >= 4) { if (unlikely (lineendp - linep < 5)) @@ -176,6 +194,8 @@ read_srclines (Dwarf *dbg, register. */ uint_fast8_t default_is_stmt = *linep++; + is_stmt = default_is_stmt; + /* Now the line base. */ int_fast8_t line_base = (int8_t) *linep++; @@ -321,29 +341,15 @@ read_srclines (Dwarf *dbg, goto out; } - /* We are about to process the statement program. Initialize the - state machine registers (see 6.2.2 in the v2.1 specification). */ - Dwarf_Word addr = 0; - unsigned int op_index = 0; - unsigned int file = 1; - /* We only store an int, but want to check for overflow (see SET below). */ - int64_t line = 1; - unsigned int column = 0; - uint_fast8_t is_stmt = default_is_stmt; - bool basic_block = false; - bool prologue_end = false; - bool epilogue_begin = false; - unsigned int isa = 0; - unsigned int discriminator = 0; - /* Apply the "operation advance" from a special opcode or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */ - inline void advance_pc (unsigned int op_advance) + INLINE_NESTED_FUNC (void, advance_pc, + (unsigned int), (unsigned int op_advance)) { addr += minimum_instr_len * ((op_index + op_advance) / max_ops_per_instr); op_index = (op_index + op_advance) % max_ops_per_instr; - } + }; /* Process the instructions. */ @@ -361,7 +367,9 @@ read_srclines (Dwarf *dbg, goto invalid_data; \ } while (0) - inline bool add_new_line (struct linelist *new_line, bool end_sequence) + INLINE_NESTED_FUNC (bool, add_new_line, + (struct linelist *, bool), + (struct linelist *new_line, bool end_sequence)) { new_line->next = linelist; new_line->sequence = nlinelist; @@ -395,7 +403,7 @@ read_srclines (Dwarf *dbg, #undef SET return false; - } + }; while (linep < lineendp) { diff --git a/libdw/libdw_visit_scopes.c b/libdw/libdw_visit_scopes.c index ac7e853..d115a39 100644 --- a/libdw/libdw_visit_scopes.c +++ b/libdw/libdw_visit_scopes.c @@ -31,6 +31,7 @@ #endif #include "libdwP.h" +#include "nested_func.h" #include <dwarf.h> @@ -65,29 +66,30 @@ may_have_scopes (Dwarf_Die *die) } int -__libdw_visit_scopes (depth, root, imports, previsit, postvisit, arg) +__libdw_visit_scopes (depth, root, imports_param, previsit, postvisit, arg) unsigned int depth; struct Dwarf_Die_Chain *root; - struct Dwarf_Die_Chain *imports; + struct Dwarf_Die_Chain *imports_param; int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *); int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *); void *arg; { - struct Dwarf_Die_Chain child; - int ret; + __BLOCK struct Dwarf_Die_Chain child; + __BLOCK int ret; + __BLOCK struct Dwarf_Die_Chain *imports = imports_param; child.parent = root; if ((ret = INTUSE(dwarf_child) (&root->die, &child.die)) != 0) return ret < 0 ? -1 : 0; // Having zero children is legal. - inline int recurse (void) + INLINE_NESTED_FUNC (int, recurse, (void), (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) + INLINE_NESTED_FUNC (bool, imports_contains, (Dwarf_Die *), (Dwarf_Die *die)) { for (struct Dwarf_Die_Chain *import = imports; import != NULL; import = import->parent) @@ -95,9 +97,9 @@ __libdw_visit_scopes (depth, root, imports, previsit, postvisit, arg) return true; return false; - } + }; - inline int walk_children () + INLINE_RECURSIVE_NESTED_FUNC (int, walk_children, (void), (void)) { do { @@ -163,7 +165,7 @@ __libdw_visit_scopes (depth, root, imports, previsit, postvisit, arg) while ((ret = INTUSE(dwarf_siblingof) (&child.die, &child.die)) == 0); return ret < 0 ? -1 : 0; - } + }; return walk_children (); } diff --git a/libdwelf/dwelf_elf_gnu_build_id.c b/libdwelf/dwelf_elf_gnu_build_id.c index 1ed501d..8aff36b 100644 --- a/libdwelf/dwelf_elf_gnu_build_id.c +++ b/libdwelf/dwelf_elf_gnu_build_id.c @@ -32,6 +32,7 @@ #include "libdwelfP.h" #include "libdwflP.h" +#include "nested_func.h" #define NO_VADDR ((GElf_Addr) -1l) @@ -42,7 +43,9 @@ find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf, const void **build_id_bits, GElf_Addr *build_id_elfaddr, int *build_id_len) { - int check_notes (Elf_Data *data, GElf_Addr data_elfaddr) + NESTED_FUNC (int, check_notes, + (Elf_Data *, GElf_Addr), + (Elf_Data *data, GElf_Addr data_elfaddr)) { size_t pos = 0; GElf_Nhdr nhdr; @@ -60,7 +63,7 @@ find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf, return 1; } return 0; - } + }; size_t shstrndx = SHN_UNDEF; int result = 0; diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c index 42b7e78..06ba3b6 100644 --- a/libdwfl/argp-std.c +++ b/libdwfl/argp-std.c @@ -27,6 +27,7 @@ not, see <http://www.gnu.org/licenses/>. */ #include "libdwflP.h" +#include "nested_func.h" #include <argp.h> #include <stdlib.h> #include <assert.h> @@ -103,7 +104,9 @@ struct parse_opt static error_t parse_opt (int key, char *arg, struct argp_state *state) { - inline void failure (Dwfl *dwfl, int errnum, const char *msg) + INLINE_NESTED_FUNC (void, failure, + (Dwfl *, int, const char *), + (Dwfl *dwfl, int errnum, const char *msg)) { if (dwfl != NULL) dwfl_end (dwfl); @@ -112,12 +115,14 @@ parse_opt (int key, char *arg, struct argp_state *state) msg, INTUSE(dwfl_errmsg) (-1)); else argp_failure (state, EXIT_FAILURE, errnum, "%s", msg); - } - inline error_t fail (Dwfl *dwfl, int errnum, const char *msg) + }; + INLINE_NESTED_FUNC (error_t, fail, + (Dwfl *, int , const char *), + (Dwfl *dwfl, int errnum, const char *msg)) { failure (dwfl, errnum, msg); return errnum == -1 ? EIO : errnum; - } + }; switch (key) { diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c index bbe0899..ad94035 100644 --- a/libdwfl/core-file.c +++ b/libdwfl/core-file.c @@ -37,6 +37,7 @@ #include <endian.h> #include <byteswap.h> #include "system.h" +#include "nested_func.h" /* This is a prototype of what a new libelf interface might be. @@ -49,14 +50,14 @@ elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next) return NULL; /* On failure return, we update *NEXT to point back at OFFSET. */ - inline Elf *fail (int error) + INLINE_NESTED_FUNC (Elf *, fail, (int), (int error)) { if (next != NULL) *next = offset; //__libelf_seterrno (error); __libdwfl_seterrno (DWFL_E (LIBELF, error)); return NULL; - } + }; loff_t min = (parent->kind == ELF_K_ELF ? (parent->class == ELFCLASS32 @@ -239,13 +240,14 @@ core_file_read_eagerly (Dwfl_Module *mod, } bool -dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, +dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx_parameter, void **buffer, size_t *buffer_available, GElf_Addr vaddr, size_t minread, void *arg) { - Elf *elf = arg; + __BLOCK int ndx = ndx_parameter; + __BLOCK Elf *elf = arg; if (ndx == -1) { @@ -258,7 +260,7 @@ dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, } const GElf_Off align = dwfl->segment_align ?: 1; - GElf_Phdr phdr; + __BLOCK GElf_Phdr phdr; do if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL)) @@ -266,20 +268,20 @@ dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, while (phdr.p_type != PT_LOAD || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr); - GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset; - GElf_Off end; - GElf_Addr end_vaddr; + __BLOCK GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset; + __BLOCK GElf_Off end; + __BLOCK GElf_Addr end_vaddr; - inline void update_end () + INLINE_NESTED_FUNC (void, update_end, (void), (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) + INLINE_NESTED_FUNC (bool, more, (size_t), (size_t size)) { while (end <= start || end - start < size) { @@ -287,7 +289,7 @@ dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, /* This segment is truncated, so no following one helps us. */ return false; - if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL)) + if (unlikely (gelf_getphdr (elf, ndx++, (Elf64_Phdr *) &phdr) == NULL)) return false; if (phdr.p_type == PT_LOAD) @@ -301,7 +303,7 @@ dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, } } return true; - } + }; /* We need at least this much. */ if (! more (minread)) diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c index 8efcfaa..7035a89 100644 --- a/libdwfl/dwfl_module.c +++ b/libdwfl/dwfl_module.c @@ -27,6 +27,7 @@ not, see <http://www.gnu.org/licenses/>. */ #include "libdwflP.h" +#include "nested_func.h" #include <search.h> #include <unistd.h> @@ -132,9 +133,9 @@ Dwfl_Module * dwfl_report_module (Dwfl *dwfl, const char *name, GElf_Addr start, GElf_Addr end) { - Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; + __BLOCK Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; - inline Dwfl_Module *use (Dwfl_Module *mod) + INLINE_NESTED_FUNC (Dwfl_Module *, use, (Dwfl_Module *), (Dwfl_Module *mod)) { mod->next = *tailp; *tailp = mod; @@ -146,7 +147,7 @@ dwfl_report_module (Dwfl *dwfl, const char *name, } return mod; - } + }; for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) { diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c index d205832..1f0d020 100644 --- a/libdwfl/dwfl_module_addrsym.c +++ b/libdwfl/dwfl_module_addrsym.c @@ -27,6 +27,7 @@ not, see <http://www.gnu.org/licenses/>. */ #include "libdwflP.h" +#include "nested_func.h" /* Returns the name of the symbol "closest" to ADDR. Never returns symbols at addresses above ADDR. */ @@ -37,14 +38,16 @@ __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); + __BLOCK int syments = INTUSE(dwfl_module_getsymtab) (mod); if (syments < 0) return NULL; /* 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) + __BLOCK GElf_Word addr_shndx = SHN_UNDEF; + __BLOCK Elf *addr_symelf = NULL; + INLINE_NESTED_FUNC (bool, same_section, + (GElf_Addr, Elf *, GElf_Word), + (GElf_Addr value, Elf *symelf, GElf_Word shndx)) { /* For absolute symbols and the like, only match exactly. */ if (shndx >= SHN_LORESERVE) @@ -87,29 +90,33 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, } return shndx == addr_shndx && addr_symelf == symelf; - } + }; /* 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; + __BLOCK const char *closest_name = NULL; + __BLOCK GElf_Addr closest_value = 0; + __BLOCK GElf_Word closest_shndx = SHN_UNDEF; + __BLOCK Elf *closest_elf = NULL; /* 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; + __BLOCK const char *sizeless_name = NULL; + __BLOCK GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }; + __BLOCK GElf_Addr sizeless_value = 0; + __BLOCK GElf_Word sizeless_shndx = SHN_UNDEF; + __BLOCK Elf *sizeless_elf = NULL; /* Keep track of the lowest address a relevant sizeless symbol could have. */ - GElf_Addr min_label = 0; + __BLOCK GElf_Addr min_label = 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) + INLINE_NESTED_FUNC (void, try_sym_value, + (GElf_Addr, GElf_Sym *, + const char *, GElf_Word, + Elf *, bool), + (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 @@ -120,7 +127,9 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, if (sym->st_size == 0 || addr - value < sym->st_size) { /* Return GELF_ST_BIND as higher-is-better integer. */ - inline int binding_value (const GElf_Sym *symp) + INLINE_NESTED_FUNC (int, binding_value, + (const GElf_Sym *), + (const GElf_Sym *symp)) { switch (GELF_ST_BIND (symp->st_info)) { @@ -133,7 +142,7 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, 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. */ @@ -185,10 +194,10 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, closest_name = name; } } - } + }; /* Look through the symbol table for a matching symbol. */ - inline void search_table (int start, int end) + INLINE_NESTED_FUNC (void, search_table, (int, int), (int start, int end)) { for (int i = start; i < end; ++i) { @@ -222,7 +231,7 @@ __libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, } } } - } + }; /* First go through global symbols. mod->first_global and mod->aux_first_global are setup by dwfl_module_getsymtab to the diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index dba9d66..3a7a00c 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -33,6 +33,7 @@ #include <unistd.h> #include "../libdw/libdwP.h" /* DWARF_E_* values are here. */ #include "../libelf/libelfP.h" +#include "nested_func.h" static inline Dwfl_Error open_elf_file (Elf **elf, int *fd, char **name) @@ -251,11 +252,11 @@ static Dwfl_Error find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) { /* The magic section is only identified by name. */ - size_t shstrndx; + __BLOCK size_t shstrndx; if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0) return DWFL_E_LIBELF; - Elf_Scn *scn = NULL; + __BLOCK Elf_Scn *scn = NULL; while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) { GElf_Shdr shdr_mem; @@ -279,7 +280,7 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) /* There was no .gnu.prelink_undo section. */ return DWFL_E_NOERROR; - Elf_Data *undodata = elf_rawdata (scn, NULL); + __BLOCK Elf_Data *undodata = elf_rawdata (scn, NULL); if (unlikely (undodata == NULL)) return DWFL_E_LIBELF; @@ -291,14 +292,14 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) Elf32_Ehdr e32; Elf64_Ehdr e64; } ehdr; - Elf_Data dst = + __BLOCK Elf_Data dst = { .d_buf = &ehdr, .d_size = sizeof ehdr, .d_type = ELF_T_EHDR, .d_version = EV_CURRENT }; - Elf_Data src = *undodata; + __BLOCK Elf_Data src = *undodata; src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT); src.d_type = ELF_T_EHDR; if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, @@ -306,11 +307,11 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) == NULL)) return DWFL_E_LIBELF; - size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT); - size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT); + __BLOCK size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT); + __BLOCK size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT); - uint_fast16_t phnum; - uint_fast16_t shnum; + __BLOCK uint_fast16_t phnum; + __BLOCK uint_fast16_t shnum; if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { if (ehdr.e32.e_shentsize != shentsize @@ -417,7 +418,7 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) Elf32_Shdr s32[shnum - 1]; Elf64_Shdr s64[shnum - 1]; } shdr; - shdr *shdrs = malloc (sizeof (shdr)); + __BLOCK shdr *shdrs = malloc (sizeof (shdr)); if (unlikely (shdrs == NULL)) return DWFL_E_NOMEM; dst.d_buf = shdrs; @@ -445,13 +446,19 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) image remaining the same but being spread across the two sections. So we consider the highest section end, which still matches up. */ - 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) + __BLOCK GElf_Addr highest; + + INLINE_NESTED_FUNC (void, consider_shdr, + (GElf_Addr, + GElf_Word, + GElf_Xword, + GElf_Addr, + GElf_Xword), + (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) @@ -461,7 +468,7 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) if (sh_end > highest) highest = sh_end; } - } + }; highest = 0; scn = NULL; @@ -673,17 +680,17 @@ find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n, static void find_dynsym (Dwfl_Module *mod) { - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem); + __BLOCK GElf_Ehdr ehdr_mem; + __BLOCK GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem); - size_t phnum; + __BLOCK size_t phnum; if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0)) return; for (size_t i = 0; i < phnum; ++i) { - GElf_Phdr phdr_mem; - GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem); + __BLOCK GElf_Phdr phdr_mem; + __BLOCK GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem); if (phdr == NULL) break; @@ -691,7 +698,7 @@ find_dynsym (Dwfl_Module *mod) { /* Examine the dynamic section for the pointers we need. */ - Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, + __BLOCK Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset, phdr->p_filesz, ELF_T_DYN); if (data == NULL) @@ -705,10 +712,17 @@ find_dynsym (Dwfl_Module *mod) i_gnu_hash, i_max }; +#if __clang__ + /* Clang Blocks cannot copy an array to a closure. */ + GElf_Addr *addrs = alloca ((int) i_max * sizeof (GElf_Addr)); + memset (addrs, 0, i_max * sizeof (GElf_Addr)); +#else + /* gcc complains about unbounded stack usage from alloca. */ GElf_Addr addrs[i_max] = { 0, }; - GElf_Xword strsz = 0; - size_t n = data->d_size / gelf_fsize (mod->main.elf, - ELF_T_DYN, 1, EV_CURRENT); +#endif + __BLOCK GElf_Xword strsz = 0; + __BLOCK size_t n = + data->d_size / gelf_fsize (mod->main.elf, ELF_T_DYN, 1, EV_CURRENT); for (size_t j = 0; j < n; ++j) { GElf_Dyn dyn_mem; @@ -747,7 +761,8 @@ find_dynsym (Dwfl_Module *mod) /* 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) + NESTED_FUNC (void, translate_offs, + (GElf_Addr), (GElf_Addr adjust)) { GElf_Off offs[i_max] = { 0, }; find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs); @@ -862,7 +877,7 @@ find_dynsym (Dwfl_Module *mod) mod->symerr = DWFL_E_NOERROR; } } - } + }; /* First try unadjusted, like ELF files from disk, vdso. Then try for already adjusted dynamic section, like ELF diff --git a/libdwfl/dwfl_module_getsrc_file.c b/libdwfl/dwfl_module_getsrc_file.c index 20aa8a5..eb5f0ca 100644 --- a/libdwfl/dwfl_module_getsrc_file.c +++ b/libdwfl/dwfl_module_getsrc_file.c @@ -28,7 +28,7 @@ #include "libdwflP.h" #include "../libdw/libdwP.h" - +#include "nested_func.h" int dwfl_module_getsrc_file (Dwfl_Module *mod, @@ -45,31 +45,34 @@ dwfl_module_getsrc_file (Dwfl_Module *mod, return -1; } - bool is_basename = strchr (fname, '/') == NULL; + const bool is_basename = strchr (fname, '/') == NULL; - size_t max_match = *nsrcs ?: ~0u; - size_t act_match = *nsrcs; - size_t cur_match = 0; - Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp; + __BLOCK size_t max_match = *nsrcs ?: ~0u; + __BLOCK size_t act_match = *nsrcs; + __BLOCK size_t cur_match = 0; + __BLOCK Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp; - struct dwfl_cu *cu = NULL; + __BLOCK struct dwfl_cu *cu = NULL; Dwfl_Error error; while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR && cu != NULL && (error = __libdwfl_cu_getsrclines (cu)) == DWFL_E_NOERROR) { - inline const char *INTUSE(dwarf_line_file) (const Dwarf_Line *line) + INLINE_INTUSE_NESTED_FUNC (const char *, dwarf_line_file, + (const Dwarf_Line *), (const Dwarf_Line *line)) { return line->files->info[line->file].name; - } - inline Dwarf_Line *dwfl_line (const Dwfl_Line *line) + }; + INLINE_NESTED_FUNC (Dwarf_Line *, dwfl_line, + (const Dwfl_Line *), (const Dwfl_Line *line)) { return &dwfl_linecu (line)->die.cu->lines->info[line->idx]; - } - inline const char *dwfl_line_file (const Dwfl_Line *line) + }; + INLINE_NESTED_FUNC (const char *, dwfl_line_file, + (const Dwfl_Line *), (const Dwfl_Line *line)) { return INTUSE(dwarf_line_file) (dwfl_line (line)); - } + }; /* Search through all the line number records for a matching file and line/column number. If any of the numbers is zero, diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c index a0f07ad..508c2ea 100644 --- a/libdwfl/dwfl_segment_report_module.c +++ b/libdwfl/dwfl_segment_report_module.c @@ -31,6 +31,7 @@ #undef _ #include "libdwflP.h" #include "common.h" +#include "nested_func.h" #include <elf.h> #include <gelf.h> @@ -232,15 +233,18 @@ invalid_elf (Elf *elf, bool disk_file_has_build_id, } 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) +dwfl_segment_report_module (Dwfl *dwfl, int const ndx_in, const char* const name_in, + Dwfl_Memory_Callback* const memory_callback, + void* const memory_callback_arg, + Dwfl_Module_Callback * const read_eagerly, + void* const read_eagerly_arg, + const void* const note_file, size_t const note_file_size, + const struct r_debug_info* const r_debug_info) { - size_t segment = ndx; + __BLOCK int ndx = ndx_in; + __BLOCK const char *name = name_in; + + __BLOCK size_t segment = ndx; if (segment >= dwfl->lookup_elts) segment = dwfl->lookup_elts - 1; @@ -254,34 +258,38 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, if (++segment == dwfl->lookup_elts) return 0; - GElf_Addr start = dwfl->lookup_addr[segment]; + __BLOCK GElf_Addr start = dwfl->lookup_addr[segment]; - inline bool segment_read (int segndx, - void **buffer, size_t *buffer_available, - GElf_Addr addr, size_t minread) + INLINE_NESTED_FUNC (bool, segment_read, + (int , void **, size_t *, GElf_Addr, size_t), + (int segndx, + void **buffer, size_t *buffer_available, + GElf_Addr addr, size_t minread)) { return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available, addr, minread, memory_callback_arg); - } + }; - inline void release_buffer (void **buffer, size_t *buffer_available) + INLINE_NESTED_FUNC (void, release_buffer, + (void **, size_t *), + (void **buffer, size_t *buffer_available)) { if (*buffer != NULL) (void) segment_read (-1, buffer, buffer_available, 0, 0); - } + }; /* 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; + __BLOCK void *buffer = NULL; + __BLOCK size_t buffer_available = INITIAL_READ; + __BLOCK Elf *elf = NULL; + __BLOCK 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; + __BLOCK void *phdrsp = NULL; - inline int finish (void) + INLINE_NESTED_FUNC (int, finish, (void), (void)) { free (phdrsp); release_buffer (&buffer, &buffer_available); @@ -290,15 +298,17 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, if (fd != -1) close (fd); return ndx; - } + }; if (segment_read (ndx, &buffer, &buffer_available, start, sizeof (Elf64_Ehdr)) || memcmp (buffer, ELFMAG, SELFMAG) != 0) return finish (); - inline bool read_portion (void **data, size_t *data_size, - GElf_Addr vaddr, size_t filesz) + INLINE_NESTED_FUNC (bool, read_portion, + (void **, size_t *, GElf_Addr, size_t), + (void **data, size_t *data_size, + GElf_Addr vaddr, size_t filesz)) { if (vaddr - start + filesz > buffer_available /* If we're in string mode, then don't consider the buffer we have @@ -316,35 +326,37 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, *data = vaddr - start + buffer; *data_size = 0; return false; - } + }; - inline void finish_portion (void **data, size_t *data_size) + INLINE_NESTED_FUNC (void, finish_portion, + (void **, size_t *), + (void **data, size_t *data_size)) { if (*data_size != 0) release_buffer (data, data_size); - } + }; /* 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 + __BLOCK const unsigned char *e_ident; + __BLOCK unsigned char ei_class; + __BLOCK unsigned char ei_data; + __BLOCK uint16_t e_type; + __BLOCK union { Elf32_Ehdr e32; Elf64_Ehdr e64; } ehdr; - GElf_Off phoff; - uint_fast16_t phnum; - uint_fast16_t phentsize; - GElf_Off shdrs_end; - Elf_Data xlatefrom = + __BLOCK GElf_Off phoff; + __BLOCK uint_fast16_t phnum; + __BLOCK uint_fast16_t phentsize; + __BLOCK GElf_Off shdrs_end; + __BLOCK Elf_Data xlatefrom = { .d_type = ELF_T_EHDR, .d_buf = (void *) buffer, .d_version = EV_CURRENT, }; - Elf_Data xlateto = + __BLOCK Elf_Data xlateto = { .d_type = ELF_T_EHDR, .d_buf = &ehdr, @@ -396,8 +408,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; xlatefrom.d_size = phnum * phentsize; - void *ph_buffer = NULL; - size_t ph_buffer_size = 0; + __BLOCK void *ph_buffer = NULL; + __BLOCK size_t ph_buffer_size = 0; if (read_portion (&ph_buffer, &ph_buffer_size, start + phoff, xlatefrom.d_size)) return finish (); @@ -413,37 +425,39 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, phdrsp = malloc (sizeof (phdrsn)); if (unlikely (phdrsp == NULL)) return finish (); - phdrsn *phdrs = (phdrsn *) phdrsp; + __BLOCK phdrsn *phdrs = (phdrsn *) phdrsp; xlateto.d_buf = phdrs; xlateto.d_size = sizeof (phdrsn); /* Track the bounds of the file visible in memory. */ - GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */ - GElf_Off file_end = 0; /* Rounded up to effective page size. */ - GElf_Off contiguous = 0; /* Visible as contiguous file from START. */ - GElf_Off total_filesz = 0; /* Total size of data to read. */ + __BLOCK GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */ + __BLOCK GElf_Off file_end = 0; /* Rounded up to effective page size. */ + __BLOCK GElf_Off contiguous = 0; /* Visible as contiguous file from START. */ + __BLOCK GElf_Off total_filesz = 0; /* Total size of data to read. */ /* Collect the bias between START and the containing PT_LOAD's p_vaddr. */ - GElf_Addr bias = 0; - bool found_bias = false; + __BLOCK GElf_Addr bias = 0; + __BLOCK bool found_bias = false; /* Collect the unbiased bounds of the module here. */ - GElf_Addr module_start = -1l; - GElf_Addr module_end = 0; - GElf_Addr module_address_sync = 0; + __BLOCK GElf_Addr module_start = -1l; + __BLOCK GElf_Addr module_end = 0; + __BLOCK GElf_Addr module_address_sync = 0; /* If we see PT_DYNAMIC, record it here. */ - GElf_Addr dyn_vaddr = 0; - GElf_Xword dyn_filesz = 0; + __BLOCK GElf_Addr dyn_vaddr = 0; + __BLOCK GElf_Xword dyn_filesz = 0; /* Collect the build ID bits here. */ - void *build_id = NULL; - size_t build_id_len = 0; - GElf_Addr build_id_vaddr = 0; + __BLOCK void *build_id = NULL; + __BLOCK size_t build_id_len = 0; + __BLOCK 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) + INLINE_NESTED_FUNC (void, consider_notes, + (GElf_Addr, GElf_Xword), + (GElf_Addr vaddr, GElf_Xword filesz)) { /* If we have already seen a build ID, we don't care any more. */ if (build_id != NULL || filesz == 0) @@ -503,13 +517,18 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, 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) + INLINE_NESTED_FUNC (void, consider_phdr, + (GElf_Word, + GElf_Addr, GElf_Xword, + GElf_Off, GElf_Xword, + GElf_Xword), + (GElf_Word type, + GElf_Addr vaddr, GElf_Xword memsz, + GElf_Off offset, GElf_Xword filesz, + GElf_Xword align)) { switch (type) { @@ -572,7 +591,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, module_end = vaddr_end; break; } - } + }; if (ei_class == ELFCLASS32) { if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) @@ -716,11 +735,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME, and they also tell us the essential portion of the file for fetching symbols. */ - GElf_Addr soname_stroff = 0; - GElf_Addr dynstr_vaddr = 0; - GElf_Xword dynstrsz = 0; - bool execlike = false; - inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val) + __BLOCK GElf_Addr soname_stroff = 0; + __BLOCK GElf_Addr dynstr_vaddr = 0; + __BLOCK GElf_Xword dynstrsz = 0; + __BLOCK bool execlike = false; + INLINE_NESTED_FUNC (bool, consider_dyn, (GElf_Sxword, GElf_Xword), + (GElf_Sxword tag, GElf_Xword val)) { switch (tag) { @@ -745,13 +765,13 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, } return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0; - } + }; const size_t dyn_entsize = (ei_class == ELFCLASS32 ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn)); - void *dyns = NULL; - void *dyn_data = NULL; - size_t dyn_data_size = 0; + __BLOCK void *dyns = NULL; + __BLOCK void *dyn_data = NULL; + __BLOCK 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)) { @@ -793,8 +813,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, if (name == NULL) name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]"; - void *soname = NULL; - size_t soname_size = 0; + __BLOCK void *soname = NULL; + __BLOCK size_t soname_size = 0; if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0) { /* We know the bounds of the .dynstr section. @@ -827,7 +847,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, /* Now that we have chosen the module's name and bounds, report it. If we found a build ID, report that too. */ - Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name, + __BLOCK Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name, module_start, module_end); // !execlike && ET_EXEC is PIE. @@ -875,29 +895,34 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, /* The caller wants to read the whole file in right now, but hasn't done it for us. Fill in a local image of the virtual file. */ - void *contents = calloc (1, file_trimmed_end); + __BLOCK 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) + INLINE_NESTED_FUNC (void, final_read, + (size_t, GElf_Addr, size_t), + (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); - } + }; 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) + INLINE_NESTED_FUNC (void, read_phdr, + (GElf_Word, GElf_Addr, + GElf_Off, GElf_Xword), + (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) diff --git a/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c index ed8f6e9..a5ab679 100644 --- a/libdwfl/elf-from-memory.c +++ b/libdwfl/elf-from-memory.c @@ -31,6 +31,7 @@ #undef _ #include "libdwflP.h" +#include "nested_func.h" #include <gelf.h> #include <sys/types.h> @@ -38,6 +39,10 @@ #include <stdlib.h> #include <string.h> +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + /* 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 @@ -65,12 +70,12 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, { /* We might have to reserve some memory for the phdrs. Set to NULL here so we can always safely free it. */ - void *phdrsp = NULL; + __BLOCK void *phdrsp = NULL; /* First read in the file header and check its sanity. */ const size_t initial_bufsize = 256; - unsigned char *buffer = malloc (initial_bufsize); + __BLOCK unsigned char *buffer = malloc (initial_bufsize); if (unlikely (buffer == NULL)) { no_memory: @@ -78,7 +83,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, return NULL; } - ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma, + __BLOCK ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma, sizeof (Elf32_Ehdr), initial_bufsize); if (nread <= 0) { @@ -100,18 +105,18 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, /* Extract the information we need from the file header. */ - union + __BLOCK union { Elf32_Ehdr e32; Elf64_Ehdr e64; } ehdr; - Elf_Data xlatefrom = + __BLOCK Elf_Data xlatefrom = { .d_type = ELF_T_EHDR, .d_buf = buffer, .d_version = EV_CURRENT, }; - Elf_Data xlateto = + __BLOCK Elf_Data xlateto = { .d_type = ELF_T_EHDR, .d_buf = &ehdr, @@ -119,10 +124,10 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, .d_version = EV_CURRENT, }; - GElf_Off phoff; - uint_fast16_t phnum; - uint_fast16_t phentsize; - GElf_Off shdrs_end; + __BLOCK GElf_Off phoff; + __BLOCK uint_fast16_t phnum; + __BLOCK uint_fast16_t phentsize; + __BLOCK GElf_Off shdrs_end; switch (buffer[EI_CLASS]) { @@ -209,48 +214,51 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, xlateto.d_size = sizeof (phdrsn); /* Scan for PT_LOAD segments to find the total size of the file image. */ - size_t contents_size = 0; - GElf_Off segments_end = 0; - GElf_Off segments_end_mem = 0; - GElf_Addr loadbase = ehdr_vma; - bool found_base = false; - switch (ehdr.e32.e_ident[EI_CLASS]) + __BLOCK size_t contents_size = 0; + __BLOCK GElf_Off segments_end = 0; + __BLOCK GElf_Off segments_end_mem = 0; + __BLOCK GElf_Addr loadbase = ehdr_vma; + __BLOCK bool found_base = false; + + /* 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_NESTED_FUNC (bool, handle_segment1, + (GElf_Addr, GElf_Off, GElf_Xword, GElf_Xword), + (GElf_Addr vaddr, GElf_Off offset, + GElf_Xword filesz, GElf_Xword memsz)) { - /* 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; + /* 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); + GElf_Off segment_end = ((offset + filesz + pagesize - 1) + & -pagesize); - if (segment_end > (GElf_Off) contents_size) - contents_size = segment_end; + 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; - } + 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; - } + segments_end = offset + filesz; + segments_end_mem = offset + memsz; + return false; + }; + switch (ehdr.e32.e_ident[EI_CLASS]) + { 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 (phdrs->p32[i].p_type == PT_LOAD) - if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset, + if (handle_segment1 (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz, phdrs->p32[i].p_memsz)) goto bad_elf; break; @@ -261,7 +269,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, goto libelf_error; for (uint_fast16_t i = 0; i < phnum; ++i) if (phdrs->p64[i].p_type == PT_LOAD) - if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset, + if (handle_segment1 (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz, phdrs->p64[i].p_memsz)) goto bad_elf; break; @@ -296,27 +304,28 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, goto no_memory; } - switch (ehdr.e32.e_ident[EI_CLASS]) + /* Reads the given segment. Returns true if reading fails, + false otherwise. */ + INLINE_NESTED_FUNC (bool, handle_segment2, + (GElf_Addr, GElf_Off, GElf_Xword), + (GElf_Addr vaddr, GElf_Off offset, GElf_Xword filesz)) { - /* 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; - } + 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; + }; + switch (ehdr.e32.e_ident[EI_CLASS]) + { case ELFCLASS32: for (uint_fast16_t i = 0; i < phnum; ++i) if (phdrs->p32[i].p_type == PT_LOAD) - if (handle_segment (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset, + if (handle_segment2 (phdrs->p32[i].p_vaddr, phdrs->p32[i].p_offset, phdrs->p32[i].p_filesz)) goto read_error; @@ -343,7 +352,7 @@ elf_from_remote_memory (GElf_Addr ehdr_vma, case ELFCLASS64: for (uint_fast16_t i = 0; i < phnum; ++i) if (phdrs->p64[i].p_type == PT_LOAD) - if (handle_segment (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset, + if (handle_segment2 (phdrs->p64[i].p_vaddr, phdrs->p64[i].p_offset, phdrs->p64[i].p_filesz)) goto read_error; diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c index 16cebd0..52c7d2d 100644 --- a/libdwfl/frame_unwind.c +++ b/libdwfl/frame_unwind.c @@ -34,6 +34,7 @@ #include <stdlib.h> #include "libdwflP.h" #include "../libdw/dwarf.h" +#include "nested_func.h" #include <sys/ptrace.h> /* Maximum number of DWARF expression stack slots before returning an error. */ @@ -108,17 +109,16 @@ static bool expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops, size_t nops, Dwarf_Addr *result, Dwarf_Addr bias) { - Dwfl_Process *process = state->thread->process; + __BLOCK Dwfl_Process *process = state->thread->process; if (nops == 0) { __libdwfl_seterrno (DWFL_E_INVALID_DWARF); return false; } - Dwarf_Addr *stack = NULL; - size_t stack_used = 0, stack_allocated = 0; + __BLOCK Dwarf_Addr *stack = NULL; + __BLOCK size_t stack_used = 0, stack_allocated = 0; - bool - push (Dwarf_Addr val) + NESTED_FUNC (bool, push, (Dwarf_Addr), (Dwarf_Addr val)) { if (stack_used >= DWARF_EXPR_STACK_MAX) { @@ -138,10 +138,9 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops, } stack[stack_used++] = val; return true; - } + }; - bool - pop (Dwarf_Addr *val) + NESTED_FUNC (bool, pop, (Dwarf_Addr *), (Dwarf_Addr *val)) { if (stack_used == 0) { @@ -150,7 +149,7 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops, } *val = stack[--stack_used]; return true; - } + }; Dwarf_Addr val1, val2; bool is_location = false; diff --git a/libdwfl/gzip.c b/libdwfl/gzip.c index b7dde5d..af466e6 100644 --- a/libdwfl/gzip.c +++ b/libdwfl/gzip.c @@ -28,6 +28,7 @@ #include "libdwflP.h" #include "system.h" +#include "nested_func.h" #include <unistd.h> @@ -79,9 +80,9 @@ unzip (int fd, off64_t start_offset, void *mapped, size_t mapped_size, void **whole, size_t *whole_size) { - void *buffer = NULL; - size_t size = 0; - inline bool bigger_buffer (size_t start) + __BLOCK void *buffer = NULL; + __BLOCK size_t size = 0; + INLINE_NESTED_FUNC (bool, bigger_buffer, (size_t), (size_t start)) { size_t more = size ? size * 2 : start; char *b = realloc (buffer, more); @@ -92,17 +93,17 @@ unzip (int fd, off64_t start_offset, buffer = b; size = more; return true; - } - inline void smaller_buffer (size_t end) + }; + INLINE_NESTED_FUNC (void, smaller_buffer, (size_t), (size_t end)) { buffer = realloc (buffer, end) ?: end == 0 ? NULL : buffer; size = end; - } + }; - void *input_buffer = NULL; - off_t input_pos = 0; + __BLOCK void *input_buffer = NULL; + __BLOCK off_t input_pos = 0; - inline Dwfl_Error fail (Dwfl_Error failure) + INLINE_NESTED_FUNC (Dwfl_Error, fail, (Dwfl_Error), (Dwfl_Error failure)) { if (input_pos == (off_t) mapped_size) *whole = input_buffer; @@ -113,9 +114,9 @@ unzip (int fd, off64_t start_offset, } free (buffer); return failure; - } + }; - inline Dwfl_Error zlib_fail (int result) + INLINE_NESTED_FUNC (Dwfl_Error, zlib_fail, (int), (int result)) { switch (result) { @@ -126,7 +127,7 @@ unzip (int fd, off64_t start_offset, default: return fail (DWFL_E_ZLIB); } - } + }; if (mapped == NULL) { @@ -169,8 +170,8 @@ unzip (int fd, off64_t start_offset, The stupid zlib interface has nothing to grok the gzip file headers except the slow gzFile interface. */ - z_stream z = { .next_in = mapped, .avail_in = mapped_size }; - int result = inflateInit (&z); + __BLOCK z_stream z = { .next_in = mapped, .avail_in = mapped_size }; + __BLOCK int result = inflateInit (&z); if (result != Z (OK)) { inflateEnd (&z); @@ -223,8 +224,8 @@ unzip (int fd, off64_t start_offset, /* Let the decompression library read the file directly. */ - gzFile zf; - Dwfl_Error open_stream (void) + __BLOCK gzFile zf; + NESTED_FUNC (Dwfl_Error, open_stream, (void), (void)) { int d = dup (fd); if (unlikely (d < 0)) @@ -248,7 +249,7 @@ unzip (int fd, off64_t start_offset, /* From here on, zlib will close D. */ return DWFL_E_NOERROR; - } + }; Dwfl_Error result = open_stream (); diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 030c600..204444d 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -30,6 +30,7 @@ #include "libdwflP.h" #include "../libdw/memory-access.h" #include "system.h" +#include "nested_func.h" #include <byteswap.h> #include <endian.h> @@ -48,14 +49,14 @@ static bool auxv_format_probe (const void *auxv, size_t size, uint_fast8_t *elfclass, uint_fast8_t *elfdata) { - const union + __BLOCK const union { char buf[size]; Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)]; Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)]; } *u = auxv; - inline bool check64 (size_t i) + INLINE_NESTED_FUNC (bool, check64, (size_t), (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. */ @@ -78,9 +79,9 @@ auxv_format_probe (const void *auxv, size_t size, } return false; - } + }; - inline bool check32 (size_t i) + INLINE_NESTED_FUNC (bool, check32, (size_t), (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. */ @@ -103,7 +104,7 @@ auxv_format_probe (const void *auxv, size_t size, } return false; - } + }; for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i) { @@ -247,20 +248,27 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, struct r_debug_info *r_debug_info) { /* Skip r_version, to aligned r_map field. */ - GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass); + __BLOCK GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass); - void *buffer = NULL; - size_t buffer_available = 0; - inline int release_buffer (int result) + __BLOCK void *buffer = NULL; + __BLOCK size_t buffer_available = 0; + INLINE_NESTED_FUNC (int, release_buffer, (int), (int result)) { if (buffer != NULL) (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0, memory_callback_arg); return result; - } + }; +#if __clang__ + /* Clang Blocks cannot copy an array to a closure. */ + __BLOCK GElf_Addr *addrs = alloca(4 * sizeof (GElf_Addr)); +#else + /* gcc complains about unbounded stack usage from alloca. */ GElf_Addr addrs[4]; - inline bool read_addrs (GElf_Addr vaddr, size_t n) +#endif + INLINE_NESTED_FUNC (bool, read_addrs, + (GElf_Addr, size_t), (GElf_Addr vaddr, size_t n)) { size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */ @@ -306,7 +314,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, } return false; - } + }; if (unlikely (read_addrs (read_vaddr, 1))) return release_buffer (-1); @@ -697,17 +705,17 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, void *memory_callback_arg, struct r_debug_info *r_debug_info) { - GElf_Addr r_debug_vaddr = 0; + __BLOCK GElf_Addr r_debug_vaddr = 0; - uint_fast8_t elfclass = ELFCLASSNONE; - uint_fast8_t elfdata = ELFDATANONE; + __BLOCK uint_fast8_t elfclass = ELFCLASSNONE; + __BLOCK uint_fast8_t elfdata = ELFDATANONE; if (likely (auxv != NULL) && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata))) { - GElf_Addr entry = 0; - GElf_Addr phdr = 0; - GElf_Xword phent = 0; - GElf_Xword phnum = 0; + __BLOCK GElf_Addr entry = 0; + __BLOCK GElf_Addr phdr = 0; + __BLOCK GElf_Xword phent = 0; + __BLOCK GElf_Xword phnum = 0; #define READ_AUXV32(ptr) read_4ubyte_unaligned_noncvt (ptr) #define READ_AUXV64(ptr) read_8ubyte_unaligned_noncvt (ptr) @@ -753,12 +761,13 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, } /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC. */ - GElf_Addr dyn_vaddr = 0; - GElf_Xword dyn_filesz = 0; - GElf_Addr dyn_bias = (GElf_Addr) -1; + __BLOCK GElf_Addr dyn_vaddr = 0; + __BLOCK GElf_Xword dyn_filesz = 0; + __BLOCK GElf_Addr dyn_bias = (GElf_Addr) -1; - inline bool consider_phdr (GElf_Word type, - GElf_Addr vaddr, GElf_Xword filesz) + INLINE_NESTED_FUNC (bool, consider_phdr, + (GElf_Word, GElf_Addr, GElf_Xword), + (GElf_Word type, GElf_Addr vaddr, GElf_Xword filesz)) { switch (type) { @@ -780,7 +789,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, } return false; - } + }; if (phdr != 0 && phnum != 0) { diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c index 236e2cd..5620bc1 100644 --- a/libdwfl/linux-kernel-modules.c +++ b/libdwfl/linux-kernel-modules.c @@ -34,6 +34,7 @@ #include <config.h> #include "libdwflP.h" +#include "nested_func.h" #include <inttypes.h> #include <errno.h> #include <stdio.h> @@ -444,7 +445,7 @@ INTDEF (dwfl_linux_kernel_report_offline) static int intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes) { - FILE *f = fopen (KSYMSFILE, "r"); + __BLOCK FILE *f = fopen (KSYMSFILE, "r"); if (f == NULL) return errno; @@ -452,13 +453,13 @@ intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes) *notes = 0; - char *line = NULL; - size_t linesz = 0; - size_t n; - char *p = NULL; - const char *type; + __BLOCK char *line = NULL; + __BLOCK size_t linesz = 0; + __BLOCK size_t n; + __BLOCK char *p = NULL; + __BLOCK const char *type; - inline bool read_address (Dwarf_Addr *addr) + INLINE_NESTED_FUNC (bool, read_address, (Dwarf_Addr *), (Dwarf_Addr *addr)) { if ((n = getline (&line, &linesz, f)) < 1 || line[n - 2] == ']') return false; @@ -468,7 +469,7 @@ intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes) if (type == NULL) return false; return p != NULL && p != line; - } + }; int result; do @@ -619,12 +620,12 @@ check_module_notes (Dwfl_Module *mod) int dwfl_linux_kernel_report_kernel (Dwfl *dwfl) { - Dwarf_Addr start; - Dwarf_Addr end; - inline Dwfl_Module *report (void) + __BLOCK Dwarf_Addr start; + __BLOCK Dwarf_Addr end; + INLINE_NESTED_FUNC (Dwfl_Module *, report, (void), (void)) { return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end); - } + }; /* This is a bit of a kludge. If we already reported the kernel, don't bother figuring it out again--it never changes. */ @@ -683,18 +684,18 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod, /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */ - char *modulesdir[] = { NULL, NULL }; + __BLOCK char *modulesdir[] = { NULL, NULL }; if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0) return -1; - FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL); + __BLOCK FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL); if (fts == NULL) { free (modulesdir[0]); return -1; } - size_t namelen = strlen (module_name); + __BLOCK size_t namelen = strlen (module_name); /* This is a kludge. There is no actual necessary relationship between the name of the .ko file installed and the module name the kernel @@ -707,13 +708,13 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod, two files when either a '_' or '-' appears in a module name, one using only '_' and one only using '-'. */ - char *alternate_name = malloc (namelen + 1); + __BLOCK char *alternate_name = malloc (namelen + 1); if (unlikely (alternate_name == NULL)) { free (modulesdir[0]); return ENOMEM; } - inline bool subst_name (char from, char to) + INLINE_NESTED_FUNC (bool, subst_name, (char, char), (char from, char to)) { const char *n = memchr (module_name, from, namelen); if (n == NULL) @@ -730,7 +731,7 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod, } memcpy (a, n, namelen - (n - module_name) + 1); return true; - } + }; if (!subst_name ('-', '_') && !subst_name ('_', '-')) alternate_name[0] = '\0'; diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c index d085834..f22e0bb 100644 --- a/libdwfl/linux-proc-maps.c +++ b/libdwfl/linux-proc-maps.c @@ -41,6 +41,7 @@ #include <assert.h> #include <endian.h> #include "system.h" +#include "nested_func.h" #define PROCMAPSFMT "/proc/%d/maps" @@ -178,12 +179,12 @@ grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr) static int proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid) { - unsigned int last_dmajor = -1, last_dminor = -1; - uint64_t last_ino = -1; - char *last_file = NULL; - Dwarf_Addr low = 0, high = 0; + __BLOCK unsigned int last_dmajor = -1, last_dminor = -1; + __BLOCK uint64_t last_ino = -1; + __BLOCK char *last_file = NULL; + __BLOCK Dwarf_Addr low = 0, high = 0; - inline bool report (void) + INLINE_NESTED_FUNC (bool, report, (void), (void)) { if (last_file != NULL) { @@ -195,7 +196,7 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid) return true; } return false; - } + }; char *line = NULL; size_t linesz; diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c index e102e1e..fdbf096 100644 --- a/libdwfl/relocate.c +++ b/libdwfl/relocate.c @@ -27,6 +27,7 @@ not, see <http://www.gnu.org/licenses/>. */ #include "libdwflP.h" +#include "nested_func.h" typedef uint8_t GElf_Byte; @@ -284,9 +285,9 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, Elf_Scn *tscn, bool debugscn, bool partial) { /* First, fetch the name of the section these relocations apply to. */ - GElf_Shdr tshdr_mem; - GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); - const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name); + __BLOCK GElf_Shdr tshdr_mem; + __BLOCK GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); + __BLOCK const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name); if (tname == NULL) return DWFL_E_LIBELF; @@ -300,7 +301,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, return DWFL_E_NOERROR; /* Fetch the section data that needs the relocations applied. */ - Elf_Data *tdata = elf_rawdata (tscn, NULL); + __BLOCK Elf_Data *tdata = elf_rawdata (tscn, NULL); if (tdata == NULL) return DWFL_E_LIBELF; @@ -310,26 +311,26 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, isn't illegal for ELF section data to overlap the header data, but updating the (relocation) data might corrupt the in-memory libelf headers causing strange corruptions or errors. */ - size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT); + __BLOCK size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT); if (unlikely (shdr->sh_offset < ehsize || tshdr->sh_offset < ehsize)) return DWFL_E_BADELF; - GElf_Off shdrs_start = ehdr->e_shoff; - size_t shnums; + __BLOCK GElf_Off shdrs_start = ehdr->e_shoff; + __BLOCK size_t shnums; if (elf_getshdrnum (relocated, &shnums) < 0) return DWFL_E_LIBELF; /* Overflows will have been checked by elf_getshdrnum/get|rawdata. */ - size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT); - GElf_Off shdrs_end = shdrs_start + shnums * shentsize; + __BLOCK size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT); + __BLOCK GElf_Off shdrs_end = shdrs_start + shnums * shentsize; if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size && shdr->sh_offset < shdrs_end) || (shdrs_start < tshdr->sh_offset + tshdr->sh_size && tshdr->sh_offset < shdrs_end))) return DWFL_E_BADELF; - GElf_Off phdrs_start = ehdr->e_phoff; - size_t phnums; + __BLOCK GElf_Off phdrs_start = ehdr->e_phoff; + __BLOCK size_t phnums; if (elf_getphdrnum (relocated, &phnums) < 0) return DWFL_E_LIBELF; if (phdrs_start != 0 && phnums != 0) @@ -345,8 +346,10 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, } /* Apply one relocation. Returns true for any invalid data. */ - Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend, - int rtype, int symndx) + NESTED_FUNC (Dwfl_Error, relocate, + (GElf_Addr, const GElf_Sxword *, int, int), + (GElf_Addr offset, const GElf_Sxword *addend, + int rtype, int symndx)) { /* First see if this is a reloc we can handle. If we are skipping it, don't bother resolving the symbol. */ @@ -482,16 +485,16 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, /* We have applied this relocation! */ return DWFL_E_NOERROR; - } + }; /* Fetch the relocation section and apply each reloc in it. */ - Elf_Data *reldata = elf_getdata (scn, NULL); + __BLOCK Elf_Data *reldata = elf_getdata (scn, NULL); if (reldata == NULL) return DWFL_E_LIBELF; - Dwfl_Error result = DWFL_E_NOERROR; - bool first_badreltype = true; - inline void check_badreltype (void) + __BLOCK Dwfl_Error result = DWFL_E_NOERROR; + __BLOCK bool first_badreltype = true; + INLINE_NESTED_FUNC (void, check_badreltype, (void), (void)) { if (first_badreltype) { @@ -501,7 +504,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, any libebl_CPU.so library. Diagnose that clearly. */ result = DWFL_E_UNKNOWN_MACHINE; } - } + }; size_t sh_entsize = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA, diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index 832f852..e0f43c6 100644 --- a/libelf/elf32_updatefile.c +++ b/libelf/elf32_updatefile.c @@ -43,6 +43,7 @@ #include <system.h> #include "libelfP.h" +#include "nested_func.h" #ifndef LIBELFBITS @@ -303,7 +304,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) Elf_Data_List *dl = &scn->data_list; bool scn_changed = false; - void fill_mmap (size_t offset) + NESTED_FUNC (void, fill_mmap, (size_t), (size_t offset)) { size_t written = 0; @@ -322,7 +323,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) memset (fill_start, __libelf_fill_byte, scn_start + offset - fill_start); } - } + }; if (scn->data_list_rear != NULL) do diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index f002ebf..6878298 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -46,6 +46,7 @@ #include <system.h> #include "libelfP.h" #include "common.h" +#include "nested_func.h" /* Create descriptor for archive in memory. */ @@ -1067,7 +1068,7 @@ elf_begin (fildes, cmd, ref) return NULL; } - Elf *lock_dup_elf () + NESTED_FUNC (Elf *, lock_dup_elf, (void), (void)) { /* We need wrlock to dup an archive. */ if (ref->kind == ELF_K_AR) @@ -1078,7 +1079,7 @@ elf_begin (fildes, cmd, ref) /* Duplicate the descriptor. */ return dup_elf (fildes, cmd, ref); - } + }; switch (cmd) { diff --git a/src/addr2line.c b/src/addr2line.c index 0ce854f..4932189 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -39,6 +39,7 @@ #include <system.h> +#include "nested_func.h" /* Name and version of program. */ static void print_version (FILE *stream, struct argp_state *state); @@ -705,20 +706,26 @@ 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) + INLINE_NESTED_FUNC (void, show, + (int (*) (Dwarf_Line *, bool *), + const char *), + (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) + }; + INLINE_NESTED_FUNC (void, show_int, + (int (*) (Dwarf_Line *, unsigned int *), + const char *), + (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)"); diff --git a/src/ar.c b/src/ar.c index 1320d07..f4f2668 100644 --- a/src/ar.c +++ b/src/ar.c @@ -43,6 +43,7 @@ #include <system.h> #include "arlib.h" +#include "nested_func.h" /* Name and version of program. */ @@ -459,8 +460,8 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, bool found[argc]; memset (found, '\0', sizeof (found)); - size_t name_max = 0; - inline bool should_truncate_fname (void) + __BLOCK size_t name_max = 0; + INLINE_NESTED_FUNC (bool, should_truncate_fname, (void), (void)) { if (errno == ENAMETOOLONG && allow_truncate_fname) { @@ -473,7 +474,7 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc, return name_max != 0; } return false; - } + }; off_t index_off = -1; size_t index_size = 0; diff --git a/src/arlib-argp.c b/src/arlib-argp.c index 1bdd8d0..1fcb375 100644 --- a/src/arlib-argp.c +++ b/src/arlib-argp.c @@ -23,6 +23,7 @@ #include <libintl.h> #include "arlib.h" +#include "nested_func.h" bool arlib_deterministic_output = DEFAULT_AR_DETERMINISTIC; @@ -59,13 +60,13 @@ parse_opt (int key, char *arg __attribute__ ((unused)), static char * help_filter (int key, const char *text, void *input __attribute__ ((unused))) { - inline char *text_for_default (void) + INLINE_NESTED_FUNC (char *, text_for_default, (void), (void)) { char *new_text; if (unlikely (asprintf (&new_text, gettext ("%s (default)"), text) < 0)) return (char *) text; return new_text; - } + }; switch (key) { diff --git a/src/elflint.c b/src/elflint.c index 0d5f34d..6781980 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -45,6 +45,7 @@ #include "../libdw/libdwP.h" #include "../libdwfl/libdwflP.h" #include "../libdw/memory-access.h" +#include "nested_func.h" /* Name and version of program. */ @@ -3387,7 +3388,7 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) return; } - Elf_Data *data = elf_rawdata (elf_getscn (ebl->elf, idx), NULL); + __BLOCK Elf_Data *data = elf_rawdata (elf_getscn (ebl->elf, idx), NULL); if (data == NULL || data->d_size == 0 || data->d_buf == NULL) { ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), @@ -3395,12 +3396,13 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) return; } - inline size_t pos (const unsigned char *p) + INLINE_NESTED_FUNC (size_t, pos, (const unsigned char *), + (const unsigned char *p)) { return p - (const unsigned char *) data->d_buf; - } + }; - const unsigned char *p = data->d_buf; + __BLOCK const unsigned char *p = data->d_buf; if (*p++ != 'A') { ERROR (gettext ("section [%2d] '%s': unrecognized attribute format\n"), @@ -3408,10 +3410,10 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) return; } - inline size_t left (void) + INLINE_NESTED_FUNC (size_t, left, (void), (void)) { return (const unsigned char *) data->d_buf + data->d_size - p; - } + }; while (left () >= 4) { diff --git a/src/ld.c b/src/ld.c index 6e96ae2..c24f75e 100644 --- a/src/ld.c +++ b/src/ld.c @@ -35,6 +35,7 @@ #include <system.h> #include "ld.h" #include "list.h" +#include "nested_func.h" /* Name and version of program. */ @@ -1078,7 +1079,7 @@ determine_output_format (void) int fd = open (runp->name, O_RDONLY); if (fd != -1) { - int try (Elf *elf) + INLINE_RECURSIVE_NESTED_FUNC (int, try, (Elf *), (Elf *elf)) { int result = 0; @@ -1121,7 +1122,7 @@ determine_output_format (void) elf_end (elf); return result; - } + }; if (try (elf_begin (fd, ELF_C_READ_MMAP, NULL)) != 0) /* Found a file. */ diff --git a/src/readelf.c b/src/readelf.c index d3c2b6b..ab7f9f7 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -53,6 +53,7 @@ #include "../libdw/memory-access.h" #include "../libdw/known-dwarf.h" +#include "nested_func.h" /* Name and version of program. */ @@ -308,7 +309,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state __attribute__ ((unused))) { - void add_dump_section (const char *name, bool implicit) + NESTED_FUNC (void, add_dump_section, + (const char *, bool), (const char *name, bool implicit)) { struct section_argument *a = xmalloc (sizeof *a); a->arg = name; @@ -318,7 +320,7 @@ parse_opt (int key, char *arg, = key == 'x' ? &dump_data_sections_tail : &string_sections_tail; **tailp = a; *tailp = &a->next; - } + }; switch (key) { @@ -3318,11 +3320,11 @@ print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr) elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_size, shdr->sh_offset); - Elf_Data *data = elf_rawdata (scn, NULL); + __BLOCK Elf_Data *data = elf_rawdata (scn, NULL); if (unlikely (data == NULL || data->d_size == 0)) return; - const unsigned char *p = data->d_buf; + __BLOCK const unsigned char *p = data->d_buf; /* There is only one 'version', A. */ if (unlikely (*p++ != 'A')) @@ -3330,10 +3332,10 @@ print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr) fputs_unlocked (gettext (" Owner Size\n"), stdout); - inline size_t left (void) + INLINE_NESTED_FUNC (size_t, left, (void), (void)) { return (const unsigned char *) data->d_buf + data->d_size - p; - } + }; /* Loop over the sections. */ while (left () >= 4) @@ -4943,12 +4945,12 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, unsigned int version, unsigned int ptr_size, Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg) { - char regnamebuf[REGNAMESZ]; - const char *regname (unsigned int regno) + __BLOCK char regnamebuf[REGNAMESZ]; + NESTED_FUNC (const char *, regname, (unsigned int), (unsigned int regno)) { register_info (ebl, regno, NULL, regnamebuf, NULL, NULL); return regnamebuf; - } + }; puts ("\n Program:"); Dwarf_Word pc = vma_base; @@ -6423,7 +6425,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, uint_fast8_t minimum_instr_len = *linep++; /* Next the maximum operations per instruction, in version 4 format. */ - uint_fast8_t max_ops_per_instr = version < 4 ? 1 : *linep++; + const uint_fast8_t max_ops_per_instr = version < 4 ? 1 : *linep++; /* Then the flag determining the default value of the is_stmt register. */ @@ -6536,8 +6538,8 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, ++linep; puts (gettext ("\nLine number statements:")); - Dwarf_Word address = 0; - unsigned int op_index = 0; + __BLOCK Dwarf_Word address = 0; + __BLOCK unsigned int op_index = 0; size_t line = 1; uint_fast8_t is_stmt = default_is_stmt; @@ -6571,9 +6573,10 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, /* 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) + __BLOCK unsigned int op_addr_advance; + __BLOCK bool show_op_index; + INLINE_NESTED_FUNC (void, advance_pc, + (unsigned int), (unsigned int op_advance)) { op_addr_advance = minimum_instr_len * ((op_index + op_advance) / max_ops_per_instr); @@ -6581,7 +6584,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, 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) { @@ -8882,7 +8885,7 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc, if (nregloc == 0) return 0; - ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL); + __BLOCK ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL); if (maxnreg <= 0) { for (size_t i = 0; i < nregloc; ++i) @@ -8891,7 +8894,7 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc, assert (maxnreg > 0); } - struct register_info regs[maxnreg]; + __BLOCK struct register_info regs[maxnreg]; memset (regs, 0, sizeof regs); /* Sort to collect the sets together. */ @@ -8913,14 +8916,17 @@ 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) + INLINE_NESTED_FUNC (bool, same_set, + (const struct register_info *, + const struct register_info *), + (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; diff --git a/src/strip.c b/src/strip.c index 5e69334..0ffad15 100644 --- a/src/strip.c +++ b/src/strip.c @@ -44,6 +44,8 @@ #include <libebl.h> #include <system.h> +#include "nested_func.h" + typedef uint8_t GElf_Byte; /* Name and version of program. */ @@ -409,16 +411,16 @@ static int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, mode_t mode, struct timespec tvp[2]) { - size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); - size_t fname_len = strlen (fname) + 1; - char *fullname = alloca (prefix_len + 1 + fname_len); - char *cp = fullname; - Elf *debugelf = NULL; + __BLOCK size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); + __BLOCK size_t fname_len = strlen (fname) + 1; + __BLOCK char *fullname = alloca (prefix_len + 1 + fname_len); + __BLOCK char *cp = fullname; + __BLOCK Elf *debugelf = NULL; tmp_debug_fname = NULL; - int result = 0; - size_t shdridx = 0; - size_t shstrndx; - struct shdr_info + __BLOCK int result = 0; + __BLOCK size_t shdridx = 0; + __BLOCK size_t shstrndx; + __BLOCK struct shdr_info { Elf_Scn *scn; GElf_Shdr shdr; @@ -435,19 +437,19 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, struct Ebl_Strent *se; Elf32_Word *newsymidx; } *shdr_info = NULL; - Elf_Scn *scn; - size_t cnt; - size_t idx; - bool changes; - GElf_Ehdr newehdr_mem; - GElf_Ehdr *newehdr; - GElf_Ehdr debugehdr_mem; - GElf_Ehdr *debugehdr; - struct Ebl_Strtab *shst = NULL; - Elf_Data debuglink_crc_data; - bool any_symtab_changes = false; - Elf_Data *shstrtab_data = NULL; - void *debuglink_buf = NULL; + __BLOCK Elf_Scn *scn; + __BLOCK size_t cnt; + __BLOCK size_t idx; + __BLOCK bool changes; + __BLOCK GElf_Ehdr newehdr_mem; + __BLOCK GElf_Ehdr *newehdr; + __BLOCK GElf_Ehdr debugehdr_mem; + __BLOCK GElf_Ehdr *debugehdr; + __BLOCK struct Ebl_Strtab *shst = NULL; + __BLOCK Elf_Data debuglink_crc_data; + __BLOCK bool any_symtab_changes = false; + __BLOCK Elf_Data *shstrtab_data = NULL; + __BLOCK void *debuglink_buf = NULL; /* Create the full name of the file. */ if (prefix != NULL) @@ -474,7 +476,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, option or resolving all relocations between debug sections with the --reloc-debug-sections option are currently the only reasons we need EBL so don't open the backend unless necessary. */ - Ebl *ebl = NULL; + __BLOCK Ebl *ebl = NULL; if (remove_debug || reloc_debug) { ebl = ebl_openbackend (elf); @@ -929,7 +931,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, file's .data pointer. Below, we'll copy the section contents. */ - inline void check_preserved (size_t i) + INLINE_NESTED_FUNC (void, check_preserved, (size_t), (size_t i)) { if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0 && shdr_info[i].debug_data == NULL) @@ -942,7 +944,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, shdr_info[i].debug_data = shdr_info[i].data; changes |= i < cnt; } - } + }; check_preserved (shdr_info[cnt].shdr.sh_link); if (SH_INFO_LINK_P (&shdr_info[cnt].shdr)) @@ -1433,7 +1435,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* 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) + INLINE_NESTED_FUNC (void, update_section_size, (const Elf_Data *), (const Elf_Data *newdata)) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); @@ -1448,7 +1450,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, 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 @@ -1459,9 +1461,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const Elf32_Word symtabidx = shdr_info[cnt].old_sh_link; elf_assert (symtabidx < shnum + 2); const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx; - switch (shdr_info[cnt].shdr.sh_type) - { - inline bool no_symtab_updates (void) + + INLINE_NESTED_FUNC (bool, no_symtab_updates, (void), (void)) { /* If the symbol table hasn't changed, do not do anything. */ if (shdr_info[symtabidx].newsymidx == NULL) @@ -1472,8 +1473,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, is discarded, don't adjust anything. */ return (shdr_info[cnt].idx == 0 && shdr_info[symtabidx].debug_data != NULL); - } + }; + switch (shdr_info[cnt].shdr.sh_type) + { case SHT_REL: case SHT_RELA: if (no_symtab_updates ()) @@ -1790,7 +1793,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Pick up the symbol table and shndx table to resolve relocation symbol indexes. */ Elf64_Word symt = shdr->sh_link; - Elf_Data *symdata, *xndxdata; + __BLOCK Elf_Data *symdata, *xndxdata; elf_assert (symt < shnum + 2); elf_assert (shdr_info[symt].symtab_idx < shnum + 2); symdata = (shdr_info[symt].debug_data @@ -1800,8 +1803,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *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) + NESTED_FUNC (bool, relocate, + (GElf_Addr, const GElf_Sxword, bool, int, int), + (GElf_Addr offset, const GElf_Sxword addend, bool is_rela, int rtype, int symndx)) { /* R_*_NONE relocs can always just be removed. */ if (rtype == 0) @@ -1924,7 +1928,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, return true; } return false; - } + }; if (shdr->sh_entsize == 0) INTERNAL_ERROR (fname); diff --git a/src/unstrip.c b/src/unstrip.c index 8833094..4d899fa 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -49,6 +49,7 @@ #include <libebl.h> #include <libdwfl.h> #include "system.h" +#include "nested_func.h" #ifndef _ # define _(str) gettext (str) @@ -395,14 +396,14 @@ static void adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, size_t map[], const GElf_Shdr *symshdr) { - Elf_Data *data = elf_getdata (outscn, NULL); + __BLOCK Elf_Data *data = elf_getdata (outscn, NULL); - inline void adjust_reloc (GElf_Xword *info) + INLINE_NESTED_FUNC (void, adjust_reloc, (GElf_Xword *), (GElf_Xword *info)) { size_t ndx = GELF_R_SYM (*info); if (ndx != STN_UNDEF) *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info)); - } + }; switch (shdr->sh_type) { @@ -1059,8 +1060,10 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, sizeof undo_sections[0], compare_sections_nonrel); } - bool fail = false; - inline void check_match (bool match, Elf_Scn *scn, const char *name) + __BLOCK bool fail = false; + INLINE_NESTED_FUNC (void, check_match, + (bool, Elf_Scn *, const char *), + (bool match, Elf_Scn *scn, const char *name)) { if (!match) { @@ -1068,7 +1071,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, 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) @@ -1260,8 +1263,8 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, more sections in stripped file than debug file -- arguments reversed?")); /* Cache the stripped file's section details. */ - struct section sections[stripped_shnum - 1]; - Elf_Scn *scn = NULL; + __BLOCK struct section sections[stripped_shnum - 1]; + __BLOCK Elf_Scn *scn = NULL; while ((scn = elf_nextscn (stripped, scn)) != NULL) { size_t i = elf_ndxscn (scn) - 1; @@ -1277,13 +1280,13 @@ more sections in stripped file than debug file -- arguments reversed?")); sections[i].strent = NULL; } - const struct section *stripped_symtab = NULL; + __BLOCK const struct section *stripped_symtab = NULL; /* Sort the sections, allocated by address and others after. */ qsort (sections, stripped_shnum - 1, sizeof sections[0], stripped_ehdr->e_type == ET_REL ? compare_sections_rel : compare_sections_nonrel); - size_t nalloc = stripped_shnum - 1; + __BLOCK size_t nalloc = stripped_shnum - 1; while (nalloc > 0 && !(sections[nalloc - 1].shdr.sh_flags & SHF_ALLOC)) { --nalloc; @@ -1292,8 +1295,9 @@ more sections in stripped file than debug file -- arguments reversed?")); } /* Locate a matching unallocated section in SECTIONS. */ - inline struct section *find_unalloc_section (const GElf_Shdr *shdr, - const char *name) + INLINE_NESTED_FUNC (struct section *, find_unalloc_section, + (const GElf_Shdr *, const char *), + (const GElf_Shdr *shdr, const char *name)) { size_t l = nalloc, u = stripped_shnum - 1; while (l < u) @@ -1310,7 +1314,7 @@ more sections in stripped file than debug file -- arguments reversed?")); return sec; } return NULL; - } + }; Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped, unstripped_shstrndx), NULL); @@ -1984,13 +1988,13 @@ handle_explicit_files (const char *output_file, bool create_dirs, bool force, /* 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) + NESTED_FUNC (void, warn, (const char *), (const char *msg)) { error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.", force ? _("WARNING: ") : "", stripped_file, unstripped_file, msg, force ? "" : _(", use --force")); - } + }; int stripped_fd = open_file (stripped_file, false); Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL); @@ -2244,11 +2248,11 @@ match_module (Dwfl_Module *mod, 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) + __BLOCK struct match_module_info mmi = { info->args, NULL, info->match_files }; + INLINE_NESTED_FUNC (ptrdiff_t, next, (ptrdiff_t), (ptrdiff_t offset)) { return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset); - } + }; ptrdiff_t offset = next (0); if (offset == 0) error (EXIT_FAILURE, 0, _("no matching modules found")); -- 2.5.0.457.gab17608