To be compiled without gnu99 extension. Signed-off-by: Chih-Hung Hsieh <c...@google.com> --- libdw/ChangeLog | 9 ++ libdw/cfi.c | 73 ++++++++-------- libdw/dwarf_getscopevar.c | 38 +++++---- libdw/dwarf_getsrclines.c | 85 +++++++++--------- libdw/libdw_visit_scopes.c | 209 +++++++++++++++++++++++++-------------------- 5 files changed, 226 insertions(+), 188 deletions(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 13beefc..13ecc1e 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,12 @@ +2015-09-14 Chih-Hung Hsieh <c...@google.com> + + * cfi.c (execute_cfi): Replace simple nested functions with macros. + * dwarf_getsrclines.c (read_srclines): Likewise. + * dwarf_getscopevar.c (dwarf_getscopevar): Move complicated + nested functions to file scope. + * dwarf_visit_scopes.c (__libdw_visit_scopes): Move recursive nested + functions to file scope; inline 'recurse' at its single call site. + 2015-09-09 Chih-Hung Hsieh <c...@google.com> * dwarf_macro_getsrcfiles.c (dwarf_macro_getsrcfiles): Remove diff --git a/libdw/cfi.c b/libdw/cfi.c index 5a6f956..d15838a 100644 --- a/libdw/cfi.c +++ b/libdw/cfi.c @@ -77,42 +77,43 @@ execute_cfi (Dwarf_CFI *cache, } while (0) Dwarf_Frame *fs = *state; - inline bool enough_registers (Dwarf_Word reg) - { - /* Don't allow insanely large register numbers. 268435456 registers - should be enough for anybody. And very large values might overflow - the array size and offsetof calculations below. */ - if (unlikely (reg >= INT32_MAX / sizeof (fs->regs[0]))) - { - result = DWARF_E_INVALID_CFI; - return false; - } - - if (fs->nregs <= reg) - { - size_t size = offsetof (Dwarf_Frame, regs[reg + 1]); - Dwarf_Frame *bigger = realloc (fs, size); - if (unlikely (bigger == NULL)) - { - result = DWARF_E_NOMEM; - return false; - } - else - { - eu_static_assert (reg_unspecified == 0); - memset (bigger->regs + bigger->nregs, 0, - (reg + 1 - bigger->nregs) * sizeof bigger->regs[0]); - bigger->nregs = reg + 1; - fs = bigger; - } - } - return true; - } - - inline void require_cfa_offset (void) - { - if (unlikely (fs->cfa_rule != cfa_offset)) - fs->cfa_rule = cfa_invalid; +#define enough_registers(_reg) \ + ( { \ + Dwarf_Word reg = _reg; \ + bool has_enough = true; \ + /* Don't allow insanely large register numbers. 268435456 registers */ \ + /* should be enough for anybody. And very large values might overflow */ \ + /* the array size and offsetof calculations below. */ \ + if (unlikely (reg >= INT32_MAX / sizeof (fs->regs[0]))) \ + { \ + result = DWARF_E_INVALID_CFI; \ + has_enough = false; \ + } \ + else if (fs->nregs <= reg) \ + { \ + size_t size = offsetof (Dwarf_Frame, regs[reg + 1]); \ + Dwarf_Frame *bigger = realloc (fs, size); \ + if (unlikely (bigger == NULL)) \ + { \ + result = DWARF_E_NOMEM; \ + has_enough = false; \ + } \ + else \ + { \ + eu_static_assert (reg_unspecified == 0); \ + memset (bigger->regs + bigger->nregs, 0, \ + (reg + 1 - bigger->nregs) * sizeof bigger->regs[0]); \ + bigger->nregs = reg + 1; \ + fs = bigger; \ + } \ + } \ + has_enough; \ + } ) + +#define require_cfa_offset() \ + { \ + if (unlikely (fs->cfa_rule != cfa_offset)) \ + fs->cfa_rule = cfa_invalid; \ } #define register_rule(regno, r_rule, r_value) do { \ diff --git a/libdw/dwarf_getscopevar.c b/libdw/dwarf_getscopevar.c index eb50c0a..e59dccd 100644 --- a/libdw/dwarf_getscopevar.c +++ b/libdw/dwarf_getscopevar.c @@ -52,6 +52,25 @@ getattr (Dwarf_Die *die, int search_name, Dwarf_Word *value) &attr_mem), value); } +inline static int +file_matches (Dwarf_Files * files, size_t idx, + const char *lastfile, size_t match_file_len, + const char *match_file, bool *lastfile_matches) +{ + if (idx >= files->nfiles) + return false; + const char *file = files->info[idx].name; + if (file != lastfile) + { + size_t len = strlen (file); + *lastfile_matches = (len >= match_file_len + && !memcmp (match_file, file, match_file_len) + && (len == match_file_len + || file[len - match_file_len - 1] == '/')); + } + return *lastfile_matches; +} + /* Search SCOPES[0..NSCOPES-1] for a variable called NAME. Ignore the first SKIP_SHADOWS scopes that match the name. If MATCH_FILE is not null, accept only declaration in that source file; @@ -72,22 +91,6 @@ dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, size_t match_file_len = match_file == NULL ? 0 : strlen (match_file); bool lastfile_matches = false; const char *lastfile = NULL; - inline bool file_matches (Dwarf_Files *files, size_t idx) - { - if (idx >= files->nfiles) - return false; - - const char *file = files->info[idx].name; - if (file != lastfile) - { - size_t len = strlen (file); - lastfile_matches = (len >= match_file_len - && !memcmp (match_file, file, match_file_len) - && (len == match_file_len - || file[len - match_file_len - 1] == '/')); - } - return lastfile_matches; - } /* Start with the innermost scope and move out. */ for (int out = 0; out < nscopes; ++out) @@ -130,7 +133,8 @@ dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, || getfiles (&scopes[out], &files) != 0) break; - if (!file_matches (files, i)) + if (!file_matches (files, i, lastfile, match_file_len, + match_file, &lastfile_matches)) break; if (match_lineno > 0 diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index 389c824..dfa3e58 100644 --- a/libdw/dwarf_getsrclines.c +++ b/libdw/dwarf_getsrclines.c @@ -338,15 +338,54 @@ read_srclines (Dwarf *dbg, /* 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) - { - addr += minimum_instr_len * ((op_index + op_advance) - / max_ops_per_instr); - op_index = (op_index + op_advance) % max_ops_per_instr; +#define advance_pc(_op_advance) \ + { \ + unsigned int op_advance = _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. */ + /* Set the line information. For some fields we use bitfields, + so we would lose information if the encoded values are too large. + Check just for paranoia, and call the data "invalid" if it + violates our assumptions on reasonable limits for the values. */ +#define SET(field) \ + new_line->line.field = field; \ + if (unlikely (new_line->line.field != field)) \ + { \ + add_new_line_result = true; \ + break; \ + } + +#define add_new_line(_new_line, _end_sequence) \ + ( { \ + struct linelist *new_line = _new_line; \ + bool end_sequence = _end_sequence; \ + bool add_new_line_result = false; \ + new_line->next = linelist; \ + new_line->sequence = nlinelist; \ + linelist = new_line; \ + ++nlinelist; \ + do { \ + SET (addr); \ + SET (op_index); \ + SET (file); \ + SET (line); \ + SET (column); \ + SET (is_stmt); \ + SET (basic_block); \ + SET (end_sequence); \ + SET (prologue_end); \ + SET (epilogue_begin); \ + SET (isa); \ + SET (discriminator); \ + } while (0); \ + add_new_line_result; \ + } ) + /* Adds a new line to the matrix. For the first MAX_STACK_LINES entries just return a slot in the preallocated stack array. */ struct linelist llstack[MAX_STACK_LINES]; @@ -361,42 +400,6 @@ read_srclines (Dwarf *dbg, goto invalid_data; \ } while (0) - inline bool add_new_line (struct linelist *new_line, bool end_sequence) - { - new_line->next = linelist; - new_line->sequence = nlinelist; - linelist = new_line; - ++nlinelist; - - /* Set the line information. For some fields we use bitfields, - so we would lose information if the encoded values are too large. - Check just for paranoia, and call the data "invalid" if it - violates our assumptions on reasonable limits for the values. */ -#define SET(field) \ - do { \ - new_line->line.field = field; \ - if (unlikely (new_line->line.field != field)) \ - return true; \ - } while (0) - - SET (addr); - SET (op_index); - SET (file); - SET (line); - SET (column); - SET (is_stmt); - SET (basic_block); - SET (end_sequence); - SET (prologue_end); - SET (epilogue_begin); - SET (isa); - SET (discriminator); - -#undef SET - - return false; - } - while (linep < lineendp) { unsigned int opcode; diff --git a/libdw/libdw_visit_scopes.c b/libdw/libdw_visit_scopes.c index d0b5134..9970e25 100644 --- a/libdw/libdw_visit_scopes.c +++ b/libdw/libdw_visit_scopes.c @@ -64,104 +64,125 @@ may_have_scopes (Dwarf_Die *die) return false; } -int -__libdw_visit_scopes (depth, root, imports, previsit, postvisit, arg) - unsigned int depth; - struct Dwarf_Die_Chain *root; - 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; +/* Checks the given DIE hasn't been imported yet to prevent cycles. */ +static inline bool +imports_contains (struct Dwarf_Die_Chain *imports, Dwarf_Die *die) { - struct Dwarf_Die_Chain child; - int ret; + for (struct Dwarf_Die_Chain *import = imports; import != NULL; + import = import->parent) + if (import->die.addr == die->addr) + return true; + + return false; +} - child.parent = root; - if ((ret = INTUSE(dwarf_child) (&root->die, &child.die)) != 0) - return ret < 0 ? -1 : 0; // Having zero children is legal. +typedef struct walk_children_closure { + /* Parameters of __libdw_visit_scopes. */ + unsigned int depth; + struct Dwarf_Die_Chain *root; + 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; + /* Return value of recursive walker. */ + int ret; + /* Extra local variables for the walker. */ + struct Dwarf_Die_Chain child; +} walk_children_closure; - inline int recurse (void) +static inline int +walk_children (walk_children_closure *walker) +{ + do { - return __libdw_visit_scopes (depth + 1, &child, imports, - previsit, postvisit, arg); + /* 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) (&walker->child.die) == DW_TAG_imported_unit) + { + Dwarf_Die orig_child_die = walker->child.die; + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&walker->child.die, + DW_AT_import, + &attr_mem); + if (INTUSE(dwarf_formref_die) (attr, &walker->child.die) != NULL + && INTUSE(dwarf_child) (&walker->child.die, + &walker->child.die) == 0) + { + if (imports_contains (walker->imports, &orig_child_die)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + struct Dwarf_Die_Chain *orig_imports = walker->imports; + struct Dwarf_Die_Chain import = { .die = orig_child_die, + .parent = orig_imports }; + walker->imports = &import; + int result = walk_children (walker); + walker->imports = orig_imports; + if (result != DWARF_CB_OK) + return result; + } + + /* Any "real" children left? */ + if ((walker->ret = INTUSE(dwarf_siblingof) (&orig_child_die, + &walker->child.die)) != 0) + return walker->ret < 0 ? -1 : 0; + } + + walker->child.prune = false; + + /* previsit is declared NN */ + int result = (*walker->previsit) + (walker->depth + 1, &walker->child, walker->arg); + if (result != DWARF_CB_OK) + return result; + + if (!walker->child.prune && may_have_scopes (&walker->child.die) + && INTUSE(dwarf_haschildren) (&walker->child.die)) + { + result = __libdw_visit_scopes (walker->depth + 1, &walker->child, + walker->imports, walker->previsit, + walker->postvisit, walker->arg); + if (result != DWARF_CB_OK) + return result; + } + + if (walker->postvisit != NULL) + { + result = (*walker->postvisit) (walker->depth + 1, &walker->child, walker->arg); + if (result != DWARF_CB_OK) + return result; + } } + while ((walker->ret = INTUSE(dwarf_siblingof) ( + &walker->child.die, &walker->child.die)) == 0); - /* 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; - } - - inline int walk_children () - { - 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; - - /* previsit is declared NN */ - int result = (*previsit) (depth + 1, &child, arg); - if (result != DWARF_CB_OK) - return result; - - if (!child.prune && may_have_scopes (&child.die) - && INTUSE(dwarf_haschildren) (&child.die)) - { - result = recurse (); - if (result != DWARF_CB_OK) - return result; - } - - if (postvisit != NULL) - { - result = (*postvisit) (depth + 1, &child, arg); - if (result != DWARF_CB_OK) - return result; - } - } - while ((ret = INTUSE(dwarf_siblingof) (&child.die, &child.die)) == 0); - - return ret < 0 ? -1 : 0; - } - - return walk_children (); + return walker->ret < 0 ? -1 : 0; +} + +int +__libdw_visit_scopes ( + unsigned int depth, + struct Dwarf_Die_Chain *root, + 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) +{ + walk_children_closure walker = { + .depth = depth, + .root = root, + .imports = imports, + .previsit = previsit, + .postvisit = postvisit, + .arg = arg + }; + + walker.child.parent = root; + if ((walker.ret = INTUSE(dwarf_child) (&walker.root->die, &walker.child.die)) != 0) + return walker.ret < 0 ? -1 : 0; // Having zero children is legal. + + return walk_children (&walker); } -- 2.6.0.rc0.131.gf624c3d