Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F163896786
D23782.id68643.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D23782.id68643.diff
View Options
Index: contrib/elftoolchain/addr2line/addr2line.c
===================================================================
--- contrib/elftoolchain/addr2line/addr2line.c
+++ contrib/elftoolchain/addr2line/addr2line.c
@@ -56,16 +56,16 @@
STAILQ_ENTRY(Func) next;
};
-struct CU {
- RB_ENTRY(CU) entry;
+struct range {
+ RB_ENTRY(range) entry;
+ Dwarf_Debug dbg;
+ Dwarf_Die die;
Dwarf_Off off;
Dwarf_Unsigned lopc;
Dwarf_Unsigned hipc;
char **srcfiles;
Dwarf_Signed nsrcfiles;
STAILQ_HEAD(, Func) funclist;
- Dwarf_Die die;
- Dwarf_Debug dbg;
};
static struct option longopts[] = {
@@ -88,16 +88,16 @@
static Dwarf_Addr section_base;
/* Need a new curlopc that stores last lopc value. */
static Dwarf_Unsigned curlopc = ~0ULL;
-static RB_HEAD(cutree, CU) cuhead = RB_INITIALIZER(&cuhead);
+static RB_HEAD(cutree, range) cuhead = RB_INITIALIZER(&cuhead);
static int
-lopccmp(struct CU *e1, struct CU *e2)
+lopccmp(struct range *e1, struct range *e2)
{
return (e1->lopc < e2->lopc ? -1 : e1->lopc > e2->lopc);
}
-RB_PROTOTYPE(cutree, CU, entry, lopccmp);
-RB_GENERATE(cutree, CU, entry, lopccmp)
+RB_PROTOTYPE(cutree, range, entry, lopccmp);
+RB_GENERATE(cutree, range, entry, lopccmp)
#define USAGE_MESSAGE "\
Usage: %s [options] hexaddress...\n\
@@ -170,7 +170,7 @@
}
static struct Func *
-search_func(struct CU *cu, Dwarf_Unsigned addr)
+search_func(struct range *range, Dwarf_Unsigned addr)
{
struct Func *f, *f0;
Dwarf_Unsigned lopc, hipc, addr_base;
@@ -178,7 +178,7 @@
f0 = NULL;
- STAILQ_FOREACH(f, &cu->funclist, next) {
+ STAILQ_FOREACH(f, &range->funclist, next) {
if (f->ranges != NULL) {
addr_base = 0;
for (i = 0; i < f->ranges_cnt; i++) {
@@ -215,7 +215,7 @@
}
static void
-collect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, struct CU *cu)
+collect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, struct range *range)
{
Dwarf_Die ret_die, abst_die, spec_die;
Dwarf_Error de;
@@ -237,7 +237,7 @@
goto cont_search;
}
if (tag == DW_TAG_subprogram || tag == DW_TAG_entry_point ||
- tag == DW_TAG_inlined_subroutine) {
+ tag == DW_TAG_inlined_subroutine || tag == DW_TAG_label) {
/*
* Function address range can be specified by either
* a DW_AT_ranges attribute which points to a range list or
@@ -258,8 +258,11 @@
/*
* Search for DW_AT_low_pc/DW_AT_high_pc if ranges pointer
- * not found.
+ * not found. Treat labels differently.
*/
+ if (tag == DW_TAG_label &&
+ dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) == DW_DLV_OK)
+ goto get_func_name;
if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ||
dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de))
goto cont_search;
@@ -322,7 +325,7 @@
dwarf_attrval_unsigned(die, DW_AT_call_line,
&f->call_line, &de);
}
- STAILQ_INSERT_TAIL(&cu->funclist, f, next);
+ STAILQ_INSERT_TAIL(&range->funclist, f, next);
}
cont_search:
@@ -333,9 +336,9 @@
warnx("dwarf_child: %s", dwarf_errmsg(de));
else if (ret == DW_DLV_OK) {
if (f != NULL)
- collect_func(dbg, ret_die, f, cu);
+ collect_func(dbg, ret_die, f, range);
else
- collect_func(dbg, ret_die, parent, cu);
+ collect_func(dbg, ret_die, parent, range);
}
/* Search sibling. */
@@ -343,10 +346,10 @@
if (ret == DW_DLV_ERROR)
warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
else if (ret == DW_DLV_OK)
- collect_func(dbg, ret_die, parent, cu);
+ collect_func(dbg, ret_die, parent, range);
/* Cleanup */
- if (die != cu->die)
+ if (die != range->die)
dwarf_dealloc(dbg, die, DW_DLA_DIE);
if (abst_die != NULL)
@@ -357,14 +360,14 @@
}
static void
-print_inlines(struct CU *cu, struct Func *f, Dwarf_Unsigned call_file,
+print_inlines(struct range *range, struct Func *f, Dwarf_Unsigned call_file,
Dwarf_Unsigned call_line)
{
char demangled[1024];
char *file;
- if (call_file > 0 && (Dwarf_Signed) call_file <= cu->nsrcfiles)
- file = cu->srcfiles[call_file - 1];
+ if (call_file > 0 && (Dwarf_Signed) call_file <= range->nsrcfiles)
+ file = range->srcfiles[call_file - 1];
else
file = unknown;
@@ -389,14 +392,14 @@
(uintmax_t) call_line);
if (f->inlined_caller != NULL)
- print_inlines(cu, f->inlined_caller, f->call_file,
+ print_inlines(range, f->inlined_caller, f->call_file,
f->call_line);
}
-static struct CU *
+static struct range *
culookup(Dwarf_Unsigned addr)
{
- struct CU find, *res;
+ struct range find, *res;
find.lopc = addr;
res = RB_NFIND(cutree, &cuhead, &find);
@@ -413,11 +416,149 @@
return (NULL);
}
+static int
+check_labels(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr,
+ struct range **range) {
+ Dwarf_Addr start;
+ Dwarf_Arange *aranges;
+ Dwarf_Die prev_die, ret_die;
+ Dwarf_Error de;
+ Dwarf_Half tag;
+ Dwarf_Off die_off;
+ Dwarf_Unsigned lopc, length;
+ Dwarf_Signed arcnt;
+ struct range *labelp, **labels;
+ int i, j, label_cnt, ret;
+
+ prev_die = ret_die = NULL;
+ labels = NULL;
+ i = label_cnt = 0;
+
+ /* find aranges */
+ ret = dwarf_get_aranges(dbg, &aranges, &arcnt, &de);
+ if (ret != DW_DLV_OK && ret != DW_DLV_NO_ENTRY) {
+ warnx("dwarf_get_aranges failed: %s", dwarf_errmsg(de));
+ }
+
+ /* Child of current CU */
+ ret = dwarf_child(die, &prev_die, &de);
+ if (ret == DW_DLV_ERROR)
+ warnx("dwarf_child: %s", dwarf_errmsg(de));
+
+ /* count labels */
+ while (1) {
+ if (dwarf_tag(prev_die, &tag, &de) != DW_DLV_OK) {
+ warnx("dwarf_tag failed: %s",
+ dwarf_errmsg(de));
+ return DW_DLV_ERROR;
+ }
+ if (tag == DW_TAG_label) {
+ if (dwarf_attrval_unsigned(prev_die, DW_AT_low_pc, &lopc, &de) ==
+ DW_DLV_OK) {
+ label_cnt++;
+ }
+ }
+
+ if (dwarf_siblingof(dbg, prev_die, &ret_die, &de) != DW_DLV_OK) {
+ break;
+ }
+
+ if (prev_die != NULL)
+ dwarf_dealloc(dbg, prev_die, DW_DLA_DIE);
+ prev_die = ret_die;
+ }
+
+ if (label_cnt == 0)
+ return (DW_DLV_NO_ENTRY);
+
+ /* Allocate space for labels */
+ if ((labels = (struct range **)calloc(label_cnt, sizeof(struct range *))) == NULL)
+ err(EXIT_FAILURE, "calloc");
+
+ /* Add labels to list */
+ ret = dwarf_child(die, &prev_die, &de);
+ if (ret == DW_DLV_ERROR)
+ warnx("dwarf_child: %s", dwarf_errmsg(de));
+ while (1) {
+ if (dwarf_tag(prev_die, &tag, &de) != DW_DLV_OK) {
+ warnx("dwarf_tag failed: %s",
+ dwarf_errmsg(de));
+ return DW_DLV_ERROR;
+ }
+ if (tag == DW_TAG_label) {
+ if (dwarf_attrval_unsigned(prev_die, DW_AT_low_pc, &lopc, &de) ==
+ DW_DLV_OK) {
+ if (curlopc == lopc) {
+ /* free memory */
+ for (i = 0; i < label_cnt - 1; i++) {
+ if (labels[i] != *range)
+ free(labels[i]);
+ }
+ free(labels);
+ return DW_DLV_ERROR;
+ }
+ if ((labelp = calloc(1, sizeof(struct range))) == NULL)
+ err(EXIT_FAILURE, "calloc");
+ labelp->lopc = lopc;
+ labelp->die = prev_die;
+ labelp->dbg = dbg;
+ STAILQ_INIT(&labelp->funclist);
+ labels[i++] = labelp;
+ }
+ }
+ if (dwarf_siblingof(dbg, prev_die, &ret_die, &de) != DW_DLV_OK) {
+ break;
+ }
+ if (prev_die != NULL && tag != DW_TAG_label)
+ dwarf_dealloc(dbg, prev_die, DW_DLA_DIE);
+ prev_die = ret_die;
+ }
+
+ /* set hipc using aranges */
+ for (i = 0; i < label_cnt; i++) {
+ for (j = 0; j < arcnt; j++) {
+ if (dwarf_get_arange_info(aranges[j], &start, &length,
+ &die_off, &de) != DW_DLV_OK) {
+ warnx("dwarf_get_arange_info failed: %s",
+ dwarf_errmsg(de));
+ continue;
+ }
+ if (labels[i]->lopc == (Dwarf_Unsigned)start) {
+ labels[i]->hipc = start + length;
+ break;
+ }
+ }
+ }
+
+ /* check in range */
+ for (i = 0; i < label_cnt; i++) {
+ if (addr >= labels[i]->lopc && addr < labels[i]->hipc) {
+ *range = labels[i];
+ /* Add to cache */
+ RB_INSERT(cutree, &cuhead, (*range));
+ curlopc = (*range)->lopc;
+ break;
+ }
+ }
+ /* free memory */
+ for (i = 0; i < label_cnt - 1; i++) {
+ if (labels[i] != *range)
+ free(labels[i]);
+ }
+ free(labels);
+ /* return status */
+ if (*range != NULL) {
+ return (DW_DLV_OK);
+ } else {
+ return (DW_DLV_NO_ENTRY);
+ }
+}
+
/* Checks whether addr falls into range(s) of current CU.
* If so, saves current CU to lookup tree */
static int
check_range(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr,
- struct CU **cu)
+ struct range **range)
{
Dwarf_Error de;
Dwarf_Unsigned addr_base, lopc, hipc;
@@ -425,38 +566,15 @@
Dwarf_Signed ranges_cnt;
Dwarf_Ranges *ranges;
int i, ret;
- bool in_range;
+ bool in_cu;
addr_base = 0;
ranges = NULL;
ranges_cnt = 0;
- in_range = false;
+ in_cu = false;
ret = dwarf_attrval_unsigned(die, DW_AT_ranges, &ranges_off, &de);
- if (ret == DW_DLV_NO_ENTRY) {
- if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ==
- DW_DLV_OK) {
- if (lopc == curlopc)
- return (DW_DLV_ERROR);
- if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc,
- &de) == DW_DLV_OK) {
- /*
- * Check if the address falls into the PC
- * range of this CU.
- */
- if (handle_high_pc(die, lopc, &hipc) !=
- DW_DLV_OK)
- return (DW_DLV_ERROR);
- } else {
- /* Assume ~0ULL if DW_AT_high_pc not present */
- hipc = ~0ULL;
- }
-
- if (addr >= lopc && addr < hipc) {
- in_range = true;
- }
- }
- } else if (ret == DW_DLV_OK) {
+ if (ret == DW_DLV_OK) {
ret = dwarf_get_ranges(dbg, ranges_off, &ranges,
&ranges_cnt, NULL, &de);
if (ret != DW_DLV_OK)
@@ -483,23 +601,48 @@
return (DW_DLV_ERROR);
if (addr >= lopc && addr < hipc){
- in_range = true;
+ in_cu = true;
break;
}
}
} else {
- return (DW_DLV_ERROR);
+ if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ==
+ DW_DLV_OK) {
+ if (lopc == curlopc)
+ return (DW_DLV_ERROR);
+ if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc,
+ &de) == DW_DLV_OK) {
+ /*
+ * Check if the address falls into the PC
+ * range of this CU.
+ */
+ if (handle_high_pc(die, lopc, &hipc) !=
+ DW_DLV_OK)
+ return (DW_DLV_ERROR);
+ } else {
+ /* Assume ~0ULL if DW_AT_high_pc not present */
+ hipc = ~0ULL;
+ }
+
+ if (addr >= lopc && addr < hipc) {
+ in_cu = true;
+ }
+ } else {
+ /* can't find addr in range die, try labels */
+ ret = check_labels(dbg, die, addr, range);
+ return ret;
+ }
}
- if (in_range) {
- if ((*cu = calloc(1, sizeof(struct CU))) == NULL)
+ if (in_cu) {
+ if ((*range = calloc(1, sizeof(struct range))) == NULL)
err(EXIT_FAILURE, "calloc");
- (*cu)->lopc = lopc;
- (*cu)->hipc = hipc;
- (*cu)->die = die;
- (*cu)->dbg = dbg;
- STAILQ_INIT(&(*cu)->funclist);
- RB_INSERT(cutree, &cuhead, *cu);
+ (*range)->lopc = lopc;
+ (*range)->hipc = hipc;
+ (*range)->die = die;
+ (*range)->dbg = dbg;
+ STAILQ_INIT(&(*range)->funclist);
+ RB_INSERT(cutree, &cuhead, *range);
curlopc = lopc;
return (DW_DLV_OK);
} else {
@@ -517,7 +660,7 @@
Dwarf_Unsigned addr, lineno, plineno;
Dwarf_Signed lcount;
Dwarf_Addr lineaddr, plineaddr;
- struct CU *cu;
+ struct range *range;
struct Func *f;
const char *funcname;
char *file, *file0, *pfile;
@@ -531,10 +674,10 @@
die = NULL;
ret = DW_DLV_OK;
- cu = culookup(addr);
- if (cu != NULL) {
- die = cu->die;
- dbg = cu->dbg;
+ range = culookup(addr);
+ if (range != NULL) {
+ die = range->die;
+ dbg = range->dbg;
goto status_ok;
}
@@ -573,7 +716,7 @@
warnx("could not find DW_TAG_compile_unit die");
goto next_cu;
}
- ret = check_range(dbg, die, addr, &cu);
+ ret = check_range(dbg, die, addr, &range);
if (ret == DW_DLV_OK)
break;
if (ret == DW_DLV_ERROR)
@@ -631,16 +774,16 @@
out:
f = NULL;
funcname = NULL;
- if (ret == DW_DLV_OK && (func || inlines) && cu != NULL) {
- if (cu->srcfiles == NULL)
- if (dwarf_srcfiles(die, &cu->srcfiles, &cu->nsrcfiles,
+ if (ret == DW_DLV_OK && (func || inlines) && range != NULL) {
+ if (range->srcfiles == NULL)
+ if (dwarf_srcfiles(die, &range->srcfiles, &range->nsrcfiles,
&de))
warnx("dwarf_srcfiles: %s", dwarf_errmsg(de));
- if (STAILQ_EMPTY(&cu->funclist)) {
- collect_func(dbg, die, NULL, cu);
+ if (STAILQ_EMPTY(&range->funclist)) {
+ collect_func(dbg, range->die, NULL, range);
die = NULL;
}
- f = search_func(cu, addr);
+ f = search_func(range, addr);
if (f != NULL)
funcname = f->name;
}
@@ -683,9 +826,9 @@
(void) printf("%s:%ju\n", base ? basename(file) : file,
(uintmax_t) lineno);
- if (ret == DW_DLV_OK && inlines && cu != NULL &&
- cu->srcfiles != NULL && f != NULL && f->inlined_caller != NULL)
- print_inlines(cu, f->inlined_caller, f->call_file,
+ if (ret == DW_DLV_OK && inlines && range != NULL &&
+ range->srcfiles != NULL && f != NULL && f->inlined_caller != NULL)
+ print_inlines(range, f->inlined_caller, f->call_file,
f->call_line);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Jul 28, 12:21 AM (6 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35623641
Default Alt Text
D23782.id68643.diff (12 KB)
Attached To
Mode
D23782: addr2line: add label checks when DW_AT_range and DW_AT_low_pc cannot be used
Attached
Detach File
Event Timeline
Log In to Comment