From: Timm Bäder <tbae...@redhat.com> src/readelf.c and libdw/dwarf_getsrclines.c contain the same code to read header_length, unit_length, minimum_instr_len, etc. Pull this code out into libdwP.h and into a header_state struct that goes with the line_state struct in dwarf_getsrclines.c.
Signed-off-by: Timm Bäder <tbae...@redhat.com> --- libdw/dwarf_getsrclines.c | 172 ++++++++--------------------------- libdw/libdwP.h | 149 ++++++++++++++++++++++++++++++ src/readelf.c | 184 +++++++++++--------------------------- 3 files changed, 237 insertions(+), 268 deletions(-) diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index d6a581ad..c54b3bb7 100644 --- a/libdw/dwarf_getsrclines.c +++ b/libdw/dwarf_getsrclines.c @@ -96,12 +96,12 @@ struct line_state }; static inline void -run_advance_pc (struct line_state *state, unsigned int op_advance, - uint_fast8_t minimum_instr_len, uint_fast8_t max_ops_per_instr) +run_advance_pc (struct line_state *state, const struct header_state *header, + unsigned int op_advance) { - state->addr += minimum_instr_len * ((state->op_index + op_advance) - / max_ops_per_instr); - state->op_index = (state->op_index + op_advance) % max_ops_per_instr; + state->addr += header->minimum_instr_len * ((state->op_index + op_advance) + / header->max_ops_per_instr); + state->op_index = (state->op_index + op_advance) % header->max_ops_per_instr; } static inline bool @@ -183,6 +183,8 @@ read_srclines (Dwarf *dbg, .discriminator = 0 }; + struct header_state header; + /* The dirs normally go on the stack, but if there are too many we alloc them all. Set up stack storage early, so we can check on error if we need to free them or not. */ @@ -194,103 +196,14 @@ read_srclines (Dwarf *dbg, struct dirlist dirstack[MAX_STACK_DIRS]; struct dirlist *dirarray = dirstack; - if (unlikely (linep + 4 > lineendp)) + int header_parse_error = header_state_parse (dbg, &header, &linep, &lineendp, + address_size); + if (header_parse_error != DWARF_E_NOERROR) { invalid_data: __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); goto out; } - - Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); - unsigned int length = 4; - if (unlikely (unit_length == DWARF3_LENGTH_64_BIT)) - { - if (unlikely (linep + 8 > lineendp)) - goto invalid_data; - unit_length = read_8ubyte_unaligned_inc (dbg, linep); - length = 8; - } - - /* Check whether we have enough room in the section. */ - 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); - if (unlikely (version < 2) || unlikely (version > 5)) - { - __libdw_seterrno (DWARF_E_VERSION); - goto out; - } - - /* DWARF5 explicitly lists address and segment_selector sizes. */ - if (version >= 5) - { - if ((size_t) (lineendp - linep) < 2) - goto invalid_data; - size_t line_address_size = *linep++; - size_t segment_selector_size = *linep++; - if (line_address_size != address_size || segment_selector_size != 0) - goto invalid_data; - } - - /* Next comes the header length. */ - Dwarf_Word header_length; - if (length == 4) - { - if ((size_t) (lineendp - linep) < 4) - goto invalid_data; - header_length = read_4ubyte_unaligned_inc (dbg, linep); - } - else - { - if ((size_t) (lineendp - linep) < 8) - goto invalid_data; - header_length = read_8ubyte_unaligned_inc (dbg, linep); - } - const unsigned char *header_start = linep; - - /* Next the minimum instruction length. */ - uint_fast8_t minimum_instr_len = *linep++; - - /* Next the maximum operations per instruction, in version 4 format. */ - uint_fast8_t max_ops_per_instr = 1; - if (version >= 4) - { - if (unlikely ((size_t) (lineendp - linep) < 1)) - goto invalid_data; - max_ops_per_instr = *linep++; - if (unlikely (max_ops_per_instr == 0)) - goto invalid_data; - } - - /* 4 more bytes, is_stmt, line_base, line_range and opcode_base. */ - if ((size_t) (lineendp - linep) < 4) - goto invalid_data; - - /* 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 = (int8_t) *linep++; - - /* And the line range. */ - uint_fast8_t line_range = *linep++; - - /* The opcode base. */ - uint_fast8_t opcode_base = *linep++; - - /* Remember array with the standard opcode length (-1 to account for - the opcode with value zero not being mentioned). */ - const uint8_t *standard_opcode_lengths = linep - 1; - if (unlikely (lineendp - linep < opcode_base - 1)) - goto invalid_data; - linep += opcode_base - 1; - /* To read DWARF5 dir and file lists we need to know the forms. For now we skip everything, except the DW_LNCT_path and DW_LNCT_directory_index. */ @@ -304,7 +217,7 @@ read_srclines (Dwarf *dbg, .dbg = dbg, .sec_idx = IDX_debug_line, .version = 5, - .offset_size = length, + .offset_size = header.length, .address_size = address_size, .startp = (void *) linep, .endp = (void *) lineendp, @@ -312,7 +225,7 @@ read_srclines (Dwarf *dbg, /* First count the entries. */ size_t ndirs = 0; - if (version < 5) + if (header.version < 5) { const unsigned char *dirp = linep; while (dirp < lineendp && *dirp != 0) @@ -383,7 +296,7 @@ read_srclines (Dwarf *dbg, /* Entry zero is implicit for older versions, but explicit for 5+. */ struct dirlist comp_dir_elem; - if (version < 5) + if (header.version < 5) { /* First comes the list of directories. Add the compilation directory first since the index zero is used for it. */ @@ -470,7 +383,7 @@ read_srclines (Dwarf *dbg, fl; }) /* Now read the files. */ - if (version < 5) + if (header.version < 5) { if (unlikely (linep >= lineendp)) goto invalid_data; @@ -649,7 +562,7 @@ read_srclines (Dwarf *dbg, } /* Consistency check. */ - if (unlikely (linep != header_start + header_length)) + if (unlikely (linep != header.header_start + header.header_length)) { __libdw_seterrno (DWARF_E_INVALID_DWARF); goto out; @@ -658,12 +571,12 @@ read_srclines (Dwarf *dbg, /* We are about to process the statement program. Most state machine registers have already been initialize above. Just add the is_stmt default. See 6.2.2 in the v2.1 specification. */ - state.is_stmt = default_is_stmt; + state.is_stmt = header.default_is_stmt; /* Apply the "operation advance" from a special opcode or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */ #define advance_pc(op_advance) \ - run_advance_pc (&state, op_advance, minimum_instr_len, max_ops_per_instr) + run_advance_pc (&state, &header, op_advance) /* Process the instructions. */ @@ -692,23 +605,14 @@ read_srclines (Dwarf *dbg, opcode = *linep++; /* Is this a special opcode? */ - if (likely (opcode >= opcode_base)) + if (likely (opcode >= header.opcode_base)) { - if (unlikely (line_range == 0)) + if (unlikely (header.line_range == 0)) goto invalid_data; - /* Yes. Handling this is quite easy since the opcode value - is computed with - - opcode = (desired line increment - line_base) - + (line_range * address advance) + opcode_base - */ - int line_increment = (line_base - + (opcode - opcode_base) % line_range); - /* Perform the increments. */ - state.line += line_increment; - advance_pc ((opcode - opcode_base) / line_range); + state.line += header_get_line_increment (&header, opcode); + advance_pc ((opcode - header.opcode_base) / header.line_range); /* Add a new line with the current state machine values. */ NEW_LINE (0); @@ -747,7 +651,7 @@ read_srclines (Dwarf *dbg, state.file = 1; state.line = 1; state.column = 0; - state.is_stmt = default_is_stmt; + state.is_stmt = header.default_is_stmt; state.basic_block = false; state.prologue_end = false; state.epilogue_begin = false; @@ -823,7 +727,7 @@ read_srclines (Dwarf *dbg, case DW_LNE_set_discriminator: /* Takes one ULEB128 parameter, the discriminator. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) + if (unlikely (header.standard_opcode_lengths[opcode] != 1)) goto invalid_data; if (unlikely (linep >= lineendp)) @@ -846,7 +750,7 @@ read_srclines (Dwarf *dbg, { case DW_LNS_copy: /* Takes no argument. */ - if (unlikely (standard_opcode_lengths[opcode] != 0)) + if (unlikely (header.standard_opcode_lengths[opcode] != 0)) goto invalid_data; /* Add a new line with the current state machine values. */ @@ -862,7 +766,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_advance_pc: /* Takes one uleb128 parameter which is added to the address. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) + if (unlikely (header.standard_opcode_lengths[opcode] != 1)) goto invalid_data; if (unlikely (linep >= lineendp)) @@ -874,7 +778,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_advance_line: /* Takes one sleb128 parameter which is added to the line. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) + if (unlikely (header.standard_opcode_lengths[opcode] != 1)) goto invalid_data; if (unlikely (linep >= lineendp)) @@ -885,7 +789,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_set_file: /* Takes one uleb128 parameter which is stored in file. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) + if (unlikely (header.standard_opcode_lengths[opcode] != 1)) goto invalid_data; if (unlikely (linep >= lineendp)) @@ -896,7 +800,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_set_column: /* Takes one uleb128 parameter which is stored in column. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) + if (unlikely (header.standard_opcode_lengths[opcode] != 1)) goto invalid_data; if (unlikely (linep >= lineendp)) @@ -907,7 +811,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_negate_stmt: /* Takes no argument. */ - if (unlikely (standard_opcode_lengths[opcode] != 0)) + if (unlikely (header.standard_opcode_lengths[opcode] != 0)) goto invalid_data; state.is_stmt = 1 - state.is_stmt; @@ -915,7 +819,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_set_basic_block: /* Takes no argument. */ - if (unlikely (standard_opcode_lengths[opcode] != 0)) + if (unlikely (header.standard_opcode_lengths[opcode] != 0)) goto invalid_data; state.basic_block = true; @@ -923,19 +827,19 @@ read_srclines (Dwarf *dbg, case DW_LNS_const_add_pc: /* Takes no argument. */ - if (unlikely (standard_opcode_lengths[opcode] != 0)) + if (unlikely (header.standard_opcode_lengths[opcode] != 0)) goto invalid_data; - if (unlikely (line_range == 0)) + if (unlikely (header.line_range == 0)) goto invalid_data; - advance_pc ((255 - opcode_base) / line_range); + advance_pc ((255 - header.opcode_base) / header.line_range); break; case DW_LNS_fixed_advance_pc: /* Takes one 16 bit parameter which is added to the address. */ - if (unlikely (standard_opcode_lengths[opcode] != 1) + if (unlikely (header.standard_opcode_lengths[opcode] != 1) || unlikely (lineendp - linep < 2)) goto invalid_data; @@ -945,7 +849,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_set_prologue_end: /* Takes no argument. */ - if (unlikely (standard_opcode_lengths[opcode] != 0)) + if (unlikely (header.standard_opcode_lengths[opcode] != 0)) goto invalid_data; state.prologue_end = true; @@ -953,7 +857,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_set_epilogue_begin: /* Takes no argument. */ - if (unlikely (standard_opcode_lengths[opcode] != 0)) + if (unlikely (header.standard_opcode_lengths[opcode] != 0)) goto invalid_data; state.epilogue_begin = true; @@ -961,7 +865,7 @@ read_srclines (Dwarf *dbg, case DW_LNS_set_isa: /* Takes one uleb128 parameter which is stored in isa. */ - if (unlikely (standard_opcode_lengths[opcode] != 1)) + if (unlikely (header.standard_opcode_lengths[opcode] != 1)) goto invalid_data; if (unlikely (linep >= lineendp)) @@ -975,7 +879,7 @@ read_srclines (Dwarf *dbg, /* This is a new opcode the generator but not we know about. Read the parameters associated with it but then discard everything. Read all the parameters for this opcode. */ - for (int n = standard_opcode_lengths[opcode]; n > 0; --n) + for (int n = header.standard_opcode_lengths[opcode]; n > 0; --n) { if (unlikely (linep >= lineendp)) goto invalid_data; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 7174ea93..139e31ef 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -1344,6 +1344,155 @@ char * __libdw_filepath (const char *debugdir, const char *dir, internal_function; +struct header_state +{ + unsigned int length; + const unsigned char *header_start; + uint16_t version; + Dwarf_Word header_length; + Dwarf_Word unit_length; + uint8_t minimum_instr_len; + uint8_t max_ops_per_instr; + uint8_t default_is_stmt; + int8_t line_base; + uint8_t line_range; + uint8_t opcode_base; + const uint8_t *standard_opcode_lengths; + char segment_selector_size; +}; + +static inline int +header_state_parse (Dwarf *dbg, + struct header_state *state, + const unsigned char **linep_inout, + const unsigned char **lineendp_inout, + unsigned address_size) +{ + const unsigned char *linep = *linep_inout; + const unsigned char *lineendp = *lineendp_inout; + int errcode = DWARF_E_INVALID_DEBUG_LINE; + + if (unlikely (linep + 4 > lineendp)) + goto error; + + state->unit_length = read_4ubyte_unaligned_inc (dbg, linep); + state->length = 4; + if (unlikely (state->unit_length == DWARF3_LENGTH_64_BIT)) + { + if (unlikely (linep + 8 > lineendp)) + goto error; + state->unit_length = read_8ubyte_unaligned_inc (dbg, linep); + state->length = 8; + } + + /* Check whether we have enough room in the section. */ + if (unlikely (state->unit_length > (size_t) (lineendp - linep))) + goto error; + + lineendp = linep + state->unit_length; + + if ((size_t) (lineendp - linep) < 2) + goto error; + + state->version = read_2ubyte_unaligned_inc (dbg, linep); + if (unlikely (state->version < 2) || unlikely (state->version > 5)) + { + errcode = DWARF_E_VERSION; + goto error; + } + + /* DWARF5 explicitly lists address and segment_selector sizes. */ + if (state->version >= 5) + { + if ((size_t) (lineendp - linep) < 2) + goto error; + size_t line_address_size = *linep++; + state->segment_selector_size = *linep++; + if (line_address_size != address_size || state->segment_selector_size != 0) + goto error; + } + + /* Next comes the header length. */ + if (state->length == 4) + { + if ((size_t) (lineendp - linep) < 4) + goto error; + state->header_length = read_4ubyte_unaligned_inc (dbg, linep); + } + else + { + if ((size_t) (lineendp - linep) < 8) + goto error; + state->header_length = read_8ubyte_unaligned_inc (dbg, linep); + } + + state->header_start = linep; + + /* Next the minimum instruction length. */ + state->minimum_instr_len = *linep++; + + /* Next the maximum operations per instruction, in version 4 format. */ + state->max_ops_per_instr = 1; + if (state->version >= 4) + { + if (unlikely ((size_t) (lineendp - linep) < 1)) + goto error; + state->max_ops_per_instr = *linep++; + if (unlikely (state->max_ops_per_instr == 0)) + goto error; + } + + /* 4 more bytes, is_stmt, line_base, line_range and opcode_base. */ + if ((size_t) (lineendp - linep) < 4) + goto error; + + /* Then the flag determining the default value of the is_stmt + register. */ + state->default_is_stmt = *linep++; + + /* Now the line base. */ + state->line_base = (int8_t) *linep++; + + /* And the line range. */ + state->line_range = *linep++; + + /* The opcode base. */ + state->opcode_base = *linep++; + + /* Remember array with the standard opcode length (-1 to account for + the opcode with value zero not being mentioned). */ + state->standard_opcode_lengths = linep - 1; + if (unlikely (lineendp - linep < state->opcode_base - 1)) + goto error; + linep += state->opcode_base - 1; + + if (unlikely (linep >= lineendp)) + goto error; /* Invalid unit */ + + /* Everything went well */ + *linep_inout = linep; + *lineendp_inout = lineendp; + return DWARF_E_NOERROR; + +error: + *linep_inout = linep; + *lineendp_inout = lineendp; + return errcode; +} + +static inline int +header_get_line_increment (const struct header_state *state, + unsigned int opcode) +{ + /* Yes. Handling this is quite easy since the opcode value + is computed with + + opcode = (desired line increment - line_base) + + (line_range * address advance) + opcode_base + */ + return state->line_base + (opcode - state->opcode_base) % state->line_range; +} + /* Aliases to avoid PLTs. */ INTDECL (dwarf_aggregate_size) INTDECL (dwarf_attr) diff --git a/src/readelf.c b/src/readelf.c index 11692bb5..b8f533f5 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -8393,104 +8393,32 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, const unsigned char *linep = (const unsigned char *) data->d_buf; const unsigned char *lineendp; - while (linep < (lineendp = (const unsigned char *) data->d_buf + data->d_size)) { size_t start_offset = linep - (const unsigned char *) data->d_buf; + struct header_state header; printf (_("\nTable at offset %zu:\n"), start_offset); - if (unlikely (linep + 4 > lineendp)) - goto invalid_data; - Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); - unsigned int length = 4; - if (unlikely (unit_length == 0xffffffff)) - { - if (unlikely (linep + 8 > lineendp)) - { - invalid_data: - error (0, 0, _("invalid data in section [%zu] '%s'"), - elf_ndxscn (scn), section_name (ebl, shdr)); - return; - } - unit_length = read_8ubyte_unaligned_inc (dbg, linep); - length = 8; - } - - /* Check whether we have enough room in the section. */ - 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) - { - if ((size_t) (lineendp - linep) < 4) - goto invalid_data; - header_length = read_4ubyte_unaligned_inc (dbg, linep); - } - else - { - if ((size_t) (lineendp - linep) < 8) - goto invalid_data; - header_length = read_8ubyte_unaligned_inc (dbg, linep); - } + = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8; - /* 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; - if (version < 4) - max_ops_per_instr = 1; - else + int header_parse_error = header_state_parse (dbg, &header, + &linep, &lineendp, + address_size); + if (header_parse_error != DWARF_E_NOERROR) { - if ((size_t) (lineendp - linep) < 1) - goto invalid_data; - max_ops_per_instr = *linep++; + invalid_data: + error (0, 0, _("invalid data in section [%zu] '%s'"), + elf_ndxscn (scn), section_name (ebl, shdr)); + return; } - /* 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. */ - uint_fast8_t default_is_stmt = *linep++; - - /* Now the line base. */ - int_fast8_t line_base = *linep++; - - /* And the line range. */ - uint_fast8_t line_range = *linep++; - - /* The opcode base. */ - uint_fast8_t opcode_base = *linep++; - /* Print what we got so far. */ printf (_("\n" " Length: %" PRIu64 "\n" - " DWARF version: %" PRIuFAST16 "\n" + " DWARF version: %" PRIu16 "\n" " Prologue length: %" PRIu64 "\n" " Address size: %zd\n" " Segment selector size: %zd\n" @@ -8502,16 +8430,17 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, " 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, - default_is_stmt, line_base, - line_range, opcode_base); + (uint64_t) header.unit_length, header.version, + (uint64_t) header.header_length, + address_size, (size_t) header.segment_selector_size, + header.minimum_instr_len, header.max_ops_per_instr, + header.default_is_stmt, header.line_base, + header.line_range, header.opcode_base); - if (version < 2 || version > 5) + if (header.version < 2 || header.version > 5) { error (0, 0, _("cannot handle .debug_line version: %u\n"), - (unsigned int) version); + (unsigned int) header.version); linep = lineendp; continue; } @@ -8524,15 +8453,15 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, continue; } - if (segment_selector_size != 0) + if (header.segment_selector_size != 0) { error (0, 0, _("cannot handle segment selector size: %u\n"), - (unsigned int) segment_selector_size); + (unsigned int) header.segment_selector_size); linep = lineendp; continue; } - if (unlikely (linep + opcode_base - 1 >= lineendp)) + if (unlikely (linep + header.opcode_base - 1 >= lineendp)) { invalid_unit: error (0, 0, @@ -8543,27 +8472,22 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, continue; } int opcode_base_l10 = 1; - unsigned int tmp = opcode_base; + unsigned int tmp = header.opcode_base; while (tmp > 10) { tmp /= 10; ++opcode_base_l10; } - const uint8_t *standard_opcode_lengths = linep - 1; - for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt) + for (uint_fast8_t cnt = 1; cnt < header.opcode_base; ++cnt) printf (ngettext (" [%*" PRIuFAST8 "] %hhu argument\n", " [%*" PRIuFAST8 "] %hhu arguments\n", - (int) linep[cnt - 1]), - opcode_base_l10, cnt, linep[cnt - 1]); - linep += opcode_base - 1; - - if (unlikely (linep >= lineendp)) - goto invalid_unit; + (int) linep[- header.opcode_base + cnt]), + opcode_base_l10, cnt, linep[- header.opcode_base + cnt]); Dwarf_Off str_offsets_base = str_offsets_base_off (dbg, NULL); puts (_("\nDirectory table:")); - if (version > 4) + if (header.version > 4) { struct encpair { uint16_t desc; uint16_t form; }; struct encpair enc[256]; @@ -8608,7 +8532,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, for (int j = 0; j < directory_entry_format_count; j++) { linep = print_form_data (dbg, enc[j].form, - linep, lineendp, length, + linep, lineendp, header.length, str_offsets_base); if (j + 1 < directory_entry_format_count) printf (", "); @@ -8640,7 +8564,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, goto invalid_unit; puts (_("\nFile name table:")); - if (version > 4) + if (header.version > 4) { struct encpair { uint16_t desc; uint16_t form; }; struct encpair enc[256]; @@ -8688,7 +8612,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, for (int j = 0; j < file_name_format_count; j++) { linep = print_form_data (dbg, enc[j].form, - linep, lineendp, length, + linep, lineendp, header.length, str_offsets_base); if (j + 1 < file_name_format_count) printf (", "); @@ -8747,20 +8671,20 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, Dwarf_Word address = 0; unsigned int op_index = 0; size_t line = 1; - uint_fast8_t is_stmt = default_is_stmt; + uint_fast8_t is_stmt = header.default_is_stmt; /* Apply the "operation advance" from a special opcode or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */ unsigned int op_addr_advance; inline void advance_pc (unsigned int op_advance) { - op_addr_advance = minimum_instr_len * ((op_index + op_advance) - / max_ops_per_instr); + op_addr_advance = header.minimum_instr_len * ((op_index + op_advance) + / header.max_ops_per_instr); address += op_addr_advance; - op_index = (op_index + op_advance) % max_ops_per_instr; + op_index = (op_index + op_advance) % header.max_ops_per_instr; } - if (max_ops_per_instr == 0) + if (header.max_ops_per_instr == 0) { error (0, 0, _("invalid maximum operations per instruction is zero")); @@ -8779,23 +8703,15 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, printf (" [%6" PRIx64 "]", (uint64_t)offset); /* Is this a special opcode? */ - if (likely (opcode >= opcode_base)) + if (likely (opcode >= header.opcode_base)) { - if (unlikely (line_range == 0)) + if (unlikely (header.line_range == 0)) goto invalid_unit; - /* Yes. Handling this is quite easy since the opcode value - is computed with - - opcode = (desired line increment - line_base) - + (line_range * address advance) + opcode_base - */ - int line_increment = (line_base - + (opcode - opcode_base) % line_range); - + int line_increment = header_get_line_increment (&header, opcode); /* Perform the increments. */ line += line_increment; - advance_pc ((opcode - opcode_base) / line_range); + advance_pc ((opcode - header.opcode_base) / header.line_range); printf (_(" special opcode %u: address+%u = "), opcode, op_addr_advance); @@ -8833,7 +8749,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, address = 0; op_index = 0; line = 1; - is_stmt = default_is_stmt; + is_stmt = header.default_is_stmt; break; case DW_LNE_set_address: @@ -8882,7 +8798,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, case DW_LNE_set_discriminator: /* Takes one ULEB128 parameter, the discriminator. */ - if (unlikely (standard_opcode_lengths[opcode] != 1 + if (unlikely (header.standard_opcode_lengths[opcode] != 1 || lineendp - linep < 1)) goto invalid_unit; @@ -8947,7 +8863,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, case DW_LNS_set_column: /* Takes one uleb128 parameter which is stored in column. */ - if (unlikely (standard_opcode_lengths[opcode] != 1 + if (unlikely (header.standard_opcode_lengths[opcode] != 1 || lineendp - linep < 1)) goto invalid_unit; @@ -8971,10 +8887,10 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, case DW_LNS_const_add_pc: /* Takes no argument. */ - if (unlikely (line_range == 0)) + if (unlikely (header.line_range == 0)) goto invalid_unit; - advance_pc ((255 - opcode_base) / line_range); + advance_pc ((255 - header.opcode_base) / header.line_range); { printf (_(" advance address by constant %u to "), op_addr_advance); @@ -8988,7 +8904,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, case DW_LNS_fixed_advance_pc: /* Takes one 16 bit parameter which is added to the address. */ - if (unlikely (standard_opcode_lengths[opcode] != 1 + if (unlikely (header.standard_opcode_lengths[opcode] != 1 || lineendp - linep < 2)) goto invalid_unit; @@ -9016,7 +8932,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, case DW_LNS_set_isa: /* Takes one uleb128 parameter which is stored in isa. */ - if (unlikely (standard_opcode_lengths[opcode] != 1 + if (unlikely (header.standard_opcode_lengths[opcode] != 1 || lineendp - linep < 1)) goto invalid_unit; @@ -9032,13 +8948,13 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, everything. Read all the parameters for this opcode. */ printf (ngettext (" unknown opcode with %" PRIu8 " parameter:", " unknown opcode with %" PRIu8 " parameters:", - standard_opcode_lengths[opcode]), - standard_opcode_lengths[opcode]); - for (int n = standard_opcode_lengths[opcode]; + header.standard_opcode_lengths[opcode]), + header.standard_opcode_lengths[opcode]); + for (int n = header.standard_opcode_lengths[opcode]; n > 0 && linep < lineendp; --n) { get_uleb128 (u128, linep, lineendp); - if (n != standard_opcode_lengths[opcode]) + if (n != header.standard_opcode_lengths[opcode]) putc_unlocked (',', stdout); printf (" %u", u128); } -- 2.26.2