Index: head/contrib/elftoolchain/addr2line/addr2line.c =================================================================== --- head/contrib/elftoolchain/addr2line/addr2line.c +++ head/contrib/elftoolchain/addr2line/addr2line.c @@ -65,6 +65,7 @@ Dwarf_Signed nsrcfiles; STAILQ_HEAD(, Func) funclist; Dwarf_Die die; + Dwarf_Debug dbg; }; static struct option longopts[] = { @@ -345,7 +346,8 @@ collect_func(dbg, ret_die, parent, cu); /* Cleanup */ - dwarf_dealloc(dbg, die, DW_DLA_DIE); + if (die != cu->die) + dwarf_dealloc(dbg, die, DW_DLA_DIE); if (abst_die != NULL) dwarf_dealloc(dbg, abst_die, DW_DLA_DIE); @@ -411,6 +413,102 @@ 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 @@ 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 @@ cu = culookup(addr); if (cu != NULL) { die = cu->die; + dbg = cu->dbg; goto status_ok; } @@ -477,44 +575,11 @@ 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; - break; - } - } + 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);