X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Fdwarf.c;h=66ad1fd2659d0c8e693b7d35322bffae2a9e6e4b;hb=91068ec6ae02e85c5ca4fbe3c6e214bd87bb872f;hp=c14049ac8d2aafa9c7fcbd247b0460ede6d6f79e;hpb=3aade68889268c7d15e121d6d63cb1b753ec12fa;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/dwarf.c b/binutils/dwarf.c index c14049ac8d..66ad1fd265 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -1,5 +1,5 @@ /* dwarf.c -- display DWARF contents of a BFD binary file - Copyright (C) 2005-2015 Free Software Foundation, Inc. + Copyright (C) 2005-2016 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -200,7 +200,7 @@ dwarf_vmatoa_1 (const char *fmtch, dwarf_vma value, unsigned num_bytes) if (num_bytes) { - /* Printf does not have a way of specifiying a maximum field width for an + /* Printf does not have a way of specifying a maximum field width for an integer value, so we print the full value into a buffer and then select the precision we need. */ snprintf (ret, sizeof (buf[0].place), DWARF_VMA_FMT_LONG, value); @@ -292,7 +292,7 @@ read_leb128 (unsigned char *data, *length_return = num_read; if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= (dwarf_vma) -1 << shift; + result |= -((dwarf_vma) 1 << shift); return result; } @@ -317,8 +317,13 @@ read_uleb128 (unsigned char * data, #define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END) \ do \ { \ - int dummy [sizeof (VAL) < (AMOUNT) ? -1 : 1] ATTRIBUTE_UNUSED ; \ unsigned int amount = (AMOUNT); \ + if (sizeof (VAL) < amount) \ + { \ + error (_("internal error: attempt to read %d bytes of data in to %d sized variable"),\ + amount, (int) sizeof (VAL)); \ + amount = sizeof (VAL); \ + } \ if (((PTR) + amount) >= (END)) \ { \ if ((PTR) < (END)) \ @@ -1819,6 +1824,7 @@ read_and_display_attr_value (unsigned long attribute, { case DW_AT_frame_base: have_frame_base = 1; + /* Fall through. */ case DW_AT_location: case DW_AT_string_length: case DW_AT_return_addr: @@ -2094,6 +2100,7 @@ read_and_display_attr_value (unsigned long attribute, case DW_AT_frame_base: have_frame_base = 1; + /* Fall through. */ case DW_AT_location: case DW_AT_string_length: case DW_AT_return_addr: @@ -3247,16 +3254,32 @@ display_debug_lines_decoded (struct dwarf_section *section, /* Traverse the Directory table just to count entries. */ data = standard_opcodes + linfo.li_opcode_base - 1; + /* PR 20440 */ + if (data >= end) + { + warn (_("opcode base of %d extends beyond end of section\n"), + linfo.li_opcode_base); + return 0; + } + if (*data != 0) { unsigned char *ptr_directory_table = data; - while (*data != 0) + while (data < end && *data != 0) { data += strnlen ((char *) data, end - data) + 1; n_directories++; } + /* PR 20440 */ + if (data >= end) + { + warn (_("directory table ends unexpectedly\n")); + n_directories = 0; + break; + } + /* Go through the directory table again to save the directories. */ directory_table = (unsigned char **) xmalloc (n_directories * sizeof (unsigned char *)); @@ -3274,11 +3297,11 @@ display_debug_lines_decoded (struct dwarf_section *section, data++; /* Traverse the File Name table just to count the entries. */ - if (*data != 0) + if (data < end && *data != 0) { unsigned char *ptr_file_name_table = data; - while (*data != 0) + while (data < end && *data != 0) { unsigned int bytes_read; @@ -3295,6 +3318,13 @@ display_debug_lines_decoded (struct dwarf_section *section, n_files++; } + if (data >= end) + { + warn (_("file table ends unexpectedly\n")); + n_files = 0; + break; + } + /* Go through the file table again to save the strings. */ file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry)); @@ -3329,7 +3359,20 @@ display_debug_lines_decoded (struct dwarf_section *section, else { unsigned int ix = file_table[0].directory_index; - const char *directory = ix ? (char *)directory_table[ix - 1] : "."; + const char *directory; + + if (ix == 0) + directory = "."; + /* PR 20439 */ + else if (n_directories == 0) + directory = _(""); + else if (ix > n_directories) + { + warn (_("directory index %u > number of directories %u\n"), ix, n_directories); + directory = _(""); + } + else + directory = (char *) directory_table[ix - 1]; if (do_wide || strlen (directory) < 76) printf (_("CU: %s/%s:\n"), directory, file_table[0].name); @@ -3487,20 +3530,35 @@ display_debug_lines_decoded (struct dwarf_section *section, data += bytes_read; state_machine_regs.file = adv; - if (file_table == NULL) - printf (_("\n [Use file table entry %d]\n"), state_machine_regs.file - 1); - else if (file_table[state_machine_regs.file - 1].directory_index == 0) - /* If directory index is 0, that means current directory. */ - printf ("\n./%s:[++]\n", - file_table[state_machine_regs.file - 1].name); - else if (directory_table == NULL) - printf (_("\n [Use directory table entry %d]\n"), - file_table[state_machine_regs.file - 1].directory_index - 1); - else - /* The directory index starts counting at 1. */ - printf ("\n%s/%s:\n", - directory_table[file_table[state_machine_regs.file - 1].directory_index - 1], - file_table[state_machine_regs.file - 1].name); + { + unsigned file = state_machine_regs.file - 1; + unsigned dir; + + if (file_table == NULL || n_files == 0) + printf (_("\n [Use file table entry %d]\n"), file); + /* PR 20439 */ + else if (file >= n_files) + { + warn (_("file index %u > number of files %u\n"), file + 1, n_files); + printf (_("\n "), file); + } + else if ((dir = file_table[file].directory_index) == 0) + /* If directory index is 0, that means current directory. */ + printf ("\n./%s:[++]\n", file_table[file].name); + else if (directory_table == NULL || n_directories == 0) + printf (_("\n [Use file %s in directory table entry %d]\n"), + file_table[file].name, dir); + /* PR 20439 */ + else if (dir > n_directories) + { + warn (_("directory index %u > number of directories %u\n"), dir, n_directories); + printf (_("\n \n"), dir); + } + else + printf ("\n%s/%s:\n", + /* The directory index starts counting at 1. */ + directory_table[dir - 1], file_table[file].name); + } break; case DW_LNS_set_column: @@ -3582,9 +3640,19 @@ display_debug_lines_decoded (struct dwarf_section *section, size_t fileNameLength; if (file_table) - fileName = (char *) file_table[state_machine_regs.file - 1].name; + { + unsigned indx = state_machine_regs.file - 1; + /* PR 20439 */ + if (indx >= n_files) + { + warn (_("corrupt file index %u encountered\n"), indx); + fileName = _(""); + } + else + fileName = (char *) file_table[indx].name; + } else - fileName = ""; + fileName = _(""); fileNameLength = strlen (fileName); @@ -4326,6 +4394,16 @@ display_debug_abbrev (struct dwarf_section *section, return 1; } +/* Return true when ADDR is the maximum address, when addresses are + POINTER_SIZE bytes long. */ + +static bfd_boolean +is_max_address (dwarf_vma addr, unsigned int pointer_size) +{ + dwarf_vma mask = ~(~(dwarf_vma) 1 << (pointer_size * 8 - 1)); + return ((addr & mask) == mask); +} + /* Display a location list from a normal (ie, non-dwo) .debug_loc section. */ static void @@ -4380,10 +4458,6 @@ display_loc_list (struct dwarf_section *section, printf (" %8.8lx ", off); - /* 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. */ SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end); SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end); @@ -4404,7 +4478,8 @@ display_loc_list (struct dwarf_section *section, } /* Check base address specifiers. */ - if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1) + if (is_max_address (begin, pointer_size) + && !is_max_address (end, pointer_size)) { base_address = end; print_dwarf_vma (begin, pointer_size); @@ -4898,7 +4973,12 @@ display_debug_aranges (struct dwarf_section *section, if (arange.ar_version != 2 && arange.ar_version != 3) { - warn (_("Only DWARF 2 and 3 aranges are currently supported.\n")); + /* PR 19872: A version number of 0 probably means that there is + padding at the end of the .debug_aranges section. Gold puts + it there when performing an incremental link, for example. + So do not generate a warning in this case. */ + if (arange.ar_version) + warn (_("Only DWARF 2 and 3 aranges are currently supported.\n")); break; } @@ -5202,11 +5282,6 @@ display_debug_ranges (struct dwarf_section *section, dwarf_vma begin; dwarf_vma end; - /* 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. */ SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, finish); if (start >= finish) break; @@ -5221,7 +5296,8 @@ display_debug_ranges (struct dwarf_section *section, } /* Check base address specifiers. */ - if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1) + if (is_max_address (begin, pointer_size) + && !is_max_address (end, pointer_size)) { base_address = end; print_dwarf_vma (begin, pointer_size); @@ -5451,6 +5527,30 @@ init_dwarf_regnames_aarch64 (void) dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_aarch64); } +static const char *const dwarf_regnames_s390[] = +{ + /* Avoid saying "r5 (r5)", so omit the names of r0-r15. */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7", + "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15", + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15", + "pswm", "pswa", + NULL, NULL, + "v16", "v18", "v20", "v22", "v17", "v19", "v21", "v23", + "v24", "v26", "v28", "v30", "v25", "v27", "v29", "v31", +}; + +void +init_dwarf_regnames_s390 (void) +{ + dwarf_regnames = dwarf_regnames_s390; + dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_s390); +} + void init_dwarf_regnames (unsigned int e_machine) { @@ -5474,6 +5574,10 @@ init_dwarf_regnames (unsigned int e_machine) init_dwarf_regnames_aarch64 (); break; + case EM_S390: + init_dwarf_regnames_s390 (); + break; + default: break; } @@ -5503,7 +5607,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg unsigned int r; char tmp[100]; - if (*max_regs < fc->ncols) + if (*max_regs != fc->ncols) *max_regs = fc->ncols; if (*need_col_headers) @@ -5518,7 +5622,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg if (fc->col_type[r] != DW_CFA_unreferenced) { if (r == fc->ra) - printf ("ra "); + printf ("ra "); else printf ("%-5s ", regname (r, 1)); } @@ -5739,6 +5843,7 @@ display_debug_frames (struct dwarf_section *section, unsigned int encoded_ptr_size = saved_eh_addr_size; unsigned int offset_size; unsigned int initial_length_size; + bfd_boolean all_nops; saved_start = start; @@ -6172,6 +6277,8 @@ display_debug_frames (struct dwarf_section *section, start = tmp; } + all_nops = TRUE; + /* Now we know what registers are used, make a second pass over the chunk, this time actually printing out the info. */ @@ -6190,6 +6297,10 @@ display_debug_frames (struct dwarf_section *section, if (op & 0xc0) op &= 0xc0; + /* Make a note if something other than DW_CFA_nop happens. */ + if (op != DW_CFA_nop) + all_nops = FALSE; + /* Warning: if you add any more cases to this switch, be sure to add them to the corresponding switch above. */ switch (op) @@ -6222,19 +6333,25 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_restore: - if (opa >= (unsigned int) cie->ncols - || opa >= (unsigned int) fc->ncols) + if (opa >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_restore: %s%s\n", reg_prefix, regname (opa, 0)); - if (*reg_prefix == '\0') + if (*reg_prefix != '\0') + break; + + if (opa >= (unsigned int) cie->ncols + || (do_debug_frames_interp + && cie->col_type[opa] == DW_CFA_unreferenced)) + { + fc->col_type[opa] = DW_CFA_undefined; + fc->col_offset[opa] = 0; + } + else { fc->col_type[opa] = cie->col_type[opa]; fc->col_offset[opa] = cie->col_offset[opa]; - if (do_debug_frames_interp - && fc->col_type[opa] == DW_CFA_unreferenced) - fc->col_type[opa] = DW_CFA_undefined; } break; @@ -6309,7 +6426,7 @@ display_debug_frames (struct dwarf_section *section, if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') - printf (" DW_CFA_val_offset: %s%s at cfa%+ld\n", + printf (" DW_CFA_val_offset: %s%s is cfa%+ld\n", reg_prefix, regname (reg, 0), roffs * fc->data_factor); if (*reg_prefix == '\0') @@ -6321,13 +6438,20 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_restore_extended: reg = LEB (); - if (reg >= (unsigned int) cie->ncols - || reg >= (unsigned int) fc->ncols) + if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_restore_extended: %s%s\n", reg_prefix, regname (reg, 0)); - if (*reg_prefix == '\0') + if (*reg_prefix != '\0') + break; + + if (reg >= (unsigned int) cie->ncols) + { + fc->col_type[reg] = DW_CFA_undefined; + fc->col_offset[reg] = 0; + } + else { fc->col_type[reg] = cie->col_type[reg]; fc->col_offset[reg] = cie->col_offset[reg]; @@ -6456,7 +6580,7 @@ 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) + if (start >= block_end || ul > (unsigned long) (block_end - start)) { printf (_(" DW_CFA_def_cfa_expression: \n"), ul); break; @@ -6544,7 +6668,7 @@ display_debug_frames (struct dwarf_section *section, if (frame_need_space (fc, reg) < 0) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') - printf (" DW_CFA_val_offset_sf: %s%s at cfa%+ld\n", + printf (" DW_CFA_val_offset_sf: %s%s is cfa%+ld\n", reg_prefix, regname (reg, 0), (long)(l * fc->data_factor)); if (*reg_prefix == '\0') @@ -6620,7 +6744,8 @@ display_debug_frames (struct dwarf_section *section, } } - if (do_debug_frames_interp) + /* Interpret the CFA - as long as it is not completely full of NOPs. */ + if (do_debug_frames_interp && ! all_nops) frame_display_row (fc, &need_col_headers, &max_regs); start = block_end; @@ -7438,7 +7563,7 @@ dwarf_select_sections_by_names (const char *names) { "macro", & do_debug_macinfo, 1 }, { "pubnames", & do_debug_pubnames, 1 }, { "pubtypes", & do_debug_pubtypes, 1 }, - /* This entry is for compatability + /* This entry is for compatibility with earlier versions of readelf. */ { "ranges", & do_debug_aranges, 1 }, { "rawline", & do_debug_lines, FLAG_DEBUG_LINES_RAW }, @@ -7531,6 +7656,7 @@ dwarf_select_sections_by_letters (const char *letters) case 'F': do_debug_frames_interp = 1; + /* Fall through. */ case 'f': do_debug_frames = 1; break;