To be compiled without gnu99 extension.
Signed-off-by: Chih-Hung Hsieh <chh(a)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 <chh(a)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 <chh(a)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