From: Nick Clifton Date: Tue, 24 Mar 2015 11:31:37 +0000 (+0000) Subject: Import fixes for invalid memory access issues in the binutils DWARF parser from the... X-Git-Tag: binutils-2_25_1~166 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=304a2b6fe67786b45889a784bf71aabf2a9d26fd;p=thirdparty%2Fbinutils-gdb.git Import fixes for invalid memory access issues in the binutils DWARF parser from the trunk sources. PR binutils/17512 * dwarf.c (display_debug_loc): Pacify the undefined behaviour sanitizer by simplifying address difference calculation. (struct Frame_Chunk): Change type of cfa_offset to dwarf_vma in order to avoid arithmetic overflows. (frame_display_row): Cast cfa_offset before printing it. (display_debug_frames): Likewise. Check for an unexpected segment size. Chnage type of 'l' local to dwarf_vma and cast it back to an int when printing. (process_cu_tu_index): Tighten check for an invalid ncols value. * readelf.c (process_corefile_note_segment): Check for inote.descdata extending beyond the end of the section. (process_v850_notes): Likewise. 2015-02-13 Nick Clifton PR binutils/17512 * dwarf.c (read_leb128): Fix test for shift becoming too large. PR binutils/17531 * dwarf.c (display_debug_aranges): Add check for an excessive ar_length value. (process_cu_tu_index): Check for a row * columns sum being too large. 2015-02-13 Alan Modra * dwarf.c: Formatting, whitespace. (process_debug_info): Style fix. 2015-02-11 Nick Clifton PR binutils/17531 * dwarf.c (display_debug_pubnames_worker): Work around compiler bug checking address ranges. (display_debug_frames): Likewise. (display_gdb_index): Likewise. (process_cu_tu_index): Add range check on the ncols value. 2015-02-10 Nick Clifton PR binutils/17512 * dwarf.c (eh_addr_size): Use an unsigned type. (size_of_encoded_value): Return an unsigned type. (read_leb128): Break if the shift becomes too big. (process_extended_line_op): Do not read the address if the length is too long. (read_cie): Warn and fail if the pointer size or segment size are too big. * dwarf.h (DWARF2_External_LineInfo): Delete unused and incorrect structure definition. (DWARF2_External_PubNames): Likewise. (DWARF2_External_CompUnit): Likewise. (DWARF2_External_ARange): Likewise. (DWARF2_Internal_LineInfo): Use dwarf_vma type for li_prologue_length. (eh_addr_size): Update prototype. PR binutils/17531 * dwarf.c (process_debug_info): Zero the debug information array since correct initialisation cannot be relied upon. (process_cu_tu_index): Improve range checks. PR binutils/17531 * dwarf.c (display_debug_pubnames_worker): Use dwarf_vma type for offset. 2015-02-06 Nick Clifton PR binutils/17512 * dwarf.c (display_debug_frames): Fix range checks to work on 32-bit binaries complied on a 64-bit host. PR binutils/17531 * dwarf.c (xcmalloc): Fail if the arguments are too big. (xcrealloc): Likewise. (xcalloc2): Likewise. * readelf.c (process_mips_specific): Fail if an option has an invalid size. 2015-02-05 Alan Modra PR binutils/17926 * dwarf.c (dwarf_select_sections_by_letters): Don't refer to optarg. 2015-02-04 Nick Clifton PR binutils/17531 * dwarf.c (read_and_display_attr_value): Test for a block length being so long that it wraps around to before the start of the block. (process_debug_info): Test for section_begin wrapping around to before the start of the section. (display_gdb_index): Test for num_cus being so large that the end address wraps around to before the start of the section. (process_cu_tu_index): Test for j being so large that the section index pool wraps around to before the start of the section. 2015-02-03 Nick Clifton PR binutils/17531 * dwarf.c (process_debug_info): Add range check. (display_debug_pubnames_worker): Likewise. (display_gdb_index): Fix range check. (process_cu_tu_index): Add range check. * readelf.c (get_data): Change parameter types from size_t to bfd_size_type. Add checks for loss of accuracy when casting from bfd_size_type to size_t. (get_dynamic_data): Likewise. (process_section_groups): Limit number of error messages. 2015-01-12 H.J. Lu * dwarf.c (process_debug_info): Properly check abbrev size. 2015-01-12 Nick Clifton PR binutils/17531 * dwarf.c (process_debug_info): Check for abbrev_base being larger than the section size. (process_cu_tu_index): Use xcalloc2 to allocate the CU and TU arrays. (xcalloc2): New function. Like xcalloc, but checks for overflow. (display_debug_addr): Use xcalloc to allocate the debug_addr_info array. Check for an address_base that is too large. * dwarf.h (xcalloc2): Prototype. 2015-01-05 Nick Clifton PR binutils/17531 * dwarf.c (alloc_num_debug_info_entries): New variable. (process_debug_info): Set it. Use it to avoid displaying attributes for which there is no info. (display_debug_abbrev): Check that the debug_info_entry index is valid before using it. (display_loc_list_dwo): Likewise. (process_cu_tu_index): Add range check for an overlarge dw_sect value. (free_debug_memory): Reset alloc_num_debug_info_entries. 2014-12-22 Nick Clifton PR binutils/17531 * dwarf.c (decode_location_expression): Check for an out of range value for a DW_OP_GNU_entry_value expression. (display_debug_lines_raw): Check for a partial .debug_line. section being encountered without a prior, full .debug.line section. (display_debug_lines_decoded): Likewise. Also check for li_line_range being zero. (display_debug_pubnames_worker): Check for an invalid pn_length field. (read_cie): Add range checks. 2014-12-11 Nick Clifton PR binutils/17512 * dwarf.c (display_gdb_index): Add more range checks. 2014-12-08 Nick Clifton PR binutils/17531 * dwarf.c (display_debug_frames): Check for a negative augmentation data length. (display_gdb_index): Check for invalid offsets. 2014-12-01 H.J. Lu * dwarf.c (process_cu_tu_index): Properly check for an out of range row index. 2014-12-01 Nick Clifton PR binutils/17512 * dwarf.h (struct dwarf_section): Add user_data field. * dwarf.c (frame_need_space): Check for an over large register number. (display_debug_frames): Check the return value from frame_need_space. Check for a CFA expression that is so long the start address wraps around. (debug_displays): Initialise the user_data field. * objdump.c (load_specific_debug_section): Save the BFD section pointer in the user_data field of the dwarf_section structure. (free_debug_section): Update BFD section data when freeing section contents. * readelf.c (load_specific_debug_section): Initialise the user_data field. 2014-12-01 Nick Clifton PR binutils/17531 * dwarf.c (process_cu_tu_index): Check for an out of range row index. * elfcomm.c (adjust_relative_path): Change name_len parameter to an unsigned long. Check for path length overflow. (process_archive_index_and_symbols): Check for invalid header size. (setup_archive): Add checks for invalid archives. (get_archive_member_name): Add range checks. * elfcomm.h (adjust_relative_path): Update prototyoe. * readelf.c (process_archive): Add range checks. 2014-11-26 Nick Clifton PR binutils/17512 * dwarf.c (display_block): Do nothing if the block starts after the end of the buffer. (read_and_display_attr_value): Add range checks. (struct Frame_Chunk): Make the ncols and ra fields unsigned. (frame_need_space): Test for an ncols of zero. (read_cie): Fail if the augmentation data extends off the end of the buffer. (display_debug_frames): Add checks for read_cie failing. Add range checks. 2014-11-21 Nick Clifton PR binutils/17512 * dwarf.c (get_encoded_value): Check for an encoded size of 0. (display_debug_lines_raw): Check for an invalid line range value. (display_debug_frames): Check for corrupt augmentation data. 2014-11-19 Jan-Benedict Glaw * dwarf.c (process_extended_line_op): Fix signedness warning. 2014-11-18 Nick Clifton PR binutils/17512 * dwarf.c (get_encoded_value): Warn and return if the encoded value is more than 64-bits long. (SAFE_BYTE_GET): Do not attempt to read more than 64-bits. (process_extended_line_op): Add more range checks. (decode_location_expression): Use the return value from display_block. Add more range checks. (read_debug_line_header): Add range check. (display_debug_lines_raw): Add range checks. (display_debug_frames): Silently skip multiple zero terminators. Add range checks. (process_cu_tu_index): Check for non-existant or empty sections. Use SAFE_BYTE_GET instead of byte_get. --- diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 1d0a8442722..a4bb426f464 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,251 @@ +2015-03-24 Nick Clifton + + Apply from master: + 2015-02-26 Nick Clifton + + PR binutils/17512 + * dwarf.c (display_debug_loc): Pacify the undefined behaviour + sanitizer by simplifying address difference calculation. + (struct Frame_Chunk): Change type of cfa_offset to dwarf_vma in + order to avoid arithmetic overflows. + (frame_display_row): Cast cfa_offset before printing it. + (display_debug_frames): Likewise. + Check for an unexpected segment size. + Chnage type of 'l' local to dwarf_vma and cast it back to an int + when printing. + (process_cu_tu_index): Tighten check for an invalid ncols value. + * readelf.c (process_corefile_note_segment): Check for + inote.descdata extending beyond the end of the section. + (process_v850_notes): Likewise. + + 2015-02-13 Nick Clifton + + PR binutils/17512 + * dwarf.c (read_leb128): Fix test for shift becoming too large. + + PR binutils/17531 + * dwarf.c (display_debug_aranges): Add check for an excessive + ar_length value. + (process_cu_tu_index): Check for a row * columns sum being too + large. + + 2015-02-13 Alan Modra + + * dwarf.c: Formatting, whitespace. + (process_debug_info): Style fix. + + 2015-02-11 Nick Clifton + + PR binutils/17531 + * dwarf.c (display_debug_pubnames_worker): Work around compiler + bug checking address ranges. + (display_debug_frames): Likewise. + (display_gdb_index): Likewise. + (process_cu_tu_index): Add range check on the ncols value. + + 2015-02-10 Nick Clifton + + PR binutils/17512 + * dwarf.c (eh_addr_size): Use an unsigned type. + (size_of_encoded_value): Return an unsigned type. + (read_leb128): Break if the shift becomes too big. + (process_extended_line_op): Do not read the address if the length + is too long. + (read_cie): Warn and fail if the pointer size or segment size are + too big. + * dwarf.h (DWARF2_External_LineInfo): Delete unused and incorrect + structure definition. + (DWARF2_External_PubNames): Likewise. + (DWARF2_External_CompUnit): Likewise. + (DWARF2_External_ARange): Likewise. + (DWARF2_Internal_LineInfo): Use dwarf_vma type for + li_prologue_length. + (eh_addr_size): Update prototype. + + PR binutils/17531 + * dwarf.c (process_debug_info): Zero the debug information array + since correct initialisation cannot be relied upon. + (process_cu_tu_index): Improve range checks. + + PR binutils/17531 + * dwarf.c (display_debug_pubnames_worker): Use dwarf_vma type for + offset. + + 2015-02-06 Nick Clifton + + PR binutils/17512 + * dwarf.c (display_debug_frames): Fix range checks to work on + 32-bit binaries complied on a 64-bit host. + + PR binutils/17531 + * dwarf.c (xcmalloc): Fail if the arguments are too big. + (xcrealloc): Likewise. + (xcalloc2): Likewise. + * readelf.c (process_mips_specific): Fail if an option has an + invalid size. + + 2015-02-05 Alan Modra + + PR binutils/17926 + * dwarf.c (dwarf_select_sections_by_letters): Don't refer to optarg. + + 2015-02-04 Nick Clifton + + PR binutils/17531 + * dwarf.c (read_and_display_attr_value): Test for a block length + being so long that it wraps around to before the start of the block. + (process_debug_info): Test for section_begin wrapping around to + before the start of the section. + (display_gdb_index): Test for num_cus being so large that the end + address wraps around to before the start of the section. + (process_cu_tu_index): Test for j being so large that the section + index pool wraps around to before the start of the section. + + 2015-02-03 Nick Clifton + + PR binutils/17531 + * dwarf.c (process_debug_info): Add range check. + (display_debug_pubnames_worker): Likewise. + (display_gdb_index): Fix range check. + (process_cu_tu_index): Add range check. + * readelf.c (get_data): Change parameter types from size_t to + bfd_size_type. Add checks for loss of accuracy when casting from + bfd_size_type to size_t. + (get_dynamic_data): Likewise. + (process_section_groups): Limit number of error messages. + + 2015-01-12 H.J. Lu + + * dwarf.c (process_debug_info): Properly check abbrev size. + + 2015-01-12 Nick Clifton + + PR binutils/17531 + * dwarf.c (process_debug_info): Check for abbrev_base being larger + than the section size. + (process_cu_tu_index): Use xcalloc2 to allocate the CU and TU + arrays. + (xcalloc2): New function. Like xcalloc, but checks for overflow. + (display_debug_addr): Use xcalloc to allocate the debug_addr_info + array. Check for an address_base that is too large. + + * dwarf.h (xcalloc2): Prototype. + + 2015-01-05 Nick Clifton + + PR binutils/17531 + * dwarf.c (alloc_num_debug_info_entries): New variable. + (process_debug_info): Set it. Use it to avoid displaying + attributes for which there is no info. + (display_debug_abbrev): Check that the debug_info_entry index is + valid before using it. + (display_loc_list_dwo): Likewise. + (process_cu_tu_index): Add range check for an overlarge dw_sect + value. + (free_debug_memory): Reset alloc_num_debug_info_entries. + + 2014-12-22 Nick Clifton + + PR binutils/17531 + * dwarf.c (decode_location_expression): Check for an out of range + value for a DW_OP_GNU_entry_value expression. + (display_debug_lines_raw): Check for a partial + .debug_line. section being encountered without a prior, full + .debug.line section. + (display_debug_lines_decoded): Likewise. Also check for + li_line_range being zero. + (display_debug_pubnames_worker): Check for an invalid pn_length + field. + (read_cie): Add range checks. + + 2014-12-11 Nick Clifton + + PR binutils/17512 + * dwarf.c (display_gdb_index): Add more range checks. + + 2014-12-08 Nick Clifton + + PR binutils/17531 + * dwarf.c (display_debug_frames): Check for a negative + augmentation data length. + (display_gdb_index): Check for invalid offsets. + + 2014-12-01 H.J. Lu + + * dwarf.c (process_cu_tu_index): Properly check for an out of + range row index. + + 2014-12-01 Nick Clifton + + PR binutils/17512 + * dwarf.h (struct dwarf_section): Add user_data field. + * dwarf.c (frame_need_space): Check for an over large register + number. + (display_debug_frames): Check the return value from + frame_need_space. Check for a CFA expression that is so long the + start address wraps around. + (debug_displays): Initialise the user_data field. + * objdump.c (load_specific_debug_section): Save the BFD section + pointer in the user_data field of the dwarf_section structure. + (free_debug_section): Update BFD section data when freeing section + contents. + * readelf.c (load_specific_debug_section): Initialise the + user_data field. + + 2014-12-01 Nick Clifton + + PR binutils/17531 + * dwarf.c (process_cu_tu_index): Check for an out of range row + index. + * elfcomm.c (adjust_relative_path): Change name_len parameter to + an unsigned long. Check for path length overflow. + (process_archive_index_and_symbols): Check for invalid header + size. + (setup_archive): Add checks for invalid archives. + (get_archive_member_name): Add range checks. + * elfcomm.h (adjust_relative_path): Update prototyoe. + * readelf.c (process_archive): Add range checks. + + 2014-11-26 Nick Clifton + + PR binutils/17512 + * dwarf.c (display_block): Do nothing if the block starts after + the end of the buffer. + (read_and_display_attr_value): Add range checks. + (struct Frame_Chunk): Make the ncols and ra fields unsigned. + (frame_need_space): Test for an ncols of zero. + (read_cie): Fail if the augmentation data extends off the end of + the buffer. + (display_debug_frames): Add checks for read_cie failing. Add + range checks. + + 2014-11-21 Nick Clifton + + PR binutils/17512 + * dwarf.c (get_encoded_value): Check for an encoded size of 0. + (display_debug_lines_raw): Check for an invalid line range value. + (display_debug_frames): Check for corrupt augmentation data. + + 2014-11-19 Jan-Benedict Glaw + + * dwarf.c (process_extended_line_op): Fix signedness warning. + + 2014-11-18 Nick Clifton + + PR binutils/17512 + * dwarf.c (get_encoded_value): Warn and return if the encoded + value is more than 64-bits long. + (SAFE_BYTE_GET): Do not attempt to read more than 64-bits. + (process_extended_line_op): Add more range checks. + (decode_location_expression): Use the return value from + display_block. Add more range checks. + (read_debug_line_header): Add range check. + (display_debug_lines_raw): Add range checks. + (display_debug_frames): Silently skip multiple zero terminators. + Add range checks. + (process_cu_tu_index): Check for non-existant or empty sections. + Use SAFE_BYTE_GET instead of byte_get. + 2015-03-24 Nick Clifton Apply from master: @@ -76,17 +324,6 @@ 2014-12-01 Nick Clifton PR binutils/17512 - * dwarf.h (struct dwarf_section): Add user_data field. - * dwarf.c (frame_need_space): Check for an over large register - number. - (display_debug_frames): Check the return value from - frame_need_space. Check for a CFA expression that is so long the - start address wraps around. - (debug_displays): Initialise the user_data field. - * objdump.c (load_specific_debug_section): Save the BFD section - pointer in the user_data field of the dwarf_section structure. - (free_debug_section): Update BFD section data when freeing section - contents. * readelf.c (load_specific_debug_section): Initialise the user_data field. diff --git a/binutils/dwarf.c b/binutils/dwarf.c index dde9066c059..a04adec9e6a 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -38,12 +38,13 @@ static unsigned int last_pointer_size = 0; static int warned_about_missing_comp_units = FALSE; static unsigned int num_debug_info_entries = 0; +static unsigned int alloc_num_debug_info_entries = 0; static debug_info *debug_information = NULL; /* Special value for num_debug_info_entries to indicate that the .debug_info section could not be loaded/parsed. */ #define DEBUG_INFO_UNAVAILABLE (unsigned int) -1 -int eh_addr_size; +unsigned int eh_addr_size; int do_debug_info; int do_debug_abbrevs; @@ -104,7 +105,7 @@ static void load_cu_tu_indexes (void *file); #define FLAG_DEBUG_LINES_RAW 1 #define FLAG_DEBUG_LINES_DECODED 2 -static int +static unsigned int size_of_encoded_value (int encoding) { switch (encoding & 0x7) @@ -124,7 +125,7 @@ get_encoded_value (unsigned char **pdata, unsigned char * end) { unsigned char * data = * pdata; - int size = size_of_encoded_value (encoding); + unsigned int size = size_of_encoded_value (encoding); dwarf_vma val; if (data + size >= end) @@ -134,6 +135,22 @@ get_encoded_value (unsigned char **pdata, return 0; } + /* PR 17512: file: 002-829853-0.004. */ + if (size > 8) + { + warn (_("Encoded size of %d is too large to read\n"), size); + * pdata = end; + return 0; + } + + /* PR 17512: file: 1085-5603-0.004. */ + if (size == 0) + { + warn (_("Encoded size of 0 is too small to read\n")); + * pdata = end; + return 0; + } + if (encoding & DW_EH_PE_signed) val = byte_get_signed (data, size); else @@ -264,6 +281,11 @@ read_leb128 (unsigned char *data, shift += 7; if ((byte & 0x80) == 0) break; + + /* PR 17512: file: 0ca183b8. + FIXME: Should we signal this error somehow ? */ + if (shift >= sizeof (result) * 8) + break; } if (length_return != NULL) @@ -304,10 +326,10 @@ read_uleb128 (unsigned char * data, else \ amount = 0; \ } \ - if (amount) \ - VAL = byte_get ((PTR), amount); \ - else \ + if (amount == 0 || amount > 8) \ VAL = 0; \ + else \ + VAL = byte_get ((PTR), amount); \ } \ while (0) @@ -408,7 +430,7 @@ process_extended_line_op (unsigned char * data, len = read_uleb128 (data, & bytes_read, end); data += bytes_read; - if (len == 0 || data == end) + if (len == 0 || data == end || len > (uintptr_t) (end - data)) { warn (_("Badly formed extended line op encountered!\n")); return bytes_read; @@ -427,7 +449,15 @@ process_extended_line_op (unsigned char * data, break; case DW_LNE_set_address: - SAFE_BYTE_GET (adr, data, len - bytes_read - 1, end); + /* PR 17512: file: 002-100480-0.004. */ + if (len - bytes_read - 1 > 8) + { + warn (_("Length (%d) of DW_LNE_set_address op is too long\n"), + len - bytes_read - 1); + adr = 0; + } + else + SAFE_BYTE_GET (adr, data, len - bytes_read - 1, end); printf (_("set Address to 0x%s\n"), dwarf_vmatoa ("x", adr)); state_machine_regs.address = adr; state_machine_regs.op_index = 0; @@ -449,7 +479,7 @@ process_extended_line_op (unsigned char * data, printf ("%s\n\n", name); if (((unsigned int) (data - orig_data) != len) || data == end) - warn (_("DW_LNE_define_file: Bad opcode length\n")); + warn (_("DW_LNE_define_file: Bad opcode length\n")); break; case DW_LNE_set_discriminator: @@ -490,68 +520,68 @@ process_extended_line_op (unsigned char * data, break; case DW_LNE_HP_source_file_correlation: { - unsigned char *edata = data + len - bytes_read - 1; - - printf ("DW_LNE_HP_source_file_correlation\n"); - - while (data < edata) - { - unsigned int opc; - - opc = read_uleb128 (data, & bytes_read, edata); - data += bytes_read; - - switch (opc) - { - case DW_LNE_HP_SFC_formfeed: - printf (" DW_LNE_HP_SFC_formfeed\n"); - break; - case DW_LNE_HP_SFC_set_listing_line: - printf (" DW_LNE_HP_SFC_set_listing_line (%s)\n", - dwarf_vmatoa ("u", - read_uleb128 (data, & bytes_read, edata))); - data += bytes_read; - break; - case DW_LNE_HP_SFC_associate: - printf (" DW_LNE_HP_SFC_associate "); - printf ("(%s", - dwarf_vmatoa ("u", - read_uleb128 (data, & bytes_read, edata))); - data += bytes_read; - printf (",%s", - dwarf_vmatoa ("u", - read_uleb128 (data, & bytes_read, edata))); - data += bytes_read; - printf (",%s)\n", - dwarf_vmatoa ("u", - read_uleb128 (data, & bytes_read, edata))); - data += bytes_read; - break; - default: - printf (_(" UNKNOWN DW_LNE_HP_SFC opcode (%u)\n"), opc); - data = edata; - break; - } - } + unsigned char *edata = data + len - bytes_read - 1; + + printf ("DW_LNE_HP_source_file_correlation\n"); + + while (data < edata) + { + unsigned int opc; + + opc = read_uleb128 (data, & bytes_read, edata); + data += bytes_read; + + switch (opc) + { + case DW_LNE_HP_SFC_formfeed: + printf (" DW_LNE_HP_SFC_formfeed\n"); + break; + case DW_LNE_HP_SFC_set_listing_line: + printf (" DW_LNE_HP_SFC_set_listing_line (%s)\n", + dwarf_vmatoa ("u", + read_uleb128 (data, & bytes_read, edata))); + data += bytes_read; + break; + case DW_LNE_HP_SFC_associate: + printf (" DW_LNE_HP_SFC_associate "); + printf ("(%s", + dwarf_vmatoa ("u", + read_uleb128 (data, & bytes_read, edata))); + data += bytes_read; + printf (",%s", + dwarf_vmatoa ("u", + read_uleb128 (data, & bytes_read, edata))); + data += bytes_read; + printf (",%s)\n", + dwarf_vmatoa ("u", + read_uleb128 (data, & bytes_read, edata))); + data += bytes_read; + break; + default: + printf (_(" UNKNOWN DW_LNE_HP_SFC opcode (%u)\n"), opc); + data = edata; + break; + } + } } break; default: { - unsigned int rlen = len - bytes_read - 1; - - if (op_code >= DW_LNE_lo_user - /* The test against DW_LNW_hi_user is redundant due to - the limited range of the unsigned char data type used - for op_code. */ - /*&& op_code <= DW_LNE_hi_user*/) - printf (_("user defined: ")); - else - printf (_("UNKNOWN: ")); - printf (_("length %d ["), rlen); - for (; rlen; rlen--) - printf (" %02x", *data++); - printf ("]\n"); + unsigned int rlen = len - bytes_read - 1; + + if (op_code >= DW_LNE_lo_user + /* The test against DW_LNW_hi_user is redundant due to + the limited range of the unsigned char data type used + for op_code. */ + /*&& op_code <= DW_LNE_hi_user*/) + printf (_("user defined: ")); + else + printf (_("UNKNOWN: ")); + printf (_("length %d ["), rlen); + for (; rlen; rlen--) + printf (" %02x", *data++); + printf ("]\n"); } break; } @@ -628,7 +658,7 @@ fetch_indexed_value (dwarf_vma offset, dwarf_vma bytes) if (offset + bytes > section->size) { warn (_("Offset into section %s too big: %s\n"), - section->name, dwarf_vmatoa ("x", offset)); + section->name, dwarf_vmatoa ("x", offset)); return ""; } @@ -841,6 +871,8 @@ display_block (unsigned char *data, dwarf_vma maxlen; printf (_(" %s byte block: "), dwarf_vmatoa ("u", length)); + if (data > end) + return (unsigned char *) end; maxlen = (dwarf_vma) (end - data); length = length > maxlen ? maxlen : length; @@ -1231,8 +1263,7 @@ decode_location_expression (unsigned char * data, printf ("DW_OP_implicit_value"); uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; - display_block (data, uvalue, end); - data += uvalue; + data = display_block (data, uvalue, end); break; /* GNU extensions. */ @@ -1245,10 +1276,11 @@ decode_location_expression (unsigned char * data, break; case DW_OP_GNU_encoded_addr: { - int encoding; + int encoding = 0; dwarf_vma addr; - encoding = *data++; + if (data < end) + encoding = *data++; addr = get_encoded_value (&data, encoding, section, end); printf ("DW_OP_GNU_encoded_addr: fmt:%02x addr:", encoding); @@ -1281,6 +1313,9 @@ decode_location_expression (unsigned char * data, case DW_OP_GNU_entry_value: uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; + /* PR 17531: file: 0cc9cd00. */ + if (uvalue > (dwarf_vma) (end - data)) + uvalue = end - data; printf ("DW_OP_GNU_entry_value: ("); if (decode_location_expression (data, pointer_size, offset_size, dwarf_version, uvalue, @@ -1288,6 +1323,8 @@ decode_location_expression (unsigned char * data, need_frame_base = 1; putchar (')'); data += uvalue; + if (data > end) + data = end; break; case DW_OP_GNU_const_type: uvalue = read_uleb128 (data, &bytes_read, end); @@ -1295,8 +1332,7 @@ decode_location_expression (unsigned char * data, printf ("DW_OP_GNU_const_type: <0x%s> ", dwarf_vmatoa ("x", cu_offset + uvalue)); SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); - display_block (data, uvalue, end); - data += uvalue; + data = display_block (data, uvalue, end); break; case DW_OP_GNU_regval_type: uvalue = read_uleb128 (data, &bytes_read, end); @@ -1331,16 +1367,16 @@ decode_location_expression (unsigned char * data, printf ("DW_OP_GNU_parameter_ref: <0x%s>", dwarf_vmatoa ("x", cu_offset + uvalue)); break; - case DW_OP_GNU_addr_index: - uvalue = read_uleb128 (data, &bytes_read, end); - data += bytes_read; - printf ("DW_OP_GNU_addr_index <0x%s>", dwarf_vmatoa ("x", uvalue)); - break; - case DW_OP_GNU_const_index: - uvalue = read_uleb128 (data, &bytes_read, end); - data += bytes_read; - printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue)); - break; + case DW_OP_GNU_addr_index: + uvalue = read_uleb128 (data, &bytes_read, end); + data += bytes_read; + printf ("DW_OP_GNU_addr_index <0x%s>", dwarf_vmatoa ("x", uvalue)); + break; + case DW_OP_GNU_const_index: + uvalue = read_uleb128 (data, &bytes_read, end); + data += bytes_read; + printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue)); + break; /* HP extensions. */ case DW_OP_HP_is_value: @@ -1633,8 +1669,18 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_exprloc: uvalue = read_uleb128 (data, & bytes_read, end); block_start = data + bytes_read; + if (block_start >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } + /* FIXME: Testing "(block_start + uvalue) < block_start" miscompiles with + gcc 4.8.3 running on an x86_64 host in 32-bit mode. So we pre-compute + block_start + uvalue here. */ + data = block_start + uvalue; /* PR 17512: file: 008-103549-0.001:0.1. */ - if (block_start + uvalue > end) + if (block_start + uvalue > end || data < block_start) { warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); uvalue = end - block_start; @@ -1648,7 +1694,14 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_block1: SAFE_BYTE_GET (uvalue, data, 1, end); block_start = data + 1; - if (block_start + uvalue > end) + if (block_start >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } + data = block_start + uvalue; + if (block_start + uvalue > end || data < block_start) { warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); uvalue = end - block_start; @@ -1662,7 +1715,14 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_block2: SAFE_BYTE_GET (uvalue, data, 2, end); block_start = data + 2; - if (block_start + uvalue > end) + if (block_start >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } + data = block_start + uvalue; + if (block_start + uvalue > end || data < block_start) { warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); uvalue = end - block_start; @@ -1676,7 +1736,17 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_block4: SAFE_BYTE_GET (uvalue, data, 4, end); block_start = data + 4; - if (block_start + uvalue > end) + /* PR 17512: file: 3371-3907-0.004. */ + if (block_start >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } + data = block_start + uvalue; + if (block_start + uvalue > end + /* PR 17531: file: 5b5f0592. */ + || data < block_start) { warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); uvalue = end - block_start; @@ -1696,14 +1766,14 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_GNU_str_index: if (!do_loc) - { - const char *suffix = strrchr (section->name, '.'); - int dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? 1 : 0; - - printf (_(" (indexed string: 0x%s): %s"), - dwarf_vmatoa ("x", uvalue), - fetch_indexed_string (uvalue, this_set, offset_size, dwo)); - } + { + const char *suffix = strrchr (section->name, '.'); + int dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? 1 : 0; + + printf (_(" (indexed string: 0x%s): %s"), + dwarf_vmatoa ("x", uvalue), + fetch_indexed_string (uvalue, this_set, offset_size, dwo)); + } break; case DW_FORM_GNU_strp_alt: @@ -1731,9 +1801,9 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_GNU_addr_index: if (!do_loc) - printf (_(" (addr_index: 0x%s): %s"), - dwarf_vmatoa ("x", uvalue), - fetch_indexed_value (uvalue * pointer_size, pointer_size)); + printf (_(" (addr_index: 0x%s): %s"), + dwarf_vmatoa ("x", uvalue), + fetch_indexed_value (uvalue * pointer_size, pointer_size)); break; default: @@ -1761,7 +1831,7 @@ read_and_display_attr_value (unsigned long attribute, case DW_AT_GNU_call_site_data_value: case DW_AT_GNU_call_site_target: case DW_AT_GNU_call_site_target_clobbered: - if ((dwarf_version < 4 + if ((dwarf_version < 4 && (form == DW_FORM_data4 || form == DW_FORM_data8)) || form == DW_FORM_sec_offset) { @@ -1773,15 +1843,15 @@ read_and_display_attr_value (unsigned long attribute, { lmax += 1024; debug_info_p->loc_offsets = (dwarf_vma *) - xcrealloc (debug_info_p->loc_offsets, - lmax, sizeof (*debug_info_p->loc_offsets)); + xcrealloc (debug_info_p->loc_offsets, + lmax, sizeof (*debug_info_p->loc_offsets)); debug_info_p->have_frame_base = (int *) - xcrealloc (debug_info_p->have_frame_base, - lmax, sizeof (*debug_info_p->have_frame_base)); + xcrealloc (debug_info_p->have_frame_base, + lmax, sizeof (*debug_info_p->have_frame_base)); debug_info_p->max_loc_offsets = lmax; } if (this_set != NULL) - uvalue += this_set->section_offsets [DW_SECT_LOC]; + uvalue += this_set->section_offsets [DW_SECT_LOC]; debug_info_p->loc_offsets [num] = uvalue; debug_info_p->have_frame_base [num] = have_frame_base; debug_info_p->num_loc_offsets++; @@ -1794,15 +1864,15 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_GNU_addr_base: - debug_info_p->addr_base = uvalue; + debug_info_p->addr_base = uvalue; break; case DW_AT_GNU_ranges_base: - debug_info_p->ranges_base = uvalue; + debug_info_p->ranges_base = uvalue; break; case DW_AT_ranges: - if ((dwarf_version < 4 + if ((dwarf_version < 4 && (form == DW_FORM_data4 || form == DW_FORM_data8)) || form == DW_FORM_sec_offset) { @@ -1814,8 +1884,8 @@ read_and_display_attr_value (unsigned long attribute, { lmax += 1024; debug_info_p->range_lists = (dwarf_vma *) - xcrealloc (debug_info_p->range_lists, - lmax, sizeof (*debug_info_p->range_lists)); + xcrealloc (debug_info_p->range_lists, + lmax, sizeof (*debug_info_p->range_lists)); debug_info_p->max_range_lists = lmax; } debug_info_p->range_lists [num] = uvalue; @@ -2033,7 +2103,7 @@ read_and_display_attr_value (unsigned long attribute, case DW_AT_GNU_call_site_target: case DW_AT_GNU_call_site_target_clobbered: if ((dwarf_version < 4 - && (form == DW_FORM_data4 || form == DW_FORM_data8)) + && (form == DW_FORM_data4 || form == DW_FORM_data8)) || form == DW_FORM_sec_offset) printf (_(" (location list)")); /* Fall through. */ @@ -2064,7 +2134,7 @@ read_and_display_attr_value (unsigned long attribute, { if (form == DW_FORM_ref_sig8 || form == DW_FORM_GNU_ref_alt) - break; + break; if (form == DW_FORM_ref1 || form == DW_FORM_ref2 @@ -2073,7 +2143,7 @@ read_and_display_attr_value (unsigned long attribute, uvalue += cu_offset; if (uvalue >= section->size) - warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset %lx is too big.\n"), + warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"), dwarf_vmatoa ("x", uvalue), (unsigned long) (orig_data - section->start)); else @@ -2166,7 +2236,7 @@ read_and_display_attr (unsigned long attribute, static int process_debug_info (struct dwarf_section *section, void *file, - enum dwarf_section_display_enum abbrev_sec, + enum dwarf_section_display_enum abbrev_sec, int do_loc, int do_types) { @@ -2207,8 +2277,8 @@ process_debug_info (struct dwarf_section *section, /* Negative values are illegal, they may even cause infinite looping. This can happen if we can't accurately apply - relocations to an object file. */ - if ((signed long) length <= 0) + relocations to an object file, or if the file is corrupt. */ + if ((signed long) length <= 0 || section_begin < start) { warn (_("Corrupt unit length (0x%s) found in section %s\n"), dwarf_vmatoa ("x", length), section->name); @@ -2224,13 +2294,22 @@ process_debug_info (struct dwarf_section *section, /* Then allocate an array to hold the information. */ debug_information = (debug_info *) cmalloc (num_units, - sizeof (* debug_information)); + sizeof (* debug_information)); if (debug_information == NULL) { error (_("Not enough memory for a debug info array of %u entries\n"), num_units); + alloc_num_debug_info_entries = num_debug_info_entries = 0; return 0; } + /* PR 17531: file: 92ca3797. + We cannot rely upon the debug_information array being initialised + before it is used. A corrupt file could easily contain references + to a unit for which information has not been made available. So + we ensure that the array is zeroed here. */ + memset (debug_information, 0, num_units * sizeof (*debug_information)); + + alloc_num_debug_info_entries = num_units; } if (!do_loc) @@ -2314,11 +2393,11 @@ process_debug_info (struct dwarf_section *section, } if (do_types) - { + { SAFE_BYTE_GET64 (hdrptr, &signature_high, &signature_low, end); hdrptr += 8; SAFE_BYTE_GET_AND_INC (type_offset, hdrptr, offset_size, end); - } + } if ((do_loc || do_debug_loc || do_debug_ranges) && num_debug_info_entries == 0 @@ -2387,14 +2466,22 @@ process_debug_info (struct dwarf_section *section, > section->size) { warn (_("Debug info is corrupted, length of CU at %s" - " extends beyond end of section (length = %s)\n"), + " extends beyond end of section (length = %s)\n"), dwarf_vmatoa ("x", cu_offset), dwarf_vmatoa ("x", compunit.cu_length)); + num_units = unit; break; } tags = hdrptr; start += compunit.cu_length + initial_length_size; + if (start > end) + { + warn (_("Debug info is corrupt. CU at %s extends beyond end of section"), + dwarf_vmatoa ("x", cu_offset)); + start = end; + } + if (compunit.cu_version != 2 && compunit.cu_version != 3 && compunit.cu_version != 4) @@ -2412,6 +2499,12 @@ process_debug_info (struct dwarf_section *section, warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"), (unsigned long) compunit.cu_abbrev_offset, (unsigned long) abbrev_size); + /* PR 17531: file:4bcd9ce9. */ + else if ((abbrev_base + abbrev_size) + > debug_displays [abbrev_sec].section.size) + warn (_("Debug info is corrupted, abbrev size (%lx) is larger than abbrev section size (%lx)\n"), + (unsigned long) abbrev_base + abbrev_size, + (unsigned long) debug_displays [abbrev_sec].section.size); else process_abbrev_section (((unsigned char *) debug_displays [abbrev_sec].section.start @@ -2511,7 +2604,7 @@ process_debug_info (struct dwarf_section *section, printf ("\n"); fflush (stdout); } - warn (_("DIE at offset %lx refers to abbreviation number %lu which does not exist\n"), + warn (_("DIE at offset 0x%lx refers to abbreviation number %lu which does not exist\n"), die_offset, abbrev_number); return 0; } @@ -2545,9 +2638,10 @@ process_debug_info (struct dwarf_section *section, /* Show the offset from where the tag was extracted. */ printf (" <%lx>", (unsigned long)(tags - section_begin)); - arg = debug_information; - if (debug_information) - arg += unit; + if (debug_information && unit < alloc_num_debug_info_entries) + arg = debug_information + unit; + else + arg = NULL; tags = read_and_display_attr (attr->attribute, attr->form, @@ -2563,9 +2657,9 @@ process_debug_info (struct dwarf_section *section, this_set); } - if (entry->children) - ++level; - } + if (entry->children) + ++level; + } } /* Set num_debug_info_entries here so that it can be used to check if @@ -2573,7 +2667,12 @@ process_debug_info (struct dwarf_section *section, if ((do_loc || do_debug_loc || do_debug_ranges) && num_debug_info_entries == 0 && ! do_types) - num_debug_info_entries = num_units; + { + if (num_units > alloc_num_debug_info_entries) + num_debug_info_entries = alloc_num_debug_info_entries; + else + num_debug_info_entries = num_units; + } if (!do_loc) printf ("\n"); @@ -2610,9 +2709,10 @@ load_debug_info (void * file) if (load_debug_section (info, file) && process_debug_info (&debug_displays [info].section, file, abbrev, 1, 0)) return num_debug_info_entries; - else if (load_debug_section (info_dwo, file) - && process_debug_info (&debug_displays [info_dwo].section, file, - abbrev_dwo, 1, 0)) + + if (load_debug_section (info_dwo, file) + && process_debug_info (&debug_displays [info_dwo].section, file, + abbrev_dwo, 1, 0)) return num_debug_info_entries; num_debug_info_entries = DEBUG_INFO_UNAVAILABLE; @@ -2637,7 +2737,7 @@ read_debug_line_header (struct dwarf_section * section, /* Extract information from the Line Number Program Header. (section 6.2.4 in the Dwarf3 doc). */ - hdrptr = data; + hdrptr = data; /* Get and check the length of the block. */ SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 4, end); @@ -2706,18 +2806,27 @@ read_debug_line_header (struct dwarf_section * section, SAFE_BYTE_GET_AND_INC (linfo->li_opcode_base, hdrptr, 1, end); * end_of_sequence = data + linfo->li_length + initial_length_size; + /* PR 17512: file:002-117414-0.004. */ + if (* end_of_sequence > end) + { + warn (_("Line length %s extends beyond end of section\n"), + dwarf_vmatoa ("u", linfo->li_length)); + * end_of_sequence = end; + return NULL; + } + return hdrptr; } static int display_debug_lines_raw (struct dwarf_section *section, unsigned char *data, - unsigned char *end) + unsigned char *end) { unsigned char *start = section->start; printf (_("Raw dump of debug contents of section %s:\n\n"), - section->name); + section->name); while (data < end) { @@ -2746,6 +2855,12 @@ display_debug_lines_raw (struct dwarf_section *section, end_of_sequence = end; standard_opcodes = NULL; linfo = saved_linfo; + /* PR 17531: file: 0522b371. */ + if (linfo.li_line_range == 0) + { + warn (_("Partial .debug_line. section encountered without a prior full .debug_line section\n")); + return 0; + } reset_state_machine (linfo.li_default_is_stmt); } else @@ -2759,7 +2874,7 @@ display_debug_lines_raw (struct dwarf_section *section, printf (_(" Offset: 0x%lx\n"), (long)(data - start)); printf (_(" Length: %ld\n"), (long) linfo.li_length); printf (_(" DWARF Version: %d\n"), linfo.li_version); - printf (_(" Prologue Length: %d\n"), linfo.li_prologue_length); + printf (_(" Prologue Length: %d\n"), (int) linfo.li_prologue_length); printf (_(" Minimum Instruction Length: %d\n"), linfo.li_min_insn_length); if (linfo.li_version >= 4) printf (_(" Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn); @@ -2768,11 +2883,25 @@ display_debug_lines_raw (struct dwarf_section *section, printf (_(" Line Range: %d\n"), linfo.li_line_range); printf (_(" Opcode Base: %d\n"), linfo.li_opcode_base); + /* PR 17512: file: 1665-6428-0.004. */ + if (linfo.li_line_range == 0) + { + warn (_("Line range of 0 is invalid, using 1 instead\n")); + linfo.li_line_range = 1; + } + reset_state_machine (linfo.li_default_is_stmt); /* Display the contents of the Opcodes table. */ standard_opcodes = hdrptr; + /* PR 17512: file: 002-417945-0.004. */ + if (standard_opcodes + linfo.li_opcode_base >= end) + { + warn (_("Line Base extends beyond end of section\n")); + return 0; + } + printf (_("\n Opcodes:\n")); for (i = 1; i < linfo.li_opcode_base; i++) @@ -2788,12 +2917,16 @@ display_debug_lines_raw (struct dwarf_section *section, printf (_("\n The Directory Table (offset 0x%lx):\n"), (long)(data - start)); - while (*data != 0) + while (data < end && *data != 0) { - printf (" %d\t%s\n", ++last_dir_entry, data); + printf (" %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data); data += strnlen ((char *) data, end - data) + 1; } + + /* PR 17512: file: 002-132094-0.004. */ + if (data >= end - 1) + break; } /* Skip the NUL at the end of the table. */ @@ -2808,7 +2941,7 @@ display_debug_lines_raw (struct dwarf_section *section, (long)(data - start)); printf (_(" Entry\tDir\tTime\tSize\tName\n")); - while (*data != 0) + while (data < end && *data != 0) { unsigned char *name; unsigned int bytes_read; @@ -2826,7 +2959,7 @@ display_debug_lines_raw (struct dwarf_section *section, printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); data += bytes_read; - printf ("%s\n", name); + printf ("%.*s\n", (int)(end - name), name); if (data == end) { @@ -3056,7 +3189,7 @@ display_debug_lines_decoded (struct dwarf_section *section, static DWARF2_Internal_LineInfo saved_linfo; printf (_("Decoded dump of debug contents of section %s:\n\n"), - section->name); + section->name); while (data < end) { @@ -3074,21 +3207,33 @@ display_debug_lines_decoded (struct dwarf_section *section, /* Note: the following does not apply to .debug_line.dwo sections. These are full debug_line sections. */ && strcmp (section->name, ".debug_line.dwo") != 0) - { + { /* See comment in display_debug_lines_raw(). */ end_of_sequence = end; standard_opcodes = NULL; linfo = saved_linfo; + /* PR 17531: file: 0522b371. */ + if (linfo.li_line_range == 0) + { + warn (_("Partial .debug_line. section encountered without a prior full .debug_line section\n")); + return 0; + } reset_state_machine (linfo.li_default_is_stmt); - } + } else - { + { unsigned char *hdrptr; if ((hdrptr = read_debug_line_header (section, data, end, & linfo, & end_of_sequence)) == NULL) return 0; + /* PR 17531: file: 0522b371. */ + if (linfo.li_line_range == 0) + { + warn (_("Line range of 0 is invalid, using 1 instead\n")); + linfo.li_line_range = 1; + } reset_state_machine (linfo.li_default_is_stmt); /* Save a pointer to the contents of the Opcodes table. */ @@ -3197,16 +3342,16 @@ display_debug_lines_decoded (struct dwarf_section *section, /* This loop iterates through the Dwarf Line Number Program. */ while (data < end_of_sequence) - { + { unsigned char op_code; - int adv; - unsigned long int uladv; - unsigned int bytes_read; - int is_special_opcode = 0; + int adv; + unsigned long int uladv; + unsigned int bytes_read; + int is_special_opcode = 0; - op_code = *data++; + op_code = *data++; - if (op_code >= linfo.li_opcode_base) + if (op_code >= linfo.li_opcode_base) { op_code -= linfo.li_opcode_base; uladv = (op_code / linfo.li_line_range); @@ -3226,11 +3371,11 @@ display_debug_lines_decoded (struct dwarf_section *section, % linfo.li_max_ops_per_insn; } - adv = (op_code % linfo.li_line_range) + linfo.li_line_base; - state_machine_regs.line += adv; - is_special_opcode = 1; - } - else switch (op_code) + adv = (op_code % linfo.li_line_range) + linfo.li_line_base; + state_machine_regs.line += adv; + is_special_opcode = 1; + } + else switch (op_code) { case DW_LNS_extended_op: { @@ -3420,15 +3565,15 @@ display_debug_lines_decoded (struct dwarf_section *section, break; } - /* Only Special opcodes, DW_LNS_copy and DW_LNE_end_sequence adds a row - to the DWARF address/line matrix. */ - if ((is_special_opcode) || (op_code == DW_LNE_end_sequence) + /* Only Special opcodes, DW_LNS_copy and DW_LNE_end_sequence adds a row + to the DWARF address/line matrix. */ + if ((is_special_opcode) || (op_code == DW_LNE_end_sequence) || (op_code == DW_LNS_copy)) - { - const unsigned int MAX_FILENAME_LENGTH = 35; - char *fileName; - char *newFileName = NULL; - size_t fileNameLength; + { + const unsigned int MAX_FILENAME_LENGTH = 35; + char *fileName; + char *newFileName = NULL; + size_t fileNameLength; if (file_table) fileName = (char *) file_table[state_machine_regs.file - 1].name; @@ -3437,22 +3582,22 @@ display_debug_lines_decoded (struct dwarf_section *section, fileNameLength = strlen (fileName); - if ((fileNameLength > MAX_FILENAME_LENGTH) && (!do_wide)) - { - newFileName = (char *) xmalloc (MAX_FILENAME_LENGTH + 1); - /* Truncate file name */ - strncpy (newFileName, - fileName + fileNameLength - MAX_FILENAME_LENGTH, - MAX_FILENAME_LENGTH + 1); - } - else - { - newFileName = (char *) xmalloc (fileNameLength + 1); - strncpy (newFileName, fileName, fileNameLength + 1); - } - - if (!do_wide || (fileNameLength <= MAX_FILENAME_LENGTH)) - { + if ((fileNameLength > MAX_FILENAME_LENGTH) && (!do_wide)) + { + newFileName = (char *) xmalloc (MAX_FILENAME_LENGTH + 1); + /* Truncate file name */ + strncpy (newFileName, + fileName + fileNameLength - MAX_FILENAME_LENGTH, + MAX_FILENAME_LENGTH + 1); + } + else + { + newFileName = (char *) xmalloc (fileNameLength + 1); + strncpy (newFileName, fileName, fileNameLength + 1); + } + + if (!do_wide || (fileNameLength <= MAX_FILENAME_LENGTH)) + { if (linfo.li_max_ops_per_insn == 1) printf ("%-35s %11d %#18" DWARF_VMA_FMT "x\n", newFileName, state_machine_regs.line, @@ -3462,9 +3607,9 @@ display_debug_lines_decoded (struct dwarf_section *section, newFileName, state_machine_regs.line, state_machine_regs.address, state_machine_regs.op_index); - } - else - { + } + else + { if (linfo.li_max_ops_per_insn == 1) printf ("%s %11d %#18" DWARF_VMA_FMT "x\n", newFileName, state_machine_regs.line, @@ -3474,14 +3619,14 @@ display_debug_lines_decoded (struct dwarf_section *section, newFileName, state_machine_regs.line, state_machine_regs.address, state_machine_regs.op_index); - } + } - if (op_code == DW_LNE_end_sequence) + if (op_code == DW_LNE_end_sequence) printf ("\n"); - free (newFileName); - } - } + free (newFileName); + } + } if (file_table) { @@ -3578,7 +3723,8 @@ display_debug_pubnames_worker (struct dwarf_section *section, while (start < end) { unsigned char *data; - unsigned long offset; + unsigned char *adr; + dwarf_vma offset; unsigned int offset_size, initial_length_size; data = start; @@ -3607,7 +3753,26 @@ display_debug_pubnames_worker (struct dwarf_section *section, SAFE_BYTE_GET_AND_INC (names.pn_size, data, offset_size, end); - start += names.pn_length + initial_length_size; + adr = start + names.pn_length + initial_length_size; + /* PR 17531: file: 7615b6b2. */ + if ((dwarf_signed_vma) names.pn_length < 0 + /* PR 17531: file: a5dbeaa7. */ + || adr < start) + { + warn (_("Negative length for public name: 0x%lx\n"), (long) names.pn_length); + start = end; + } + else + start = adr; + + printf (_(" Length: %ld\n"), + (long) names.pn_length); + printf (_(" Version: %d\n"), + names.pn_version); + printf (_(" Offset into .debug_info section: 0x%lx\n"), + (unsigned long) names.pn_offset); + printf (_(" Size of area in .debug_info section: %ld\n"), + (long) names.pn_size); if (names.pn_version != 2 && names.pn_version != 3) { @@ -3622,15 +3787,6 @@ display_debug_pubnames_worker (struct dwarf_section *section, continue; } - printf (_(" Length: %ld\n"), - (long) names.pn_length); - printf (_(" Version: %d\n"), - names.pn_version); - printf (_(" Offset into .debug_info section: 0x%lx\n"), - (unsigned long) names.pn_offset); - printf (_(" Size of area in .debug_info section: %ld\n"), - (long) names.pn_size); - if (is_gnu) printf (_("\n Offset Kind Name\n")); else @@ -3648,7 +3804,7 @@ display_debug_pubnames_worker (struct dwarf_section *section, if (data >= end) break; maxprint = (end - data) - 1; - + if (is_gnu) { unsigned int kind_data; @@ -3668,11 +3824,12 @@ display_debug_pubnames_worker (struct dwarf_section *section, kind_name = get_gdb_index_symbol_kind_name (kind); is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (kind_data); printf (" %-6lx %s,%-10s %.*s\n", - offset, is_static ? _("s") : _("g"), + (unsigned long) offset, is_static ? _("s") : _("g"), kind_name, (int) maxprint, data); } else - printf (" %-6lx\t%.*s\n", offset, (int) maxprint, data); + printf (" %-6lx\t%.*s\n", + (unsigned long) offset, (int) maxprint, data); data += strnlen ((char *) data, maxprint) + 1; if (data >= end) @@ -4112,7 +4269,7 @@ display_debug_macro (struct dwarf_section *section, } printf ("\n"); - } + } return 1; } @@ -4167,24 +4324,36 @@ display_debug_abbrev (struct dwarf_section *section, static void display_loc_list (struct dwarf_section *section, - unsigned char **start_ptr, - int debug_info_entry, - unsigned long offset, - unsigned long base_address, - int has_frame_base) + unsigned char **start_ptr, + unsigned int debug_info_entry, + unsigned long offset, + unsigned long base_address, + int has_frame_base) { unsigned char *start = *start_ptr; unsigned char *section_end = section->start + section->size; - unsigned long cu_offset = debug_information [debug_info_entry].cu_offset; - unsigned int pointer_size = debug_information [debug_info_entry].pointer_size; - unsigned int offset_size = debug_information [debug_info_entry].offset_size; - int dwarf_version = debug_information [debug_info_entry].dwarf_version; + unsigned long cu_offset; + unsigned int pointer_size; + unsigned int offset_size; + int dwarf_version; dwarf_vma begin; dwarf_vma end; unsigned short length; int need_frame_base; + if (debug_info_entry >= num_debug_info_entries) + { + warn (_("No debug information available for loc lists of entry: %u\n"), + debug_info_entry); + return; + } + + cu_offset = debug_information [debug_info_entry].cu_offset; + pointer_size = debug_information [debug_info_entry].pointer_size; + offset_size = debug_information [debug_info_entry].offset_size; + dwarf_version = debug_information [debug_info_entry].dwarf_version; + if (pointer_size < 2 || pointer_size > 8) { warn (_("Invalid pointer size (%d) in debug info for entry %d\n"), @@ -4195,72 +4364,72 @@ display_loc_list (struct dwarf_section *section, while (1) { if (start + 2 * pointer_size > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } printf (" %8.8lx ", offset + (start - *start_ptr)); /* Note: we use sign extension here in order to be sure that we can detect - the -1 escape value. Sign extension into the top 32 bits of a 32-bit - address will not affect the values that we display since we always show - hex values, and always the bottom 32-bits. */ + the -1 escape value. Sign extension into the top 32 bits of a 32-bit + address will not affect the values that we display since we always show + hex values, and always the bottom 32-bits. */ SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end); SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end); if (begin == 0 && end == 0) - { - printf (_("\n")); - break; - } + { + printf (_("\n")); + break; + } /* Check base address specifiers. */ if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1) - { - base_address = end; - print_dwarf_vma (begin, pointer_size); - print_dwarf_vma (end, pointer_size); - printf (_("(base address)\n")); - continue; - } + { + base_address = end; + print_dwarf_vma (begin, pointer_size); + print_dwarf_vma (end, pointer_size); + printf (_("(base address)\n")); + continue; + } if (start + 2 > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } SAFE_BYTE_GET_AND_INC (length, start, 2, section_end); if (start + length > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } print_dwarf_vma (begin + base_address, pointer_size); print_dwarf_vma (end + base_address, pointer_size); putchar ('('); need_frame_base = decode_location_expression (start, - pointer_size, - offset_size, - dwarf_version, - length, - cu_offset, section); + pointer_size, + offset_size, + dwarf_version, + length, + cu_offset, section); putchar (')'); if (need_frame_base && !has_frame_base) - printf (_(" [without DW_AT_frame_base]")); + printf (_(" [without DW_AT_frame_base]")); if (begin == end) - fputs (_(" (start == end)"), stdout); + fputs (_(" (start == end)"), stdout); else if (begin > end) - fputs (_(" (start > end)"), stdout); + fputs (_(" (start > end)"), stdout); putchar ('\n'); @@ -4287,23 +4456,35 @@ print_addr_index (unsigned int idx, unsigned int len) static void display_loc_list_dwo (struct dwarf_section *section, - unsigned char **start_ptr, - int debug_info_entry, - unsigned long offset, - int has_frame_base) + unsigned char **start_ptr, + unsigned int debug_info_entry, + unsigned long offset, + int has_frame_base) { unsigned char *start = *start_ptr; unsigned char *section_end = section->start + section->size; - unsigned long cu_offset = debug_information [debug_info_entry].cu_offset; - unsigned int pointer_size = debug_information [debug_info_entry].pointer_size; - unsigned int offset_size = debug_information [debug_info_entry].offset_size; - int dwarf_version = debug_information [debug_info_entry].dwarf_version; + unsigned long cu_offset; + unsigned int pointer_size; + unsigned int offset_size; + int dwarf_version; int entry_type; unsigned short length; int need_frame_base; unsigned int idx; unsigned int bytes_read; + if (debug_info_entry >= num_debug_info_entries) + { + warn (_("No debug information for loc lists of entry: %u\n"), + debug_info_entry); + return; + } + + cu_offset = debug_information [debug_info_entry].cu_offset; + pointer_size = debug_information [debug_info_entry].pointer_size; + offset_size = debug_information [debug_info_entry].offset_size; + dwarf_version = debug_information [debug_info_entry].dwarf_version; + if (pointer_size < 2 || pointer_size > 8) { warn (_("Invalid pointer size (%d) in debug info for entry %d\n"), @@ -4316,79 +4497,79 @@ display_loc_list_dwo (struct dwarf_section *section, printf (" %8.8lx ", offset + (start - *start_ptr)); if (start >= section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } SAFE_BYTE_GET_AND_INC (entry_type, start, 1, section_end); switch (entry_type) - { - case 0: /* A terminating entry. */ - *start_ptr = start; - printf (_("\n")); - return; - case 1: /* A base-address entry. */ - idx = read_uleb128 (start, &bytes_read, section_end); - start += bytes_read; - print_addr_index (idx, 8); - printf (" "); - printf (_("(base address selection entry)\n")); - continue; - case 2: /* A start/end entry. */ - idx = read_uleb128 (start, &bytes_read, section_end); - start += bytes_read; - print_addr_index (idx, 8); - idx = read_uleb128 (start, &bytes_read, section_end); - start += bytes_read; - print_addr_index (idx, 8); - break; - case 3: /* A start/length entry. */ - idx = read_uleb128 (start, &bytes_read, section_end); - start += bytes_read; - print_addr_index (idx, 8); - SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); - printf ("%08x ", idx); - break; - case 4: /* An offset pair entry. */ - SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); - printf ("%08x ", idx); - SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); - printf ("%08x ", idx); - break; - default: - warn (_("Unknown location list entry type 0x%x.\n"), entry_type); - *start_ptr = start; - return; - } + { + case 0: /* A terminating entry. */ + *start_ptr = start; + printf (_("\n")); + return; + case 1: /* A base-address entry. */ + idx = read_uleb128 (start, &bytes_read, section_end); + start += bytes_read; + print_addr_index (idx, 8); + printf (" "); + printf (_("(base address selection entry)\n")); + continue; + case 2: /* A start/end entry. */ + idx = read_uleb128 (start, &bytes_read, section_end); + start += bytes_read; + print_addr_index (idx, 8); + idx = read_uleb128 (start, &bytes_read, section_end); + start += bytes_read; + print_addr_index (idx, 8); + break; + case 3: /* A start/length entry. */ + idx = read_uleb128 (start, &bytes_read, section_end); + start += bytes_read; + print_addr_index (idx, 8); + SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); + printf ("%08x ", idx); + break; + case 4: /* An offset pair entry. */ + SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); + printf ("%08x ", idx); + SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); + printf ("%08x ", idx); + break; + default: + warn (_("Unknown location list entry type 0x%x.\n"), entry_type); + *start_ptr = start; + return; + } if (start + 2 > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } SAFE_BYTE_GET_AND_INC (length, start, 2, section_end); if (start + length > section_end) - { - warn (_("Location list starting at offset 0x%lx is not terminated.\n"), - offset); - break; - } + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } putchar ('('); need_frame_base = decode_location_expression (start, - pointer_size, - offset_size, - dwarf_version, - length, - cu_offset, section); + pointer_size, + offset_size, + dwarf_version, + length, + cu_offset, section); putchar (')'); if (need_frame_base && !has_frame_base) - printf (_(" [without DW_AT_frame_base]")); + printf (_(" [without DW_AT_frame_base]")); putchar ('\n'); @@ -4536,11 +4717,11 @@ display_debug_loc (struct dwarf_section *section, void *file) if (start < next) warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"), (unsigned long) (start - section_begin), - (unsigned long) (next - section_begin)); + (unsigned long) offset); else if (start > next) warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"), (unsigned long) (start - section_begin), - (unsigned long) (next - section_begin)); + (unsigned long) offset); } start = next; @@ -4551,11 +4732,11 @@ display_debug_loc (struct dwarf_section *section, void *file) continue; } - if (is_dwo) - display_loc_list_dwo (section, &start, i, offset, has_frame_base); - else - display_loc_list (section, &start, i, offset, base_address, - has_frame_base); + if (is_dwo) + display_loc_list_dwo (section, &start, i, offset, has_frame_base); + else + display_loc_list (section, &start, i, offset, base_address, + has_frame_base); } } @@ -4740,7 +4921,13 @@ display_debug_aranges (struct dwarf_section *section, if (excess) addr_ranges += (2 * address_size) - excess; - start += arange.ar_length + initial_length_size; + hdrptr = start + arange.ar_length + initial_length_size; + if (hdrptr < start || hdrptr > end) + { + error (_("Excessive header length: %lx\n"), (long) arange.ar_length); + break; + } + start = hdrptr; while (addr_ranges + 2 * address_size <= start) { @@ -4771,7 +4958,7 @@ comp_addr_base (const void * v0, const void * v1) /* Display the debug_addr section. */ static int display_debug_addr (struct dwarf_section *section, - void *file) + void *file) { debug_info **debug_addr_info; unsigned char *entry; @@ -4794,42 +4981,51 @@ display_debug_addr (struct dwarf_section *section, printf (_("Contents of the %s section:\n\n"), section->name); - debug_addr_info = (debug_info **) xmalloc ((num_debug_info_entries + 1) - * sizeof (debug_info *)); + /* PR 17531: file: cf38d01b. + We use xcalloc because a corrupt file may not have initialised all of the + fields in the debug_info structure, which means that the sort below might + try to move uninitialised data. */ + debug_addr_info = (debug_info **) xcalloc ((num_debug_info_entries + 1), + sizeof (debug_info *)); count = 0; for (i = 0; i < num_debug_info_entries; i++) - { - if (debug_information [i].addr_base != DEBUG_INFO_UNAVAILABLE) - debug_addr_info [count++] = &debug_information [i]; - } + if (debug_information [i].addr_base != DEBUG_INFO_UNAVAILABLE) + { + /* PR 17531: file: cf38d01b. */ + if (debug_information[i].addr_base >= section->size) + warn (_("Corrupt address base (%lx) found in debug section %u\n"), + (unsigned long) debug_information[i].addr_base, i); + else + debug_addr_info [count++] = debug_information + i; + } /* Add a sentinel to make iteration convenient. */ debug_addr_info [count] = (debug_info *) xmalloc (sizeof (debug_info)); debug_addr_info [count]->addr_base = section->size; - qsort (debug_addr_info, count, sizeof (debug_info *), comp_addr_base); + for (i = 0; i < count; i++) { unsigned int idx; unsigned int address_size = debug_addr_info [i]->pointer_size; printf (_(" For compilation unit at offset 0x%s:\n"), - dwarf_vmatoa ("x", debug_addr_info [i]->cu_offset)); + dwarf_vmatoa ("x", debug_addr_info [i]->cu_offset)); printf (_("\tIndex\tAddress\n")); entry = section->start + debug_addr_info [i]->addr_base; end = section->start + debug_addr_info [i + 1]->addr_base; idx = 0; while (entry < end) - { - dwarf_vma base = byte_get (entry, address_size); - printf (_("\t%d:\t"), idx); - print_dwarf_vma (base, address_size); - printf ("\n"); - entry += address_size; - idx++; - } + { + dwarf_vma base = byte_get (entry, address_size); + printf (_("\t%d:\t"), idx); + print_dwarf_vma (base, address_size); + printf ("\n"); + entry += address_size; + idx++; + } } printf ("\n"); @@ -4840,7 +5036,7 @@ display_debug_addr (struct dwarf_section *section, /* Display the .debug_str_offsets and .debug_str_offsets.dwo sections. */ static int display_debug_str_offsets (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) + void *file ATTRIBUTE_UNUSED) { if (section->size == 0) { @@ -4909,7 +5105,7 @@ display_debug_ranges (struct dwarf_section *section, if (num_range_list == 0) { /* This can happen when the file was compiled with -gsplit-debug - which removes references to range lists from the primary .o file. */ + which removes references to range lists from the primary .o file. */ printf (_("No range lists in .debug_info section.\n")); return 1; } @@ -4962,7 +5158,7 @@ display_debug_ranges (struct dwarf_section *section, pointer_size, offset); continue; } - + if (dwarf_check != 0 && i > 0) { if (start < next) @@ -5036,7 +5232,7 @@ typedef struct Frame_Chunk { struct Frame_Chunk *next; unsigned char *chunk_start; - int ncols; + unsigned int ncols; /* DW_CFA_{undefined,same_value,offset,register,unreferenced} */ short int *col_type; int *col_offset; @@ -5046,8 +5242,8 @@ typedef struct Frame_Chunk dwarf_vma pc_begin; dwarf_vma pc_range; int cfa_reg; - int cfa_offset; - int ra; + dwarf_vma cfa_offset; + unsigned int ra; unsigned char fde_encoding; unsigned char cfa_exp; unsigned char ptr_size; @@ -5062,13 +5258,13 @@ static unsigned int dwarf_regnames_count; in the frame info. */ #define DW_CFA_unreferenced (-1) -/* Return 0 if not more space is needed, 1 if more space is needed, +/* Return 0 if no more space is needed, 1 if more space is needed, -1 for invalid reg. */ static int frame_need_space (Frame_Chunk *fc, unsigned int reg) { - int prev = fc->ncols; + unsigned int prev = fc->ncols; if (reg < (unsigned int) fc->ncols) return 0; @@ -5078,10 +5274,25 @@ frame_need_space (Frame_Chunk *fc, unsigned int reg) return -1; fc->ncols = reg + 1; + /* PR 17512: file: 10450-2643-0.004. + If reg == -1 then this can happen... */ + if (fc->ncols == 0) + return -1; + + /* PR 17512: file: 2844a11d. */ + if (fc->ncols > 1024) + { + error (_("Unfeasibly large register number: %u\n"), reg); + fc->ncols = 0; + /* FIXME: 1024 is an arbitrary limit. Increase it if + we ever encounter a valid binary that exceeds it. */ + return -1; + } + fc->col_type = (short int *) xcrealloc (fc->col_type, fc->ncols, - sizeof (short int)); + sizeof (short int)); fc->col_offset = (int *) xcrealloc (fc->col_offset, fc->ncols, sizeof (int)); - /* PR 17512: file:002-10025-0.005. */ + /* PR 17512: file:002-10025-0.005. */ if (fc->col_type == NULL || fc->col_offset == NULL) { error (_("Out of memory allocating %u columns in dwarf frame arrays\n"), @@ -5171,16 +5382,16 @@ init_dwarf_regnames_x86_64 (void) static const char *const dwarf_regnames_aarch64[] = { - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", + "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", NULL, "elr", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", - "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", }; @@ -5236,9 +5447,9 @@ regname (unsigned int regno, int row) } static void -frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) +frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_regs) { - int r; + unsigned int r; char tmp[100]; if (*max_regs < fc->ncols) @@ -5268,7 +5479,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) if (fc->cfa_exp) strcpy (tmp, "exp"); else - sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), fc->cfa_offset); + sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), (int) fc->cfa_offset); printf ("%-8s ", tmp); for (r = 0; r < fc->ncols; r++) @@ -5354,7 +5565,20 @@ read_cie (unsigned char *start, unsigned char *end, if (version >= 4) { GET (fc->ptr_size, 1); + if (fc->ptr_size < 1 || fc->ptr_size > 8) + { + warn (_("Invalid pointer size (%d) in CIE data\n"), fc->ptr_size); + return end; + } + GET (fc->segment_size, 1); + /* PR 17512: file: e99d2804. */ + if (fc->segment_size > 8 || fc->segment_size + fc->ptr_size > 8) + { + warn (_("Invalid segment size (%d) in CIE data\n"), fc->segment_size); + return end; + } + eh_addr_size = fc->ptr_size; } else @@ -5378,15 +5602,32 @@ read_cie (unsigned char *start, unsigned char *end, augmentation_data_len = LEB (); augmentation_data = start; start += augmentation_data_len; + /* PR 17512: file: 11042-2589-0.004. */ + if (start > end) + { + warn (_("Augmentation data too long: 0x%lx\n"), augmentation_data_len); + return end; + } } if (augmentation_data_len) { - unsigned char *p, *q; + unsigned char *p; + unsigned char *q; + unsigned char *qend; + p = (unsigned char *) fc->augmentation + 1; q = augmentation_data; + qend = q + augmentation_data_len; - while (1) + /* PR 17531: file: 015adfaa. */ + if (qend < q) + { + warn (_("Negative augmentation data length: 0x%lx"), augmentation_data_len); + augmentation_data_len = 0; + } + + while (p < end && q < augmentation_data + augmentation_data_len) { if (*p == 'L') q++; @@ -5400,6 +5641,8 @@ read_cie (unsigned char *start, unsigned char *end, break; p++; } + /* Note - it is OK if this loop terminates with q < qend. + Padding may have been inserted to align the end of the CIE. */ } *p_cie = fc; @@ -5425,9 +5668,9 @@ display_debug_frames (struct dwarf_section *section, Frame_Chunk *rs; int is_eh = strcmp (section->name, ".eh_frame") == 0; unsigned int length_return; - int max_regs = 0; + unsigned int max_regs = 0; const char *bad_reg = _("bad register: "); - int saved_eh_addr_size = eh_addr_size; + unsigned int saved_eh_addr_size = eh_addr_size; printf (_("Contents of the %s section:\n"), section->name); @@ -5454,6 +5697,12 @@ display_debug_frames (struct dwarf_section *section, { printf ("\n%08lx ZERO terminator\n\n", (unsigned long)(saved_start - section_start)); + /* Skip any zero terminators that directly follow. + A corrupt section size could have loaded a whole + slew of zero filled memory bytes. eg + PR 17512: file: 070-19381-0.004. */ + while (start < end && * start == 0) + ++ start; continue; } @@ -5484,21 +5733,23 @@ display_debug_frames (struct dwarf_section *section, || (offset_size == 8 && cie_id == DW64_CIE_ID))) { int version; - int mreg; + unsigned int mreg; start = read_cie (start, end, &cie, &version, &augmentation_data_len, &augmentation_data); /* PR 17512: file: 027-135133-0.005. */ if (cie == NULL) break; + fc = cie; fc->next = chunks; chunks = fc; fc->chunk_start = saved_start; - mreg = max_regs - 1; + mreg = max_regs > 0 ? max_regs - 1 : 0; if (mreg < fc->ra) mreg = fc->ra; - frame_need_space (fc, mreg); + if (frame_need_space (fc, mreg) < 0) + break; if (fc->fde_encoding) encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); @@ -5528,8 +5779,11 @@ display_debug_frames (struct dwarf_section *section, if (augmentation_data_len) { unsigned long i; + printf (" Augmentation data: "); for (i = 0; i < augmentation_data_len; ++i) + /* FIXME: If do_wide is FALSE, then we should + add carriage returns at 80 columns... */ printf (" %02x", augmentation_data[i]); putchar ('\n'); } @@ -5585,17 +5839,27 @@ display_debug_frames (struct dwarf_section *section, || (off_size == 8 && c_id == DW64_CIE_ID))) { int version; - int mreg; + unsigned int mreg; read_cie (cie_scan, end, &cie, &version, &augmentation_data_len, &augmentation_data); + /* PR 17512: file: 3450-2098-0.004. */ + if (cie == NULL) + { + warn (_("Failed to read CIE information\n")); + break; + } cie->next = forward_refs; forward_refs = cie; cie->chunk_start = look_for; - mreg = max_regs - 1; + mreg = max_regs > 0 ? max_regs - 1 : 0; if (mreg < cie->ra) mreg = cie->ra; - frame_need_space (cie, mreg); + if (frame_need_space (cie, mreg) < 0) + { + warn (_("Invalid max register\n")); + break; + } if (cie->fde_encoding) encoded_ptr_size = size_of_encoded_value (cie->fde_encoding); @@ -5615,7 +5879,11 @@ display_debug_frames (struct dwarf_section *section, fc->ncols = 0; fc->col_type = (short int *) xmalloc (sizeof (short int)); fc->col_offset = (int *) xmalloc (sizeof (int)); - frame_need_space (fc, max_regs - 1); + if (frame_need_space (fc, max_regs > 0 ? max_regs - 1 : 0) < 0) + { + warn (_("Invalid max register\n")); + break; + } cie = fc; fc->augmentation = ""; fc->fde_encoding = 0; @@ -5638,7 +5906,11 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_reg = cie->cfa_reg; fc->cfa_offset = cie->cfa_offset; fc->ra = cie->ra; - frame_need_space (fc, max_regs - 1); + if (frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0) < 0) + { + warn (_("Invalid max register\n")); + break; + } fc->fde_encoding = cie->fde_encoding; } @@ -5647,7 +5919,15 @@ display_debug_frames (struct dwarf_section *section, segment_selector = 0; if (fc->segment_size) - SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end); + { + if (fc->segment_size > sizeof (segment_selector)) + { + /* PR 17512: file: 9e196b3e. */ + warn (_("Probably corrupt segment size: %d - using 4 instead\n"), fc->segment_size); + fc->segment_size = 4; + } + SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end); + } fc->pc_begin = get_encoded_value (&start, fc->fde_encoding, section, end); @@ -5662,6 +5942,15 @@ display_debug_frames (struct dwarf_section *section, augmentation_data_len = LEB (); augmentation_data = start; start += augmentation_data_len; + /* PR 17512: file: 722-8446-0.004. */ + if (start >= end || ((signed long) augmentation_data_len) < 0) + { + warn (_("Corrupt augmentation data length: %lx\n"), + augmentation_data_len); + start = end; + augmentation_data = NULL; + augmentation_data_len = 0; + } } printf ("\n%08lx %s %s FDE cie=%08lx pc=", @@ -5706,6 +5995,7 @@ display_debug_frames (struct dwarf_section *section, { unsigned int reg, op, opa; unsigned long temp; + unsigned char * new_start; op = *start++; opa = op & 0x3f; @@ -5747,7 +6037,6 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_restore_extended: reg = LEB (); - frame_need_space (fc, reg); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; @@ -5777,26 +6066,28 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_def_cfa_expression: temp = LEB (); - if (start + temp < start) + new_start = start + temp; + if (new_start < start) { warn (_("Corrupt CFA_def expression value: %lu\n"), temp); start = block_end; } else - start += temp; + start = new_start; break; case DW_CFA_expression: case DW_CFA_val_expression: reg = LEB (); temp = LEB (); - if (start + temp < start) + new_start = start + temp; + if (new_start < start) { - /* PR 17512: file:306-192417-0.005. */ + /* PR 17512: file:306-192417-0.005. */ warn (_("Corrupt CFA expression value: %lu\n"), temp); start = block_end; } else - start += temp; + start = new_start; if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; @@ -5835,9 +6126,10 @@ display_debug_frames (struct dwarf_section *section, while (start < block_end) { + unsigned char * tmp; unsigned op, opa; unsigned long ul, reg, roffs; - long l; + dwarf_vma l; dwarf_vma ofs; dwarf_vma vma; const char *reg_prefix = ""; @@ -5857,7 +6149,7 @@ display_debug_frames (struct dwarf_section *section, else printf (" DW_CFA_advance_loc: %d to %s\n", opa * fc->code_factor, - dwarf_vmatoa_1 (NULL, + dwarf_vmatoa_1 (NULL, fc->pc_begin + opa * fc->code_factor, fc->ptr_size)); fc->pc_begin += opa * fc->code_factor; @@ -5896,7 +6188,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_set_loc: - vma = get_encoded_value (&start, fc->fde_encoding, section, end); + vma = get_encoded_value (&start, fc->fde_encoding, section, block_end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else @@ -5919,7 +6211,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_advance_loc2: - SAFE_BYTE_GET_AND_INC (ofs, start, 2, end); + SAFE_BYTE_GET_AND_INC (ofs, start, 2, block_end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else @@ -5932,7 +6224,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_advance_loc4: - SAFE_BYTE_GET_AND_INC (ofs, start, 4, end); + SAFE_BYTE_GET_AND_INC (ofs, start, 4, block_end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else @@ -6041,13 +6333,13 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp) printf (" DW_CFA_remember_state\n"); rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); - rs->cfa_offset = fc->cfa_offset; + rs->cfa_offset = fc->cfa_offset; rs->cfa_reg = fc->cfa_reg; rs->ra = fc->ra; rs->cfa_exp = fc->cfa_exp; rs->ncols = fc->ncols; rs->col_type = (short int *) xcmalloc (rs->ncols, - sizeof (* rs->col_type)); + sizeof (* rs->col_type)); rs->col_offset = (int *) xcmalloc (rs->ncols, sizeof (* rs->col_offset)); memcpy (rs->col_type, fc->col_type, rs->ncols * sizeof (* fc->col_type)); memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (* fc->col_offset)); @@ -6064,9 +6356,14 @@ display_debug_frames (struct dwarf_section *section, remembered_state = rs->next; fc->cfa_offset = rs->cfa_offset; fc->cfa_reg = rs->cfa_reg; - fc->ra = rs->ra; - fc->cfa_exp = rs->cfa_exp; - frame_need_space (fc, rs->ncols - 1); + fc->ra = rs->ra; + fc->cfa_exp = rs->cfa_exp; + if (frame_need_space (fc, rs->ncols - 1) < 0) + { + warn (_("Invalid column number in saved frame state\n")); + fc->ncols = 0; + break; + } memcpy (fc->col_type, rs->col_type, rs->ncols * sizeof (* rs->col_type)); memcpy (fc->col_offset, rs->col_offset, rs->ncols * sizeof (* rs->col_offset)); @@ -6084,7 +6381,7 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa: %s ofs %d\n", - regname (fc->cfa_reg, 0), fc->cfa_offset); + regname (fc->cfa_reg, 0), (int) fc->cfa_offset); break; case DW_CFA_def_cfa_register: @@ -6098,7 +6395,7 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa_offset: fc->cfa_offset = LEB (); if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset); + printf (" DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset); break; case DW_CFA_nop: @@ -6108,6 +6405,11 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa_expression: ul = LEB (); + if (start >= block_end || start + ul > block_end || start + ul < start) + { + printf (_(" DW_CFA_def_cfa_expression: \n"), ul); + break; + } if (! do_debug_frames_interp) { printf (" DW_CFA_def_cfa_expression ("); @@ -6124,6 +6426,14 @@ display_debug_frames (struct dwarf_section *section, ul = LEB (); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; + /* PR 17512: file: 069-133014-0.006. */ + /* PR 17512: file: 98c02eb4. */ + tmp = start + ul; + if (start >= block_end || tmp > block_end || tmp < start) + { + printf (_(" DW_CFA_expression: \n"), ul); + break; + } if (! do_debug_frames_interp || *reg_prefix != '\0') { printf (" DW_CFA_expression: %s%s (", @@ -6134,7 +6444,7 @@ display_debug_frames (struct dwarf_section *section, } if (*reg_prefix == '\0') fc->col_type[reg] = DW_CFA_expression; - start += ul; + start = tmp; break; case DW_CFA_val_expression: @@ -6142,6 +6452,12 @@ display_debug_frames (struct dwarf_section *section, ul = LEB (); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; + tmp = start + ul; + if (start >= block_end || tmp > block_end || tmp < start) + { + printf (" DW_CFA_val_expression: \n", ul); + break; + } if (! do_debug_frames_interp || *reg_prefix != '\0') { printf (" DW_CFA_val_expression: %s%s (", @@ -6152,7 +6468,7 @@ display_debug_frames (struct dwarf_section *section, } if (*reg_prefix == '\0') fc->col_type[reg] = DW_CFA_val_expression; - start += ul; + start = tmp; break; case DW_CFA_offset_extended_sf: @@ -6163,7 +6479,7 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n", reg_prefix, regname (reg, 0), - l * fc->data_factor); + (long)(l * fc->data_factor)); if (*reg_prefix == '\0') { fc->col_type[reg] = DW_CFA_offset; @@ -6179,7 +6495,7 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_val_offset_sf: %s%s at cfa%+ld\n", reg_prefix, regname (reg, 0), - l * fc->data_factor); + (long)(l * fc->data_factor)); if (*reg_prefix == '\0') { fc->col_type[reg] = DW_CFA_val_offset; @@ -6194,18 +6510,18 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_sf: %s ofs %d\n", - regname (fc->cfa_reg, 0), fc->cfa_offset); + regname (fc->cfa_reg, 0), (int) fc->cfa_offset); break; case DW_CFA_def_cfa_offset_sf: fc->cfa_offset = SLEB (); - fc->cfa_offset = fc->cfa_offset * fc->data_factor; + fc->cfa_offset *= fc->data_factor; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset); + printf (" DW_CFA_def_cfa_offset_sf: %d\n", (int) fc->cfa_offset); break; case DW_CFA_MIPS_advance_loc8: - SAFE_BYTE_GET_AND_INC (ofs, start, 8, end); + SAFE_BYTE_GET_AND_INC (ofs, start, 8, block_end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else @@ -6236,7 +6552,7 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n", reg_prefix, regname (reg, 0), - l * fc->data_factor); + (long)(l * fc->data_factor)); if (*reg_prefix == '\0') { fc->col_type[reg] = DW_CFA_offset; @@ -6332,9 +6648,42 @@ display_gdb_index (struct dwarf_section *section, return 0; } + /* PR 17531: file: 418d0a8a. */ + if (tu_list_offset < cu_list_offset) + { + warn (_("TU offset (%x) is less than CU offset (%x)\n"), + tu_list_offset, cu_list_offset); + return 0; + } + cu_list_elements = (tu_list_offset - cu_list_offset) / 8; + + if (address_table_offset < tu_list_offset) + { + warn (_("Address table offset (%x) is less than TU offset (%x)\n"), + address_table_offset, tu_list_offset); + return 0; + } + tu_list_elements = (address_table_offset - tu_list_offset) / 8; + + /* PR 17531: file: 18a47d3d. */ + if (symbol_table_offset < address_table_offset) + { + warn (_("Symbol table offset (%xl) is less then Address table offset (%x)\n"), + symbol_table_offset, address_table_offset); + return 0; + } + address_table_size = symbol_table_offset - address_table_offset; + + if (constant_pool_offset < symbol_table_offset) + { + warn (_("Constant pool offset (%x) is less than symbol table offset (%x)\n"), + constant_pool_offset, symbol_table_offset); + return 0; + } + symbol_table_slots = (constant_pool_offset - symbol_table_offset) / 8; cu_list = start + cu_list_offset; @@ -6343,6 +6692,12 @@ display_gdb_index (struct dwarf_section *section, symbol_table = start + symbol_table_offset; constant_pool = start + constant_pool_offset; + if (address_table + address_table_size * (2 + 8 + 4) > section->start + section->size) + { + warn (_("Address table extends beyond end of section.\n")); + return 0; + } + printf (_("\nCU table:\n")); for (i = 0; i < cu_list_elements; i += 2) { @@ -6369,7 +6724,8 @@ display_gdb_index (struct dwarf_section *section, } printf (_("\nAddress table:\n")); - for (i = 0; i < address_table_size; i += 2 * 8 + 4) + for (i = 0; i < address_table_size && i <= address_table_size - (2 * 8 + 4); + i += 2 * 8 + 4) { uint64_t low = byte_get_little_endian (address_table + i, 8); uint64_t high = byte_get_little_endian (address_table + i + 8, 8); @@ -6391,11 +6747,46 @@ display_gdb_index (struct dwarf_section *section, || cu_vector_offset != 0) { unsigned int j; + unsigned char * adr; + + adr = constant_pool + name_offset; + /* PR 17531: file: 5b7b07ad. */ + if (adr < constant_pool || adr >= section->start + section->size) + { + printf (_("[%3u] "), i, name_offset); + warn (_("Corrupt name offset of 0x%x found for symbol table slot %d\n"), + name_offset, i); + } + else + printf ("[%3u] %.*s:", i, + (int) (section->size - (constant_pool_offset + name_offset)), + constant_pool + name_offset); + + adr = constant_pool + cu_vector_offset; + if (adr < constant_pool || adr >= section->start + section->size - 3) + { + printf (_("\n"), cu_vector_offset); + warn (_("Corrupt CU vector offset of 0x%x found for symbol table slot %d\n"), + cu_vector_offset, i); + continue; + } + + num_cus = byte_get_little_endian (adr, 4); + + adr = constant_pool + cu_vector_offset + 4 + num_cus * 4; + if (num_cus * 4 < num_cus + || adr >= section->start + section->size + || adr < constant_pool) + { + printf ("\n", num_cus); + warn (_("Invalid number of CUs (0x%x) for symbol table slot %d\n"), + num_cus, i); + continue; + } - printf ("[%3u] %s:", i, constant_pool + name_offset); - num_cus = byte_get_little_endian (constant_pool + cu_vector_offset, 4); if (num_cus > 1) printf ("\n"); + for (j = 0; j < num_cus; ++j) { int is_static; @@ -6494,7 +6885,7 @@ get_DW_SECT_short_name (unsigned int dw_sect) case DW_SECT_MACRO: return "macro"; default: - break; + break; } snprintf (buf, sizeof (buf), "%d", dw_sect); @@ -6523,15 +6914,38 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) dwarf_vma signature_low; char buf[64]; - version = byte_get (phdr, 4); + /* PR 17512: file: 002-168123-0.004. */ + if (phdr == NULL) + { + warn (_("Section %s is empty\n"), section->name); + return 0; + } + /* PR 17512: file: 002-376-0.004. */ + if (section->size < 24) + { + warn (_("Section %s is too small to contain a CU/TU header\n"), + section->name); + return 0; + } + + SAFE_BYTE_GET (version, phdr, 4, limit); if (version >= 2) - ncols = byte_get (phdr + 4, 4); - nused = byte_get (phdr + 8, 4); - nslots = byte_get (phdr + 12, 4); + SAFE_BYTE_GET (ncols, phdr + 4, 4, limit); + SAFE_BYTE_GET (nused, phdr + 8, 4, limit); + SAFE_BYTE_GET (nslots, phdr + 12, 4, limit); + phash = phdr + 16; pindex = phash + nslots * 8; ppool = pindex + nslots * 4; + /* PR 17531: file: 45d69832. */ + if (pindex < phash || ppool < phdr || (pindex == phash && nslots != 0)) + { + warn (_("Section %s is too small for %d slots\n"), + section->name, nslots); + return 0; + } + if (do_display) { printf (_("Contents of the %s section:\n\n"), section->name); @@ -6542,7 +6956,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) printf (_(" Number of slots: %d\n\n"), nslots); } - if (ppool > limit) + if (ppool > limit || ppool < phdr) { warn (_("Section %s too small for %d hash table entries\n"), section->name, nslots); @@ -6558,11 +6972,18 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) unsigned char *shndx_list; unsigned int shndx; - byte_get_64 (phash, &signature_high, &signature_low); + SAFE_BYTE_GET64 (phash, &signature_high, &signature_low, limit); if (signature_high != 0 || signature_low != 0) { - j = byte_get (pindex, 4); + SAFE_BYTE_GET (j, pindex, 4, limit); shndx_list = ppool + j * 4; + /* PR 17531: file: 705e010d. */ + if (shndx_list < ppool) + { + warn (_("Section index pool located before start of section\n")); + return 0; + } + if (do_display) printf (_(" [%3d] Signature: 0x%s Sections: "), i, dwarf_vmatoa64 (signature_high, signature_low, @@ -6575,7 +6996,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) section->name); return 0; } - shndx = byte_get (shndx_list, 4); + SAFE_BYTE_GET (shndx, shndx_list, 4, limit); if (shndx == 0) break; if (do_display) @@ -6609,6 +7030,14 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) is_tu_index = strcmp (section->name, ".debug_tu_index") == 0; + /* PR 17531: file: 0dd159bf. + Check for wraparound with an overlarge ncols value. */ + if (poffsets < ppool || (unsigned int) ((poffsets - ppool) / 4) != ncols) + { + warn (_("Overlarge number of columns: %x\n"), ncols); + return 0; + } + if (pend > limit) { warn (_("Section %s too small for offset and size tables\n"), @@ -6627,49 +7056,75 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) if (is_tu_index) { tu_count = nused; - tu_sets = xcmalloc (nused, sizeof (struct cu_tu_set)); + tu_sets = xcalloc2 (nused, sizeof (struct cu_tu_set)); this_set = tu_sets; } else { cu_count = nused; - cu_sets = xcmalloc (nused, sizeof (struct cu_tu_set)); + cu_sets = xcalloc2 (nused, sizeof (struct cu_tu_set)); this_set = cu_sets; } } + if (do_display) { for (j = 0; j < ncols; j++) { - dw_sect = byte_get (ppool + j * 4, 4); + SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit); printf (" %8s", get_DW_SECT_short_name (dw_sect)); } printf ("\n"); } + for (i = 0; i < nslots; i++) { - byte_get_64 (ph, &signature_high, &signature_low); - row = byte_get (pi, 4); + SAFE_BYTE_GET64 (ph, &signature_high, &signature_low, limit); + + SAFE_BYTE_GET (row, pi, 4, limit); if (row != 0) { + /* PR 17531: file: a05f6ab3. */ + if (row > nused) + { + warn (_("Row index (%u) is larger than number of used entries (%u)\n"), + row, nused); + return 0; + } + if (!do_display) memcpy (&this_set[row - 1].signature, ph, sizeof (uint64_t)); + prow = poffsets + (row - 1) * ncols * 4; + /* PR 17531: file: b8ce60a8. */ + if (prow < poffsets || prow > limit) + { + warn (_("Row index (%u) * num columns (%u) > space remaining in section\n"), + row, ncols); + return 0; + } + if (do_display) printf (_(" [%3d] 0x%s"), i, dwarf_vmatoa64 (signature_high, signature_low, buf, sizeof (buf))); for (j = 0; j < ncols; j++) { - val = byte_get (prow + j * 4, 4); + SAFE_BYTE_GET (val, prow + j * 4, 4, limit); if (do_display) printf (" %8d", val); else { - dw_sect = byte_get (ppool + j * 4, 4); - this_set [row - 1].section_offsets [dw_sect] = val; + SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit); + + /* PR 17531: file: 10796eb3. */ + if (dw_sect >= DW_SECT_MAX) + warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect); + else + this_set [row - 1].section_offsets [dw_sect] = val; } } + if (do_display) printf ("\n"); } @@ -6680,51 +7135,62 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) ph = phash; pi = pindex; if (do_display) - { + { printf ("\n"); printf (_(" Size table\n")); printf (" slot %-16s ", is_tu_index ? _("signature") : _("dwo_id")); - } + } + for (j = 0; j < ncols; j++) { - val = byte_get (ppool + j * 4, 4); + SAFE_BYTE_GET (val, ppool + j * 4, 4, limit); if (do_display) printf (" %8s", get_DW_SECT_short_name (val)); } + if (do_display) printf ("\n"); + for (i = 0; i < nslots; i++) { - byte_get_64 (ph, &signature_high, &signature_low); - row = byte_get (pi, 4); + SAFE_BYTE_GET64 (ph, &signature_high, &signature_low, limit); + + SAFE_BYTE_GET (row, pi, 4, limit); if (row != 0) { prow = psizes + (row - 1) * ncols * 4; + if (do_display) printf (_(" [%3d] 0x%s"), i, dwarf_vmatoa64 (signature_high, signature_low, buf, sizeof (buf))); + for (j = 0; j < ncols; j++) { - val = byte_get (prow + j * 4, 4); + SAFE_BYTE_GET (val, prow + j * 4, 4, limit); if (do_display) printf (" %8d", val); else { - dw_sect = byte_get (ppool + j * 4, 4); + SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit); + if (dw_sect >= DW_SECT_MAX) + warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect); + else this_set [row - 1].section_sizes [dw_sect] = val; } } + if (do_display) printf ("\n"); } + ph += 8; pi += 4; } } else if (do_display) - printf (_(" Unsupported version\n")); + printf (_(" Unsupported version (%d)\n"), version); if (do_display) printf ("\n"); @@ -6795,34 +7261,69 @@ display_debug_not_supported (struct dwarf_section *section, return 1; } +/* Like malloc, but takes two parameters like calloc. + Verifies that the first parameter is not too large. + Note: does *not* initialise the allocated memory to zero. */ void * cmalloc (size_t nmemb, size_t size) { /* Check for overflow. */ if (nmemb >= ~(size_t) 0 / size) return NULL; - else - return malloc (nmemb * size); + + return xmalloc (nmemb * size); } +/* Like xmalloc, but takes two parameters like calloc. + Verifies that the first parameter is not too large. + Note: does *not* initialise the allocated memory to zero. */ void * xcmalloc (size_t nmemb, size_t size) { /* Check for overflow. */ if (nmemb >= ~(size_t) 0 / size) - return NULL; - else - return xmalloc (nmemb * size); + { + fprintf (stderr, + _("Attempt to allocate an array with an excessive number of elements: 0x%lx\n"), + (long) nmemb); + xexit (1); + } + + return xmalloc (nmemb * size); } +/* Like xrealloc, but takes three parameters. + Verifies that the second parameter is not too large. + Note: does *not* initialise any new memory to zero. */ void * xcrealloc (void *ptr, size_t nmemb, size_t size) { /* Check for overflow. */ if (nmemb >= ~(size_t) 0 / size) - return NULL; - else - return xrealloc (ptr, nmemb * size); + { + fprintf (stderr, + _("Attempt to re-allocate an array with an excessive number of elements: 0x%lx\n"), + (long) nmemb); + xexit (1); + } + + return xrealloc (ptr, nmemb * size); +} + +/* Like xcalloc, but verifies that the first parameter is not too large. */ +void * +xcalloc2 (size_t nmemb, size_t size) +{ + /* Check for overflow. */ + if (nmemb >= ~(size_t) 0 / size) + { + fprintf (stderr, + _("Attempt to allocate a zero'ed array with an excessive number of elements: 0x%lx\n"), + (long) nmemb); + xexit (1); + } + + return xcalloc (nmemb, size); } void @@ -6850,10 +7351,9 @@ free_debug_memory (void) free (debug_information [i].range_lists); } } - free (debug_information); debug_information = NULL; - num_debug_info_entries = 0; + alloc_num_debug_info_entries = num_debug_info_entries = 0; } } @@ -6997,7 +7497,7 @@ dwarf_select_sections_by_letters (const char *letters) break; default: - warn (_("Unrecognized debug option '%s'\n"), optarg); + warn (_("Unrecognized debug option '%s'\n"), letters); break; } } @@ -7026,76 +7526,76 @@ dwarf_select_sections_all (void) struct dwarf_section_display debug_displays[] = { - { { ".debug_abbrev", ".zdebug_abbrev", NULL, NULL, 0, 0, 0 }, + { { ".debug_abbrev", ".zdebug_abbrev", NULL, NULL, 0, 0, 0, NULL }, display_debug_abbrev, &do_debug_abbrevs, 0 }, - { { ".debug_aranges", ".zdebug_aranges", NULL, NULL, 0, 0, 0 }, + { { ".debug_aranges", ".zdebug_aranges", NULL, NULL, 0, 0, 0, NULL }, display_debug_aranges, &do_debug_aranges, 1 }, - { { ".debug_frame", ".zdebug_frame", NULL, NULL, 0, 0, 0 }, + { { ".debug_frame", ".zdebug_frame", NULL, NULL, 0, 0, 0, NULL }, display_debug_frames, &do_debug_frames, 1 }, - { { ".debug_info", ".zdebug_info", NULL, NULL, 0, 0, abbrev }, + { { ".debug_info", ".zdebug_info", NULL, NULL, 0, 0, abbrev, NULL }, display_debug_info, &do_debug_info, 1 }, - { { ".debug_line", ".zdebug_line", NULL, NULL, 0, 0, 0 }, + { { ".debug_line", ".zdebug_line", NULL, NULL, 0, 0, 0, NULL }, display_debug_lines, &do_debug_lines, 1 }, - { { ".debug_pubnames", ".zdebug_pubnames", NULL, NULL, 0, 0, 0 }, + { { ".debug_pubnames", ".zdebug_pubnames", NULL, NULL, 0, 0, 0, NULL }, display_debug_pubnames, &do_debug_pubnames, 0 }, - { { ".debug_gnu_pubnames", ".zdebug_gnu_pubnames", NULL, NULL, 0, 0, 0 }, + { { ".debug_gnu_pubnames", ".zdebug_gnu_pubnames", NULL, NULL, 0, 0, 0, NULL }, display_debug_gnu_pubnames, &do_debug_pubnames, 0 }, - { { ".eh_frame", "", NULL, NULL, 0, 0, 0 }, + { { ".eh_frame", "", NULL, NULL, 0, 0, 0, NULL }, display_debug_frames, &do_debug_frames, 1 }, - { { ".debug_macinfo", ".zdebug_macinfo", NULL, NULL, 0, 0, 0 }, + { { ".debug_macinfo", ".zdebug_macinfo", NULL, NULL, 0, 0, 0, NULL }, display_debug_macinfo, &do_debug_macinfo, 0 }, - { { ".debug_macro", ".zdebug_macro", NULL, NULL, 0, 0, 0 }, + { { ".debug_macro", ".zdebug_macro", NULL, NULL, 0, 0, 0, NULL }, display_debug_macro, &do_debug_macinfo, 1 }, - { { ".debug_str", ".zdebug_str", NULL, NULL, 0, 0, 0 }, + { { ".debug_str", ".zdebug_str", NULL, NULL, 0, 0, 0, NULL }, display_debug_str, &do_debug_str, 0 }, - { { ".debug_loc", ".zdebug_loc", NULL, NULL, 0, 0, 0 }, + { { ".debug_loc", ".zdebug_loc", NULL, NULL, 0, 0, 0, NULL }, display_debug_loc, &do_debug_loc, 1 }, - { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0, 0 }, + { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0, 0, NULL }, display_debug_pubnames, &do_debug_pubtypes, 0 }, - { { ".debug_gnu_pubtypes", ".zdebug_gnu_pubtypes", NULL, NULL, 0, 0, 0 }, + { { ".debug_gnu_pubtypes", ".zdebug_gnu_pubtypes", NULL, NULL, 0, 0, 0, NULL }, display_debug_gnu_pubnames, &do_debug_pubtypes, 0 }, - { { ".debug_ranges", ".zdebug_ranges", NULL, NULL, 0, 0, 0 }, + { { ".debug_ranges", ".zdebug_ranges", NULL, NULL, 0, 0, 0, NULL }, display_debug_ranges, &do_debug_ranges, 1 }, - { { ".debug_static_func", ".zdebug_static_func", NULL, NULL, 0, 0, 0 }, + { { ".debug_static_func", ".zdebug_static_func", NULL, NULL, 0, 0, 0, NULL }, display_debug_not_supported, NULL, 0 }, - { { ".debug_static_vars", ".zdebug_static_vars", NULL, NULL, 0, 0, 0 }, + { { ".debug_static_vars", ".zdebug_static_vars", NULL, NULL, 0, 0, 0, NULL }, display_debug_not_supported, NULL, 0 }, - { { ".debug_types", ".zdebug_types", NULL, NULL, 0, 0, abbrev }, + { { ".debug_types", ".zdebug_types", NULL, NULL, 0, 0, abbrev, NULL }, display_debug_types, &do_debug_info, 1 }, - { { ".debug_weaknames", ".zdebug_weaknames", NULL, NULL, 0, 0, 0 }, + { { ".debug_weaknames", ".zdebug_weaknames", NULL, NULL, 0, 0, 0, NULL }, display_debug_not_supported, NULL, 0 }, - { { ".gdb_index", "", NULL, NULL, 0, 0, 0 }, + { { ".gdb_index", "", NULL, NULL, 0, 0, 0, NULL }, display_gdb_index, &do_gdb_index, 0 }, - { { ".trace_info", "", NULL, NULL, 0, 0, trace_abbrev }, + { { ".trace_info", "", NULL, NULL, 0, 0, trace_abbrev, NULL }, display_trace_info, &do_trace_info, 1 }, - { { ".trace_abbrev", "", NULL, NULL, 0, 0, 0 }, + { { ".trace_abbrev", "", NULL, NULL, 0, 0, 0, NULL }, display_debug_abbrev, &do_trace_abbrevs, 0 }, - { { ".trace_aranges", "", NULL, NULL, 0, 0, 0 }, + { { ".trace_aranges", "", NULL, NULL, 0, 0, 0, NULL }, display_debug_aranges, &do_trace_aranges, 0 }, - { { ".debug_info.dwo", ".zdebug_info.dwo", NULL, NULL, 0, 0, abbrev_dwo }, + { { ".debug_info.dwo", ".zdebug_info.dwo", NULL, NULL, 0, 0, abbrev_dwo, NULL }, display_debug_info, &do_debug_info, 1 }, - { { ".debug_abbrev.dwo", ".zdebug_abbrev.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_abbrev.dwo", ".zdebug_abbrev.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_abbrev, &do_debug_abbrevs, 0 }, - { { ".debug_types.dwo", ".zdebug_types.dwo", NULL, NULL, 0, 0, abbrev_dwo }, + { { ".debug_types.dwo", ".zdebug_types.dwo", NULL, NULL, 0, 0, abbrev_dwo, NULL }, display_debug_types, &do_debug_info, 1 }, - { { ".debug_line.dwo", ".zdebug_line.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_line.dwo", ".zdebug_line.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_lines, &do_debug_lines, 1 }, - { { ".debug_loc.dwo", ".zdebug_loc.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_loc.dwo", ".zdebug_loc.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_loc, &do_debug_loc, 1 }, - { { ".debug_macro.dwo", ".zdebug_macro.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_macro.dwo", ".zdebug_macro.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_macro, &do_debug_macinfo, 1 }, - { { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_macinfo, &do_debug_macinfo, 0 }, - { { ".debug_str.dwo", ".zdebug_str.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_str.dwo", ".zdebug_str.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_str, &do_debug_str, 1 }, - { { ".debug_str_offsets", ".zdebug_str_offsets", NULL, NULL, 0, 0, 0 }, + { { ".debug_str_offsets", ".zdebug_str_offsets", NULL, NULL, 0, 0, 0, NULL }, display_debug_str_offsets, NULL, 0 }, - { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_str_offsets, NULL, 0 }, - { { ".debug_addr", ".zdebug_addr", NULL, NULL, 0, 0, 0 }, + { { ".debug_addr", ".zdebug_addr", NULL, NULL, 0, 0, 0, NULL }, display_debug_addr, &do_debug_addr, 1 }, - { { ".debug_cu_index", "", NULL, NULL, 0, 0, 0 }, + { { ".debug_cu_index", "", NULL, NULL, 0, 0, 0, NULL }, display_cu_index, &do_debug_cu_index, 0 }, - { { ".debug_tu_index", "", NULL, NULL, 0, 0, 0 }, + { { ".debug_tu_index", "", NULL, NULL, 0, 0, 0, NULL }, display_cu_index, &do_debug_cu_index, 0 }, }; diff --git a/binutils/dwarf.h b/binutils/dwarf.h index 124d9d6d358..2084a222f23 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -23,24 +23,11 @@ typedef HOST_WIDEST_INT dwarf_signed_vma; typedef unsigned HOST_WIDEST_INT dwarf_size_type; /* Structure found in the .debug_line section. */ -typedef struct -{ - unsigned char li_length [4]; - unsigned char li_version [2]; - unsigned char li_prologue_length [4]; - unsigned char li_min_insn_length [1]; - unsigned char li_default_is_stmt [1]; - unsigned char li_line_base [1]; - unsigned char li_line_range [1]; - unsigned char li_opcode_base [1]; -} -DWARF2_External_LineInfo; - typedef struct { dwarf_vma li_length; unsigned short li_version; - unsigned int li_prologue_length; + dwarf_vma li_prologue_length; unsigned char li_min_insn_length; unsigned char li_max_ops_per_insn; unsigned char li_default_is_stmt; @@ -51,15 +38,6 @@ typedef struct DWARF2_Internal_LineInfo; /* Structure found in .debug_pubnames section. */ -typedef struct -{ - unsigned char pn_length [4]; - unsigned char pn_version [2]; - unsigned char pn_offset [4]; - unsigned char pn_size [4]; -} -DWARF2_External_PubNames; - typedef struct { dwarf_vma pn_length; @@ -70,15 +48,6 @@ typedef struct DWARF2_Internal_PubNames; /* Structure found in .debug_info section. */ -typedef struct -{ - unsigned char cu_length [4]; - unsigned char cu_version [2]; - unsigned char cu_abbrev_offset [4]; - unsigned char cu_pointer_size [1]; -} -DWARF2_External_CompUnit; - typedef struct { dwarf_vma cu_length; @@ -88,16 +57,7 @@ typedef struct } DWARF2_Internal_CompUnit; -typedef struct -{ - unsigned char ar_length [4]; - unsigned char ar_version [2]; - unsigned char ar_info_offset [4]; - unsigned char ar_pointer_size [1]; - unsigned char ar_segment_size [1]; -} -DWARF2_External_ARange; - +/* Structure found in .debug_aranges section. */ typedef struct { dwarf_vma ar_length; @@ -164,6 +124,8 @@ struct dwarf_section dwarf_vma address; dwarf_size_type size; enum dwarf_section_display_enum abbrev_sec; + /* A spare field for random use. */ + void *user_data; }; /* A structure containing the name of a debug section @@ -205,7 +167,7 @@ typedef struct } debug_info; -extern int eh_addr_size; +extern unsigned int eh_addr_size; extern int do_debug_info; extern int do_debug_abbrevs; @@ -246,10 +208,11 @@ extern void dwarf_select_sections_by_names (const char *); extern void dwarf_select_sections_by_letters (const char *); extern void dwarf_select_sections_all (void); -unsigned int * find_cu_tu_set (void *, unsigned int); +extern unsigned int * find_cu_tu_set (void *, unsigned int); -void * cmalloc (size_t, size_t); -void * xcmalloc (size_t, size_t); -void * xcrealloc (void *, size_t, size_t); +extern void * cmalloc (size_t, size_t); +extern void * xcalloc2 (size_t, size_t); +extern void * xcmalloc (size_t, size_t); +extern void * xcrealloc (void *, size_t, size_t); extern dwarf_vma read_leb128 (unsigned char *, unsigned int *, bfd_boolean, const unsigned char * const);