addr2line: Handle DW_AT_ranges in compile units
Based on original submission by Marat Radchenko in ELF Tool Chain ticket #545, rebased and updated by Tiger Gao. PR: 217736 Submitted by: Marat Radchenko <marat@slonopotamus.org> Submitted by: Tiger Gao <tig@freebsdfoundation.org> Reviewed by: markj MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D23501
This commit is contained in:
parent
99a7fa9268
commit
6c4a4f1bc2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=357844
@ -65,6 +65,7 @@ struct CU {
|
||||
Dwarf_Signed nsrcfiles;
|
||||
STAILQ_HEAD(, Func) funclist;
|
||||
Dwarf_Die die;
|
||||
Dwarf_Debug dbg;
|
||||
};
|
||||
|
||||
static struct option longopts[] = {
|
||||
@ -345,6 +346,7 @@ collect_func(Dwarf_Debug dbg, Dwarf_Die die, struct Func *parent, struct CU *cu)
|
||||
collect_func(dbg, ret_die, parent, cu);
|
||||
|
||||
/* Cleanup */
|
||||
if (die != cu->die)
|
||||
dwarf_dealloc(dbg, die, DW_DLA_DIE);
|
||||
|
||||
if (abst_die != NULL)
|
||||
@ -411,6 +413,102 @@ culookup(Dwarf_Unsigned addr)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether addr falls into range(s) of current CU, and save current CU
|
||||
* to lookup tree if so.
|
||||
*/
|
||||
static int
|
||||
check_range(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Unsigned addr,
|
||||
struct CU **cu)
|
||||
{
|
||||
Dwarf_Error de;
|
||||
Dwarf_Unsigned addr_base, lopc, hipc;
|
||||
Dwarf_Off ranges_off;
|
||||
Dwarf_Signed ranges_cnt;
|
||||
Dwarf_Ranges *ranges;
|
||||
int i, ret;
|
||||
bool in_range;
|
||||
|
||||
addr_base = 0;
|
||||
ranges = NULL;
|
||||
ranges_cnt = 0;
|
||||
in_range = 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) {
|
||||
ret = dwarf_get_ranges(dbg, ranges_off, &ranges,
|
||||
&ranges_cnt, NULL, &de);
|
||||
if (ret != DW_DLV_OK)
|
||||
return (ret);
|
||||
|
||||
if (!ranges || ranges_cnt <= 0)
|
||||
return (DW_DLV_ERROR);
|
||||
|
||||
for (i = 0; i < ranges_cnt; i++) {
|
||||
if (ranges[i].dwr_type == DW_RANGES_END)
|
||||
return (DW_DLV_NO_ENTRY);
|
||||
|
||||
if (ranges[i].dwr_type ==
|
||||
DW_RANGES_ADDRESS_SELECTION) {
|
||||
addr_base = ranges[i].dwr_addr2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* DW_RANGES_ENTRY */
|
||||
lopc = ranges[i].dwr_addr1 + addr_base;
|
||||
hipc = ranges[i].dwr_addr2 + addr_base;
|
||||
|
||||
if (lopc == curlopc)
|
||||
return (DW_DLV_ERROR);
|
||||
|
||||
if (addr >= lopc && addr < hipc){
|
||||
in_range = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return (DW_DLV_ERROR);
|
||||
}
|
||||
|
||||
if (in_range) {
|
||||
if ((*cu = calloc(1, sizeof(struct CU))) == 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);
|
||||
curlopc = lopc;
|
||||
return (DW_DLV_OK);
|
||||
} else {
|
||||
return (DW_DLV_NO_ENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
translate(Dwarf_Debug dbg, Elf *e, const char* addrstr)
|
||||
{
|
||||
@ -418,10 +516,9 @@ translate(Dwarf_Debug dbg, Elf *e, const char* addrstr)
|
||||
Dwarf_Line *lbuf;
|
||||
Dwarf_Error de;
|
||||
Dwarf_Half tag;
|
||||
Dwarf_Unsigned lopc, hipc, addr, lineno, plineno;
|
||||
Dwarf_Unsigned addr, lineno, plineno;
|
||||
Dwarf_Signed lcount;
|
||||
Dwarf_Addr lineaddr, plineaddr;
|
||||
Dwarf_Off off;
|
||||
struct CU *cu;
|
||||
struct Func *f;
|
||||
const char *funcname;
|
||||
@ -439,6 +536,7 @@ translate(Dwarf_Debug dbg, Elf *e, const char* addrstr)
|
||||
cu = culookup(addr);
|
||||
if (cu != NULL) {
|
||||
die = cu->die;
|
||||
dbg = cu->dbg;
|
||||
goto status_ok;
|
||||
}
|
||||
|
||||
@ -477,44 +575,11 @@ translate(Dwarf_Debug dbg, Elf *e, const char* addrstr)
|
||||
warnx("could not find DW_TAG_compile_unit die");
|
||||
goto next_cu;
|
||||
}
|
||||
if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ==
|
||||
DW_DLV_OK) {
|
||||
if (lopc == curlopc)
|
||||
goto out;
|
||||
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)
|
||||
goto out;
|
||||
} else {
|
||||
/* Assume ~0ULL if DW_AT_high_pc not present */
|
||||
hipc = ~0ULL;
|
||||
}
|
||||
|
||||
if (dwarf_dieoffset(die, &off, &de) != DW_DLV_OK) {
|
||||
warnx("dwarf_dieoffset failed: %s",
|
||||
dwarf_errmsg(de));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (addr >= lopc && addr < hipc) {
|
||||
if ((cu = calloc(1, sizeof(*cu))) == NULL)
|
||||
err(EXIT_FAILURE, "calloc");
|
||||
cu->off = off;
|
||||
cu->lopc = lopc;
|
||||
cu->hipc = hipc;
|
||||
cu->die = die;
|
||||
STAILQ_INIT(&cu->funclist);
|
||||
RB_INSERT(cutree, &cuhead, cu);
|
||||
|
||||
curlopc = lopc;
|
||||
ret = check_range(dbg, die, addr, &cu);
|
||||
if (ret == DW_DLV_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == DW_DLV_ERROR)
|
||||
goto out;
|
||||
next_cu:
|
||||
if (die != NULL) {
|
||||
dwarf_dealloc(dbg, die, DW_DLA_DIE);
|
||||
|
Loading…
Reference in New Issue
Block a user