Index: contrib/elftoolchain/addr2line/addr2line.c =================================================================== --- contrib/elftoolchain/addr2line/addr2line.c +++ contrib/elftoolchain/addr2line/addr2line.c @@ -84,6 +84,8 @@ static char unknown[] = { '?', '?', '\0' }; static Dwarf_Addr section_base; static struct CU *culist; +static Dwarf_Unsigned locache = ~0ULL, hicache; +static Dwarf_Die last_die = NULL; #define USAGE_MESSAGE "\ Usage: %s [options] hexaddress...\n\ @@ -403,8 +405,27 @@ cu = NULL; die = NULL; - while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, - &de)) == DW_DLV_OK) { + + if (addr >= locache && addr < hicache && last_die != NULL) { + die = last_die; + goto status_ok; + } + + while (true) { + /* + * We resume the CU scan from the last place we found a match. Because + * when we have 2 sequential addresses, and the second one is of the next CU, + * it is faster to just go to the next CU instead of starting from the beginning. + */ + ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, + &de); + if (ret == DW_DLV_NO_ENTRY) { + if (locache == ~0ULL) { + goto out; + } + ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, + &de); + } die = NULL; while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) { if (die != NULL) @@ -420,12 +441,16 @@ if (tag == DW_TAG_compile_unit) break; } + if (ret_die == NULL) { 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 == locache) { + goto out; + } if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de) == DW_DLV_OK) { /* @@ -465,7 +490,7 @@ } next_cu: - if (die != NULL) { + if (die != NULL && die != last_die) { dwarf_dealloc(dbg, die, DW_DLA_DIE); die = NULL; } @@ -474,6 +499,16 @@ if (ret != DW_DLV_OK || die == NULL) goto out; + locache = lopc; + hicache = hipc; + if (last_die != NULL) { + dwarf_dealloc(dbg, last_die, DW_DLA_DIE); + last_die = NULL; + } + last_die = die; + +status_ok: + switch (dwarf_srclines(die, &lbuf, &lcount, &de)) { case DW_DLV_OK: break; @@ -572,21 +607,6 @@ cu->srcfiles != NULL && f != NULL && f->inlined_caller != NULL) print_inlines(cu, f->inlined_caller, f->call_file, f->call_line); - - if (die != NULL) - dwarf_dealloc(dbg, die, DW_DLA_DIE); - - /* - * Reset internal CU pointer, so we will start from the first CU - * next round. - */ - while (ret != DW_DLV_NO_ENTRY) { - if (ret == DW_DLV_ERROR) - errx(EXIT_FAILURE, "dwarf_next_cu_header: %s", - dwarf_errmsg(de)); - ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, - &de); - } } static void @@ -739,6 +759,10 @@ translate(dbg, e, line); } + if (last_die != NULL) { + dwarf_dealloc(dbg, last_die, DW_DLA_DIE); + } + dwarf_finish(dbg, &de); (void) elf_end(e);