From: Mark Wielaard Date: Sun, 20 May 2018 21:30:01 +0000 (+0200) Subject: libdw: Support DW_OP_addrx/constx and split DWARF addrx/constx support. X-Git-Tag: elfutils-0.171~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6e3d2521a2b5a3b436901f52cfb9785887a7c961;p=thirdparty%2Felfutils.git libdw: Support DW_OP_addrx/constx and split DWARF addrx/constx support. DW_OP_addrx/constx and GNU DebugFission DW_OP_GNU_addr/const_index take as argument an index into the .debug_addr section for the associated CU. This index gets resolved through dwarf_getlocation_attr. A new fake addr CU is created per Dwarf for use with this new attribute. For split DWARF files, the IDX_debug_addr gets replaced with the skeleton section and the addr base is resolved immediately when constructing the split DWARF CU. Move __libdw_cu_addr_base to libdwP.h to share with eu-readelf. Also make it possible to resolve addrx[1234]/GNU_addr_index also as constant indexes to (also) show when displaying these attributes in eu-readelf. A new varlocs tests is added to test the resolving for both the DWARF4 and DWARF5 DW_OP variants. And now that addrx forms are resolved in split DWARF files add the new DIEs with "single ranges" (those DIEs that have a lowpc/highpc attribute pair) to run-all-dwarf-ranges.sh. Signed-off-by: Mark Wielaard --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 08c8f7be1..f56896325 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,22 @@ +2018-05-21 Mark Wielaard + + * dwarf_begin_elf.c (valid_p): Add a fake_addr_cu to the result. + * dwarf_end.c (cu_free): Disconnect the fake_addr_cu from the split + dwarf if shared with skeleton. + (dwarf_end): release fake_addr_cu. + * dwarf_formaddr.c (__libdw_cu_addr_base): Move to... + * libdwP.h (__libdw_cu_addr_base): ... here. + (struct Dwarf): Add fake_addr_cu field. + * dwarf_formudata.c (dwarf_formudata): Handle + DW_FORM_GNU_addr_index and DW_FORM_addrx[1234]. + * dwarf_getlocation_attr.c (addr_valp): New static function. + (dwarf_getlocation_attr): Create attribute for values of + DW_OP_GNU_const_index, DW_OP_constx and DW_OP_GNU_addr_index and + DW_OP_addrx. + * libdw_find_split_unit.c (__libdw_find_split_unit): Connect + IDX_debug_addr sectiondata and fake_addr_cu between split and + skeleton. + 2018-05-20 Mark Wielaard * dwarf_cu_info.c: New file. diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 0e435c578..5d8e79e3f 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -246,6 +246,33 @@ valid_p (Dwarf *result) } } + /* For DW_OP_constx/GNU_const_index and DW_OP_addrx/GNU_addr_index + the dwarf_location_attr () will need a "fake" address CU to + indicate where the attribute data comes from. This is a just + inside the .debug_addr section, if it exists. */ + if (result != NULL && result->sectiondata[IDX_debug_addr] != NULL) + { + result->fake_addr_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU)); + if (unlikely (result->fake_addr_cu == NULL)) + { + Dwarf_Sig8_Hash_free (&result->sig8_hash); + __libdw_seterrno (DWARF_E_NOMEM); + free (result->fake_loc_cu); + free (result); + result = NULL; + } + else + { + result->fake_addr_cu->sec_idx = IDX_debug_addr; + result->fake_addr_cu->dbg = result; + result->fake_addr_cu->startp + = result->sectiondata[IDX_debug_addr]->d_buf; + result->fake_addr_cu->endp + = (result->sectiondata[IDX_debug_addr]->d_buf + + result->sectiondata[IDX_debug_addr]->d_size); + } + } + if (result != NULL) result->debugdir = __libdw_debugdir (result->elf->fildes); diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index 4702f1b1f..19546741e 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -59,7 +59,12 @@ cu_free (void *arg) /* Free split dwarf one way (from skeleton to split). */ if (p->unit_type == DW_UT_skeleton && p->split != NULL && p->split != (void *)-1) - INTUSE(dwarf_end) (p->split->dbg); + { + /* The fake_addr_cu might be shared, only release one. */ + if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu) + p->split->dbg->fake_addr_cu = NULL; + INTUSE(dwarf_end) (p->split->dbg); + } } @@ -108,6 +113,11 @@ dwarf_end (Dwarf *dwarf) cu_free (dwarf->fake_loc_cu); free (dwarf->fake_loc_cu); } + if (dwarf->fake_addr_cu != NULL) + { + cu_free (dwarf->fake_addr_cu); + free (dwarf->fake_addr_cu); + } /* Did we find and allocate the alt Dwarf ourselves? */ if (dwarf->alt_fd != -1) diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c index c917deac0..3c89a5d21 100644 --- a/libdw/dwarf_formaddr.c +++ b/libdw/dwarf_formaddr.c @@ -136,21 +136,3 @@ dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr) return 0; } INTDEF(dwarf_formaddr) - -Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu) -{ - if (cu->addr_base == (Dwarf_Off) -1) - { - Dwarf_Die cu_die = CUDIE(cu); - Dwarf_Attribute attr; - if (dwarf_attr (&cu_die, DW_AT_GNU_addr_base, &attr) != NULL - || dwarf_attr (&cu_die, DW_AT_addr_base, &attr) != NULL) - { - Dwarf_Word off; - if (dwarf_formudata (&attr, &off) == 0) - cu->addr_base = off; - } - } - - return cu->addr_base; -} diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c index 316ad8655..d56e7dc16 100644 --- a/libdw/dwarf_formudata.c +++ b/libdw/dwarf_formudata.c @@ -288,6 +288,39 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) get_sleb128_unchecked (*return_uval, datap); break; + /* These are indexes into the .debug_addr section, normally resolved + with dwarf_formaddr. Here treat as constants. */ + case DW_FORM_GNU_addr_index: + case DW_FORM_addrx: + if (datap >= endp) + goto invalid; + get_uleb128 (*return_uval, datap, endp); + break; + + case DW_FORM_addrx1: + if (datap >= endp - 1) + goto invalid; + *return_uval = *datap; + break; + + case DW_FORM_addrx2: + if (datap >= endp - 2) + goto invalid; + *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap); + break; + + case DW_FORM_addrx3: + if (datap >= endp - 3) + goto invalid; + *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap); + break; + + case DW_FORM_addrx4: + if (datap >= endp - 4) + goto invalid; + *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap); + break; + default: __libdw_seterrno (DWARF_E_NO_CONSTANT); return -1; diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c index 162330f61..62ef47abf 100644 --- a/libdw/dwarf_getlocation_attr.c +++ b/libdw/dwarf_getlocation_attr.c @@ -52,6 +52,18 @@ attr_form_cu (Dwarf_Attribute *attr) } } +static unsigned char * +addr_valp (Dwarf_CU *cu, Dwarf_Word index) +{ + Elf_Data *debug_addr = cu->dbg->sectiondata[IDX_debug_addr]; + Dwarf_Word offset = __libdw_cu_addr_base (cu) + (index * cu->address_size); + if (debug_addr == NULL) + /* This is really an error, will trigger with dwarf_formaddr. */ + return (unsigned char *) offset; + + return (unsigned char *) debug_addr->d_buf + offset; +} + int dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribute *result) { @@ -83,6 +95,25 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu result->cu = attr_form_cu (attr); break; + case DW_OP_GNU_const_index: + case DW_OP_constx: + result->code = DW_AT_const_value; + if (attr->cu->address_size == 4) + result->form = DW_FORM_data4; + else + result->form = DW_FORM_data8; + result->valp = addr_valp (attr->cu, op->number); + result->cu = attr->cu->dbg->fake_addr_cu; + break; + + case DW_OP_GNU_addr_index: + case DW_OP_addrx: + result->code = DW_AT_low_pc; + result->form = DW_FORM_addr; + result->valp = addr_valp (attr->cu, op->number); + result->cu = attr->cu->dbg->fake_addr_cu; + break; + case DW_OP_call2: case DW_OP_call4: case DW_OP_call_ref: diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 2b5b5eadb..82ee5d03e 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -204,6 +204,9 @@ struct Dwarf came from a location list entry in dwarf_getlocation_attr. */ struct Dwarf_CU *fake_loc_cu; + /* Similar for addrx/constx, which will come from .debug_addr section. */ + struct Dwarf_CU *fake_addr_cu; + /* Internal memory handling. This is basically a simplified reimplementation of obstacks. Unfortunately the standard obstack implementation is not usable in libraries. */ @@ -947,7 +950,26 @@ const char *__libdw_getcompdir (Dwarf_Die *cudie); Dwarf_Addr __libdw_cu_base_address (Dwarf_CU *cu); /* Get the address base for the CU, fetches it when not yet set. */ -Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu); +static inline Dwarf_Off +__libdw_cu_addr_base (Dwarf_CU *cu) +{ + if (cu->addr_base == (Dwarf_Off) -1) + { + Dwarf_Die cu_die = CUDIE(cu); + Dwarf_Attribute attr; + Dwarf_Off offset = 0; + if (dwarf_attr (&cu_die, DW_AT_GNU_addr_base, &attr) != NULL + || dwarf_attr (&cu_die, DW_AT_addr_base, &attr) != NULL) + { + Dwarf_Word off; + if (dwarf_formudata (&attr, &off) == 0) + offset = off; + } + cu->addr_base = offset; + } + + return cu->addr_base; +} /* Gets the .debug_str_offsets base offset to use. static inline to be shared between libdw and eu-readelf. */ diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c index bd48b9e51..78c9a2a50 100644 --- a/libdw/libdw_find_split_unit.c +++ b/libdw/libdw_find_split_unit.c @@ -88,6 +88,20 @@ __libdw_find_split_unit (Dwarf_CU *cu) cu->split = split; split->split = cu; + /* Get .debug_addr and addr_base greedy. + We also need it for the fake addr cu. + There is only one per split debug. */ + Dwarf *dbg = cu->dbg; + Dwarf *sdbg = split->dbg; + if (sdbg->sectiondata[IDX_debug_addr] == NULL + && dbg->sectiondata[IDX_debug_addr] != NULL) + { + sdbg->sectiondata[IDX_debug_addr] + = dbg->sectiondata[IDX_debug_addr]; + split->addr_base = __libdw_cu_addr_base (cu); + sdbg->fake_addr_cu = dbg->fake_addr_cu; + } + /* We have everything we need from this ELF file. And we are going to close the fd to not run out of file diff --git a/src/ChangeLog b/src/ChangeLog index e18727758..1a9f4a334 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2018-01-21 Mark Wielaard + + * readelf.c (get_indexed_addr): New function. + (print_ops): Handle DW_OP_addrx, DW_OP_GNU_addr_index, + DW_OP_constx, DW_OP_GNU_const_index separately and resolve + address. + (attr_callback): Print index and address for + DW_FORM_GNU_addr_index and DW_FORM_addrx[1234]. + 2018-01-19 Mark Wielaard * readelf.c (options): Add info+. diff --git a/src/readelf.c b/src/readelf.c index 466d941e6..18588022d 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -4180,6 +4180,29 @@ print_bytes (size_t n, const unsigned char *bytes) } } +static int +get_indexed_addr (Dwarf_CU *cu, Dwarf_Word idx, Dwarf_Addr *addr) +{ + Elf_Data *debug_addr = cu->dbg->sectiondata[IDX_debug_addr]; + if (debug_addr == NULL) + return -1; + + Dwarf_Off base = __libdw_cu_addr_base (cu); + Dwarf_Word off = idx * cu->address_size; + if (base > debug_addr->d_size + || off > debug_addr->d_size - base + || cu->address_size > debug_addr->d_size - base - off) + return -1; + + const unsigned char *addrp = debug_addr->d_buf + base + off; + if (cu->address_size == 4) + *addr = read_4ubyte_unaligned (cu->dbg, addrp); + else + *addr = read_8ubyte_unaligned (cu->dbg, addrp); + + return 0; +} + static void print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, unsigned int vers, unsigned int addrsize, unsigned int offset_size, @@ -4348,19 +4371,36 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, case DW_OP_piece: case DW_OP_regx: case DW_OP_plus_uconst: - case DW_OP_constu: + case DW_OP_constu:; + const unsigned char *start = data; + uint64_t uleb; + NEED (1); + get_uleb128 (uleb, data, data + len); + printf ("%*s[%2" PRIuMAX "] %s %" PRIu64 "\n", + indent, "", (uintmax_t) offset, op_name, uleb); + CONSUME (data - start); + offset += 1 + (data - start); + break; + case DW_OP_addrx: case DW_OP_GNU_addr_index: case DW_OP_constx: case DW_OP_GNU_const_index:; - const unsigned char *start = data; - uint64_t uleb; + start = data; NEED (1); get_uleb128 (uleb, data, data + len); - printf ("%*s[%2" PRIuMAX "] %s %" PRIu64 "\n", + printf ("%*s[%2" PRIuMAX "] %s [%" PRIu64 "] ", indent, "", (uintmax_t) offset, op_name, uleb); CONSUME (data - start); offset += 1 + (data - start); + if (get_indexed_addr (cu, uleb, &addr) != 0) + printf ("???\n"); + else + { + a = format_dwarf_addr (dwflmod, 0, addr, addr); + printf ("%s\n", a); + free (a); + } break; case DW_OP_bit_piece: @@ -6148,9 +6188,19 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) } char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize, addr, addr); - printf (" %*s%-20s (%s) %s\n", - (int) (level * 2), "", dwarf_attr_name (attr), - dwarf_form_name (form), a); + if (form != DW_FORM_addr ) + { + Dwarf_Word index; + if (dwarf_formudata (attrp, &index) != 0) + goto attrval_out; + printf (" %*s%-20s (%s) [%" PRIx64 "] %s\n", + (int) (level * 2), "", dwarf_attr_name (attr), + dwarf_form_name (form), index, a); + } + else + printf (" %*s%-20s (%s) %s\n", + (int) (level * 2), "", dwarf_attr_name (attr), + dwarf_form_name (form), a); free (a); } break; diff --git a/tests/ChangeLog b/tests/ChangeLog index a93b0e981..2f92cc2f1 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,17 @@ +2018-05-21 Mark Wielaard + + * addrx_constx-4.dwo.bz2: New testfile. + * addrx_constx-5.dwo.bz2: Likewise. + * testfile-addrx_constx-4.bz2: Likewise. + * testfile-addrx_constx-5.bz2: Likewise + * Makefile.am (EXTRA_DIST): Add addrx_constx-5.dwo.bz2 + testfile-addrx_constx-4\ .bz2 testfile-addrx_constx-5.bz2. + * run-varlocs.sh: Add addrx_constx tests for DWARF4 and DWARF5. + * varlocx.c (print_expr): Handle DW_OP_GNU_addr_index, + DW_OP_addrx, DW_OP_GNU_const_index and DW_OP_constx. + (main): Handle split DWARF. + * run-all-dwarf-ranges.sh: Add new ranges for addrx low/highpc. + 2018-05-20 Mark Wielaard * unit-info.c: New test. diff --git a/tests/Makefile.am b/tests/Makefile.am index 9beae1407..4b13be271 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -305,6 +305,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfile_entry_value.c testfile_entry_value.bz2 \ testfile_implicit_value.c testfile_implicit_value.bz2 \ testfile_aarch64_core.bz2 testfile_i686_core.bz2 \ + addrx_constx-4.dwo.bz2 addrx_constx-5.dwo.bz2 \ + testfile-addrx_constx-4.bz2 testfile-addrx_constx-5.bz2 \ run-funcretval.sh funcretval_test.c funcretval_test_aarch64.bz2 \ run-backtrace-data.sh run-backtrace-dwarf.sh cleanup-13.c \ run-backtrace-native.sh run-backtrace-native-biarch.sh \ diff --git a/tests/addrx_constx-4.dwo.bz2 b/tests/addrx_constx-4.dwo.bz2 new file mode 100644 index 000000000..f0bae1cd5 Binary files /dev/null and b/tests/addrx_constx-4.dwo.bz2 differ diff --git a/tests/addrx_constx-5.dwo.bz2 b/tests/addrx_constx-5.dwo.bz2 new file mode 100644 index 000000000..a5f4b1a67 Binary files /dev/null and b/tests/addrx_constx-5.dwo.bz2 differ diff --git a/tests/run-all-dwarf-ranges.sh b/tests/run-all-dwarf-ranges.sh index ba5528d2f..ad5e634fb 100755 --- a/tests/run-all-dwarf-ranges.sh +++ b/tests/run-all-dwarf-ranges.sh @@ -33,9 +33,30 @@ die: hello.c (11) 4004e0..4004ff 4003e0..4003f7 +die: no_say (2e) + 4004f0..4004ff + +die: main (2e) + 4003e0..4003f7 + +die: subject (1d) + 4003e3..4003ef + +die: subject (2e) + 4004e0..4004f0 + die: world.c (11) 400500..400567 +die: no_main (2e) + 400550..400567 + +die: no_subject (1d) + 400553..40055f + +die: say (2e) + 400500..400540 + die: happy (1d) 40051c..400526 400530..400534 @@ -45,6 +66,9 @@ die: sad (1d) 40051c..400526 400535..40053f +die: no_subject (2e) + 400540..400550 + EOF exit 0 diff --git a/tests/run-varlocs.sh b/tests/run-varlocs.sh index 9c4b313ea..2781fef44 100755 --- a/tests/run-varlocs.sh +++ b/tests/run-varlocs.sh @@ -125,4 +125,212 @@ module 'testfile_implicit_pointer' EOF +# DW_OP_addrx and DW_OP_constx testcases. +# +# int i, j, k; +# __thread int l, m, n; +# +# int main () +# { +# int r1 = i + j + k; +# int r2 = l + m + n; +# int res = r1 + r2; +# +# return res; +# } +# +# gcc -O2 -gdwarf-5 -gsplit-dwarf -o addrx_constx-5.o -c addrx_constx.c +# gcc -O2 -gdwarf-5 -gsplit-dwarf -o testfile-addrx_constx-5 addrx_constx-5.o +# gcc -O2 -gdwarf-4 -gsplit-dwarf -o addrx_constx-4.o -c addrx_constx.c +# gcc -O2 -gdwarf-4 -gsplit-dwarf -o testfile-addrx_constx-4 addrx_constx-4.o + +testfiles testfile-addrx_constx-5 addrx_constx-5.dwo +testrun_compare ${abs_top_builddir}/tests/varlocs --exprlocs -e testfile-addrx_constx-5 <<\EOF +module 'testfile-addrx_constx-5' +[14] CU 'addrx_constx.c' + producer (strx) + language (data1) + name (strx) + comp_dir (strx) + [19] variable "i" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {addr: 0x404038} + [25] base_type "int" + byte_size (data1) + encoding (data1) + name (string) + [2c] variable "j" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {addr: 0x404034} + [38] variable "k" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {addr: 0x40403c} + [44] variable "l" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {const: 0x403e10, form_tls_address} + [51] variable "m" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {const: 0x403e0c, form_tls_address} + [5e] variable "n" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {const: 0x403e08, form_tls_address} + [6b] subprogram "main" + external (flag_present) + name (strx) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + low_pc (addrx) + high_pc (data8) + frame_base (exprloc) {call_frame_cfa {bregx(7,8)}} + call_all_calls (flag_present) + [7f] variable "r1" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (implicit_const) + type (ref4) + location (exprloc) {addr: 0x404038, deref_size(4), addr: 0x404034, deref_size(4), plus, addr: 0x40403c, deref_size(4), plus, stack_value} + [98] variable "r2" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (implicit_const) + type (ref4) + location (exprloc) {form_tls_address, const: 0x403e10, deref_size(4), form_tls_address, const: 0x403e0c, deref_size(4), plus, form_tls_address, const: 0x403e08, deref_size(4), plus, stack_value} + [b4] variable "res" + name (string) + decl_file (implicit_const) + decl_line (data1) + decl_column (implicit_const) + type (ref4) + location (exprloc) {addr: 0x404038, deref_size(4), form_tls_address, const: 0x403e08, deref_size(4), plus, form_tls_address, const: 0x403e0c, deref_size(4), plus, form_tls_address, const: 0x403e10, deref_size(4), plus, addr: 0x404034, deref_size(4), plus, addr: 0x40403c, deref_size(4), plus, stack_value} +EOF + +testfiles testfile-addrx_constx-4 addrx_constx-4.dwo +testrun_compare ${abs_top_builddir}/tests/varlocs --exprlocs -e testfile-addrx_constx-4 <<\EOF +module 'testfile-addrx_constx-4' +[b] CU 'addrx_constx.c' + producer (GNU_str_index) + language (data1) + name (GNU_str_index) + comp_dir (GNU_str_index) + GNU_dwo_id (data8) + [18] variable "i" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {addr: 0x404038} + [25] base_type "int" + byte_size (data1) + encoding (data1) + name (string) + [2c] variable "j" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {addr: 0x404034} + [39] variable "k" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {addr: 0x40403c} + [46] variable "l" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {const: 0x403e10, GNU_push_tls_address} + [54] variable "m" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {const: 0x403e0c, GNU_push_tls_address} + [62] variable "n" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + external (flag_present) + location (exprloc) {const: 0x403e08, GNU_push_tls_address} + [70] subprogram "main" + external (flag_present) + name (GNU_str_index) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + low_pc (GNU_addr_index) + high_pc (data8) + frame_base (exprloc) {call_frame_cfa {bregx(7,8)}} + GNU_all_call_sites (flag_present) + [84] variable "r1" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + location (exprloc) {addr: 0x404038, deref_size(4), addr: 0x404034, deref_size(4), plus, addr: 0x40403c, deref_size(4), plus, stack_value} + [9f] variable "r2" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + location (exprloc) {GNU_push_tls_address, const: 0x403e10, deref_size(4), GNU_push_tls_address, const: 0x403e0c, deref_size(4), plus, GNU_push_tls_address, const: 0x403e08, deref_size(4), plus, stack_value} + [bd] variable "res" + name (string) + decl_file (data1) + decl_line (data1) + decl_column (data1) + type (ref4) + location (exprloc) {addr: 0x404038, deref_size(4), GNU_push_tls_address, const: 0x403e08, deref_size(4), plus, GNU_push_tls_address, const: 0x403e0c, deref_size(4), plus, GNU_push_tls_address, const: 0x403e10, deref_size(4), plus, addr: 0x404034, deref_size(4), plus, addr: 0x40403c, deref_size(4), plus, stack_value} +EOF + exit 0 diff --git a/tests/testfile-addrx_constx-4.bz2 b/tests/testfile-addrx_constx-4.bz2 new file mode 100755 index 000000000..cf10fbb10 Binary files /dev/null and b/tests/testfile-addrx_constx-4.bz2 differ diff --git a/tests/testfile-addrx_constx-5.bz2 b/tests/testfile-addrx_constx-5.bz2 new file mode 100755 index 000000000..eb2a1f178 Binary files /dev/null and b/tests/testfile-addrx_constx-5.bz2 differ diff --git a/tests/varlocs.c b/tests/varlocs.c index b2ceda2ef..859068d62 100644 --- a/tests/varlocs.c +++ b/tests/varlocs.c @@ -652,6 +652,42 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr) } break; + case DW_OP_GNU_addr_index: + case DW_OP_addrx: + /* Address from the .debug_addr section (indexed based on CU). */ + { + Dwarf_Attribute addr_attr; + if (dwarf_getlocation_attr (attr, expr, &addr_attr) != 0) + error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for addr: %s", + dwarf_errmsg (-1)); + + Dwarf_Addr address; + if (dwarf_formaddr (&addr_attr, &address) != 0) + error (EXIT_FAILURE, 0, "dwarf_formaddr address failed: %s", + dwarf_errmsg (-1)); + + printf ("addr: 0x%" PRIx64, address); + } + break; + + case DW_OP_GNU_const_index: + case DW_OP_constx: + /* Constant from the .debug_addr section (indexed based on CU). */ + { + Dwarf_Attribute addr_attr; + if (dwarf_getlocation_attr (attr, expr, &addr_attr) != 0) + error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for addr: %s", + dwarf_errmsg (-1)); + + Dwarf_Word constant; + if (dwarf_formudata (&addr_attr, &constant) != 0) + error (EXIT_FAILURE, 0, "dwarf_formudata constant failed: %s", + dwarf_errmsg (-1)); + + printf ("const: 0x%" PRIx64, constant); + } + break; + default: error (EXIT_FAILURE, 0, "unhandled opcode: DW_OP_%s (0x%x)", opname, atom); @@ -1019,9 +1055,18 @@ main (int argc, char *argv[]) /* Only walk actual compile units (not partial units) that contain code if we are only interested in the function variable locations. */ + Dwarf_Die cudie; + Dwarf_Die subdie; + uint8_t unit_type; + if (dwarf_cu_info (cu->cu, NULL, &unit_type, &cudie, &subdie, + NULL, NULL, NULL) != 0) + error (EXIT_FAILURE, 0, "dwarf_cu_info: %s", dwarf_errmsg (-1)); + if (unit_type == DW_UT_skeleton) + cudie = subdie; + Dwarf_Addr cubase; - if (dwarf_tag (cu) == DW_TAG_compile_unit - && (exprlocs || dwarf_lowpc (cu, &cubase) == 0)) + if (dwarf_tag (&cudie) == DW_TAG_compile_unit + && (exprlocs || dwarf_lowpc (&cudie, &cubase) == 0)) { found_cu = true; @@ -1043,7 +1088,7 @@ main (int argc, char *argv[]) ? modname : basename (mainfile)); printf ("module '%s'\n", name); - print_die (cu, "CU", 0); + print_die (&cudie, "CU", 0); Dwarf_Addr elfbias; Elf *elf = dwfl_module_getelf (mod, &elfbias); @@ -1060,18 +1105,10 @@ main (int argc, char *argv[]) GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); is_ET_REL = ehdr->e_type == ET_REL; - // Get the actual CU DIE and walk all all DIEs (or just the - // functions) inside it. - Dwarf_Die cudie; - uint8_t offsize; - uint8_t addrsize; - if (dwarf_diecu (cu, &cudie, &addrsize, &offsize) == NULL) - error (EXIT_FAILURE, 0, "dwarf_diecu %s", dwarf_errmsg (-1)); - if (exprlocs) { Dwarf_Addr entrypc; - if (dwarf_entrypc (cu, &entrypc) != 0) + if (dwarf_entrypc (&cudie, &entrypc) != 0) entrypc = 0; /* XXX - Passing true for has_frame_base is not really true. @@ -1079,9 +1116,9 @@ main (int argc, char *argv[]) attributes. Technically we should check that the DIE (types) are referenced from variables that are defined in a context (function) that has a frame base. */ - handle_die (cu, 0, true /* Should be false */, entrypc); + handle_die (&cudie, 0, true /* Should be false */, entrypc); } - else if (dwarf_getfuncs (cu, handle_function, NULL, 0) != 0) + else if (dwarf_getfuncs (&cudie, handle_function, NULL, 0) != 0) error (EXIT_FAILURE, 0, "dwarf_getfuncs %s", dwarf_errmsg (-1)); }