svn commit: r358587 - stable/12/contrib/elftoolchain/addr2line
Ed Maste
emaste at FreeBSD.org
Tue Mar 3 16:25:31 UTC 2020
Author: emaste
Date: Tue Mar 3 16:25:28 2020
New Revision: 358587
URL: https://svnweb.freebsd.org/changeset/base/358587
Log:
MFC r357844: 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.
Also r357862, use stdbool.h header for bool
PR: 217736
Submitted by: Marat Radchenko <marat at slonopotamus.org>
Submitted by: Tiger Gao <tig at freebsdfoundation.org>
Sponsored by: The FreeBSD Foundation
Modified:
stable/12/contrib/elftoolchain/addr2line/addr2line.c
Directory Properties:
stable/12/ (props changed)
Modified: stable/12/contrib/elftoolchain/addr2line/addr2line.c
==============================================================================
--- stable/12/contrib/elftoolchain/addr2line/addr2line.c Tue Mar 3 15:49:34 2020 (r358586)
+++ stable/12/contrib/elftoolchain/addr2line/addr2line.c Tue Mar 3 16:25:28 2020 (r358587)
@@ -65,6 +65,7 @@ struct CU {
Dwarf_Signed nsrcfiles;
STAILQ_HEAD(, Func) funclist;
Dwarf_Die die;
+ Dwarf_Debug dbg;
};
static struct option longopts[] = {
@@ -345,7 +346,8 @@ cont_search:
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 @@ 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;
- 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);
More information about the svn-src-stable-12
mailing list