The new DWARF5 .debug_loclists sections are like .debug_rnglists, but plus locations. For Split Dwarf GCC generates the .debug_loclists fully in the split .dwo file. Any references to addresses need to be resolved through the skeleton .debug_addr section.
Signed-off-by: Mark Wielaard <m...@klomp.org> --- libdw/ChangeLog | 15 ++ libdw/dwarf.h | 16 ++ libdw/dwarf_begin_elf.c | 1 + libdw/dwarf_error.c | 4 +- libdw/dwarf_formudata.c | 23 +- libdw/dwarf_getlocation.c | 4 +- libdw/libdwP.h | 5 +- src/ChangeLog | 19 ++ src/readelf.c | 562 ++++++++++++++++++++++++++++++++++++++++++++-- tests/ChangeLog | 4 + tests/run-readelf-loc.sh | 560 +++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 1191 insertions(+), 22 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 9991686..0db49bf 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,18 @@ +2018-04-12 Mark Wielaard <m...@klomp.org> + + * dwarf.h: Add DWARF5 location list entry DW_LLE encodings. + * begin_elf.c (dwarf_scnnames): Add IDX_debug_loclists. + * dwarf_error.c (errmsgs): Remove DWARF_E_NO_LOCLIST. And replace + with DWARF_E_NO_DEBUG_LOC, DWARF_E_NO_DEBUG_LOCLISTS and + DWARF_E_NO_LOC_VALUE. + * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_loclists_base + and DW_FORM_loclistx. + * dwarf_getlocation.c (attr_ok): Use DWARF_E_NO_LOC_VALUE. + (initial_offset): Use DWARF_E_NO_DEBUG_LOC. + * libdwP.h: Add IDX_debug_rnglists. Remove DWARF_E_NO_LOCLIST. + Add DWARF_E_NO_DEBUG_LOC, DWARF_E_NO_DEBUG_LOCLISTS and + DWARF_E_NO_LOC_VALUE. + 2018-05-25 Mark Wielaard <m...@klomp.org> * libdw_find_split_unit.c (__libdw_find_split_unit): Extract linking diff --git a/libdw/dwarf.h b/libdw/dwarf.h index 9c2495e..8985a9d 100644 --- a/libdw/dwarf.h +++ b/libdw/dwarf.h @@ -899,6 +899,22 @@ enum DW_RLE_start_length = 0x7 }; + +/* Location list entry encoding. */ +enum + { + DW_LLE_end_of_list = 0x0, + DW_LLE_base_addressx = 0x1, + DW_LLE_startx_endx = 0x2, + DW_LLE_startx_length = 0x3, + DW_LLE_offset_pair = 0x4, + DW_LLE_default_location = 0x5, + DW_LLE_base_address = 0x6, + DW_LLE_start_end = 0x7, + DW_LLE_start_length = 0x8 + }; + + /* DWARF call frame instruction encodings. */ enum { diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 2e8c5f3..af5096f 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -58,6 +58,7 @@ static const char dwarf_scnnames[IDX_last][19] = [IDX_debug_line_str] = ".debug_line_str", [IDX_debug_frame] = ".debug_frame", [IDX_debug_loc] = ".debug_loc", + [IDX_debug_loclists] = ".debug_loclists", [IDX_debug_pubnames] = ".debug_pubnames", [IDX_debug_str] = ".debug_str", [IDX_debug_str_offsets] = ".debug_str_offsets", diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c index 2e8cd77..46ea16b 100644 --- a/libdw/dwarf_error.c +++ b/libdw/dwarf_error.c @@ -85,7 +85,9 @@ static const char *errmsgs[] = [DWARF_E_VERSION] = N_("invalid DWARF version"), [DWARF_E_INVALID_DIR_IDX] = N_("invalid directory index"), [DWARF_E_ADDR_OUTOFRANGE] = N_("address out of range"), - [DWARF_E_NO_LOCLIST] = N_("no location list value"), + [DWARF_E_NO_DEBUG_LOC] = N_(".debug_loc section missing"), + [DWARF_E_NO_DEBUG_LOCLISTS] = N_(".debug_loclists section missing"), + [DWARF_E_NO_LOC_VALUE] = N_("not a location list value"), [DWARF_E_NO_BLOCK] = N_("no block data"), [DWARF_E_INVALID_LINE_IDX] = N_("invalid line index"), [DWARF_E_INVALID_ARANGE_IDX] = N_("invalid address range index"), diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c index 280fef2..26f86f1 100644 --- a/libdw/dwarf_formudata.c +++ b/libdw/dwarf_formudata.c @@ -184,11 +184,23 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) case DW_AT_use_location: case DW_AT_vtable_elem_location: case DW_AT_GNU_locviews: - /* loclistptr */ - if (__libdw_formptr (attr, IDX_debug_loc, - DWARF_E_NO_LOCLIST, NULL, - return_uval) == NULL) - return -1; + case DW_AT_loclists_base: + if (attr->cu->version < 5) + { + /* loclistptr */ + if (__libdw_formptr (attr, IDX_debug_loc, + DWARF_E_NO_DEBUG_LOC, NULL, + return_uval) == NULL) + return -1; + } + else + { + /* loclist, loclistsptr */ + if (__libdw_formptr (attr, IDX_debug_loclists, + DWARF_E_NO_DEBUG_LOCLISTS, NULL, + return_uval) == NULL) + return -1; + } break; case DW_AT_macro_info: @@ -291,6 +303,7 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) case DW_FORM_udata: case DW_FORM_rnglistx: + case DW_FORM_loclistx: if (datap + 1 > endp) goto invalid; get_uleb128 (*return_uval, datap, endp); diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index 0e7115f..d4b8eff 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -87,7 +87,7 @@ attr_ok (Dwarf_Attribute *attr) break; default: - __libdw_seterrno (DWARF_E_NO_LOCLIST); + __libdw_seterrno (DWARF_E_NO_LOC_VALUE); return false; } @@ -700,7 +700,7 @@ initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset) Dwarf_Word start_offset; if (__libdw_formptr (attr, secidx, - DWARF_E_NO_LOCLIST, + DWARF_E_NO_DEBUG_LOC, NULL, &start_offset) == NULL) return -1; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 18576d6..f99ea58 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -78,6 +78,7 @@ enum IDX_debug_line_str, IDX_debug_frame, IDX_debug_loc, + IDX_debug_loclists, IDX_debug_pubnames, IDX_debug_str, IDX_debug_str_offsets, @@ -124,7 +125,9 @@ enum DWARF_E_VERSION, DWARF_E_INVALID_DIR_IDX, DWARF_E_ADDR_OUTOFRANGE, - DWARF_E_NO_LOCLIST, + DWARF_E_NO_DEBUG_LOC, + DWARF_E_NO_DEBUG_LOCLISTS, + DWARF_E_NO_LOC_VALUE, DWARF_E_NO_BLOCK, DWARF_E_INVALID_LINE_IDX, DWARF_E_INVALID_ARANGE_IDX, diff --git a/src/ChangeLog b/src/ChangeLog index c99bb41..8e02d3c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,22 @@ +2018-04-12 Mark Wielaard <m...@klomp.org> + + * readelf.c (dwarf_loc_list_encoding_string): New functions. + (dwarf_loc_list_encoding_name): Likewise. + (known_loclistptr): Renamed and split in two... + (known_locsptr): this and ... + (known_loclistsptr): this. + (listptr_base): Split out... + (cudie_base): ...this. + (is_split_dwarf): New function. + (attr_callback): Handle DW_AT_loclists_base and notice sec_offset + in correct list. + (print_debug_rnglists_section): Use spit_dwarf_cu_base. + (print_debug_loclists_section): New function. + (print_debug_loc_section): Use known_locsptr instead of + known_loclistptr. + (print_debug): Recognize .debug_loclists. Reset known_locsptr and + known_loclistsptr. + 2018-05-25 Mark Wielaard <m...@klomp.org> * readelf.c (DWARF_SKELETON): New constant. diff --git a/src/readelf.c b/src/readelf.c index b82e9ca..311a3ca 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -4026,6 +4026,20 @@ dwarf_range_list_encoding_string (unsigned int kind) static const char * +dwarf_loc_list_encoding_string (unsigned int kind) +{ + switch (kind) + { +#define DWARF_ONE_KNOWN_DW_LLE(NAME, CODE) case CODE: return #NAME; + DWARF_ALL_KNOWN_DW_LLE +#undef DWARF_ONE_KNOWN_DW_LLE + default: + return NULL; + } +} + + +static const char * dwarf_line_content_description_string (unsigned int kind) { switch (kind) @@ -4195,6 +4209,14 @@ dwarf_range_list_encoding_name (unsigned int kind) static const char * +dwarf_loc_list_encoding_name (unsigned int kind) +{ + const char *ret = dwarf_loc_list_encoding_string (kind); + return string_or_unknown (ret, kind, 0, 0, false); +} + + +static const char * dwarf_line_content_description_name (unsigned int kind) { const char *ret = dwarf_line_content_description_string (kind); @@ -4710,25 +4732,31 @@ struct listptr #define listptr_address_size(p) ((p)->addr64 ? 8 : 4) static Dwarf_Addr -listptr_base (struct listptr *p) +cudie_base (Dwarf_Die *cudie) { Dwarf_Addr base; - Dwarf_Die cu = CUDIE (p->cu); /* Find the base address of the compilation unit. It will normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, the base address could be overridden by DW_AT_entry_pc. It's been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for compilation units with discontinuous ranges. */ - if (unlikely (dwarf_lowpc (&cu, &base) != 0)) + if (unlikely (dwarf_lowpc (cudie, &base) != 0)) { Dwarf_Attribute attr_mem; - if (dwarf_formaddr (dwarf_attr (&cu, DW_AT_entry_pc, &attr_mem), + if (dwarf_formaddr (dwarf_attr (cudie, DW_AT_entry_pc, &attr_mem), &base) != 0) base = 0; } return base; } +static Dwarf_Addr +listptr_base (struct listptr *p) +{ + Dwarf_Die cu = CUDIE (p->cu); + return cudie_base (&cu); +} + static int compare_listptr (const void *a, const void *b, void *arg) { @@ -4785,7 +4813,8 @@ struct listptr_table struct listptr *table; }; -static struct listptr_table known_loclistptr; +static struct listptr_table known_locsptr; +static struct listptr_table known_loclistsptr; static struct listptr_table known_rangelistptr; static struct listptr_table known_rnglistptr; @@ -5231,6 +5260,27 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)), } } + +static bool is_split_dwarf (Dwarf *dbg, uint64_t *id, Dwarf_CU **split_cu); + +/* Returns true and sets cu and cu_base if the given Dwarf is a split + DWARF (.dwo) file. */ +static bool +split_dwarf_cu_base (Dwarf *dbg, Dwarf_CU **cu, Dwarf_Addr *cu_base) +{ + uint64_t id; + if (is_split_dwarf (dbg, &id, cu)) + { + Dwarf_Die cudie; + if (dwarf_cu_info (*cu, NULL, NULL, &cudie, NULL, NULL, NULL, NULL) == 0) + { + *cu_base = cudie_base (&cudie); + return true; + } + } + return false; +} + /* Print content of DWARF .debug_rnglists section. */ static void print_debug_rnglists_section (Dwfl_Module *dwflmod, @@ -5334,7 +5384,8 @@ print_debug_rnglists_section (Dwfl_Module *dwflmod, if (listptr_cu (&known_rnglistptr, &listptr_idx, (Dwarf_Off) offset, (Dwarf_Off) (nexthdr - (unsigned char *) data->d_buf), - &cu_base, &cu)) + &cu_base, &cu) + || split_dwarf_cu_base (dbg, &cu, &cu_base)) { char *basestr = format_dwarf_addr (dwflmod, address_size, cu_base, cu_base); @@ -6772,9 +6823,50 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) case DW_AT_GNU_call_site_target_clobbered: case DW_AT_GNU_locviews: { - bool nlpt = notice_listptr (section_loc, &known_loclistptr, - cbargs->addrsize, cbargs->offset_size, - cbargs->cu, num, attr); + bool nlpt; + if (cbargs->cu->version < 5) + nlpt = notice_listptr (section_loc, &known_locsptr, + cbargs->addrsize, cbargs->offset_size, + cbargs->cu, num, attr); + else + { + /* Only register for a real section offset. Otherwise + it is a DW_FORM_loclistx which is just an index + number and we should already have registered the + section offset for the index when we saw the + DW_AT_loclists_base CU attribute. */ + if (form == DW_FORM_sec_offset) + nlpt = notice_listptr (section_loc, &known_loclistsptr, + cbargs->addrsize, cbargs->offset_size, + cbargs->cu, num, attr); + else + nlpt = true; + + } + + if (!cbargs->silent) + { + if (cbargs->cu->version < 5 || form == DW_FORM_sec_offset) + printf (" %*s%-20s (%s) location list [%6" + PRIxMAX "]%s\n", + (int) (level * 2), "", dwarf_attr_name (attr), + dwarf_form_name (form), (uintmax_t) num, + nlpt ? "" : " <WARNING offset too big>"); + else + printf (" %*s%-20s (%s) location index [%6" + PRIxMAX "]\n", + (int) (level * 2), "", dwarf_attr_name (attr), + dwarf_form_name (form), (uintmax_t) num); + } + } + return DWARF_CB_OK; + + case DW_AT_loclists_base: + { + bool nlpt = notice_listptr (section_loc, &known_loclistsptr, + cbargs->addrsize, cbargs->offset_size, + cbargs->cu, num, attr); + if (!cbargs->silent) printf (" %*s%-20s (%s) location list [%6" PRIxMAX "]%s\n", (int) (level * 2), "", dwarf_attr_name (attr), @@ -8370,6 +8462,446 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, static void +print_debug_loclists_section (Dwfl_Module *dwflmod, + Ebl *ebl, GElf_Ehdr *ehdr, + Elf_Scn *scn, GElf_Shdr *shdr, + Dwarf *dbg) +{ + printf (gettext ("\ +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), section_name (ebl, ehdr, shdr), + (uint64_t) shdr->sh_offset); + + Elf_Data *data = (dbg->sectiondata[IDX_debug_loclists] + ?: elf_rawdata (scn, NULL)); + if (unlikely (data == NULL)) + { + error (0, 0, gettext ("cannot get .debug_loclists content: %s"), + elf_errmsg (-1)); + return; + } + + /* For the listptr to get the base address/CU. */ + sort_listptr (&known_loclistsptr, "loclistsptr"); + size_t listptr_idx = 0; + + const unsigned char *readp = data->d_buf; + const unsigned char *const dataend = ((unsigned char *) data->d_buf + + data->d_size); + while (readp < dataend) + { + if (unlikely (readp > dataend - 4)) + { + invalid_data: + error (0, 0, gettext ("invalid data in section [%zu] '%s'"), + elf_ndxscn (scn), section_name (ebl, ehdr, shdr)); + return; + } + + ptrdiff_t offset = readp - (unsigned char *) data->d_buf; + printf (gettext ("Table at Offset 0x%" PRIx64 ":\n\n"), + (uint64_t) offset); + + uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp); + unsigned int offset_size = 4; + if (unlikely (unit_length == 0xffffffff)) + { + if (unlikely (readp > dataend - 8)) + goto invalid_data; + + unit_length = read_8ubyte_unaligned_inc (dbg, readp); + offset_size = 8; + } + printf (gettext (" Length: %8" PRIu64 "\n"), unit_length); + + /* We need at least 2-bytes + 1-byte + 1-byte + 4-bytes = 8 + bytes to complete the header. And this unit cannot go beyond + the section data. */ + if (readp > dataend - 8 + || unit_length < 8 + || unit_length > (uint64_t) (dataend - readp)) + goto invalid_data; + + const unsigned char *nexthdr = readp + unit_length; + + uint16_t version = read_2ubyte_unaligned_inc (dbg, readp); + printf (gettext (" DWARF version: %8" PRIu16 "\n"), version); + + if (version != 5) + { + error (0, 0, gettext ("Unknown version")); + goto next_table; + } + + uint8_t address_size = *readp++; + printf (gettext (" Address size: %8" PRIu64 "\n"), + (uint64_t) address_size); + + if (address_size != 4 && address_size != 8) + { + error (0, 0, gettext ("unsupported address size")); + goto next_table; + } + + uint8_t segment_size = *readp++; + printf (gettext (" Segment size: %8" PRIu64 "\n"), + (uint64_t) segment_size); + + if (segment_size != 0) + { + error (0, 0, gettext ("unsupported segment size")); + goto next_table; + } + + uint32_t offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp); + printf (gettext (" Offset entries: %8" PRIu64 "\n"), + (uint64_t) offset_entry_count); + + /* We need the CU that uses this unit to get the initial base address. */ + Dwarf_Addr cu_base = 0; + struct Dwarf_CU *cu = NULL; + if (listptr_cu (&known_loclistsptr, &listptr_idx, + (Dwarf_Off) offset, + (Dwarf_Off) (nexthdr - (unsigned char *) data->d_buf), + &cu_base, &cu) + || split_dwarf_cu_base (dbg, &cu, &cu_base)) + { + char *basestr = format_dwarf_addr (dwflmod, address_size, + cu_base, cu_base); + Dwarf_Die cudie; + if (dwarf_cu_die (cu, &cudie, + NULL, NULL, NULL, NULL, + NULL, NULL) == NULL) + printf (gettext (" Unknown CU base: %s\n"), basestr); + else + printf (gettext (" CU [%6" PRIx64 "] base: %s\n"), + dwarf_dieoffset (&cudie), basestr); + free (basestr); + } + else + printf (gettext (" Not associated with a CU.\n")); + + printf ("\n"); + + const unsigned char *offset_array_start = readp; + if (offset_entry_count > 0) + { + uint64_t needed = offset_entry_count * offset_size; + if (unit_length - 8 < needed) + { + error (0, 0, + gettext ("too many offset entries for unit length")); + goto next_table; + } + + printf (gettext (" Offsets starting at 0x%" PRIx64 ":\n"), + (uint64_t) (offset_array_start + - (unsigned char *) data->d_buf)); + for (uint32_t idx = 0; idx < offset_entry_count; idx++) + { + printf (" [%6" PRIu32 "] ", idx); + if (offset_size == 4) + { + uint32_t off = read_4ubyte_unaligned_inc (dbg, readp); + printf ("0x%" PRIx32 "\n", off); + } + else + { + uint64_t off = read_8ubyte_unaligned_inc (dbg, readp); + printf ("0x%" PRIx64 "\n", off); + } + } + printf ("\n"); + } + + Dwarf_Addr base = cu_base; + bool start_of_list = true; + while (readp < nexthdr) + { + uint8_t kind = *readp++; + uint64_t op1, op2, len; + char *a1, *a2; + + /* Skip padding. */ + if (start_of_list && kind == DW_LLE_end_of_list) + continue; + + if (start_of_list) + { + base = cu_base; + printf (" Offset: %" PRIx64 ", Index: %" PRIx64 "\n", + (uint64_t) (readp - (unsigned char *) data->d_buf - 1), + (uint64_t) (readp - offset_array_start - 1)); + start_of_list = false; + } + + printf (" %s", dwarf_loc_list_encoding_name (kind)); + switch (kind) + { + case DW_LLE_end_of_list: + start_of_list = true; + printf ("\n\n"); + break; + + case DW_LLE_base_addressx: + if ((uint64_t) (nexthdr - readp) < 1) + { + invalid_entry: + error (0, 0, gettext ("invalid loclists data")); + goto next_table; + } + get_uleb128 (op1, readp, nexthdr); + printf (" %" PRIx64 "\n", op1); + if (! print_unresolved_addresses) + { + Dwarf_Addr addr; + if (get_indexed_addr (cu, op1, &addr) != 0) + printf (" ???\n"); + else + { + a1 = format_dwarf_addr (dwflmod, address_size, + addr, addr); + printf (" %s\n", a1); + free (a1); + } + } + break; + + case DW_LLE_startx_endx: + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (op1, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (op2, readp, nexthdr); + printf (" %" PRIx64 ", %" PRIx64 "\n", op1, op2); + if (! print_unresolved_addresses) + { + Dwarf_Addr addr1; + Dwarf_Addr addr2; + if (get_indexed_addr (cu, op1, &addr1) != 0 + || get_indexed_addr (cu, op2, &addr2) != 0) + { + printf (" ???..\n"); + printf (" ???\n"); + } + else + { + a1 = format_dwarf_addr (dwflmod, address_size, + addr1, addr1); + a2 = format_dwarf_addr (dwflmod, address_size, + addr2 - 1, addr2); + printf (" %s..\n", a1); + printf (" %s\n", a2); + free (a1); + free (a2); + } + } + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (len, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < len) + goto invalid_entry; + print_ops (dwflmod, dbg, 8, 8, version, + address_size, offset_size, cu, len, readp); + readp += len; + break; + + case DW_LLE_startx_length: + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (op1, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (op2, readp, nexthdr); + printf (" %" PRIx64 ", %" PRIx64 "\n", op1, op2); + if (! print_unresolved_addresses) + { + Dwarf_Addr addr1; + Dwarf_Addr addr2; + if (get_indexed_addr (cu, op1, &addr1) != 0) + { + printf (" ???..\n"); + printf (" ???\n"); + } + else + { + addr2 = addr1 + op2; + a1 = format_dwarf_addr (dwflmod, address_size, + addr1, addr1); + a2 = format_dwarf_addr (dwflmod, address_size, + addr2 - 1, addr2); + printf (" %s..\n", a1); + printf (" %s..\n", a2); + free (a1); + free (a2); + } + } + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (len, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < len) + goto invalid_entry; + print_ops (dwflmod, dbg, 8, 8, version, + address_size, offset_size, cu, len, readp); + readp += len; + break; + + case DW_LLE_offset_pair: + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (op1, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (op2, readp, nexthdr); + printf (" %" PRIx64 ", %" PRIx64 "\n", op1, op2); + if (! print_unresolved_addresses) + { + op1 += base; + op2 += base; + a1 = format_dwarf_addr (dwflmod, address_size, op1, op1); + a2 = format_dwarf_addr (dwflmod, address_size, + op2 - 1, op2); + printf (" %s..\n", a1); + printf (" %s\n", a2); + free (a1); + free (a2); + } + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (len, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < len) + goto invalid_entry; + print_ops (dwflmod, dbg, 8, 8, version, + address_size, offset_size, cu, len, readp); + readp += len; + break; + + case DW_LLE_default_location: + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (len, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < len) + goto invalid_entry; + print_ops (dwflmod, dbg, 8, 8, version, + address_size, offset_size, cu, len, readp); + readp += len; + break; + + case DW_LLE_base_address: + if (address_size == 4) + { + if ((uint64_t) (nexthdr - readp) < 4) + goto invalid_entry; + op1 = read_4ubyte_unaligned_inc (dbg, readp); + } + else + { + if ((uint64_t) (nexthdr - readp) < 8) + goto invalid_entry; + op1 = read_8ubyte_unaligned_inc (dbg, readp); + } + base = op1; + printf (" 0x%" PRIx64 "\n", base); + if (! print_unresolved_addresses) + { + a1 = format_dwarf_addr (dwflmod, address_size, base, base); + printf (" %s\n", a1); + free (a1); + } + break; + + case DW_LLE_start_end: + if (address_size == 4) + { + if ((uint64_t) (nexthdr - readp) < 8) + goto invalid_entry; + op1 = read_4ubyte_unaligned_inc (dbg, readp); + op2 = read_4ubyte_unaligned_inc (dbg, readp); + } + else + { + if ((uint64_t) (nexthdr - readp) < 16) + goto invalid_entry; + op1 = read_8ubyte_unaligned_inc (dbg, readp); + op2 = read_8ubyte_unaligned_inc (dbg, readp); + } + printf (" 0x%" PRIx64 "..0x%" PRIx64 "\n", op1, op2); + if (! print_unresolved_addresses) + { + a1 = format_dwarf_addr (dwflmod, address_size, op1, op1); + a2 = format_dwarf_addr (dwflmod, address_size, + op2 - 1, op2); + printf (" %s..\n", a1); + printf (" %s\n", a2); + free (a1); + free (a2); + } + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (len, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < len) + goto invalid_entry; + print_ops (dwflmod, dbg, 8, 8, version, + address_size, offset_size, cu, len, readp); + readp += len; + break; + + case DW_LLE_start_length: + if (address_size == 4) + { + if ((uint64_t) (nexthdr - readp) < 4) + goto invalid_entry; + op1 = read_4ubyte_unaligned_inc (dbg, readp); + } + else + { + if ((uint64_t) (nexthdr - readp) < 8) + goto invalid_entry; + op1 = read_8ubyte_unaligned_inc (dbg, readp); + } + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (op2, readp, nexthdr); + printf (" 0x%" PRIx64 ", %" PRIx64 "\n", op1, op2); + if (! print_unresolved_addresses) + { + a1 = format_dwarf_addr (dwflmod, address_size, op1, op1); + op2 = op1 + op2; + a2 = format_dwarf_addr (dwflmod, address_size, + op2 - 1, op2); + printf (" %s..\n", a1); + printf (" %s\n", a2); + free (a1); + free (a2); + } + if ((uint64_t) (nexthdr - readp) < 1) + goto invalid_entry; + get_uleb128 (len, readp, nexthdr); + if ((uint64_t) (nexthdr - readp) < len) + goto invalid_entry; + print_ops (dwflmod, dbg, 8, 8, version, + address_size, offset_size, cu, len, readp); + readp += len; + break; + + default: + goto invalid_entry; + } + } + + next_table: + if (readp != nexthdr) + { + size_t padding = nexthdr - readp; + printf (gettext (" %zu padding bytes\n\n"), padding); + readp = nexthdr; + } + } +} + + +static void print_debug_loc_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) @@ -8389,7 +8921,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod, elf_ndxscn (scn), section_name (ebl, ehdr, shdr), (uint64_t) shdr->sh_offset); - sort_listptr (&known_loclistptr, "loclistptr"); + sort_listptr (&known_locsptr, "loclistptr"); size_t listptr_idx = 0; uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; @@ -8406,7 +8938,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod, Dwarf_CU *cu = last_cu; unsigned int attr = 0; - if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx, + if (first && skip_listptr_hole (&known_locsptr, &listptr_idx, &address_size, &offset_size, &base, &cu, offset, &readp, endp, &attr)) continue; @@ -8429,7 +8961,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod, if (attr == DW_AT_GNU_locviews) { - Dwarf_Off next_off = next_listptr_offset (&known_loclistptr, + Dwarf_Off next_off = next_listptr_offset (&known_loclistsptr, listptr_idx); const unsigned char *locp = readp; const unsigned char *locendp; @@ -9945,6 +10477,9 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr) NEW_SECTION (types), NEW_SECTION (line), NEW_SECTION (loc), + /* loclists is loc for DWARF5. */ + { ".debug_loclists", section_loc, + print_debug_loclists_section }, NEW_SECTION (pubnames), NEW_SECTION (str), /* A DWARF5 specialised debug string section. */ @@ -10000,7 +10535,8 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr) dwfl_end (skel_dwfl); free (skel_name); - reset_listptr (&known_loclistptr); + reset_listptr (&known_locsptr); + reset_listptr (&known_loclistsptr); reset_listptr (&known_rangelistptr); reset_listptr (&known_rnglistptr); } diff --git a/tests/ChangeLog b/tests/ChangeLog index 5eb1e77..6e366eb 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2018-04-12 Mark Wielaard <m...@klomp.org> + + * run-readelf-loc.sh: Add new testcases. + 2018-04-06 Mark Wielaard <m...@klomp.org> * testfileranges5.debug.bz2: New testfile. diff --git a/tests/run-readelf-loc.sh b/tests/run-readelf-loc.sh index e5152df..622cc19 100755 --- a/tests/run-readelf-loc.sh +++ b/tests/run-readelf-loc.sh @@ -167,4 +167,564 @@ DWARF section [34] '.debug_ranges' at offset 0xd94: range 12, 1a EOF +# .debug_rnglists (DWARF5), see tests/testfile-dwarf-45.source +testfiles testfile-dwarf-5 +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=loc testfile-dwarf-5<<\EOF + +DWARF section [31] '.debug_loclists' at offset 0x1c0c: +Table at Offset 0x0: + + Length: 96 + DWARF version: 5 + Address size: 8 + Segment size: 0 + Offset entries: 0 + CU [ c] base: 0x0000000000400510 <foo> + + Offset: c, Index: 0 + offset_pair 0, a + 0x0000000000400510 <foo>.. + 0x0000000000400519 <foo+0x9> + [ 0] reg5 + offset_pair a, 34 + 0x000000000040051a <foo+0xa>.. + 0x0000000000400543 <foo+0x33> + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: 1a, Index: e + offset_pair 1b, 2d + 0x000000000040052b <foo+0x1b>.. + 0x000000000040053c <foo+0x2c> + [ 0] addr 0x601038 <m> + end_of_list + + Offset: 28, Index: 1c + offset_pair 1b, 21 + 0x000000000040052b <foo+0x1b>.. + 0x0000000000400530 <foo+0x20> + [ 0] reg5 + end_of_list + + Offset: 2e, Index: 22 + offset_pair 1b, 27 + 0x000000000040052b <foo+0x1b>.. + 0x0000000000400536 <foo+0x26> + [ 0] reg5 + offset_pair 29, 2d + 0x0000000000400539 <foo+0x29>.. + 0x000000000040053c <foo+0x2c> + [ 0] reg5 + end_of_list + + Offset: 39, Index: 2d + offset_pair 21, 27 + 0x0000000000400531 <foo+0x21>.. + 0x0000000000400536 <foo+0x26> + [ 0] reg5 + offset_pair 29, 2d + 0x0000000000400539 <foo+0x29>.. + 0x000000000040053c <foo+0x2c> + [ 0] reg5 + end_of_list + + Offset: 44, Index: 38 + offset_pair 21, 2d + 0x0000000000400531 <foo+0x21>.. + 0x000000000040053c <foo+0x2c> + [ 0] reg5 + end_of_list + + Offset: 4a, Index: 3e + offset_pair 2d, 33 + 0x000000000040053d <foo+0x2d>.. + 0x0000000000400542 <foo+0x32> + [ 0] reg5 + end_of_list + + Offset: 50, Index: 44 + offset_pair 40, 4f + 0x0000000000400550 <baz>.. + 0x000000000040055e <baz+0xe> + [ 0] reg5 + offset_pair 4f, 51 + 0x000000000040055f <baz+0xf>.. + 0x0000000000400560 <baz+0x10> + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: 5e, Index: 52 + offset_pair 40, 50 + 0x0000000000400550 <baz>.. + 0x000000000040055f <baz+0xf> + [ 0] reg5 + end_of_list + +Table at Offset 0x64: + + Length: 159 + DWARF version: 5 + Address size: 8 + Segment size: 0 + Offset entries: 0 + CU [ 218] base: 000000000000000000 + + Offset: 70, Index: 0 + base_address 0x400410 + 0x0000000000400410 <main> + offset_pair 0, 14 + 0x0000000000400410 <main>.. + 0x0000000000400423 <main+0x13> + [ 0] reg5 + offset_pair 14, 20 + 0x0000000000400424 <main+0x14>.. + 0x000000000040042f <main+0x1f> + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: 87, Index: 17 + base_address 0x400410 + 0x0000000000400410 <main> + offset_pair 0, 18 + 0x0000000000400410 <main>.. + 0x0000000000400427 <main+0x17> + [ 0] reg4 + offset_pair 18, 20 + 0x0000000000400428 <main+0x18>.. + 0x000000000040042f <main+0x1f> + [ 0] entry_value: + [ 0] reg4 + [ 3] stack_value + end_of_list + + Offset: 9e, Index: 2e + start_length 0x400421, 7 + 0x0000000000400421 <main+0x11>.. + 0x0000000000400427 <main+0x17> + [ 0] reg0 + end_of_list + + Offset: ab, Index: 3b + base_address 0x400570 + 0x0000000000400570 <calc> + offset_pair 0, 8 + 0x0000000000400570 <calc>.. + 0x0000000000400577 <calc+0x7> + [ 0] reg5 + offset_pair 8, 2b + 0x0000000000400578 <calc+0x8>.. + 0x000000000040059a <calc+0x2a> + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: c2, Index: 52 + start_length 0x400588, b + 0x0000000000400588 <calc+0x18>.. + 0x0000000000400592 <calc+0x22> + [ 0] reg0 + end_of_list + + Offset: cf, Index: 5f + base_address 0x400588 + 0x0000000000400588 <calc+0x18> + offset_pair 0, 2 + 0x0000000000400588 <calc+0x18>.. + 0x0000000000400589 <calc+0x19> + [ 0] reg1 + offset_pair 2, 7 + 0x000000000040058a <calc+0x1a>.. + 0x000000000040058e <calc+0x1e> + [ 0] reg5 + offset_pair 7, b + 0x000000000040058f <calc+0x1f>.. + 0x0000000000400592 <calc+0x22> + [ 0] entry_value: + [ 0] reg5 + [ 3] deref_size 1 + [ 5] const1u 56 + [ 7] shl + [ 8] const1u 56 + [10] shra + [11] stack_value + end_of_list + + Offset: f3, Index: 83 + base_address 0x400588 + 0x0000000000400588 <calc+0x18> + offset_pair 0, 2 + 0x0000000000400588 <calc+0x18>.. + 0x0000000000400589 <calc+0x19> + [ 0] reg1 + offset_pair 2, b + 0x000000000040058a <calc+0x1a>.. + 0x0000000000400592 <calc+0x22> + [ 0] reg5 + end_of_list + +EOF + +# Same as above, but for DWARF4, note completely different encoding, but +# the information is the same (check with diff -uwb). +testfiles testfile-dwarf-4 +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=loc testfile-dwarf-4<<\EOF + +DWARF section [31] '.debug_loc' at offset 0x1c86: + + CU [ b] base: 0x0000000000400510 <foo> + [ 0] range 0, a + 0x0000000000400510 <foo>.. + 0x0000000000400519 <foo+0x9> + [ 0] reg5 + range a, 34 + 0x000000000040051a <foo+0xa>.. + 0x0000000000400543 <foo+0x33> + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 39] range 1b, 2d + 0x000000000040052b <foo+0x1b>.. + 0x000000000040053c <foo+0x2c> + [ 0] addr 0x601038 <m> + [ 64] range 1b, 21 + 0x000000000040052b <foo+0x1b>.. + 0x0000000000400530 <foo+0x20> + [ 0] reg5 + [ 87] range 1b, 27 + 0x000000000040052b <foo+0x1b>.. + 0x0000000000400536 <foo+0x26> + [ 0] reg5 + range 29, 2d + 0x0000000000400539 <foo+0x29>.. + 0x000000000040053c <foo+0x2c> + [ 0] reg5 + [ bd] range 21, 27 + 0x0000000000400531 <foo+0x21>.. + 0x0000000000400536 <foo+0x26> + [ 0] reg5 + range 29, 2d + 0x0000000000400539 <foo+0x29>.. + 0x000000000040053c <foo+0x2c> + [ 0] reg5 + [ f3] range 21, 2d + 0x0000000000400531 <foo+0x21>.. + 0x000000000040053c <foo+0x2c> + [ 0] reg5 + [ 116] range 2d, 33 + 0x000000000040053d <foo+0x2d>.. + 0x0000000000400542 <foo+0x32> + [ 0] reg5 + [ 139] range 40, 4f + 0x0000000000400550 <baz>.. + 0x000000000040055e <baz+0xe> + [ 0] reg5 + range 4f, 51 + 0x000000000040055f <baz+0xf>.. + 0x0000000000400560 <baz+0x10> + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 172] range 40, 50 + 0x0000000000400550 <baz>.. + 0x000000000040055f <baz+0xf> + [ 0] reg5 + + CU [ 21c] base: 000000000000000000 + [ 195] range 400410, 400424 + 0x0000000000400410 <main>.. + 0x0000000000400423 <main+0x13> + [ 0] reg5 + range 400424, 400430 + 0x0000000000400424 <main+0x14>.. + 0x000000000040042f <main+0x1f> + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 1ce] range 400410, 400428 + 0x0000000000400410 <main>.. + 0x0000000000400427 <main+0x17> + [ 0] reg4 + range 400428, 400430 + 0x0000000000400428 <main+0x18>.. + 0x000000000040042f <main+0x1f> + [ 0] GNU_entry_value: + [ 0] reg4 + [ 3] stack_value + [ 207] range 400421, 400428 + 0x0000000000400421 <main+0x11>.. + 0x0000000000400427 <main+0x17> + [ 0] reg0 + [ 22a] range 400570, 400578 + 0x0000000000400570 <calc>.. + 0x0000000000400577 <calc+0x7> + [ 0] reg5 + range 400578, 40059b + 0x0000000000400578 <calc+0x8>.. + 0x000000000040059a <calc+0x2a> + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] stack_value + [ 263] range 400588, 400593 + 0x0000000000400588 <calc+0x18>.. + 0x0000000000400592 <calc+0x22> + [ 0] reg0 + [ 286] range 400588, 40058a + 0x0000000000400588 <calc+0x18>.. + 0x0000000000400589 <calc+0x19> + [ 0] reg1 + range 40058a, 40058f + 0x000000000040058a <calc+0x1a>.. + 0x000000000040058e <calc+0x1e> + [ 0] reg5 + range 40058f, 400593 + 0x000000000040058f <calc+0x1f>.. + 0x0000000000400592 <calc+0x22> + [ 0] GNU_entry_value: + [ 0] reg5 + [ 3] deref_size 1 + [ 5] const1u 56 + [ 7] shl + [ 8] const1u 56 + [10] shra + [11] stack_value + [ 2da] range 400588, 40058a + 0x0000000000400588 <calc+0x18>.. + 0x0000000000400589 <calc+0x19> + [ 0] reg1 + range 40058a, 400593 + 0x000000000040058a <calc+0x1a>.. + 0x0000000000400592 <calc+0x22> + [ 0] reg5 +EOF + +# Split DWARF5 variant. Note that the .debug_loclists moved to the .dwo file +# and now uses an index and addrx indirections. +testfiles testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=loc --dwarf-skeleton=testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo <<\EOF + +testfile-hello5.dwo: + + +DWARF section [ 3] '.debug_loclists.dwo' at offset 0x236: +Table at Offset 0x0: + + Length: 125 + DWARF version: 5 + Address size: 8 + Segment size: 0 + Offset entries: 9 + CU [ 14] base: 0x0000000000401160 <foo> + + Offsets starting at 0xc: + [ 0] 0x24 + [ 1] 0x32 + [ 2] 0x39 + [ 3] 0x3f + [ 4] 0x4a + [ 5] 0x55 + [ 6] 0x5b + [ 7] 0x61 + [ 8] 0x6f + + Offset: 30, Index: 24 + startx_length f, a + 0x0000000000401160 <foo>.. + 0x0000000000401169 <foo+0x9>.. + [ 0] reg5 + startx_length 0, 2a + 0x000000000040116a <foo+0xa>.. + 0x0000000000401193 <foo+0x33>.. + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: 3e, Index: 32 + startx_length 11, 12 + 0x000000000040117b <foo+0x1b>.. + 0x000000000040118c <foo+0x2c>.. + [ 0] addrx [18] 0x404038 <m> + end_of_list + + Offset: 45, Index: 39 + startx_length 11, 6 + 0x000000000040117b <foo+0x1b>.. + 0x0000000000401180 <foo+0x20>.. + [ 0] reg5 + end_of_list + + Offset: 4b, Index: 3f + startx_length 11, c + 0x000000000040117b <foo+0x1b>.. + 0x0000000000401186 <foo+0x26>.. + [ 0] reg5 + startx_length 1, 4 + 0x0000000000401189 <foo+0x29>.. + 0x000000000040118c <foo+0x2c>.. + [ 0] reg5 + end_of_list + + Offset: 56, Index: 4a + startx_length 4, 6 + 0x0000000000401181 <foo+0x21>.. + 0x0000000000401186 <foo+0x26>.. + [ 0] reg5 + startx_length 1, 4 + 0x0000000000401189 <foo+0x29>.. + 0x000000000040118c <foo+0x2c>.. + [ 0] reg5 + end_of_list + + Offset: 61, Index: 55 + startx_length 4, c + 0x0000000000401181 <foo+0x21>.. + 0x000000000040118c <foo+0x2c>.. + [ 0] reg5 + end_of_list + + Offset: 67, Index: 5b + startx_length 2, 6 + 0x000000000040118d <foo+0x2d>.. + 0x0000000000401192 <foo+0x32>.. + [ 0] reg5 + end_of_list + + Offset: 6d, Index: 61 + startx_length 9, f + 0x00000000004011a0 <baz>.. + 0x00000000004011ae <baz+0xe>.. + [ 0] reg5 + startx_length 5, 2 + 0x00000000004011af <baz+0xf>.. + 0x00000000004011b0 <baz+0x10>.. + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: 7b, Index: 6f + startx_length 9, 10 + 0x00000000004011a0 <baz>.. + 0x00000000004011af <baz+0xf>.. + [ 0] reg5 + end_of_list + + +testfile-world5.dwo: + + +DWARF section [ 3] '.debug_loclists.dwo' at offset 0x217: +Table at Offset 0x0: + + Length: 128 + DWARF version: 5 + Address size: 8 + Segment size: 0 + Offset entries: 7 + CU [ 14] base: 000000000000000000 + + Offsets starting at 0xc: + [ 0] 0x1c + [ 1] 0x2a + [ 2] 0x38 + [ 3] 0x3e + [ 4] 0x4c + [ 5] 0x52 + [ 6] 0x6d + + Offset: 28, Index: 1c + startx_length 2, 14 + 0x0000000000401060 <main>.. + 0x0000000000401073 <main+0x13>.. + [ 0] reg5 + startx_length 4, c + 0x0000000000401074 <main+0x14>.. + 0x000000000040107f <main+0x1f>.. + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: 36, Index: 2a + startx_length 2, 18 + 0x0000000000401060 <main>.. + 0x0000000000401077 <main+0x17>.. + [ 0] reg4 + startx_length 7, 6 + 0x0000000000401078 <main+0x18>.. + 0x000000000040107d <main+0x1d>.. + [ 0] entry_value: + [ 0] reg4 + [ 3] stack_value + end_of_list + + Offset: 44, Index: 38 + startx_length 3, 7 + 0x0000000000401071 <main+0x11>.. + 0x0000000000401077 <main+0x17>.. + [ 0] reg0 + end_of_list + + Offset: 4a, Index: 3e + startx_length d, 8 + 0x00000000004011c0 <calc>.. + 0x00000000004011c7 <calc+0x7>.. + [ 0] reg5 + startx_length e, 23 + 0x00000000004011c8 <calc+0x8>.. + 0x00000000004011ea <calc+0x2a>.. + [ 0] entry_value: + [ 0] reg5 + [ 3] stack_value + end_of_list + + Offset: 58, Index: 4c + startx_length f, b + 0x00000000004011d8 <calc+0x18>.. + 0x00000000004011e2 <calc+0x22>.. + [ 0] reg0 + end_of_list + + Offset: 5e, Index: 52 + startx_length f, 2 + 0x00000000004011d8 <calc+0x18>.. + 0x00000000004011d9 <calc+0x19>.. + [ 0] reg1 + startx_length 10, 5 + 0x00000000004011da <calc+0x1a>.. + 0x00000000004011de <calc+0x1e>.. + [ 0] reg5 + startx_length 0, 4 + 0x00000000004011df <calc+0x1f>.. + 0x00000000004011e2 <calc+0x22>.. + [ 0] entry_value: + [ 0] reg5 + [ 3] deref_size 1 + [ 5] const1u 56 + [ 7] shl + [ 8] const1u 56 + [10] shra + [11] stack_value + end_of_list + + Offset: 79, Index: 6d + startx_length f, 2 + 0x00000000004011d8 <calc+0x18>.. + 0x00000000004011d9 <calc+0x19>.. + [ 0] reg1 + startx_length 10, 9 + 0x00000000004011da <calc+0x1a>.. + 0x00000000004011e2 <calc+0x22>.. + [ 0] reg5 + end_of_list + +EOF + exit 0 -- 1.8.3.1