From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 69876 invoked by alias); 11 May 2018 12:29:28 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 69862 invoked by uid 89); 11 May 2018 12:29:26 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.4 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=20d, 2cc X-Spam-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 11 May 2018 12:29:20 +0000 Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id A883831F8B53; Fri, 11 May 2018 14:29:16 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id 65A3D413CB3E; Fri, 11 May 2018 14:29:16 +0200 (CEST) From: Mark Wielaard To: elfutils-devel@sourceware.org Cc: Mark Wielaard Subject: [PATCH] readelf: Add DWARF5 .debug_line support. Date: Fri, 11 May 2018 12:29:00 -0000 Message-Id: <1526041736-7697-1-git-send-email-mark@klomp.org> X-Mailer: git-send-email 1.8.3.1 X-Spam-Flag: NO X-IsSubscribed: yes X-SW-Source: 2018-q2/txt/msg00030.txt.bz2 This only changes the parsing of the directory and file name tables. It does this by sharing the printing of (non-CU based) from data from the .debug_macro code. Adding support for printing strx[1234] form data by sharing the code that detects the correct str_offsets_base in libdw. The header format is also cleaned up a bit so that it better lines out. Testcases adjusted and new ones added. Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 7 + libdw/dwarf_formstring.c | 17 -- libdw/libdwP.h | 107 ++++++- src/ChangeLog | 11 + src/readelf.c | 711 +++++++++++++++++++++++++++++++------------ tests/ChangeLog | 6 + tests/run-readelf-line.sh | 712 +++++++++++++++++++++++++++++++++++++++++--- tests/run-readelf-zdebug.sh | 20 +- 8 files changed, 1333 insertions(+), 258 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 86d2b78..efdd927 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,10 @@ +2018-05-09 Mark Wielaard + + * dwarf_formstring.c (__libdw_cu_str_off_base): Moved to... + * libdwP.h (__libdw_cu_str_off_base): ...here. Make static inline. + (str_offsets_base_off): New internal function that also parses + .debug_str_offsets header if necessary. + 2018-05-11 Mark Wielaard * dwarf_siblingof.c (dwarf_siblingof): Don't reference cu till it is diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c index c55c7f0..251784d 100644 --- a/libdw/dwarf_formstring.c +++ b/libdw/dwarf_formstring.c @@ -177,20 +177,3 @@ dwarf_formstring (Dwarf_Attribute *attrp) return (const char *) data->d_buf + off; } INTDEF(dwarf_formstring) - -Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu) -{ - if (cu->str_off_base == (Dwarf_Off) -1) - { - Dwarf_Die cu_die = CUDIE(cu); - Dwarf_Attribute attr; - if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL) - { - Dwarf_Word off; - if (dwarf_formudata (&attr, &off) == 0) - cu->str_off_base = off; - } - } - - return cu->str_off_base; -} diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 7aa290e..da0383f 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -933,8 +933,113 @@ 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); +/* Gets the .debug_str_offsets base offset to use. static inline to + be shared between libdw and eu-readelf. */ +static inline Dwarf_Off +str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu) +{ + /* If we don't have a CU, then find and use the first one in the + debug file (when we support .dwp files, we must actually find the + one matching our "caller" - aka macro or line). If we (now) have + a cu and str_offsets_base attribute, just use that. Otherwise + use the first offset. But we might have to parse the header + first, but only if this is version 5. Assume if all else fails, + this is version 4, without header. */ + + if (cu == NULL && dbg != NULL) + { + Dwarf_CU *first_cu; + if (dwarf_get_units (dbg, NULL, &first_cu, + NULL, NULL, NULL, NULL) == 0) + cu = first_cu; + } + + if (cu != NULL) + { + if (cu->str_off_base == (Dwarf_Off) -1) + { + Dwarf_Die cu_die = CUDIE(cu); + Dwarf_Attribute attr; + if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL) + { + Dwarf_Word off; + if (dwarf_formudata (&attr, &off) == 0) + { + cu->str_off_base = off; + return cu->str_off_base; + } + } + /* For older DWARF simply assume zero (no header). */ + if (cu->version < 5) + { + cu->str_off_base = 0; + return cu->str_off_base; + } + } + else + return cu->str_off_base; + } + + /* No str_offsets_base attribute, we have to assume "zero". + But there could be a header first. */ + Dwarf_Off off = 0; + if (dbg == NULL) + goto no_header; + + Elf_Data *data = dbg->sectiondata[IDX_debug_str_offsets]; + if (data == NULL) + goto no_header; + + const unsigned char *start; + const unsigned char *readp; + const unsigned char *readendp; + start = readp = (const unsigned char *) data->d_buf; + readendp = (const unsigned char *) data->d_buf + data->d_size; + + uint64_t unit_length; + uint16_t version; + + unit_length = read_4ubyte_unaligned_inc (dbg, readp); + if (unlikely (unit_length == 0xffffffff)) + { + if (unlikely (readendp - readp < 8)) + goto no_header; + unit_length = read_8ubyte_unaligned_inc (dbg, readp); + /* In theory the offset size could be different + between CU and str_offsets unit. But we just + ignore that here. */ + } + + /* We need at least 2-bytes (version) + 2-bytes (padding) = + 4 bytes to complete the header. And this unit cannot go + beyond the section data. */ + if (readendp - readp < 4 + || unit_length < 4 + || (uint64_t) (readendp - readp) < unit_length) + goto no_header; + + version = read_2ubyte_unaligned_inc (dbg, readp); + if (version != 5) + goto no_header; + /* padding */ + read_2ubyte_unaligned_inc (dbg, readp); + + off = (Dwarf_Off) (readp - start); + + no_header: + if (cu != NULL) + cu->str_off_base = off; + + return off; +} + + /* Get the string offsets base for the CU, fetches it when not yet set. */ -Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu); +static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu) +{ + return str_offsets_base_off (NULL, cu); +} + /* Given a file descriptor, dir and file returns a full path. If the file is absolute (starts with a /) a copy of file is returned. If diff --git a/src/ChangeLog b/src/ChangeLog index a6ee30b..4208b52 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,14 @@ +2018-05-09 Mark Wielaard + + * readelf.c (dwarf_line_content_description_string): New function. + (dwarf_line_content_description_name): Likewise. + (print_bytes): Likewise. + (print_form_data): Likewise. Based on code taken from... + (print_debug_macro_section): ...here. Now calls print_form_data + and str_offsets_base_off. + (print_debug_line_section): Parse DWARF5 header, directory and file + name tables. + 2018-04-28 Mark Wielaard * readelf.c (print_debug): If .debug_info is needed implicitly by diff --git a/src/readelf.c b/src/readelf.c index e44b2a3..ba4c1d7 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -1,7 +1,6 @@ /* Print information from ELF file in human-readable form. - Copyright (C) 1999-2017 Red Hat, Inc. + Copyright (C) 1999-2018 Red Hat, Inc. This file is part of elfutils. - Written by Ulrich Drepper , 1999. This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3975,6 +3974,20 @@ dwarf_unit_string (unsigned int type) } +static const char * +dwarf_line_content_description_string (unsigned int kind) +{ + switch (kind) + { +#define DWARF_ONE_KNOWN_DW_LNCT(NAME, CODE) case CODE: return #NAME; + DWARF_ALL_KNOWN_DW_LNCT +#undef DWARF_ONE_KNOWN_DW_LNCT + default: + return NULL; + } +} + + /* Used by all dwarf_foo_name functions. */ static const char * string_or_unknown (const char *known, unsigned int code, @@ -4122,6 +4135,15 @@ dwarf_unit_name (unsigned int type) } +static const char * +dwarf_line_content_description_name (unsigned int kind) +{ + const char *ret = dwarf_line_content_description_string (kind); + return string_or_unknown (ret, kind, DW_LNCT_lo_user, DW_LNCT_hi_user, + false); +} + + static void print_block (size_t n, const void *block) { @@ -4139,6 +4161,17 @@ print_block (size_t n, const void *block) } static void +print_bytes (size_t n, const unsigned char *bytes) +{ + while (n-- > 0) + { + printf ("%02x", *bytes++); + if (n > 0) + printf (" "); + } +} + +static void print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, unsigned int vers, unsigned int addrsize, unsigned int offset_size, struct Dwarf_CU *cu, Dwarf_Word len, const unsigned char *data) @@ -6747,6 +6780,230 @@ print_decoded_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, } +/* Print the value of a form. + Returns new value of readp, or readendp on failure. */ +static const unsigned char * +print_form_data (Dwarf *dbg, int form, const unsigned char *readp, + const unsigned char *readendp, unsigned int offset_len, + Dwarf_Off str_offsets_base) +{ + Dwarf_Word val; + unsigned char *endp; + Elf_Data *data; + char *str; + switch (form) + { + case DW_FORM_data1: + if (readendp - readp < 1) + { + invalid_data: + error (0, 0, "invalid data"); + return readendp; + } + val = *readp++; + printf (" %" PRIx8, (unsigned int) val); + break; + + case DW_FORM_data2: + if (readendp - readp < 2) + goto invalid_data; + val = read_2ubyte_unaligned_inc (dbg, readp); + printf(" %" PRIx16, (unsigned int) val); + break; + + case DW_FORM_data4: + if (readendp - readp < 4) + goto invalid_data; + val = read_4ubyte_unaligned_inc (dbg, readp); + printf (" %" PRIx32, (unsigned int) val); + break; + + case DW_FORM_data8: + if (readendp - readp < 8) + goto invalid_data; + val = read_8ubyte_unaligned_inc (dbg, readp); + printf (" %" PRIx64, val); + break; + + case DW_FORM_sdata: + if (readendp - readp < 1) + goto invalid_data; + get_sleb128 (val, readp, readendp); + printf (" %" PRIx64, val); + break; + + case DW_FORM_udata: + if (readendp - readp < 1) + goto invalid_data; + get_uleb128 (val, readp, readendp); + printf (" %" PRIx64, val); + break; + + case DW_FORM_block: + if (readendp - readp < 1) + goto invalid_data; + get_uleb128 (val, readp, readendp); + if (readendp - readp < (ptrdiff_t) val) + goto invalid_data; + print_bytes (val, readp); + readp += val; + break; + + case DW_FORM_block1: + if (readendp - readp < 1) + goto invalid_data; + val = *readp++; + if (readendp - readp < (ptrdiff_t) val) + goto invalid_data; + print_bytes (val, readp); + readp += val; + break; + + case DW_FORM_block2: + if (readendp - readp < 2) + goto invalid_data; + val = read_2ubyte_unaligned_inc (dbg, readp); + if (readendp - readp < (ptrdiff_t) val) + goto invalid_data; + print_bytes (val, readp); + readp += val; + break; + + case DW_FORM_block4: + if (readendp - readp < 2) + goto invalid_data; + val = read_4ubyte_unaligned_inc (dbg, readp); + if (readendp - readp < (ptrdiff_t) val) + goto invalid_data; + print_bytes (val, readp); + readp += val; + break; + + case DW_FORM_data16: + if (readendp - readp < 16) + goto invalid_data; + print_bytes (16, readp); + readp += 16; + break; + + case DW_FORM_flag: + if (readendp - readp < 1) + goto invalid_data; + val = *readp++; + printf ("%s", val != 0 ? gettext ("yes") : gettext ("no")); + break; + + case DW_FORM_string: + endp = memchr (readp, '\0', readendp - readp); + if (endp == NULL) + goto invalid_data; + printf ("%s", readp); + readp = endp + 1; + break; + + case DW_FORM_strp: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: + if (readendp - readp < offset_len) + goto invalid_data; + if (offset_len == 8) + val = read_8ubyte_unaligned_inc (dbg, readp); + else + val = read_4ubyte_unaligned_inc (dbg, readp); + if (form == DW_FORM_strp) + data = dbg->sectiondata[IDX_debug_str]; + else if (form == DW_FORM_line_strp) + data = dbg->sectiondata[IDX_debug_line_str]; + else /* form == DW_FORM_strp_sup */ + { + Dwarf *alt = dwarf_getalt (dbg); + data = alt != NULL ? alt->sectiondata[IDX_debug_str] : NULL; + } + if (data == NULL || val >= data->d_size + || memchr (data->d_buf + val, '\0', data->d_size - val) == NULL) + str = "???"; + else + str = (char *) data->d_buf + val; + printf ("%s (%" PRIu64 ")", str, val); + break; + + case DW_FORM_sec_offset: + if (readendp - readp < offset_len) + goto invalid_data; + if (offset_len == 8) + val = read_8ubyte_unaligned_inc (dbg, readp); + else + val = read_4ubyte_unaligned_inc (dbg, readp); + printf ("[%" PRIx64 "]", val); + break; + + case DW_FORM_strx: + if (readendp - readp < 1) + goto invalid_data; + get_uleb128 (val, readp, readendp); + strx_val: + data = dbg->sectiondata[IDX_debug_str_offsets]; + if (data == NULL + || data->d_size - str_offsets_base < val) + str = "???"; + else + { + readp = data->d_buf + str_offsets_base + val; + readendp = data->d_buf + data->d_size; + if (readendp - readp < offset_len) + str = "???"; + else + { + Dwarf_Off idx; + if (offset_len == 8) + idx = read_8ubyte_unaligned_inc (dbg, readp); + else + idx = read_4ubyte_unaligned_inc (dbg, readp); + + data = dbg->sectiondata[IDX_debug_str]; + if (data == NULL || idx >= data->d_size + || memchr (data->d_buf + idx, '\0', + data->d_size - idx) == NULL) + str = "???"; + else + str = (char *) data->d_buf + idx; + } + } + printf ("%s (%" PRIu64 ")", str, val); + break; + + case DW_FORM_strx1: + if (readendp - readp < 1) + goto invalid_data; + val = *readp; + goto strx_val; + + case DW_FORM_strx2: + if (readendp - readp < 2) + goto invalid_data; + val = read_2ubyte_unaligned (dbg, readp); + goto strx_val; + + case DW_FORM_strx3: + if (readendp - readp < 3) + goto invalid_data; + val = read_3ubyte_unaligned (dbg, readp); + goto strx_val; + + case DW_FORM_strx4: + if (readendp - readp < 4) + goto invalid_data; + val = read_4ubyte_unaligned (dbg, readp); + goto strx_val; + + default: + error (0, 0, gettext ("unknown form: %s"), dwarf_form_name (form)); + return readendp; + } + + return readp; +} + static void print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) @@ -6803,35 +7060,67 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, } /* Check whether we have enough room in the section. */ - if (unlikely (unit_length > (size_t) (lineendp - linep) - || unit_length < 2 + length + 5 * 1)) + if (unlikely (unit_length > (size_t) (lineendp - linep))) goto invalid_data; lineendp = linep + unit_length; /* The next element of the header is the version identifier. */ + if ((size_t) (lineendp - linep) < 2) + goto invalid_data; uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); + size_t address_size + = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8; + unsigned char segment_selector_size = 0; + if (version > 4) + { + if ((size_t) (lineendp - linep) < 2) + goto invalid_data; + address_size = *linep++; + segment_selector_size = *linep++; + } + /* Next comes the header length. */ Dwarf_Word header_length; if (length == 4) - header_length = read_4ubyte_unaligned_inc (dbg, linep); + { + if ((size_t) (lineendp - linep) < 4) + goto invalid_data; + header_length = read_4ubyte_unaligned_inc (dbg, linep); + } else - header_length = read_8ubyte_unaligned_inc (dbg, linep); - //const unsigned char *header_start = linep; + { + if ((size_t) (lineendp - linep) < 8) + goto invalid_data; + header_length = read_8ubyte_unaligned_inc (dbg, linep); + } /* Next the minimum instruction length. */ + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; uint_fast8_t minimum_instr_len = *linep++; /* Next the maximum operations per instruction, in version 4 format. */ - uint_fast8_t max_ops_per_instr = version < 4 ? 1 : *linep++; + uint_fast8_t max_ops_per_instr; + if (version < 4) + max_ops_per_instr = 1; + else + { + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + max_ops_per_instr = *linep++; + } + + /* We need at least 4 more bytes. */ + if ((size_t) (lineendp - linep) < 4) + goto invalid_data; - /* Then the flag determining the default value of the is_stmt - register. */ + /* Then the flag determining the default value of the is_stmt + register. */ uint_fast8_t default_is_stmt = *linep++; /* Now the line base. */ - int_fast8_t line_base = *((const int_fast8_t *) linep); - ++linep; + int_fast8_t line_base = *linep++; /* And the line range. */ uint_fast8_t line_range = *linep++; @@ -6841,22 +7130,49 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, /* Print what we got so far. */ printf (gettext ("\n" - " Length: %" PRIu64 "\n" - " DWARF version: %" PRIuFAST16 "\n" - " Prologue length: %" PRIu64 "\n" - " Minimum instruction length: %" PRIuFAST8 "\n" - " Maximum operations per instruction: %" PRIuFAST8 "\n" - " Initial value if '%s': %" PRIuFAST8 "\n" - " Line base: %" PRIdFAST8 "\n" - " Line range: %" PRIuFAST8 "\n" - " Opcode base: %" PRIuFAST8 "\n" + " Length: %" PRIu64 "\n" + " DWARF version: %" PRIuFAST16 "\n" + " Prologue length: %" PRIu64 "\n" + " Address size: %zd\n" + " Segment selector size: %zd\n" + " Min instruction length: %" PRIuFAST8 "\n" + " Max operations per instruction: %" PRIuFAST8 "\n" + " Initial value if 'is_stmt': %" PRIuFAST8 "\n" + " Line base: %" PRIdFAST8 "\n" + " Line range: %" PRIuFAST8 "\n" + " Opcode base: %" PRIuFAST8 "\n" "\n" "Opcodes:\n"), (uint64_t) unit_length, version, (uint64_t) header_length, + address_size, (size_t) segment_selector_size, minimum_instr_len, max_ops_per_instr, - "is_stmt", default_is_stmt, line_base, + default_is_stmt, line_base, line_range, opcode_base); + if (version < 2 || version > 5) + { + error (0, 0, gettext ("cannot handle .debug_line version: %u\n"), + (unsigned int) version); + linep = lineendp; + continue; + } + + if (address_size != 4 && address_size != 8) + { + error (0, 0, gettext ("cannot handle address size: %u\n"), + (unsigned int) address_size); + linep = lineendp; + continue; + } + + if (segment_selector_size != 0) + { + error (0, 0, gettext ("cannot handle segment selector size: %u\n"), + (unsigned int) segment_selector_size); + linep = lineendp; + continue; + } + if (unlikely (linep + opcode_base - 1 >= lineendp)) { invalid_unit: @@ -6881,59 +7197,178 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, (int) linep[cnt - 1]), opcode_base_l10, cnt, linep[cnt - 1]); linep += opcode_base - 1; + if (unlikely (linep >= lineendp)) goto invalid_unit; + Dwarf_Off str_offsets_base = str_offsets_base_off (dbg, NULL); + puts (gettext ("\nDirectory table:")); - while (*linep != 0) + if (version > 4) { - unsigned char *endp = memchr (linep, '\0', lineendp - linep); - if (unlikely (endp == NULL)) - goto invalid_unit; + struct encpair { uint16_t desc; uint16_t form; }; + struct encpair enc[256]; + + printf (gettext (" [")); + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + unsigned char directory_entry_format_count = *linep++; + for (int i = 0; i < directory_entry_format_count; i++) + { + uint16_t desc, form; + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + get_uleb128 (desc, linep, lineendp); + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + get_uleb128 (form, linep, lineendp); + + enc[i].desc = desc; + enc[i].form = form; + + printf ("%s(%s)", + dwarf_line_content_description_name (desc), + dwarf_form_name (form)); + if (i + 1 < directory_entry_format_count) + printf (", "); + } + printf ("]\n"); + + uint64_t directories_count; + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + get_uleb128 (directories_count, linep, lineendp); - printf (" %s\n", (char *) linep); + if (directory_entry_format_count == 0 + && directories_count != 0) + goto invalid_data; + + for (uint64_t i = 0; i < directories_count; i++) + { + printf (" %-5lu ", i); + for (int j = 0; j < directory_entry_format_count; j++) + { + linep = print_form_data (dbg, enc[j].form, + linep, lineendp, length, + str_offsets_base); + if (j + 1 < directory_entry_format_count) + printf (", "); + } + printf ("\n"); + } + } + else + { + while (*linep != 0) + { + unsigned char *endp = memchr (linep, '\0', lineendp - linep); + if (unlikely (endp == NULL)) + goto invalid_unit; - linep = endp + 1; + printf (" %s\n", (char *) linep); + + linep = endp + 1; + } + /* Skip the final NUL byte. */ + ++linep; } - /* Skip the final NUL byte. */ - ++linep; if (unlikely (linep >= lineendp)) goto invalid_unit; - puts (gettext ("\nFile name table:\n" - " Entry Dir Time Size Name")); - for (unsigned int cnt = 1; *linep != 0; ++cnt) + + puts (gettext ("\nFile name table:")); + if (version > 4) { - /* First comes the file name. */ - char *fname = (char *) linep; - unsigned char *endp = memchr (fname, '\0', lineendp - linep); - if (unlikely (endp == NULL)) - goto invalid_unit; - linep = endp + 1; + struct encpair { uint16_t desc; uint16_t form; }; + struct encpair enc[256]; - /* Then the index. */ - unsigned int diridx; - if (lineendp - linep < 1) - goto invalid_unit; - get_uleb128 (diridx, linep, lineendp); + printf (gettext (" [")); + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + unsigned char file_name_format_count = *linep++; + for (int i = 0; i < file_name_format_count; i++) + { + uint64_t desc, form; + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + get_uleb128 (desc, linep, lineendp); + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + get_uleb128 (form, linep, lineendp); - /* Next comes the modification time. */ - unsigned int mtime; - if (lineendp - linep < 1) - goto invalid_unit; - get_uleb128 (mtime, linep, lineendp); + if (! libdw_valid_user_form (form)) + goto invalid_data; - /* Finally the length of the file. */ - unsigned int fsize; - if (lineendp - linep < 1) - goto invalid_unit; - get_uleb128 (fsize, linep, lineendp); + enc[i].desc = desc; + enc[i].form = form; - printf (" %-5u %-5u %-9u %-9u %s\n", - cnt, diridx, mtime, fsize, fname); + printf ("%s(%s)", + dwarf_line_content_description_name (desc), + dwarf_form_name (form)); + if (i + 1 < file_name_format_count) + printf (", "); + } + printf ("]\n"); + + uint64_t file_name_count; + if ((size_t) (lineendp - linep) < 1) + goto invalid_data; + get_uleb128 (file_name_count, linep, lineendp); + + if (file_name_format_count == 0 + && file_name_count != 0) + goto invalid_data; + + for (uint64_t i = 0; i < file_name_count; i++) + { + printf (" %-5lu ", i); + for (int j = 0; j < file_name_format_count; j++) + { + linep = print_form_data (dbg, enc[j].form, + linep, lineendp, length, + str_offsets_base); + if (j + 1 < file_name_format_count) + printf (", "); + } + printf ("\n"); + } + } + else + { + puts (gettext (" Entry Dir Time Size Name")); + for (unsigned int cnt = 1; *linep != 0; ++cnt) + { + /* First comes the file name. */ + char *fname = (char *) linep; + unsigned char *endp = memchr (fname, '\0', lineendp - linep); + if (unlikely (endp == NULL)) + goto invalid_unit; + linep = endp + 1; + + /* Then the index. */ + unsigned int diridx; + if (lineendp - linep < 1) + goto invalid_unit; + get_uleb128 (diridx, linep, lineendp); + + /* Next comes the modification time. */ + unsigned int mtime; + if (lineendp - linep < 1) + goto invalid_unit; + get_uleb128 (mtime, linep, lineendp); + + /* Finally the length of the file. */ + unsigned int fsize; + if (lineendp - linep < 1) + goto invalid_unit; + get_uleb128 (fsize, linep, lineendp); + + printf (" %-5u %-5u %-9u %-9u %s\n", + cnt, diridx, mtime, fsize, fname); + } + /* Skip the final NUL byte. */ + ++linep; } - /* Skip the final NUL byte. */ - ++linep; puts (gettext ("\nLine number statements:")); Dwarf_Word address = 0; @@ -6941,10 +7376,6 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, size_t line = 1; uint_fast8_t is_stmt = default_is_stmt; - /* Default address value, in case we do not find the CU. */ - size_t address_size - = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8; - /* Determine the CU this block is for. */ Dwarf_Off cuoffset; Dwarf_Off ncuoffset = 0; @@ -7721,6 +8152,18 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)), line_offset); } + struct mac_culist *cu = NULL; + if (line_offset != (Dwarf_Off) -1) + { + cu = culist; + while (cu != NULL && line_offset != cu->offset) + cu = cu->next; + } + + Dwarf_Off str_offsets_base = str_offsets_base_off (dbg, (cu != NULL + ? cu->die.cu + : NULL)); + const unsigned char *vendor[DW_MACRO_hi_user - DW_MACRO_lo_user]; memset (vendor, 0, sizeof vendor); if (flag & 0x04) @@ -7804,22 +8247,16 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)), /* Find the CU DIE that matches this line offset. */ const char *fname = "???"; - if (line_offset != (Dwarf_Off) -1) + if (cu != NULL) { - struct mac_culist *cu = culist; - while (cu != NULL && line_offset != cu->offset) - cu = cu->next; - if (cu != NULL) - { - if (cu->files == NULL - && dwarf_getsrcfiles (&cu->die, &cu->files, - NULL) != 0) - cu->files = (Dwarf_Files *) -1l; - - if (cu->files != (Dwarf_Files *) -1l) - fname = (dwarf_filesrc (cu->files, u128_2, - NULL, NULL) ?: "???"); - } + if (cu->files == NULL + && dwarf_getsrcfiles (&cu->die, &cu->files, + NULL) != 0) + cu->files = (Dwarf_Files *) -1l; + + if (cu->files != (Dwarf_Files *) -1l) + fname = (dwarf_filesrc (cu->files, u128_2, + NULL, NULL) ?: "???"); } printf ("%*sstart_file %u, [%u] %s\n", level, "", u128, u128_2, fname); @@ -7965,125 +8402,11 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)), while (args > 0) { unsigned int form = *op_desc++; - Dwarf_Word val; - switch (form) - { - case DW_FORM_data1: - if (readp + 1 > readendp) - goto invalid_data; - val = *readp++; - printf (" %" PRIx8, (unsigned int) val); - break; - - case DW_FORM_data2: - if (readp + 2 > readendp) - goto invalid_data; - val = read_2ubyte_unaligned_inc (dbg, readp); - printf(" %" PRIx16, (unsigned int) val); - break; - - case DW_FORM_data4: - if (readp + 4 > readendp) - goto invalid_data; - val = read_4ubyte_unaligned_inc (dbg, readp); - printf (" %" PRIx32, (unsigned int) val); - break; - - case DW_FORM_data8: - if (readp + 8 > readendp) - goto invalid_data; - val = read_8ubyte_unaligned_inc (dbg, readp); - printf (" %" PRIx64, val); - break; - - case DW_FORM_sdata: - get_sleb128 (val, readp, readendp); - printf (" %" PRIx64, val); - break; - - case DW_FORM_udata: - get_uleb128 (val, readp, readendp); - printf (" %" PRIx64, val); - break; - - case DW_FORM_block: - get_uleb128 (val, readp, readendp); - printf (" block[%" PRIu64 "]", val); - if (readp + val > readendp) - goto invalid_data; - readp += val; - break; - - case DW_FORM_block1: - if (readp + 1 > readendp) - goto invalid_data; - val = *readp++; - printf (" block[%" PRIu64 "]", val); - if (readp + val > readendp) - goto invalid_data; - break; - - case DW_FORM_block2: - if (readp + 2 > readendp) - goto invalid_data; - val = read_2ubyte_unaligned_inc (dbg, readp); - printf (" block[%" PRIu64 "]", val); - if (readp + val > readendp) - goto invalid_data; - break; - - case DW_FORM_block4: - if (readp + 2 > readendp) - goto invalid_data; - val =read_4ubyte_unaligned_inc (dbg, readp); - printf (" block[%" PRIu64 "]", val); - if (readp + val > readendp) - goto invalid_data; - break; - - case DW_FORM_flag: - if (readp + 1 > readendp) - goto invalid_data; - val = *readp++; - printf (" %s", val != 0 ? gettext ("yes") : gettext ("no")); - break; - - case DW_FORM_string: - endp = memchr (readp, '\0', readendp - readp); - if (endp == NULL) - goto invalid_data; - printf (" %s", readp); - readp = endp + 1; - break; - - case DW_FORM_strp: - if (readp + offset_len > readendp) - goto invalid_data; - if (offset_len == 8) - val = read_8ubyte_unaligned_inc (dbg, readp); - else - val = read_4ubyte_unaligned_inc (dbg, readp); - printf (" %s", dwarf_getstring (dbg, val, NULL)); - break; - - case DW_FORM_sec_offset: - if (readp + offset_len > readendp) - goto invalid_data; - if (offset_len == 8) - val = read_8ubyte_unaligned_inc (dbg, readp); - else - val = read_4ubyte_unaligned_inc (dbg, readp); - printf (" %" PRIx64, val); - break; - - default: - error (0, 0, gettext ("vendor opcode not verified?")); - return; - } - + print_form_data (dbg, form, readp, readendp, offset_len, + str_offsets_base); args--; if (args > 0) - putchar_unlocked (','); + printf (", "); } putchar_unlocked ('\n'); } diff --git a/tests/ChangeLog b/tests/ChangeLog index b236ee7..16011c8 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2018-05-09 Mark Wielaard + + * run-readelf-zdebug.sh: Adjust test output for new header layout. + * run-readelf-line.sh: Likewise. Add new tests for testfile-dwarf-4 + and testfile-dwarf-5. + 2018-05-11 Mark Wielaard * Makefile.am (check_PROGRAMS): Add get-units-invalid. diff --git a/tests/run-readelf-line.sh b/tests/run-readelf-line.sh index b08752e..a95e6aa 100755 --- a/tests/run-readelf-line.sh +++ b/tests/run-readelf-line.sh @@ -1,5 +1,5 @@ #! /bin/sh -# Copyright (C) 2013 Red Hat, Inc. +# Copyright (C) 2013, 2018 Red Hat, Inc. # This file is part of elfutils. # # This file is free software; you can redistribute it and/or modify @@ -28,15 +28,17 @@ DWARF section [30] '.debug_line' at offset 0x15f6: Table at offset 0: - Length: 83 - DWARF version: 2 - Prologue length: 43 - Minimum instruction length: 1 - Maximum operations per instruction: 1 - Initial value if 'is_stmt': 1 - Line base: -5 - Line range: 14 - Opcode base: 13 + Length: 83 + DWARF version: 2 + Prologue length: 43 + Address size: 4 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -5 + Line range: 14 + Opcode base: 13 Opcodes: [ 1] 0 arguments @@ -83,15 +85,17 @@ Line number statements: Table at offset 87: - Length: 72 - DWARF version: 2 - Prologue length: 28 - Minimum instruction length: 1 - Maximum operations per instruction: 1 - Initial value if 'is_stmt': 1 - Line base: -5 - Line range: 14 - Opcode base: 13 + Length: 72 + DWARF version: 2 + Prologue length: 28 + Address size: 4 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -5 + Line range: 14 + Opcode base: 13 Opcodes: [ 1] 0 arguments @@ -133,15 +137,17 @@ Line number statements: Table at offset 163: - Length: 106 - DWARF version: 2 - Prologue length: 43 - Minimum instruction length: 1 - Maximum operations per instruction: 1 - Initial value if 'is_stmt': 1 - Line base: -5 - Line range: 14 - Opcode base: 13 + Length: 106 + DWARF version: 2 + Prologue length: 43 + Address size: 4 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -5 + Line range: 14 + Opcode base: 13 Opcodes: [ 1] 0 arguments @@ -280,15 +286,17 @@ DWARF section [29] '.debug_line' at offset 0xdf6: Table at offset 0: - Length: 69 - DWARF version: 2 - Prologue length: 30 - Minimum instruction length: 4 - Maximum operations per instruction: 1 - Initial value if 'is_stmt': 1 - Line base: -5 - Line range: 14 - Opcode base: 13 + Length: 69 + DWARF version: 2 + Prologue length: 30 + Address size: 8 + Segment selector size: 0 + Min instruction length: 4 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -5 + Line range: 14 + Opcode base: 13 Opcodes: [ 1] 0 arguments @@ -508,4 +516,634 @@ DWARF section [29] '.debug_line' at offset 0x171f: EOF +# After discarding the different offsets in the line number statements, +# the remaining difference between 4 and 5 is (besides the header/length) +# Just the representation of the directory and line tables: + +# Directory table: +# - /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include +# + [path(line_strp)] +# + 0 /var/tmp/hello (90) +# + 1 /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include (17) +# +# File name table: +# - Entry Dir Time Size Name +# - 1 0 0 0 hello.c +# - 2 0 0 0 hello.h +# - 3 1 0 0 stddef.h +# + [path(line_strp), directory_index(data1)] +# + 0 hello.c (9), 0 +# + 1 hello.c (9), 0 +# + 2 hello.h (82), 0 +# + 3 stddef.h (0), 1 +# +# Directory table: +# - /usr/include +# + [path(line_strp)] +# + 0 /var/tmp/hello (90) +# + 1 /usr/include (122) +# +# File name table: +# - Entry Dir Time Size Name +# - 1 0 0 0 world.c +# - 2 0 0 0 hello.h +# - 3 1 0 0 stdlib.h +# + [path(line_strp), directory_index(data1)] +# + 0 world.c (114), 0 +# + 1 world.c (114), 0 +# + 2 hello.h (82), 0 +# + 3 stdlib.h (105), 1 + +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=line testfile-dwarf-4 << \EOF + +DWARF section [29] '.debug_line' at offset 0x1734: + +Table at offset 0: + + Length: 608 + DWARF version: 4 + Prologue length: 119 + Address size: 8 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -10 + Line range: 242 + Opcode base: 13 + +Opcodes: + [ 1] 0 arguments + [ 2] 1 argument + [ 3] 1 argument + [ 4] 1 argument + [ 5] 1 argument + [ 6] 0 arguments + [ 7] 0 arguments + [ 8] 0 arguments + [ 9] 1 argument + [10] 0 arguments + [11] 0 arguments + [12] 1 argument + +Directory table: + /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include + +File name table: + Entry Dir Time Size Name + 1 0 0 0 hello.c + 2 0 0 0 hello.h + 3 1 0 0 stddef.h + +Line number statements: + [ 81] extended opcode 2: set address to 0x400510 + [ 8c] special opcode 43: address+0 = 0x400510 , line+20 = 21 + [ 8d] set column to 1 + [ 8f] extended opcode 2: set address to 0x400510 + [ 9a] special opcode 24: address+0 = 0x400510 , line+1 = 22 + [ 9b] set column to 3 + [ 9d] extended opcode 2: set address to 0x400510 + [ a8] set 'is_stmt' to 0 + [ a9] copy + [ aa] set column to 6 + [ ac] extended opcode 2: set address to 0x400514 + [ b7] special opcode 26: address+0 = 0x400514 , line+3 = 25 + [ b8] set column to 34 + [ ba] extended opcode 2: set address to 0x40051a + [ c5] set 'is_stmt' to 1 + [ c6] copy + [ c7] set column to 3 + [ c9] extended opcode 2: set address to 0x40051a + [ d4] set 'is_stmt' to 0 + [ d5] copy + [ d6] set column to 34 + [ d8] extended opcode 2: set address to 0x40051e + [ e3] special opcode 24: address+0 = 0x40051e , line+1 = 26 + [ e4] set column to 1 + [ e6] extended opcode 2: set address to 0x400528 + [ f1] extended opcode 4: set discriminator to 1 + [ f5] special opcode 22: address+0 = 0x400528 , line-1 = 25 + [ f6] set column to 18 + [ f8] extended opcode 2: set address to 0x40052b + [ 103] set file to 2 + [ 105] set 'is_stmt' to 1 + [ 106] advance line by constant -18 to 7 + [ 108] copy + [ 109] set column to 3 + [ 10b] extended opcode 2: set address to 0x40052b + [ 116] special opcode 25: address+0 = 0x40052b , line+2 = 9 + [ 117] set column to 3 + [ 119] extended opcode 2: set address to 0x40052b + [ 124] set 'is_stmt' to 0 + [ 125] copy + [ 126] set column to 6 + [ 128] extended opcode 2: set address to 0x40052f + [ 133] extended opcode 4: set discriminator to 0 + [ 137] set 'is_stmt' to 1 + [ 138] special opcode 24: address+0 = 0x40052f , line+1 = 10 + [ 139] set column to 5 + [ 13b] extended opcode 2: set address to 0x40052f + [ 146] set 'is_stmt' to 0 + [ 147] copy + [ 148] set column to 7 + [ 14a] extended opcode 2: set address to 0x400531 + [ 155] set 'is_stmt' to 1 + [ 156] special opcode 25: address+0 = 0x400531 , line+2 = 12 + [ 157] set column to 3 + [ 159] extended opcode 2: set address to 0x400531 + [ 164] set file to 1 + [ 166] special opcode 21: address+0 = 0x400531 , line-2 = 10 + [ 167] set column to 3 + [ 169] extended opcode 2: set address to 0x400531 + [ 174] special opcode 25: address+0 = 0x400531 , line+2 = 12 + [ 175] set column to 3 + [ 177] extended opcode 2: set address to 0x400531 + [ 182] set 'is_stmt' to 0 + [ 183] copy + [ 184] set column to 6 + [ 186] extended opcode 2: set address to 0x400535 + [ 191] set 'is_stmt' to 1 + [ 192] special opcode 24: address+0 = 0x400535 , line+1 = 13 + [ 193] set column to 5 + [ 195] extended opcode 2: set address to 0x400535 + [ 1a0] set 'is_stmt' to 0 + [ 1a1] copy + [ 1a2] set column to 7 + [ 1a4] extended opcode 2: set address to 0x400539 + [ 1af] set 'is_stmt' to 1 + [ 1b0] special opcode 25: address+0 = 0x400539 , line+2 = 15 + [ 1b1] set column to 3 + [ 1b3] extended opcode 2: set address to 0x400539 + [ 1be] special opcode 30: address+0 = 0x400539 , line+7 = 22 + [ 1bf] set column to 3 + [ 1c1] extended opcode 2: set address to 0x400539 + [ 1cc] set 'is_stmt' to 0 + [ 1cd] copy + [ 1ce] set column to 6 + [ 1d0] extended opcode 2: set address to 0x40053d + [ 1db] set 'is_stmt' to 1 + [ 1dc] special opcode 24: address+0 = 0x40053d , line+1 = 23 + [ 1dd] set column to 5 + [ 1df] extended opcode 2: set address to 0x40053d + [ 1ea] set 'is_stmt' to 0 + [ 1eb] copy + [ 1ec] set column to 12 + [ 1ee] extended opcode 2: set address to 0x400550 + [ 1f9] set 'is_stmt' to 1 + [ 1fa] advance line by constant -14 to 9 + [ 1fc] copy + [ 1fd] set column to 1 + [ 1ff] extended opcode 2: set address to 0x400550 + [ 20a] special opcode 24: address+0 = 0x400550 , line+1 = 10 + [ 20b] set column to 3 + [ 20d] extended opcode 2: set address to 0x400550 + [ 218] special opcode 25: address+0 = 0x400550 , line+2 = 12 + [ 219] set column to 3 + [ 21b] extended opcode 2: set address to 0x400550 + [ 226] set 'is_stmt' to 0 + [ 227] copy + [ 228] set column to 9 + [ 22a] extended opcode 2: set address to 0x400556 + [ 235] special opcode 24: address+0 = 0x400556 , line+1 = 13 + [ 236] set column to 7 + [ 238] extended opcode 2: set address to 0x40055f + [ 243] set 'is_stmt' to 1 + [ 244] special opcode 25: address+0 = 0x40055f , line+2 = 15 + [ 245] set column to 3 + [ 247] extended opcode 2: set address to 0x40055f + [ 252] set 'is_stmt' to 0 + [ 253] copy + [ 254] set column to 7 + [ 256] extended opcode 2: set address to 0x400561 + [ 261] extended opcode 1: end of sequence + +Table at offset 612: + + Length: 450 + DWARF version: 4 + Prologue length: 67 + Address size: 8 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -10 + Line range: 242 + Opcode base: 13 + +Opcodes: + [ 1] 0 arguments + [ 2] 1 argument + [ 3] 1 argument + [ 4] 1 argument + [ 5] 1 argument + [ 6] 0 arguments + [ 7] 0 arguments + [ 8] 0 arguments + [ 9] 1 argument + [10] 0 arguments + [11] 0 arguments + [12] 1 argument + +Directory table: + /usr/include + +File name table: + Entry Dir Time Size Name + 1 0 0 0 world.c + 2 0 0 0 hello.h + 3 1 0 0 stdlib.h + +Line number statements: + [ 2b1] extended opcode 2: set address to 0x400410
+ [ 2bc] special opcode 37: address+0 = 0x400410
, line+14 = 15 + [ 2bd] set column to 1 + [ 2bf] extended opcode 2: set address to 0x400410
+ [ 2ca] special opcode 24: address+0 = 0x400410
, line+1 = 16 + [ 2cb] set column to 3 + [ 2cd] extended opcode 2: set address to 0x400410
+ [ 2d8] special opcode 24: address+0 = 0x400410
, line+1 = 17 + [ 2d9] set column to 3 + [ 2db] extended opcode 2: set address to 0x400410
+ [ 2e6] set 'is_stmt' to 0 + [ 2e7] special opcode 21: address+0 = 0x400410
, line-2 = 15 + [ 2e8] set column to 1 + [ 2ea] extended opcode 2: set address to 0x400419 + [ 2f5] special opcode 25: address+0 = 0x400419 , line+2 = 17 + [ 2f6] set column to 6 + [ 2f8] extended opcode 2: set address to 0x40041e + [ 303] set 'is_stmt' to 1 + [ 304] special opcode 24: address+0 = 0x40041e , line+1 = 18 + [ 305] set column to 5 + [ 307] extended opcode 2: set address to 0x40041e + [ 312] set 'is_stmt' to 0 + [ 313] copy + [ 314] set column to 7 + [ 316] extended opcode 2: set address to 0x400421 + [ 321] set 'is_stmt' to 1 + [ 322] special opcode 27: address+0 = 0x400421 , line+4 = 22 + [ 323] set column to 3 + [ 325] extended opcode 2: set address to 0x400430 <_start> + [ 330] extended opcode 1: end of sequence + [ 333] extended opcode 2: set address to 0x400570 + [ 33e] special opcode 28: address+0 = 0x400570 , line+5 = 6 + [ 33f] set column to 1 + [ 341] extended opcode 2: set address to 0x400570 + [ 34c] special opcode 24: address+0 = 0x400570 , line+1 = 7 + [ 34d] set column to 3 + [ 34f] extended opcode 2: set address to 0x400570 + [ 35a] set 'is_stmt' to 0 + [ 35b] copy + [ 35c] set column to 6 + [ 35e] extended opcode 2: set address to 0x400575 + [ 369] extended opcode 4: set discriminator to 1 + [ 36d] copy + [ 36e] set column to 24 + [ 370] extended opcode 2: set address to 0x400578 + [ 37b] copy + [ 37c] set column to 17 + [ 37e] extended opcode 2: set address to 0x40057d + [ 389] extended opcode 4: set discriminator to 0 + [ 38d] set 'is_stmt' to 1 + [ 38e] special opcode 26: address+0 = 0x40057d , line+3 = 10 + [ 38f] set column to 3 + [ 391] extended opcode 2: set address to 0x40057d + [ 39c] set 'is_stmt' to 0 + [ 39d] copy + [ 39e] set column to 10 + [ 3a0] extended opcode 2: set address to 0x400583 + [ 3ab] set file to 2 + [ 3ad] copy + [ 3ae] set column to 7 + [ 3b0] extended opcode 2: set address to 0x400585 + [ 3bb] set file to 1 + [ 3bd] copy + [ 3be] set column to 10 + [ 3c0] extended opcode 2: set address to 0x400588 + [ 3cb] set file to 2 + [ 3cd] set 'is_stmt' to 1 + [ 3ce] special opcode 20: address+0 = 0x400588 , line-3 = 7 + [ 3cf] set column to 3 + [ 3d1] extended opcode 2: set address to 0x400588 + [ 3dc] special opcode 25: address+0 = 0x400588 , line+2 = 9 + [ 3dd] set column to 3 + [ 3df] extended opcode 2: set address to 0x400588 + [ 3ea] set 'is_stmt' to 0 + [ 3eb] special opcode 24: address+0 = 0x400588 , line+1 = 10 + [ 3ec] set column to 7 + [ 3ee] extended opcode 2: set address to 0x40058f + [ 3f9] set 'is_stmt' to 1 + [ 3fa] special opcode 25: address+0 = 0x40058f , line+2 = 12 + [ 3fb] set column to 3 + [ 3fd] extended opcode 2: set address to 0x40058f + [ 408] set 'is_stmt' to 0 + [ 409] copy + [ 40a] set column to 10 + [ 40c] extended opcode 2: set address to 0x400598 + [ 417] set file to 1 + [ 419] special opcode 22: address+0 = 0x400598 , line-1 = 11 + [ 41a] set column to 1 + [ 41c] extended opcode 2: set address to 0x40059b + [ 427] extended opcode 1: end of sequence +EOF + +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=line testfile-dwarf-5 << \EOF + +DWARF section [29] '.debug_line' at offset 0x171f: + +Table at offset 0: + + Length: 547 + DWARF version: 5 + Prologue length: 56 + Address size: 8 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -10 + Line range: 242 + Opcode base: 13 + +Opcodes: + [ 1] 0 arguments + [ 2] 1 argument + [ 3] 1 argument + [ 4] 1 argument + [ 5] 1 argument + [ 6] 0 arguments + [ 7] 0 arguments + [ 8] 0 arguments + [ 9] 1 argument + [10] 0 arguments + [11] 0 arguments + [12] 1 argument + +Directory table: + [path(line_strp)] + 0 /var/tmp/hello (90) + 1 /opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include (17) + +File name table: + [path(line_strp), directory_index(data1)] + 0 hello.c (9), 0 + 1 hello.c (9), 0 + 2 hello.h (82), 0 + 3 stddef.h (0), 1 + +Line number statements: + [ 44] extended opcode 2: set address to 0x400510 + [ 4f] special opcode 43: address+0 = 0x400510 , line+20 = 21 + [ 50] set column to 1 + [ 52] extended opcode 2: set address to 0x400510 + [ 5d] special opcode 24: address+0 = 0x400510 , line+1 = 22 + [ 5e] set column to 3 + [ 60] extended opcode 2: set address to 0x400510 + [ 6b] set 'is_stmt' to 0 + [ 6c] copy + [ 6d] set column to 6 + [ 6f] extended opcode 2: set address to 0x400514 + [ 7a] special opcode 26: address+0 = 0x400514 , line+3 = 25 + [ 7b] set column to 34 + [ 7d] extended opcode 2: set address to 0x40051a + [ 88] set 'is_stmt' to 1 + [ 89] copy + [ 8a] set column to 3 + [ 8c] extended opcode 2: set address to 0x40051a + [ 97] set 'is_stmt' to 0 + [ 98] copy + [ 99] set column to 34 + [ 9b] extended opcode 2: set address to 0x40051e + [ a6] special opcode 24: address+0 = 0x40051e , line+1 = 26 + [ a7] set column to 1 + [ a9] extended opcode 2: set address to 0x400528 + [ b4] extended opcode 4: set discriminator to 1 + [ b8] special opcode 22: address+0 = 0x400528 , line-1 = 25 + [ b9] set column to 18 + [ bb] extended opcode 2: set address to 0x40052b + [ c6] set file to 2 + [ c8] set 'is_stmt' to 1 + [ c9] advance line by constant -18 to 7 + [ cb] copy + [ cc] set column to 3 + [ ce] extended opcode 2: set address to 0x40052b + [ d9] special opcode 25: address+0 = 0x40052b , line+2 = 9 + [ da] set column to 3 + [ dc] extended opcode 2: set address to 0x40052b + [ e7] set 'is_stmt' to 0 + [ e8] copy + [ e9] set column to 6 + [ eb] extended opcode 2: set address to 0x40052f + [ f6] extended opcode 4: set discriminator to 0 + [ fa] set 'is_stmt' to 1 + [ fb] special opcode 24: address+0 = 0x40052f , line+1 = 10 + [ fc] set column to 5 + [ fe] extended opcode 2: set address to 0x40052f + [ 109] set 'is_stmt' to 0 + [ 10a] copy + [ 10b] set column to 7 + [ 10d] extended opcode 2: set address to 0x400531 + [ 118] set 'is_stmt' to 1 + [ 119] special opcode 25: address+0 = 0x400531 , line+2 = 12 + [ 11a] set column to 3 + [ 11c] extended opcode 2: set address to 0x400531 + [ 127] set file to 1 + [ 129] special opcode 21: address+0 = 0x400531 , line-2 = 10 + [ 12a] set column to 3 + [ 12c] extended opcode 2: set address to 0x400531 + [ 137] special opcode 25: address+0 = 0x400531 , line+2 = 12 + [ 138] set column to 3 + [ 13a] extended opcode 2: set address to 0x400531 + [ 145] set 'is_stmt' to 0 + [ 146] copy + [ 147] set column to 6 + [ 149] extended opcode 2: set address to 0x400535 + [ 154] set 'is_stmt' to 1 + [ 155] special opcode 24: address+0 = 0x400535 , line+1 = 13 + [ 156] set column to 5 + [ 158] extended opcode 2: set address to 0x400535 + [ 163] set 'is_stmt' to 0 + [ 164] copy + [ 165] set column to 7 + [ 167] extended opcode 2: set address to 0x400539 + [ 172] set 'is_stmt' to 1 + [ 173] special opcode 25: address+0 = 0x400539 , line+2 = 15 + [ 174] set column to 3 + [ 176] extended opcode 2: set address to 0x400539 + [ 181] special opcode 30: address+0 = 0x400539 , line+7 = 22 + [ 182] set column to 3 + [ 184] extended opcode 2: set address to 0x400539 + [ 18f] set 'is_stmt' to 0 + [ 190] copy + [ 191] set column to 6 + [ 193] extended opcode 2: set address to 0x40053d + [ 19e] set 'is_stmt' to 1 + [ 19f] special opcode 24: address+0 = 0x40053d , line+1 = 23 + [ 1a0] set column to 5 + [ 1a2] extended opcode 2: set address to 0x40053d + [ 1ad] set 'is_stmt' to 0 + [ 1ae] copy + [ 1af] set column to 12 + [ 1b1] extended opcode 2: set address to 0x400550 + [ 1bc] set 'is_stmt' to 1 + [ 1bd] advance line by constant -14 to 9 + [ 1bf] copy + [ 1c0] set column to 1 + [ 1c2] extended opcode 2: set address to 0x400550 + [ 1cd] special opcode 24: address+0 = 0x400550 , line+1 = 10 + [ 1ce] set column to 3 + [ 1d0] extended opcode 2: set address to 0x400550 + [ 1db] special opcode 25: address+0 = 0x400550 , line+2 = 12 + [ 1dc] set column to 3 + [ 1de] extended opcode 2: set address to 0x400550 + [ 1e9] set 'is_stmt' to 0 + [ 1ea] copy + [ 1eb] set column to 9 + [ 1ed] extended opcode 2: set address to 0x400556 + [ 1f8] special opcode 24: address+0 = 0x400556 , line+1 = 13 + [ 1f9] set column to 7 + [ 1fb] extended opcode 2: set address to 0x40055f + [ 206] set 'is_stmt' to 1 + [ 207] special opcode 25: address+0 = 0x40055f , line+2 = 15 + [ 208] set column to 3 + [ 20a] extended opcode 2: set address to 0x40055f + [ 215] set 'is_stmt' to 0 + [ 216] copy + [ 217] set column to 7 + [ 219] extended opcode 2: set address to 0x400561 + [ 224] extended opcode 1: end of sequence + +Table at offset 551: + + Length: 441 + DWARF version: 5 + Prologue length: 56 + Address size: 8 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -10 + Line range: 242 + Opcode base: 13 + +Opcodes: + [ 1] 0 arguments + [ 2] 1 argument + [ 3] 1 argument + [ 4] 1 argument + [ 5] 1 argument + [ 6] 0 arguments + [ 7] 0 arguments + [ 8] 0 arguments + [ 9] 1 argument + [10] 0 arguments + [11] 0 arguments + [12] 1 argument + +Directory table: + [path(line_strp)] + 0 /var/tmp/hello (90) + 1 /usr/include (122) + +File name table: + [path(line_strp), directory_index(data1)] + 0 world.c (114), 0 + 1 world.c (114), 0 + 2 hello.h (82), 0 + 3 stdlib.h (105), 1 + +Line number statements: + [ 26b] extended opcode 2: set address to 0x400410
+ [ 276] special opcode 37: address+0 = 0x400410
, line+14 = 15 + [ 277] set column to 1 + [ 279] extended opcode 2: set address to 0x400410
+ [ 284] special opcode 24: address+0 = 0x400410
, line+1 = 16 + [ 285] set column to 3 + [ 287] extended opcode 2: set address to 0x400410
+ [ 292] special opcode 24: address+0 = 0x400410
, line+1 = 17 + [ 293] set column to 3 + [ 295] extended opcode 2: set address to 0x400410
+ [ 2a0] set 'is_stmt' to 0 + [ 2a1] special opcode 21: address+0 = 0x400410
, line-2 = 15 + [ 2a2] set column to 1 + [ 2a4] extended opcode 2: set address to 0x400419 + [ 2af] special opcode 25: address+0 = 0x400419 , line+2 = 17 + [ 2b0] set column to 6 + [ 2b2] extended opcode 2: set address to 0x40041e + [ 2bd] set 'is_stmt' to 1 + [ 2be] special opcode 24: address+0 = 0x40041e , line+1 = 18 + [ 2bf] set column to 5 + [ 2c1] extended opcode 2: set address to 0x40041e + [ 2cc] set 'is_stmt' to 0 + [ 2cd] copy + [ 2ce] set column to 7 + [ 2d0] extended opcode 2: set address to 0x400421 + [ 2db] set 'is_stmt' to 1 + [ 2dc] special opcode 27: address+0 = 0x400421 , line+4 = 22 + [ 2dd] set column to 3 + [ 2df] extended opcode 2: set address to 0x400430 <_start> + [ 2ea] extended opcode 1: end of sequence + [ 2ed] extended opcode 2: set address to 0x400570 + [ 2f8] special opcode 28: address+0 = 0x400570 , line+5 = 6 + [ 2f9] set column to 1 + [ 2fb] extended opcode 2: set address to 0x400570 + [ 306] special opcode 24: address+0 = 0x400570 , line+1 = 7 + [ 307] set column to 3 + [ 309] extended opcode 2: set address to 0x400570 + [ 314] set 'is_stmt' to 0 + [ 315] copy + [ 316] set column to 6 + [ 318] extended opcode 2: set address to 0x400575 + [ 323] extended opcode 4: set discriminator to 1 + [ 327] copy + [ 328] set column to 24 + [ 32a] extended opcode 2: set address to 0x400578 + [ 335] copy + [ 336] set column to 17 + [ 338] extended opcode 2: set address to 0x40057d + [ 343] extended opcode 4: set discriminator to 0 + [ 347] set 'is_stmt' to 1 + [ 348] special opcode 26: address+0 = 0x40057d , line+3 = 10 + [ 349] set column to 3 + [ 34b] extended opcode 2: set address to 0x40057d + [ 356] set 'is_stmt' to 0 + [ 357] copy + [ 358] set column to 10 + [ 35a] extended opcode 2: set address to 0x400583 + [ 365] set file to 2 + [ 367] copy + [ 368] set column to 7 + [ 36a] extended opcode 2: set address to 0x400585 + [ 375] set file to 1 + [ 377] copy + [ 378] set column to 10 + [ 37a] extended opcode 2: set address to 0x400588 + [ 385] set file to 2 + [ 387] set 'is_stmt' to 1 + [ 388] special opcode 20: address+0 = 0x400588 , line-3 = 7 + [ 389] set column to 3 + [ 38b] extended opcode 2: set address to 0x400588 + [ 396] special opcode 25: address+0 = 0x400588 , line+2 = 9 + [ 397] set column to 3 + [ 399] extended opcode 2: set address to 0x400588 + [ 3a4] set 'is_stmt' to 0 + [ 3a5] special opcode 24: address+0 = 0x400588 , line+1 = 10 + [ 3a6] set column to 7 + [ 3a8] extended opcode 2: set address to 0x40058f + [ 3b3] set 'is_stmt' to 1 + [ 3b4] special opcode 25: address+0 = 0x40058f , line+2 = 12 + [ 3b5] set column to 3 + [ 3b7] extended opcode 2: set address to 0x40058f + [ 3c2] set 'is_stmt' to 0 + [ 3c3] copy + [ 3c4] set column to 10 + [ 3c6] extended opcode 2: set address to 0x400598 + [ 3d1] set file to 1 + [ 3d3] special opcode 22: address+0 = 0x400598 , line-1 = 11 + [ 3d4] set column to 1 + [ 3d6] extended opcode 2: set address to 0x40059b + [ 3e1] extended opcode 1: end of sequence +EOF + exit 0 diff --git a/tests/run-readelf-zdebug.sh b/tests/run-readelf-zdebug.sh index 28128ad..878e0ba 100755 --- a/tests/run-readelf-zdebug.sh +++ b/tests/run-readelf-zdebug.sh @@ -361,15 +361,17 @@ DWARF section [34] '.debug_line' at offset 0x104c: Table at offset 0: - Length: 70 - DWARF version: 2 - Prologue length: 40 - Minimum instruction length: 1 - Maximum operations per instruction: 1 - Initial value if 'is_stmt': 1 - Line base: -5 - Line range: 14 - Opcode base: 13 + Length: 70 + DWARF version: 2 + Prologue length: 40 + Address size: 8 + Segment selector size: 0 + Min instruction length: 1 + Max operations per instruction: 1 + Initial value if 'is_stmt': 1 + Line base: -5 + Line range: 14 + Opcode base: 13 Opcodes: [ 1] 0 arguments -- 1.8.3.1