X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=binutils%2Fdwarf.c;h=5eeef088911ac3f3ee2ac1d66b9f9e360e125955;hp=9cfb158aa30c95cabb2113a66e77fbb10e2518a3;hb=88750007d7869f178f0ba528f41efd3b74c424cf;hpb=6df9443a374e2b81278c61b8afc0a1eef7db280b diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 9cfb158..5eeef08 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -1,5 +1,5 @@ /* dwarf.c -- display DWARF contents of a BFD binary file - Copyright 2005, 2006, 2007 + Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -23,7 +23,8 @@ #include "libiberty.h" #include "bfd.h" #include "bucomm.h" -#include "elf/dwarf2.h" +#include "elf/common.h" +#include "dwarf2.h" #include "dwarf.h" static int have_frame_base; @@ -34,9 +35,11 @@ static int warned_about_missing_comp_units = FALSE; static unsigned int 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 -dwarf_vma eh_addr_size; -int is_relocatable; +int eh_addr_size; int do_debug_info; int do_debug_abbrevs; @@ -49,6 +52,11 @@ int do_debug_frames_interp; int do_debug_macinfo; int do_debug_str; int do_debug_loc; +int do_wide; + +/* Values for do_debug_lines. */ +#define FLAG_DEBUG_LINES_RAW 1 +#define FLAG_DEBUG_LINES_DECODED 2 dwarf_vma (*byte_get) (unsigned char *, int); @@ -64,6 +72,11 @@ byte_get_little_endian (unsigned char *field, int size) return ((unsigned int) (field[0])) | (((unsigned int) (field[1])) << 8); + case 3: + return ((unsigned long) (field[0])) + | (((unsigned long) (field[1])) << 8) + | (((unsigned long) (field[2])) << 16); + case 4: return ((unsigned long) (field[0])) | (((unsigned long) (field[1])) << 8) @@ -106,6 +119,11 @@ byte_get_big_endian (unsigned char *field, int size) case 2: return ((unsigned int) (field[1])) | (((int) (field[0])) << 8); + case 3: + return ((unsigned long) (field[2])) + | (((unsigned long) (field[1])) << 8) + | (((unsigned long) (field[0])) << 16); + case 4: return ((unsigned long) (field[3])) | (((unsigned long) (field[2])) << 8) @@ -159,6 +177,55 @@ byte_get_signed (unsigned char *field, int size) } } +static int +size_of_encoded_value (int encoding) +{ + switch (encoding & 0x7) + { + default: /* ??? */ + case 0: return eh_addr_size; + case 2: return 2; + case 3: return 4; + case 4: return 8; + } +} + +static dwarf_vma +get_encoded_value (unsigned char *data, int encoding) +{ + int size = size_of_encoded_value (encoding); + + if (encoding & DW_EH_PE_signed) + return byte_get_signed (data, size); + else + return byte_get (data, size); +} + +/* Print a dwarf_vma value (typically an address, offset or length) in + hexadecimal format, followed by a space. The length of the value (and + hence the precision displayed) is determined by the byte_size parameter. */ + +static void +print_dwarf_vma (dwarf_vma val, unsigned byte_size) +{ + static char buff[18]; + + /* Printf does not have a way of specifiying a maximum field width for an + integer value, so we print the full value into a buffer and then select + the precision we need. */ +#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) +#ifndef __MSVCRT__ + snprintf (buff, sizeof (buff), "%16.16llx ", val); +#else + snprintf (buff, sizeof (buff), "%016I64x ", val); +#endif +#else + snprintf (buff, sizeof (buff), "%16.16lx ", val); +#endif + + fputs (buff + (byte_size == 4 ? 8 : 0), stdout); +} + static unsigned long int read_leb128 (unsigned char *data, unsigned int *length_return, int sign) { @@ -271,8 +338,52 @@ process_extended_line_op (unsigned char *data, int is_stmt) printf (_("%s\n\n"), name); break; + case DW_LNE_set_discriminator: + printf (_("set Discriminator to %lu\n"), + read_leb128 (data, & bytes_read, 0)); + break; + + /* HP extensions. */ + case DW_LNE_HP_negate_is_UV_update: + printf ("DW_LNE_HP_negate_is_UV_update\n"); + break; + case DW_LNE_HP_push_context: + printf ("DW_LNE_HP_push_context\n"); + break; + case DW_LNE_HP_pop_context: + printf ("DW_LNE_HP_pop_context\n"); + break; + case DW_LNE_HP_set_file_line_column: + printf ("DW_LNE_HP_set_file_line_column\n"); + break; + case DW_LNE_HP_set_routine_name: + printf ("DW_LNE_HP_set_routine_name\n"); + break; + case DW_LNE_HP_set_sequence: + printf ("DW_LNE_HP_set_sequence\n"); + break; + case DW_LNE_HP_negate_post_semantics: + printf ("DW_LNE_HP_negate_post_semantics\n"); + break; + case DW_LNE_HP_negate_function_exit: + printf ("DW_LNE_HP_negate_function_exit\n"); + break; + case DW_LNE_HP_negate_front_end_logical: + printf ("DW_LNE_HP_negate_front_end_logical\n"); + break; + case DW_LNE_HP_define_proc: + printf ("DW_LNE_HP_define_proc\n"); + break; + default: - printf (_("UNKNOWN: length %d\n"), len - bytes_read); + 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: length %d\n"), len - bytes_read); + else + printf (_("UNKNOWN: length %d\n"), len - bytes_read); break; } @@ -353,7 +464,7 @@ add_abbrev (unsigned long number, unsigned long tag, int children) { abbrev_entry *entry; - entry = malloc (sizeof (*entry)); + entry = (abbrev_entry *) malloc (sizeof (*entry)); if (entry == NULL) /* ugg */ @@ -379,7 +490,7 @@ add_abbrev_attr (unsigned long attribute, unsigned long form) { abbrev_attr *attr; - attr = malloc (sizeof (*attr)); + attr = (abbrev_attr *) malloc (sizeof (*attr)); if (attr == NULL) /* ugg */ @@ -582,7 +693,8 @@ static int decode_location_expression (unsigned char * data, unsigned int pointer_size, unsigned long length, - unsigned long cu_offset) + unsigned long cu_offset, + struct dwarf_section * section) { unsigned op; unsigned int bytes_read; @@ -893,15 +1005,95 @@ decode_location_expression (unsigned char * data, data += 4; break; case DW_OP_call_ref: - printf ("DW_OP_call_ref"); + /* XXX: Strictly speaking for 64-bit DWARF3 files + this ought to be an 8-byte wide computation. */ + printf ("DW_OP_call_ref: <%lx>", (long) byte_get (data, 4) + cu_offset); + data += 4; break; case DW_OP_form_tls_address: printf ("DW_OP_form_tls_address"); break; + case DW_OP_call_frame_cfa: + printf ("DW_OP_call_frame_cfa"); + break; + case DW_OP_bit_piece: + printf ("DW_OP_bit_piece: "); + printf ("size: %lu ", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + printf ("offset: %lu ", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + + /* DWARF 4 extensions. */ + case DW_OP_stack_value: + printf ("DW_OP_stack_value"); + break; + + case DW_OP_implicit_value: + printf ("DW_OP_implicit_value"); + uvalue = read_leb128 (data, &bytes_read, 0); + data += bytes_read; + display_block (data, uvalue); + data += uvalue; + break; /* GNU extensions. */ case DW_OP_GNU_push_tls_address: - printf ("DW_OP_GNU_push_tls_address"); + printf ("DW_OP_GNU_push_tls_address or DW_OP_HP_unknown"); + break; + case DW_OP_GNU_uninit: + printf ("DW_OP_GNU_uninit"); + /* FIXME: Is there data associated with this OP ? */ + break; + case DW_OP_GNU_encoded_addr: + { + int encoding; + dwarf_vma addr; + + encoding = *data++; + addr = get_encoded_value (data, encoding); + if ((encoding & 0x70) == DW_EH_PE_pcrel) + addr += section->address + (data - section->start); + data += size_of_encoded_value (encoding); + + printf ("DW_OP_GNU_encoded_addr: fmt:%02x addr:", encoding); + print_dwarf_vma (addr, pointer_size); + } + break; + + /* HP extensions. */ + case DW_OP_HP_is_value: + printf ("DW_OP_HP_is_value"); + /* FIXME: Is there data associated with this OP ? */ + break; + case DW_OP_HP_fltconst4: + printf ("DW_OP_HP_fltconst4"); + /* FIXME: Is there data associated with this OP ? */ + break; + case DW_OP_HP_fltconst8: + printf ("DW_OP_HP_fltconst8"); + /* FIXME: Is there data associated with this OP ? */ + break; + case DW_OP_HP_mod_range: + printf ("DW_OP_HP_mod_range"); + /* FIXME: Is there data associated with this OP ? */ + break; + case DW_OP_HP_unmod_range: + printf ("DW_OP_HP_unmod_range"); + /* FIXME: Is there data associated with this OP ? */ + break; + case DW_OP_HP_tls: + printf ("DW_OP_HP_tls"); + /* FIXME: Is there data associated with this OP ? */ + break; + + /* PGI (STMicroelectronics) extensions. */ + case DW_OP_PGI_omp_thread_num: + /* Pushes the thread number for the current thread as it would be + returned by the standard OpenMP library function: + omp_get_thread_num(). The "current thread" is the thread for + which the expression is being evaluated. */ + printf ("DW_OP_PGI_omp_thread_num"); break; default: @@ -925,16 +1117,18 @@ decode_location_expression (unsigned char * data, static unsigned char * read_and_display_attr_value (unsigned long attribute, unsigned long form, - unsigned char *data, + unsigned char * data, unsigned long cu_offset, unsigned long pointer_size, unsigned long offset_size, int dwarf_version, - debug_info *debug_info_p, - int do_loc) + debug_info * debug_info_p, + int do_loc, + struct dwarf_section * section) { unsigned long uvalue = 0; unsigned char *block_start = NULL; + unsigned char * orig_data = data; unsigned int bytes_read; switch (form) @@ -1006,14 +1200,15 @@ read_and_display_attr_value (unsigned long attribute, return read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size, offset_size, dwarf_version, - debug_info_p, do_loc); + debug_info_p, do_loc, + section); } switch (form) { case DW_FORM_ref_addr: if (!do_loc) - printf (" <#%lx>", uvalue); + printf (" <0x%lx>", uvalue); break; case DW_FORM_ref1: @@ -1021,13 +1216,13 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_ref4: case DW_FORM_ref_udata: if (!do_loc) - printf (" <%lx>", uvalue + cu_offset); + printf (" <0x%lx>", uvalue + cu_offset); break; case DW_FORM_data4: case DW_FORM_addr: if (!do_loc) - printf (" %#lx", uvalue); + printf (" 0x%lx", uvalue); break; case DW_FORM_flag: @@ -1044,8 +1239,8 @@ read_and_display_attr_value (unsigned long attribute, if (!do_loc) { uvalue = byte_get (data, 4); - printf (" %lx", uvalue); - printf (" %lx", (unsigned long) byte_get (data + 4, 4)); + printf (" 0x%lx", uvalue); + printf (" 0x%lx", (unsigned long) byte_get (data + 4, 4)); } if ((do_loc || do_debug_loc || do_debug_ranges) && num_debug_info_entries == 0) @@ -1115,7 +1310,6 @@ read_and_display_attr_value (unsigned long attribute, break; } - /* For some attributes we can display further information. */ if ((do_loc || do_debug_loc || do_debug_ranges) && num_debug_info_entries == 0) { @@ -1124,15 +1318,14 @@ read_and_display_attr_value (unsigned long attribute, case DW_AT_frame_base: have_frame_base = 1; case DW_AT_location: + case DW_AT_string_length: + case DW_AT_return_addr: case DW_AT_data_member_location: case DW_AT_vtable_elem_location: - case DW_AT_allocated: - case DW_AT_associated: - case DW_AT_data_location: - case DW_AT_stride: - case DW_AT_upper_bound: - case DW_AT_lower_bound: - if (form == DW_FORM_data4 || form == DW_FORM_data8) + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + if (form == DW_FORM_data4 || form == DW_FORM_data8) { /* Process location list. */ unsigned int max = debug_info_p->max_loc_offsets; @@ -1141,11 +1334,11 @@ read_and_display_attr_value (unsigned long attribute, if (max == 0 || num >= max) { max += 1024; - debug_info_p->loc_offsets - = xcrealloc (debug_info_p->loc_offsets, + debug_info_p->loc_offsets = (long unsigned int *) + xcrealloc (debug_info_p->loc_offsets, max, sizeof (*debug_info_p->loc_offsets)); - debug_info_p->have_frame_base - = xcrealloc (debug_info_p->have_frame_base, + debug_info_p->have_frame_base = (int *) + xcrealloc (debug_info_p->have_frame_base, max, sizeof (*debug_info_p->have_frame_base)); debug_info_p->max_loc_offsets = max; } @@ -1154,7 +1347,7 @@ read_and_display_attr_value (unsigned long attribute, debug_info_p->num_loc_offsets++; } break; - + case DW_AT_low_pc: if (need_base_address) debug_info_p->base_address = uvalue; @@ -1170,8 +1363,8 @@ read_and_display_attr_value (unsigned long attribute, if (max == 0 || num >= max) { max += 1024; - debug_info_p->range_lists - = xcrealloc (debug_info_p->range_lists, + debug_info_p->range_lists = (long unsigned int *) + xcrealloc (debug_info_p->range_lists, max, sizeof (*debug_info_p->range_lists)); debug_info_p->max_range_lists = max; } @@ -1188,6 +1381,7 @@ read_and_display_attr_value (unsigned long attribute, if (do_loc) return data; + /* For some attributes we can display further information. */ printf ("\t"); switch (attribute) @@ -1263,9 +1457,24 @@ read_and_display_attr_value (unsigned long attribute, case DW_ATE_signed_char: printf ("(signed char)"); break; case DW_ATE_unsigned: printf ("(unsigned)"); break; case DW_ATE_unsigned_char: printf ("(unsigned char)"); break; - /* DWARF 2.1 value. */ + /* DWARF 2.1 values: */ case DW_ATE_imaginary_float: printf ("(imaginary float)"); break; case DW_ATE_decimal_float: printf ("(decimal float)"); break; + /* DWARF 3 values: */ + case DW_ATE_packed_decimal: printf ("(packed_decimal)"); break; + case DW_ATE_numeric_string: printf ("(numeric_string)"); break; + case DW_ATE_edited: printf ("(edited)"); break; + case DW_ATE_signed_fixed: printf ("(signed_fixed)"); break; + case DW_ATE_unsigned_fixed: printf ("(unsigned_fixed)"); break; + /* HP extensions: */ + case DW_ATE_HP_float80: printf ("(HP_float80)"); break; + case DW_ATE_HP_complex_float80: printf ("(HP_complex_float80)"); break; + case DW_ATE_HP_float128: printf ("(HP_float128)"); break; + case DW_ATE_HP_complex_float128:printf ("(HP_complex_float128)"); break; + case DW_ATE_HP_floathpintel: printf ("(HP_floathpintel)"); break; + case DW_ATE_HP_imaginary_float80: printf ("(HP_imaginary_float80)"); break; + case DW_ATE_HP_imaginary_float128: printf ("(HP_imaginary_float128)"); break; + default: if (uvalue >= DW_ATE_lo_user && uvalue <= DW_ATE_hi_user) @@ -1346,8 +1555,16 @@ read_and_display_attr_value (unsigned long attribute, case DW_AT_frame_base: have_frame_base = 1; case DW_AT_location: + case DW_AT_string_length: + case DW_AT_return_addr: case DW_AT_data_member_location: case DW_AT_vtable_elem_location: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + if (form == DW_FORM_data4 || form == DW_FORM_data8) + printf (_("(location list)")); + /* Fall through. */ case DW_AT_allocated: case DW_AT_associated: case DW_AT_data_location: @@ -1362,14 +1579,39 @@ read_and_display_attr_value (unsigned long attribute, need_frame_base = decode_location_expression (block_start, pointer_size, uvalue, - cu_offset); + cu_offset, section); printf (")"); if (need_frame_base && !have_frame_base) printf (_(" [without DW_AT_frame_base]")); } - else if (form == DW_FORM_data4 || form == DW_FORM_data8) - printf (_("(location list)")); + break; + case DW_AT_import: + { + if (form == DW_FORM_ref1 + || form == DW_FORM_ref2 + || form == DW_FORM_ref4) + uvalue += cu_offset; + + if (uvalue >= section->size) + warn (_("Offset %lx used as value for DW_AT_import attribute of DIE at offset %lx is too big.\n"), + uvalue, (unsigned long) (orig_data - section->start)); + else + { + unsigned long abbrev_number; + abbrev_entry * entry; + + abbrev_number = read_leb128 (section->start + uvalue, NULL, 0); + + printf ("[Abbrev Number: %ld", abbrev_number); + for (entry = first_abbrev; entry != NULL; entry = entry->next) + if (entry->entry == abbrev_number) + break; + if (entry != NULL) + printf (" (%s)", get_TAG_name (entry->tag)); + printf ("]"); + } + } break; default: @@ -1459,19 +1701,52 @@ get_AT_name (unsigned long attribute) case DW_AT_call_column: return "DW_AT_call_column"; case DW_AT_call_file: return "DW_AT_call_file"; case DW_AT_call_line: return "DW_AT_call_line"; - /* SGI/MIPS extensions. */ - case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; - case DW_AT_MIPS_loop_begin: return "DW_AT_MIPS_loop_begin"; - case DW_AT_MIPS_tail_loop_begin: return "DW_AT_MIPS_tail_loop_begin"; - case DW_AT_MIPS_epilog_begin: return "DW_AT_MIPS_epilog_begin"; - case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor"; - case DW_AT_MIPS_software_pipeline_depth: - return "DW_AT_MIPS_software_pipeline_depth"; - case DW_AT_MIPS_linkage_name: return "DW_AT_MIPS_linkage_name"; - case DW_AT_MIPS_stride: return "DW_AT_MIPS_stride"; - case DW_AT_MIPS_abstract_name: return "DW_AT_MIPS_abstract_name"; - case DW_AT_MIPS_clone_origin: return "DW_AT_MIPS_clone_origin"; - case DW_AT_MIPS_has_inlines: return "DW_AT_MIPS_has_inlines"; + case DW_AT_description: return "DW_AT_description"; + case DW_AT_binary_scale: return "DW_AT_binary_scale"; + case DW_AT_decimal_scale: return "DW_AT_decimal_scale"; + case DW_AT_small: return "DW_AT_small"; + case DW_AT_decimal_sign: return "DW_AT_decimal_sign"; + case DW_AT_digit_count: return "DW_AT_digit_count"; + case DW_AT_picture_string: return "DW_AT_picture_string"; + case DW_AT_mutable: return "DW_AT_mutable"; + case DW_AT_threads_scaled: return "DW_AT_threads_scaled"; + case DW_AT_explicit: return "DW_AT_explicit"; + case DW_AT_object_pointer: return "DW_AT_object_pointer"; + case DW_AT_endianity: return "DW_AT_endianity"; + case DW_AT_elemental: return "DW_AT_elemental"; + case DW_AT_pure: return "DW_AT_pure"; + case DW_AT_recursive: return "DW_AT_recursive"; + + /* HP and SGI/MIPS extensions. */ + case DW_AT_MIPS_loop_begin: return "DW_AT_MIPS_loop_begin"; + case DW_AT_MIPS_tail_loop_begin: return "DW_AT_MIPS_tail_loop_begin"; + case DW_AT_MIPS_epilog_begin: return "DW_AT_MIPS_epilog_begin"; + case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor"; + case DW_AT_MIPS_software_pipeline_depth: return "DW_AT_MIPS_software_pipeline_depth"; + case DW_AT_MIPS_linkage_name: return "DW_AT_MIPS_linkage_name"; + case DW_AT_MIPS_stride: return "DW_AT_MIPS_stride"; + case DW_AT_MIPS_abstract_name: return "DW_AT_MIPS_abstract_name"; + case DW_AT_MIPS_clone_origin: return "DW_AT_MIPS_clone_origin"; + case DW_AT_MIPS_has_inlines: return "DW_AT_MIPS_has_inlines"; + + /* HP Extensions. */ + case DW_AT_HP_block_index: return "DW_AT_HP_block_index"; + case DW_AT_HP_actuals_stmt_list: return "DW_AT_HP_actuals_stmt_list"; + case DW_AT_HP_proc_per_section: return "DW_AT_HP_proc_per_section"; + case DW_AT_HP_raw_data_ptr: return "DW_AT_HP_raw_data_ptr"; + case DW_AT_HP_pass_by_reference: return "DW_AT_HP_pass_by_reference"; + case DW_AT_HP_opt_level: return "DW_AT_HP_opt_level"; + case DW_AT_HP_prof_version_id: return "DW_AT_HP_prof_version_id"; + case DW_AT_HP_opt_flags: return "DW_AT_HP_opt_flags"; + case DW_AT_HP_cold_region_low_pc: return "DW_AT_HP_cold_region_low_pc"; + case DW_AT_HP_cold_region_high_pc: return "DW_AT_HP_cold_region_high_pc"; + case DW_AT_HP_all_variables_modifiable: return "DW_AT_HP_all_variables_modifiable"; + case DW_AT_HP_linkage_name: return "DW_AT_HP_linkage_name"; + case DW_AT_HP_prof_flags: return "DW_AT_HP_prof_flags"; + + /* One value is shared by the MIPS and HP extensions: */ + case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde or DW_AT_HP_unmodifiable"; + /* GNU extensions. */ case DW_AT_sf_names: return "DW_AT_sf_names"; case DW_AT_src_info: return "DW_AT_src_info"; @@ -1480,8 +1755,15 @@ get_AT_name (unsigned long attribute) case DW_AT_body_begin: return "DW_AT_body_begin"; case DW_AT_body_end: return "DW_AT_body_end"; case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; + /* UPC extension. */ case DW_AT_upc_threads_scaled: return "DW_AT_upc_threads_scaled"; + + /* PGI (STMicroelectronics) extensions. */ + case DW_AT_PGI_lbase: return "DW_AT_PGI_lbase"; + case DW_AT_PGI_soffset: return "DW_AT_PGI_soffset"; + case DW_AT_PGI_lstride: return "DW_AT_PGI_lstride"; + default: { static char buffer[100]; @@ -1496,20 +1778,21 @@ get_AT_name (unsigned long attribute) static unsigned char * read_and_display_attr (unsigned long attribute, unsigned long form, - unsigned char *data, + unsigned char * data, unsigned long cu_offset, unsigned long pointer_size, unsigned long offset_size, int dwarf_version, - debug_info *debug_info_p, - int do_loc) + debug_info * debug_info_p, + int do_loc, + struct dwarf_section * section) { if (!do_loc) - printf (" %-18s:", get_AT_name (attribute)); + printf (" %-18s:", get_AT_name (attribute)); data = read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size, offset_size, dwarf_version, debug_info_p, - do_loc); + do_loc, section); if (!do_loc) printf ("\n"); return data; @@ -1521,7 +1804,8 @@ read_and_display_attr (unsigned long attribute, anything to the user. */ static int -process_debug_info (struct dwarf_section *section, void *file, +process_debug_info (struct dwarf_section *section, + void *file, int do_loc) { unsigned char *start = section->start; @@ -1549,8 +1833,22 @@ process_debug_info (struct dwarf_section *section, void *file, length = byte_get (section_begin + 4, 8); section_begin += length + 12; } + else if (length >= 0xfffffff0 && length < 0xffffffff) + { + warn (_("Reserved length value (%lx) found in section %s\n"), length, section->name); + return 0; + } else section_begin += length + 4; + + /* 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) + { + warn (_("Corrupt unit length (%lx) found in section %s\n"), length, section->name); + return 0; + } } if (num_units == 0) @@ -1560,8 +1858,8 @@ process_debug_info (struct dwarf_section *section, void *file, } /* Then allocate an array to hold the information. */ - debug_information = cmalloc (num_units, - sizeof (* debug_information)); + debug_information = (debug_info *) cmalloc (num_units, + sizeof (* debug_information)); if (debug_information == NULL) { error (_("Not enough memory for a debug info array of %u entries"), @@ -1572,7 +1870,7 @@ process_debug_info (struct dwarf_section *section, void *file, if (!do_loc) { - printf (_("The section %s contains:\n\n"), section->name); + printf (_("Contents of the %s section:\n\n"), section->name); load_debug_section (str, file); } @@ -1644,7 +1942,8 @@ process_debug_info (struct dwarf_section *section, void *file, if (!do_loc) { printf (_(" Compilation Unit @ offset 0x%lx:\n"), cu_offset); - printf (_(" Length: %ld\n"), compunit.cu_length); + printf (_(" Length: 0x%lx (%s)\n"), compunit.cu_length, + initial_length_size == 8 ? "64-bit" : "32-bit"); printf (_(" Version: %d\n"), compunit.cu_version); printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset); printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size); @@ -1653,8 +1952,8 @@ process_debug_info (struct dwarf_section *section, void *file, if (cu_offset + compunit.cu_length + initial_length_size > section->size) { - warn (_("Debug info is corrupted, length is invalid (section is %lu bytes)\n"), - (unsigned long)section->size); + warn (_("Debug info is corrupted, length of CU at %lx extends beyond end of section (length = %lx)\n"), + cu_offset, compunit.cu_length); break; } tags = hdrptr; @@ -1662,7 +1961,8 @@ process_debug_info (struct dwarf_section *section, void *file, if (compunit.cu_version != 2 && compunit.cu_version != 3) { - warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n")); + warn (_("CU at offset %lx contains corrupt or unsupported version number: %d.\n"), + cu_offset, compunit.cu_version); continue; } @@ -1671,8 +1971,9 @@ process_debug_info (struct dwarf_section *section, void *file, /* Process the abbrevs used by this compilation unit. DWARF sections under Mach-O have non-zero addresses. */ if (compunit.cu_abbrev_offset >= debug_displays [abbrev].section.size) - warn (_("Debug info is corrupted, abbrev offset is invalid (section is %lu bytes)\n"), - (unsigned long)debug_displays [abbrev].section.size); + warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"), + (unsigned long) compunit.cu_abbrev_offset, + (unsigned long) debug_displays [abbrev].section.size); else process_abbrev_section ((unsigned char *) debug_displays [abbrev].section.start @@ -1685,26 +1986,52 @@ process_debug_info (struct dwarf_section *section, void *file, { unsigned int bytes_read; unsigned long abbrev_number; + unsigned long die_offset; abbrev_entry *entry; abbrev_attr *attr; + die_offset = tags - section_begin; + abbrev_number = read_leb128 (tags, & bytes_read, 0); tags += bytes_read; - /* A null DIE marks the end of a list of children. */ + /* A null DIE marks the end of a list of siblings or it may also be + a section padding. */ if (abbrev_number == 0) { + /* Check if it can be a section padding for the last CU. */ + if (level == 0 && start == end) + { + unsigned char *chk; + + for (chk = tags; chk < start; chk++) + if (*chk != 0) + break; + if (chk == start) + break; + } + --level; + if (level < 0) + { + static unsigned num_bogus_warns = 0; + + if (num_bogus_warns < 3) + { + warn (_("Bogus end-of-siblings marker detected at offset %lx in .debug_info section\n"), + die_offset); + num_bogus_warns ++; + if (num_bogus_warns == 3) + warn (_("Further warnings about bogus end-of-sibling markers suppressed\n")); + } + } continue; } if (!do_loc) printf (_(" <%d><%lx>: Abbrev Number: %lu"), - level, - (unsigned long) (tags - section_begin - - bytes_read), - abbrev_number); - + level, die_offset, abbrev_number); + /* Scan through the abbreviation list until we reach the correct entry. */ for (entry = first_abbrev; @@ -1719,14 +2046,14 @@ process_debug_info (struct dwarf_section *section, void *file, printf ("\n"); fflush (stdout); } - warn (_("Unable to locate entry %lu in the abbreviation table\n"), - abbrev_number); + warn (_("DIE at offset %lx refers to abbreviation number %lu which does not exist\n"), + die_offset, abbrev_number); return 0; } if (!do_loc) printf (_(" (%s)\n"), get_TAG_name (entry->tag)); - + switch (entry->tag) { default: @@ -1747,7 +2074,7 @@ process_debug_info (struct dwarf_section *section, void *file, { if (! do_loc) /* Show the offset from where the tag was extracted. */ - printf (" <%2lx>", (unsigned long)(tags - section_begin)); + printf (" <%2lx>", (unsigned long)(tags - section_begin)); tags = read_and_display_attr (attr->attribute, attr->form, @@ -1755,26 +2082,26 @@ process_debug_info (struct dwarf_section *section, void *file, compunit.cu_pointer_size, offset_size, compunit.cu_version, - &debug_information [unit], - do_loc); + debug_information + unit, + do_loc, section); } - + if (entry->children) ++level; } } - + /* Set num_debug_info_entries here so that it can be used to check if we need to process .debug_loc and .debug_ranges sections. */ if ((do_loc || do_debug_loc || do_debug_ranges) && num_debug_info_entries == 0) num_debug_info_entries = num_units; - + if (!do_loc) { printf ("\n"); } - + return 1; } @@ -1792,6 +2119,11 @@ load_debug_info (void * file) last_pointer_size = 0; warned_about_missing_comp_units = FALSE; + /* If we have already tried and failed to load the .debug_info + section then do not bother to repear the task. */ + if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE) + return 0; + /* If we already have the information there is nothing else to do. */ if (num_debug_info_entries > 0) return num_debug_info_entries; @@ -1799,21 +2131,20 @@ load_debug_info (void * file) if (load_debug_section (info, file) && process_debug_info (&debug_displays [info].section, file, 1)) return num_debug_info_entries; - else - return 0; + + num_debug_info_entries = DEBUG_INFO_UNAVAILABLE; + return 0; } static int -display_debug_lines (struct dwarf_section *section, void *file) +display_debug_lines_raw (struct dwarf_section *section, + unsigned char *data, + unsigned char *end) { unsigned char *start = section->start; - unsigned char *data = start; - unsigned char *end = start + section->size; - printf (_("\nDump of debug contents of section %s:\n\n"), - section->name); - - load_debug_info (file); + printf (_("Raw dump of debug contents of section %s:\n\n"), + section->name); while (data < end) { @@ -1821,11 +2152,13 @@ display_debug_lines (struct dwarf_section *section, void *file) unsigned char *standard_opcodes; unsigned char *end_of_sequence; unsigned char *hdrptr; + unsigned long hdroff; int initial_length_size; int offset_size; int i; hdrptr = data; + hdroff = hdrptr - start; /* Check the length of the block. */ info.li_length = byte_get (hdrptr, 4); @@ -1848,7 +2181,8 @@ display_debug_lines (struct dwarf_section *section, void *file) if (info.li_length + initial_length_size > section->size) { warn - (_("The line info appears to be corrupt - the section is too small\n")); + (_("The information in section %s appears to be corrupt - the section is too small\n"), + section->name); return 0; } @@ -1878,6 +2212,7 @@ display_debug_lines (struct dwarf_section *section, void *file) info.li_line_base <<= 24; info.li_line_base >>= 24; + printf (_(" Offset: 0x%lx\n"), hdroff); printf (_(" Length: %ld\n"), info.li_length); printf (_(" DWARF Version: %d\n"), info.li_version); printf (_(" Prologue Length: %d\n"), info.li_prologue_length); @@ -2077,6 +2412,461 @@ display_debug_lines (struct dwarf_section *section, void *file) return 1; } +typedef struct +{ + unsigned char *name; + unsigned int directory_index; + unsigned int modification_date; + unsigned int length; +} File_Entry; + +/* Output a decoded representation of the .debug_line section. */ + +static int +display_debug_lines_decoded (struct dwarf_section *section, + unsigned char *data, + unsigned char *end) +{ + printf (_("Decoded dump of debug contents of section %s:\n\n"), + section->name); + + while (data < end) + { + /* This loop amounts to one iteration per compilation unit. */ + DWARF2_Internal_LineInfo info; + unsigned char *standard_opcodes; + unsigned char *end_of_sequence; + unsigned char *hdrptr; + int initial_length_size; + int offset_size; + int i; + File_Entry *file_table = NULL; + unsigned char **directory_table = NULL; + unsigned int prev_line = 0; + + hdrptr = data; + + /* Extract information from the Line Number Program Header. + (section 6.2.4 in the Dwarf3 doc). */ + + /* Get the length of this CU's line number information block. */ + info.li_length = byte_get (hdrptr, 4); + hdrptr += 4; + + if (info.li_length == 0xffffffff) + { + /* This section is 64-bit DWARF 3. */ + info.li_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + if (info.li_length + initial_length_size > section->size) + { + warn (_("The line info appears to be corrupt - " + "the section is too small\n")); + return 0; + } + + /* Get this CU's Line Number Block version number. */ + info.li_version = byte_get (hdrptr, 2); + hdrptr += 2; + if (info.li_version != 2 && info.li_version != 3) + { + warn (_("Only DWARF version 2 and 3 line info is currently " + "supported.\n")); + return 0; + } + + info.li_prologue_length = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + info.li_min_insn_length = byte_get (hdrptr, 1); + hdrptr++; + info.li_default_is_stmt = byte_get (hdrptr, 1); + hdrptr++; + info.li_line_base = byte_get (hdrptr, 1); + hdrptr++; + info.li_line_range = byte_get (hdrptr, 1); + hdrptr++; + info.li_opcode_base = byte_get (hdrptr, 1); + hdrptr++; + + /* Sign extend the line base field. */ + info.li_line_base <<= 24; + info.li_line_base >>= 24; + + /* Find the end of this CU's Line Number Information Block. */ + end_of_sequence = data + info.li_length + initial_length_size; + + reset_state_machine (info.li_default_is_stmt); + + /* Save a pointer to the contents of the Opcodes table. */ + standard_opcodes = hdrptr; + + /* Traverse the Directory table just to count entries. */ + data = standard_opcodes + info.li_opcode_base - 1; + if (*data != 0) + { + unsigned int n_directories = 0; + unsigned char *ptr_directory_table = data; + int i; + + while (*data != 0) + { + data += strlen ((char *) data) + 1; + n_directories++; + } + + /* Go through the directory table again to save the directories. */ + directory_table = (unsigned char **) + xmalloc (n_directories * sizeof (unsigned char *)); + + i = 0; + while (*ptr_directory_table != 0) + { + directory_table[i] = ptr_directory_table; + ptr_directory_table += strlen ((char *) ptr_directory_table) + 1; + i++; + } + } + /* Skip the NUL at the end of the table. */ + data++; + + /* Traverse the File Name table just to count the entries. */ + if (*data != 0) + { + unsigned int n_files = 0; + unsigned char *ptr_file_name_table = data; + int i; + + while (*data != 0) + { + unsigned int bytes_read; + + /* Skip Name, directory index, last modification time and length + of file. */ + data += strlen ((char *) data) + 1; + read_leb128 (data, & bytes_read, 0); + data += bytes_read; + read_leb128 (data, & bytes_read, 0); + data += bytes_read; + read_leb128 (data, & bytes_read, 0); + data += bytes_read; + + n_files++; + } + + /* Go through the file table again to save the strings. */ + file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry)); + + i = 0; + while (*ptr_file_name_table != 0) + { + unsigned int bytes_read; + + file_table[i].name = ptr_file_name_table; + ptr_file_name_table += strlen ((char *) ptr_file_name_table) + 1; + + /* We are not interested in directory, time or size. */ + file_table[i].directory_index = read_leb128 (ptr_file_name_table, + & bytes_read, 0); + ptr_file_name_table += bytes_read; + file_table[i].modification_date = read_leb128 (ptr_file_name_table, + & bytes_read, 0); + ptr_file_name_table += bytes_read; + file_table[i].length = read_leb128 (ptr_file_name_table, & bytes_read, 0); + ptr_file_name_table += bytes_read; + i++; + } + i = 0; + + /* Print the Compilation Unit's name and a header. */ + if (directory_table == NULL) + { + printf (_("CU: %s:\n"), file_table[0].name); + printf (_("File name Line number Starting address\n")); + } + else + { + if (do_wide || strlen ((char *) directory_table[0]) < 76) + { + printf (_("CU: %s/%s:\n"), directory_table[0], + file_table[0].name); + } + else + { + printf (_("%s:\n"), file_table[0].name); + } + printf (_("File name Line number Starting address\n")); + } + } + + /* Skip the NUL at the end of the table. */ + data++; + + /* 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; + + op_code = *data++; + prev_line = state_machine_regs.line; + + if (op_code >= info.li_opcode_base) + { + op_code -= info.li_opcode_base; + uladv = (op_code / info.li_line_range) * info.li_min_insn_length; + state_machine_regs.address += uladv; + + adv = (op_code % info.li_line_range) + info.li_line_base; + state_machine_regs.line += adv; + is_special_opcode = 1; + } + else switch (op_code) + { + case DW_LNS_extended_op: + { + unsigned int ext_op_code_len; + unsigned int bytes_read; + unsigned char ext_op_code; + unsigned char *op_code_data = data; + + ext_op_code_len = read_leb128 (op_code_data, &bytes_read, 0); + op_code_data += bytes_read; + + if (ext_op_code_len == 0) + { + warn (_("badly formed extended line op encountered!\n")); + break; + } + ext_op_code_len += bytes_read; + ext_op_code = *op_code_data++; + + switch (ext_op_code) + { + case DW_LNE_end_sequence: + reset_state_machine (info.li_default_is_stmt); + break; + case DW_LNE_set_address: + state_machine_regs.address = + byte_get (op_code_data, ext_op_code_len - bytes_read - 1); + break; + case DW_LNE_define_file: + { + unsigned int dir_index = 0; + + ++state_machine_regs.last_file_entry; + op_code_data += strlen ((char *) op_code_data) + 1; + dir_index = read_leb128 (op_code_data, & bytes_read, 0); + op_code_data += bytes_read; + read_leb128 (op_code_data, & bytes_read, 0); + op_code_data += bytes_read; + read_leb128 (op_code_data, & bytes_read, 0); + + printf (_("%s:\n"), directory_table[dir_index]); + break; + } + default: + printf (_("UNKNOWN: length %d\n"), ext_op_code_len - bytes_read); + break; + } + data += ext_op_code_len; + break; + } + case DW_LNS_copy: + break; + + case DW_LNS_advance_pc: + uladv = read_leb128 (data, & bytes_read, 0); + uladv *= info.li_min_insn_length; + data += bytes_read; + state_machine_regs.address += uladv; + break; + + case DW_LNS_advance_line: + adv = read_leb128 (data, & bytes_read, 1); + data += bytes_read; + state_machine_regs.line += adv; + break; + + case DW_LNS_set_file: + adv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + state_machine_regs.file = adv; + 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 + { + /* 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); + } + break; + + case DW_LNS_set_column: + uladv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + state_machine_regs.column = uladv; + break; + + case DW_LNS_negate_stmt: + adv = state_machine_regs.is_stmt; + adv = ! adv; + state_machine_regs.is_stmt = adv; + break; + + case DW_LNS_set_basic_block: + state_machine_regs.basic_block = 1; + break; + + case DW_LNS_const_add_pc: + uladv = (((255 - info.li_opcode_base) / info.li_line_range) + * info.li_min_insn_length); + state_machine_regs.address += uladv; + break; + + case DW_LNS_fixed_advance_pc: + uladv = byte_get (data, 2); + data += 2; + state_machine_regs.address += uladv; + break; + + case DW_LNS_set_prologue_end: + break; + + case DW_LNS_set_epilogue_begin: + break; + + case DW_LNS_set_isa: + uladv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + printf (_(" Set ISA to %lu\n"), uladv); + break; + + default: + printf (_(" Unknown opcode %d with operands: "), op_code); + + for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) + { + printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0), + i == 1 ? "" : ", "); + data += bytes_read; + } + putchar ('\n'); + 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) + || (op_code == DW_LNS_copy)) + { + const unsigned int MAX_FILENAME_LENGTH = 35; + char *fileName = (char *)file_table[state_machine_regs.file - 1].name; + char *newFileName = NULL; + size_t 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)) + { + printf (_("%-35s %11d %#18lx\n"), newFileName, + state_machine_regs.line, state_machine_regs.address); + } + else + { + printf (_("%s %11d %#18lx\n"), newFileName, + state_machine_regs.line, state_machine_regs.address); + } + + if (op_code == DW_LNE_end_sequence) + printf ("\n"); + + free (newFileName); + } + } + free (file_table); + file_table = NULL; + free (directory_table); + directory_table = NULL; + putchar ('\n'); + } + + return 1; +} + +static int +display_debug_lines (struct dwarf_section *section, void *file) +{ + unsigned char *data = section->start; + unsigned char *end = data + section->size; + int retValRaw = 1; + int retValDecoded = 1; + + if (load_debug_info (file) == 0) + { + warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"), + section->name); + return 0; + } + + if (do_debug_lines == 0) + do_debug_lines |= FLAG_DEBUG_LINES_RAW; + + if (do_debug_lines & FLAG_DEBUG_LINES_RAW) + retValRaw = display_debug_lines_raw (section, data, end); + + if (do_debug_lines & FLAG_DEBUG_LINES_DECODED) + retValDecoded = display_debug_lines_decoded (section, data, end); + + if (!retValRaw || !retValDecoded) + return 0; + + return 1; +} + +static debug_info * +find_debug_info_for_offset (unsigned long offset) +{ + unsigned int i; + + if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE) + return NULL; + + for (i = 0; i < num_debug_info_entries; i++) + if (debug_information[i].cu_offset == offset) + return debug_information + i; + + return NULL; +} + static int display_debug_pubnames (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) @@ -2085,6 +2875,10 @@ display_debug_pubnames (struct dwarf_section *section, unsigned char *start = section->start; unsigned char *end = start + section->size; + /* It does not matter if this load fails, + we test for that later on. */ + load_debug_info (file); + printf (_("Contents of the %s section:\n\n"), section->name); while (start < end) @@ -2112,8 +2906,16 @@ display_debug_pubnames (struct dwarf_section *section, pubnames.pn_version = byte_get (data, 2); data += 2; + pubnames.pn_offset = byte_get (data, offset_size); data += offset_size; + + if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE + && num_debug_info_entries > 0 + && find_debug_info_for_offset (pubnames.pn_offset) == NULL) + warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"), + pubnames.pn_offset, section->name); + pubnames.pn_size = byte_get (data, offset_size); data += offset_size; @@ -2136,7 +2938,7 @@ display_debug_pubnames (struct dwarf_section *section, pubnames.pn_length); printf (_(" Version: %d\n"), pubnames.pn_version); - printf (_(" Offset into .debug_info section: %ld\n"), + printf (_(" Offset into .debug_info section: 0x%lx\n"), pubnames.pn_offset); printf (_(" Size of area in .debug_info section: %ld\n"), pubnames.pn_size); @@ -2150,7 +2952,7 @@ display_debug_pubnames (struct dwarf_section *section, if (offset != 0) { data += offset_size; - printf (" %-6ld\t\t%s\n", offset, data); + printf (" %-6lx\t%s\n", offset, data); data += strlen ((char *) data) + 1; } } @@ -2178,7 +2980,7 @@ display_debug_macinfo (struct dwarf_section *section, unsigned int lineno; const char *string; - op = *curr; + op = (enum dwarf_macinfo_record_type) *curr; curr++; switch (op) @@ -2305,7 +3107,12 @@ display_debug_loc (struct dwarf_section *section, void *file) return 0; } - load_debug_info (file); + if (load_debug_info (file) == 0) + { + warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"), + section->name); + return 0; + } /* Check the order of location list in .debug_info section. If offsets of location lists are in the ascending order, we can @@ -2363,8 +3170,8 @@ display_debug_loc (struct dwarf_section *section, void *file) seen_first_offset = 0; for (i = first; i < num_debug_info_entries; i++) { - unsigned long begin; - unsigned long end; + dwarf_vma begin; + dwarf_vma end; unsigned short length; unsigned long offset; unsigned int pointer_size; @@ -2380,7 +3187,7 @@ display_debug_loc (struct dwarf_section *section, void *file) { has_frame_base = debug_information [i].have_frame_base [j]; /* DWARF sections under Mach-O have non-zero addresses. */ - offset = debug_information [i].loc_offsets [j] - section->address; + offset = debug_information [i].loc_offsets [j] - section->address; next = section_begin + offset; base_address = debug_information [i].base_address; @@ -2390,10 +3197,12 @@ 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"), - (long)(start - section_begin), (long)(next - section_begin)); + (unsigned long) (start - section_begin), + (unsigned long) (next - section_begin)); else if (start > next) warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"), - (long)(start - section_begin), (long)(next - section_begin)); + (unsigned long) (start - section_begin), + (unsigned long) (next - section_begin)); } start = next; @@ -2413,23 +3222,31 @@ display_debug_loc (struct dwarf_section *section, void *file) break; } - begin = byte_get (start, pointer_size); + /* 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. */ + begin = byte_get_signed (start, pointer_size); start += pointer_size; - end = byte_get (start, pointer_size); + end = byte_get_signed (start, pointer_size); start += pointer_size; + printf (" %8.8lx ", offset); + if (begin == 0 && end == 0) { - printf (_(" %8.8lx \n"), offset); + printf (_("\n")); break; } /* Check base address specifiers. */ - if (begin == -1UL && end != -1UL) + if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1) { base_address = end; - printf (_(" %8.8lx %8.8lx %8.8lx (base address)\n"), - offset, begin, end); + print_dwarf_vma (begin, pointer_size); + print_dwarf_vma (end, pointer_size); + printf (_("(base address)\n")); continue; } @@ -2450,12 +3267,14 @@ display_debug_loc (struct dwarf_section *section, void *file) break; } - printf (" %8.8lx %8.8lx %8.8lx (", - offset, begin + base_address, end + base_address); + 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, length, - cu_offset); + cu_offset, section); putchar (')'); if (need_frame_base && !has_frame_base) @@ -2472,6 +3291,11 @@ display_debug_loc (struct dwarf_section *section, void *file) } } } + + if (start < section_end) + warn (_("There are %ld unused bytes at the end of section %s\n"), + (long) (section_end - start), section->name); + putchar ('\n'); return 1; } @@ -2547,15 +3371,19 @@ display_debug_aranges (struct dwarf_section *section, unsigned char *start = section->start; unsigned char *end = start + section->size; - printf (_("The section %s contains:\n\n"), section->name); + printf (_("Contents of the %s section:\n\n"), section->name); + + /* It does not matter if this load fails, + we test for that later on. */ + load_debug_info (file); while (start < end) { unsigned char *hdrptr; DWARF2_Internal_ARange arange; unsigned char *ranges; - unsigned long length; - unsigned long address; + dwarf_vma length; + dwarf_vma address; unsigned char address_size; int excess; int offset_size; @@ -2585,6 +3413,12 @@ display_debug_aranges (struct dwarf_section *section, arange.ar_info_offset = byte_get (hdrptr, offset_size); hdrptr += offset_size; + if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE + && num_debug_info_entries > 0 + && find_debug_info_for_offset (arange.ar_info_offset) == NULL) + warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"), + arange.ar_info_offset, section->name); + arange.ar_pointer_size = byte_get (hdrptr, 1); hdrptr += 1; @@ -2599,7 +3433,7 @@ display_debug_aranges (struct dwarf_section *section, printf (_(" Length: %ld\n"), arange.ar_length); printf (_(" Version: %d\n"), arange.ar_version); - printf (_(" Offset into .debug_info: %lx\n"), arange.ar_info_offset); + printf (_(" Offset into .debug_info: 0x%lx\n"), arange.ar_info_offset); printf (_(" Pointer Size: %d\n"), arange.ar_pointer_size); printf (_(" Segment Size: %d\n"), arange.ar_segment_size); @@ -2613,7 +3447,7 @@ display_debug_aranges (struct dwarf_section *section, warn (_("Pointer size + Segment size is not a power of two.\n")); break; } - + if (address_size > 4) printf (_("\n Address Length\n")); else @@ -2638,10 +3472,10 @@ display_debug_aranges (struct dwarf_section *section, ranges += address_size; - if (address_size > 4) - printf (" 0x%16.16lx 0x%lx\n", address, length); - else - printf (" 0x%8.8lx 0x%lx\n", address, length); + printf (" "); + print_dwarf_vma (address, address_size); + print_dwarf_vma (length, address_size); + putchar ('\n'); } } @@ -2650,6 +3484,31 @@ display_debug_aranges (struct dwarf_section *section, return 1; } +/* Each debug_information[x].range_lists[y] gets this representation for + sorting purposes. */ + +struct range_entry + { + /* The debug_information[x].range_lists[y] value. */ + unsigned long ranges_offset; + + /* Original debug_information to find parameters of the data. */ + debug_info *debug_info_p; + }; + +/* Sort struct range_entry in ascending order of its RANGES_OFFSET. */ + +static int +range_entry_compar (const void *ap, const void *bp) +{ + const struct range_entry *a_re = (const struct range_entry *) ap; + const struct range_entry *b_re = (const struct range_entry *) bp; + const unsigned long a = a_re->ranges_offset; + const unsigned long b = b_re->ranges_offset; + + return (a > b) - (b > a); +} + static int display_debug_ranges (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) @@ -2658,14 +3517,8 @@ display_debug_ranges (struct dwarf_section *section, unsigned char *section_end; unsigned long bytes; unsigned char *section_begin = start; - unsigned int num_range_list = 0; - unsigned long last_offset = 0; - unsigned int first = 0; - unsigned int i; - unsigned int j; - int seen_first_offset = 0; - int use_debug_info = 1; - unsigned char *next; + unsigned int num_range_list, i; + struct range_entry *range_entries, *range_entry_fill; bytes = section->size; section_end = start + bytes; @@ -2676,129 +3529,125 @@ display_debug_ranges (struct dwarf_section *section, return 0; } - load_debug_info (file); + if (load_debug_info (file) == 0) + { + warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"), + section->name); + return 0; + } - /* Check the order of range list in .debug_info section. If - offsets of range lists are in the ascending order, we can - use `debug_information' directly. */ + num_range_list = 0; for (i = 0; i < num_debug_info_entries; i++) - { - unsigned int num; + num_range_list += debug_information [i].num_range_lists; - num = debug_information [i].num_range_lists; - num_range_list += num; + if (num_range_list == 0) + error (_("No range lists in .debug_info section!\n")); - /* Check if we can use `debug_information' directly. */ - if (use_debug_info && num != 0) - { - if (!seen_first_offset) - { - /* This is the first range list. */ - last_offset = debug_information [i].range_lists [0]; - first = i; - seen_first_offset = 1; - j = 1; - } - else - j = 0; + range_entries = (struct range_entry *) + xmalloc (sizeof (*range_entries) * num_range_list); + range_entry_fill = range_entries; - for (; j < num; j++) - { - if (last_offset > - debug_information [i].range_lists [j]) - { - use_debug_info = 0; - break; - } - last_offset = debug_information [i].range_lists [j]; - } + for (i = 0; i < num_debug_info_entries; i++) + { + debug_info *debug_info_p = &debug_information[i]; + unsigned int j; + + for (j = 0; j < debug_info_p->num_range_lists; j++) + { + range_entry_fill->ranges_offset = debug_info_p->range_lists[j]; + range_entry_fill->debug_info_p = debug_info_p; + range_entry_fill++; } } - if (!use_debug_info) - /* FIXME: Should we handle this case? */ - error (_("Range lists in .debug_info section aren't in ascending order!\n")); - - if (!seen_first_offset) - error (_("No range lists in .debug_info section!\n")); + qsort (range_entries, num_range_list, sizeof (*range_entries), + range_entry_compar); /* DWARF sections under Mach-O have non-zero addresses. */ - if (debug_information [first].num_range_lists > 0 - && debug_information [first].range_lists [0] != section->address) + if (range_entries[0].ranges_offset != section->address) warn (_("Range lists in %s section start at 0x%lx\n"), - section->name, debug_information [first].range_lists [0]); + section->name, range_entries[0].ranges_offset); printf (_("Contents of the %s section:\n\n"), section->name); printf (_(" Offset Begin End\n")); - seen_first_offset = 0; - for (i = first; i < num_debug_info_entries; i++) + for (i = 0; i < num_range_list; i++) { - unsigned long begin; - unsigned long end; - unsigned long offset; + struct range_entry *range_entry = &range_entries[i]; + debug_info *debug_info_p = range_entry->debug_info_p; unsigned int pointer_size; + unsigned long offset; + unsigned char *next; unsigned long base_address; - pointer_size = debug_information [i].pointer_size; + pointer_size = debug_info_p->pointer_size; + + /* DWARF sections under Mach-O have non-zero addresses. */ + offset = range_entry->ranges_offset - section->address; + next = section_begin + offset; + base_address = debug_info_p->base_address; - for (j = 0; j < debug_information [i].num_range_lists; j++) + if (i > 0) { - /* DWARF sections under Mach-O have non-zero addresses. */ - offset = debug_information [i].range_lists [j] - section->address; - next = section_begin + offset; - base_address = debug_information [i].base_address; + if (start < next) + warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"), + (unsigned long) (start - section_begin), + (unsigned long) (next - section_begin), section->name); + else if (start > next) + warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"), + (unsigned long) (start - section_begin), + (unsigned long) (next - section_begin), section->name); + } + start = next; - if (!seen_first_offset) - seen_first_offset = 1; - else + while (1) + { + 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. */ + begin = byte_get_signed (start, pointer_size); + start += pointer_size; + end = byte_get_signed (start, pointer_size); + start += pointer_size; + + printf (" %8.8lx ", offset); + + if (begin == 0 && end == 0) { - if (start < next) - warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"), - (long)(start - section_begin), - (long)(next - section_begin), section->name); - else if (start > next) - warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"), - (long)(start - section_begin), - (long)(next - section_begin), section->name); + printf (_("\n")); + break; } - start = next; - while (1) + /* Check base address specifiers. */ + if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1) { - begin = byte_get (start, pointer_size); - start += pointer_size; - end = byte_get (start, pointer_size); - start += pointer_size; - - if (begin == 0 && end == 0) - { - printf (_(" %8.8lx \n"), offset); - break; - } - - /* Check base address specifiers. */ - if (begin == -1UL && end != -1UL) - { - base_address = end; - printf (" %8.8lx %8.8lx %8.8lx (base address)\n", - offset, begin, end); - continue; - } + base_address = end; + print_dwarf_vma (begin, pointer_size); + print_dwarf_vma (end, pointer_size); + printf ("(base address)\n"); + continue; + } - printf (" %8.8lx %8.8lx %8.8lx", - offset, begin + base_address, end + base_address); + print_dwarf_vma (begin + base_address, pointer_size); + print_dwarf_vma (end + base_address, pointer_size); - if (begin == end) - fputs (_(" (start == end)"), stdout); - else if (begin > end) - fputs (_(" (start > end)"), stdout); + if (begin == end) + fputs (_("(start == end)"), stdout); + else if (begin > end) + fputs (_("(start > end)"), stdout); - putchar ('\n'); - } + putchar ('\n'); } } putchar ('\n'); + + free (range_entries); + return 1; } @@ -2823,21 +3672,32 @@ typedef struct Frame_Chunk } Frame_Chunk; +static const char *const *dwarf_regnames; +static unsigned int dwarf_regnames_count; + /* A marker for a col_type that means this column was never referenced in the frame info. */ #define DW_CFA_unreferenced (-1) -static void -frame_need_space (Frame_Chunk *fc, int reg) +/* Return 0 if not 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; - if (reg < fc->ncols) - return; + if (reg < (unsigned int) fc->ncols) + return 0; + + if (dwarf_regnames_count + && reg > dwarf_regnames_count) + return -1; fc->ncols = reg + 1; - fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int)); - fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int)); + fc->col_type = (short int *) xcrealloc (fc->col_type, fc->ncols, + sizeof (short int)); + fc->col_offset = (int *) xcrealloc (fc->col_offset, fc->ncols, sizeof (int)); while (prev < fc->ncols) { @@ -2845,6 +3705,85 @@ frame_need_space (Frame_Chunk *fc, int reg) fc->col_offset[prev] = 0; prev++; } + return 1; +} + +static const char *const dwarf_regnames_i386[] = +{ + "eax", "ecx", "edx", "ebx", + "esp", "ebp", "esi", "edi", + "eip", "eflags", NULL, + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + NULL, NULL, + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + "fcw", "fsw", "mxcsr", + "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, + "tr", "ldtr" +}; + +static const char *const dwarf_regnames_x86_64[] = +{ + "rax", "rdx", "rcx", "rbx", + "rsi", "rdi", "rbp", "rsp", + "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", + "rip", + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15", + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + "rflags", + "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, + "fs.base", "gs.base", NULL, NULL, + "tr", "ldtr", + "mxcsr", "fcw", "fsw" +}; + +void +init_dwarf_regnames (unsigned int e_machine) +{ + switch (e_machine) + { + case EM_386: + case EM_486: + dwarf_regnames = dwarf_regnames_i386; + dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_i386); + break; + + case EM_X86_64: + dwarf_regnames = dwarf_regnames_x86_64; + dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_x86_64); + break; + + default: + break; + } +} + +static const char * +regname (unsigned int regno, int row) +{ + static char reg[64]; + if (dwarf_regnames + && regno < dwarf_regnames_count + && dwarf_regnames [regno] != NULL) + { + if (row) + return dwarf_regnames [regno]; + snprintf (reg, sizeof (reg), "r%d (%s)", regno, + dwarf_regnames [regno]); + } + else + snprintf (reg, sizeof (reg), "r%d", regno); + return reg; } static void @@ -2858,27 +3797,29 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) if (*need_col_headers) { + static const char *loc = " LOC"; + *need_col_headers = 0; - printf (" LOC CFA "); + printf ("%-*s CFA ", eh_addr_size * 2, loc); for (r = 0; r < *max_regs; r++) if (fc->col_type[r] != DW_CFA_unreferenced) { if (r == fc->ra) - printf ("ra "); + printf ("ra "); else - printf ("r%-4d", r); + printf ("%-5s ", regname (r, 1)); } printf ("\n"); } - printf ("%08lx ", fc->pc_begin); + printf ("%0*lx ", eh_addr_size * 2, fc->pc_begin); if (fc->cfa_exp) strcpy (tmp, "exp"); else - sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset); + sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), fc->cfa_offset); printf ("%-8s ", tmp); for (r = 0; r < fc->ncols; r++) @@ -2900,7 +3841,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) sprintf (tmp, "v%+d", fc->col_offset[r]); break; case DW_CFA_register: - sprintf (tmp, "r%d", fc->col_offset[r]); + sprintf (tmp, "%s", regname (fc->col_offset[r], 0)); break; case DW_CFA_expression: strcpy (tmp, "exp"); @@ -2912,36 +3853,12 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) strcpy (tmp, "n/a"); break; } - printf ("%-5s", tmp); + printf ("%-5s ", tmp); } } printf ("\n"); } -static int -size_of_encoded_value (int encoding) -{ - switch (encoding & 0x7) - { - default: /* ??? */ - case 0: return eh_addr_size; - case 2: return 2; - case 3: return 4; - case 4: return 8; - } -} - -static dwarf_vma -get_encoded_value (unsigned char *data, int encoding) -{ - int size = size_of_encoded_value (encoding); - - if (encoding & DW_EH_PE_signed) - return byte_get_signed (data, size); - else - return byte_get (data, size); -} - #define GET(N) byte_get (start, N); start += N #define LEB() read_leb128 (start, & length_return, 0); start += length_return #define SLEB() read_leb128 (start, & length_return, 1); start += length_return @@ -2959,8 +3876,9 @@ display_debug_frames (struct dwarf_section *section, int is_eh = strcmp (section->name, ".eh_frame") == 0; unsigned int length_return; int max_regs = 0; + const char *bad_reg = _("bad register: "); - printf (_("The section %s contains:\n"), section->name); + printf (_("Contents of the %s section:\n"), section->name); while (start < end) { @@ -3013,16 +3931,16 @@ display_debug_frames (struct dwarf_section *section, { int version; - fc = xmalloc (sizeof (Frame_Chunk)); + fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); memset (fc, 0, sizeof (Frame_Chunk)); fc->next = chunks; chunks = fc; fc->chunk_start = saved_start; fc->ncols = 0; - fc->col_type = xmalloc (sizeof (short int)); - fc->col_offset = xmalloc (sizeof (int)); - frame_need_space (fc, max_regs-1); + fc->col_type = (short int *) xmalloc (sizeof (short int)); + fc->col_offset = (int *) xmalloc (sizeof (int)); + frame_need_space (fc, max_regs - 1); version = *start++; @@ -3144,8 +4062,8 @@ display_debug_frames (struct dwarf_section *section, warn ("Invalid CIE pointer %#08lx in FDE at %#08lx\n", cie_id, (unsigned long)(saved_start - section_start)); fc->ncols = 0; - fc->col_type = xmalloc (sizeof (short int)); - fc->col_offset = xmalloc (sizeof (int)); + fc->col_type = (short int *) xmalloc (sizeof (short int)); + fc->col_offset = (int *) xmalloc (sizeof (int)); frame_need_space (fc, max_regs - 1); cie = fc; fc->augmentation = ""; @@ -3154,8 +4072,8 @@ display_debug_frames (struct dwarf_section *section, else { fc->ncols = cie->ncols; - fc->col_type = xcmalloc (fc->ncols, sizeof (short int)); - fc->col_offset = xcmalloc (fc->ncols, sizeof (int)); + fc->col_type = (short int *) xcmalloc (fc->ncols, sizeof (short int)); + fc->col_offset = (int *) xcmalloc (fc->ncols, sizeof (int)); memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int)); memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int)); fc->augmentation = cie->augmentation; @@ -3164,7 +4082,7 @@ 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); + frame_need_space (fc, max_regs - 1); fc->fde_encoding = cie->fde_encoding; } @@ -3172,11 +4090,7 @@ display_debug_frames (struct dwarf_section *section, encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); fc->pc_begin = get_encoded_value (start, fc->fde_encoding); - if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel - /* Don't adjust for relocatable file since there's - invariably a pcrel reloc here, which we haven't - applied. */ - && !is_relocatable) + if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel) fc->pc_begin += section->address + (start - section_start); start += encoded_ptr_size; fc->pc_range = byte_get (start, encoded_ptr_size); @@ -3236,12 +4150,12 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_offset: LEB (); - frame_need_space (fc, opa); - fc->col_type[opa] = DW_CFA_undefined; + if (frame_need_space (fc, opa) >= 0) + fc->col_type[opa] = DW_CFA_undefined; break; case DW_CFA_restore: - frame_need_space (fc, opa); - fc->col_type[opa] = DW_CFA_undefined; + if (frame_need_space (fc, opa) >= 0) + fc->col_type[opa] = DW_CFA_undefined; break; case DW_CFA_set_loc: start += encoded_ptr_size; @@ -3258,28 +4172,29 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_offset_extended: case DW_CFA_val_offset: reg = LEB (); LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_restore_extended: reg = LEB (); frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_undefined: reg = LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_same_value: reg = LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_register: reg = LEB (); LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_def_cfa: LEB (); LEB (); @@ -3299,14 +4214,14 @@ display_debug_frames (struct dwarf_section *section, reg = LEB (); tmp = LEB (); start += tmp; - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_offset_extended_sf: case DW_CFA_val_offset_sf: reg = LEB (); SLEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_def_cfa_sf: LEB (); SLEB (); @@ -3322,9 +4237,9 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_GNU_negative_offset_extended: reg = LEB (); LEB (); - frame_need_space (fc, reg); - fc->col_type[reg] = DW_CFA_undefined; - + if (frame_need_space (fc, reg) >= 0) + fc->col_type[reg] = DW_CFA_undefined; + break; default: break; } @@ -3341,6 +4256,7 @@ display_debug_frames (struct dwarf_section *section, unsigned long ul, reg, roffs; long l, ofs; dwarf_vma vma; + const char *reg_prefix = ""; op = *start++; opa = op & 0x3f; @@ -3363,24 +4279,36 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_offset: roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_offset: r%d at cfa%+ld\n", - opa, roffs * fc->data_factor); - fc->col_type[opa] = DW_CFA_offset; - fc->col_offset[opa] = roffs * fc->data_factor; + if (opa >= (unsigned int) fc->ncols) + reg_prefix = bad_reg; + if (! do_debug_frames_interp || *reg_prefix != '\0') + printf (" DW_CFA_offset: %s%s at cfa%+ld\n", + reg_prefix, regname (opa, 0), + roffs * fc->data_factor); + if (*reg_prefix == '\0') + { + fc->col_type[opa] = DW_CFA_offset; + fc->col_offset[opa] = roffs * fc->data_factor; + } break; case DW_CFA_restore: - if (! do_debug_frames_interp) - printf (" DW_CFA_restore: r%d\n", opa); - fc->col_type[opa] = cie->col_type[opa]; - fc->col_offset[opa] = cie->col_offset[opa]; + if (opa >= (unsigned int) cie->ncols + || 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') + { + fc->col_type[opa] = cie->col_type[opa]; + fc->col_offset[opa] = cie->col_offset[opa]; + } break; case DW_CFA_set_loc: vma = get_encoded_value (start, fc->fde_encoding); - if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel - && !is_relocatable) + if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel) vma += section->address + (start - section_start); start += encoded_ptr_size; if (do_debug_frames_interp) @@ -3426,63 +4354,104 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_offset_extended: reg = LEB (); roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_offset_extended: r%ld at cfa%+ld\n", - reg, roffs * fc->data_factor); - fc->col_type[reg] = DW_CFA_offset; - fc->col_offset[reg] = roffs * fc->data_factor; + if (reg >= (unsigned int) fc->ncols) + reg_prefix = bad_reg; + if (! do_debug_frames_interp || *reg_prefix != '\0') + printf (" DW_CFA_offset_extended: %s%s at cfa%+ld\n", + reg_prefix, regname (reg, 0), + roffs * fc->data_factor); + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_offset; + fc->col_offset[reg] = roffs * fc->data_factor; + } break; case DW_CFA_val_offset: reg = LEB (); roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_val_offset: r%ld at cfa%+ld\n", - reg, roffs * fc->data_factor); - fc->col_type[reg] = DW_CFA_val_offset; - fc->col_offset[reg] = roffs * fc->data_factor; + 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", + reg_prefix, regname (reg, 0), + roffs * fc->data_factor); + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_val_offset; + fc->col_offset[reg] = roffs * fc->data_factor; + } break; case DW_CFA_restore_extended: reg = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_restore_extended: r%ld\n", reg); - fc->col_type[reg] = cie->col_type[reg]; - fc->col_offset[reg] = cie->col_offset[reg]; + if (reg >= (unsigned int) cie->ncols + || 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') + { + fc->col_type[reg] = cie->col_type[reg]; + fc->col_offset[reg] = cie->col_offset[reg]; + } break; case DW_CFA_undefined: reg = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_undefined: r%ld\n", reg); - fc->col_type[reg] = DW_CFA_undefined; - fc->col_offset[reg] = 0; + if (reg >= (unsigned int) fc->ncols) + reg_prefix = bad_reg; + if (! do_debug_frames_interp || *reg_prefix != '\0') + printf (" DW_CFA_undefined: %s%s\n", + reg_prefix, regname (reg, 0)); + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_undefined; + fc->col_offset[reg] = 0; + } break; case DW_CFA_same_value: reg = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_same_value: r%ld\n", reg); - fc->col_type[reg] = DW_CFA_same_value; - fc->col_offset[reg] = 0; + if (reg >= (unsigned int) fc->ncols) + reg_prefix = bad_reg; + if (! do_debug_frames_interp || *reg_prefix != '\0') + printf (" DW_CFA_same_value: %s%s\n", + reg_prefix, regname (reg, 0)); + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_same_value; + fc->col_offset[reg] = 0; + } break; case DW_CFA_register: reg = LEB (); roffs = LEB (); - if (! do_debug_frames_interp) - printf (" DW_CFA_register: r%ld in r%ld\n", reg, roffs); - fc->col_type[reg] = DW_CFA_register; - fc->col_offset[reg] = roffs; + if (reg >= (unsigned int) fc->ncols) + reg_prefix = bad_reg; + if (! do_debug_frames_interp || *reg_prefix != '\0') + { + printf (" DW_CFA_register: %s%s in ", + reg_prefix, regname (reg, 0)); + puts (regname (roffs, 0)); + } + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_register; + fc->col_offset[reg] = roffs; + } break; case DW_CFA_remember_state: if (! do_debug_frames_interp) printf (" DW_CFA_remember_state\n"); - rs = xmalloc (sizeof (Frame_Chunk)); + rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); rs->ncols = fc->ncols; - rs->col_type = xcmalloc (rs->ncols, sizeof (short int)); - rs->col_offset = xcmalloc (rs->ncols, sizeof (int)); + rs->col_type = (short int *) xcmalloc (rs->ncols, + sizeof (short int)); + rs->col_offset = (int *) xcmalloc (rs->ncols, sizeof (int)); memcpy (rs->col_type, fc->col_type, rs->ncols); memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int)); rs->next = remembered_state; @@ -3496,7 +4465,7 @@ display_debug_frames (struct dwarf_section *section, if (rs) { remembered_state = rs->next; - frame_need_space (fc, rs->ncols-1); + frame_need_space (fc, rs->ncols - 1); memcpy (fc->col_type, rs->col_type, rs->ncols); memcpy (fc->col_offset, rs->col_offset, rs->ncols * sizeof (int)); @@ -3513,15 +4482,16 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_offset = LEB (); fc->cfa_exp = 0; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa: r%d ofs %d\n", - fc->cfa_reg, fc->cfa_offset); + printf (" DW_CFA_def_cfa: %s ofs %d\n", + regname (fc->cfa_reg, 0), fc->cfa_offset); break; case DW_CFA_def_cfa_register: fc->cfa_reg = LEB (); fc->cfa_exp = 0; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg); + printf (" DW_CFA_def_cfa_register: %s\n", + regname (fc->cfa_reg, 0)); break; case DW_CFA_def_cfa_offset: @@ -3540,7 +4510,8 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp) { printf (" DW_CFA_def_cfa_expression ("); - decode_location_expression (start, eh_addr_size, ul, 0); + decode_location_expression (start, eh_addr_size, ul, 0, + section); printf (")\n"); } fc->cfa_exp = 1; @@ -3550,49 +4521,69 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_expression: reg = LEB (); ul = LEB (); - if (! do_debug_frames_interp) + if (reg >= (unsigned int) fc->ncols) + reg_prefix = bad_reg; + if (! do_debug_frames_interp || *reg_prefix != '\0') { - printf (" DW_CFA_expression: r%ld (", reg); - decode_location_expression (start, eh_addr_size, ul, 0); + printf (" DW_CFA_expression: %s%s (", + reg_prefix, regname (reg, 0)); + decode_location_expression (start, eh_addr_size, + ul, 0, section); printf (")\n"); } - fc->col_type[reg] = DW_CFA_expression; + if (*reg_prefix == '\0') + fc->col_type[reg] = DW_CFA_expression; start += ul; break; case DW_CFA_val_expression: reg = LEB (); ul = LEB (); - if (! do_debug_frames_interp) + if (reg >= (unsigned int) fc->ncols) + reg_prefix = bad_reg; + if (! do_debug_frames_interp || *reg_prefix != '\0') { - printf (" DW_CFA_val_expression: r%ld (", reg); - decode_location_expression (start, eh_addr_size, ul, 0); + printf (" DW_CFA_val_expression: %s%s (", + reg_prefix, regname (reg, 0)); + decode_location_expression (start, eh_addr_size, ul, 0, + section); printf (")\n"); } - fc->col_type[reg] = DW_CFA_val_expression; + if (*reg_prefix == '\0') + fc->col_type[reg] = DW_CFA_val_expression; start += ul; break; case DW_CFA_offset_extended_sf: reg = LEB (); l = SLEB (); - frame_need_space (fc, reg); - if (! do_debug_frames_interp) - printf (" DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n", - reg, l * fc->data_factor); - fc->col_type[reg] = DW_CFA_offset; - fc->col_offset[reg] = l * fc->data_factor; + if (frame_need_space (fc, reg) < 0) + reg_prefix = bad_reg; + 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); + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_offset; + fc->col_offset[reg] = l * fc->data_factor; + } break; case DW_CFA_val_offset_sf: reg = LEB (); l = SLEB (); - frame_need_space (fc, reg); - if (! do_debug_frames_interp) - printf (" DW_CFA_val_offset_sf: r%ld at cfa%+ld\n", - reg, l * fc->data_factor); - fc->col_type[reg] = DW_CFA_val_offset; - fc->col_offset[reg] = l * fc->data_factor; + 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", + reg_prefix, regname (reg, 0), + l * fc->data_factor); + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_val_offset; + fc->col_offset[reg] = l * fc->data_factor; + } break; case DW_CFA_def_cfa_sf: @@ -3601,8 +4592,8 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_offset = fc->cfa_offset * fc->data_factor; fc->cfa_exp = 0; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_sf: r%d ofs %d\n", - fc->cfa_reg, fc->cfa_offset); + printf (" DW_CFA_def_cfa_sf: %s ofs %d\n", + regname (fc->cfa_reg, 0), fc->cfa_offset); break; case DW_CFA_def_cfa_offset_sf: @@ -3637,19 +4628,24 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_GNU_negative_offset_extended: reg = LEB (); l = - LEB (); - frame_need_space (fc, reg); - if (! do_debug_frames_interp) - printf (" DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n", - reg, l * fc->data_factor); - fc->col_type[reg] = DW_CFA_offset; - fc->col_offset[reg] = l * fc->data_factor; + if (frame_need_space (fc, reg) < 0) + reg_prefix = bad_reg; + 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); + if (*reg_prefix == '\0') + { + fc->col_type[reg] = DW_CFA_offset; + fc->col_offset[reg] = l * fc->data_factor; + } break; default: if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user) printf (_(" DW_CFA_??? (User defined call frame op: %#x)\n"), op); else - warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op); + warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op); start = block_end; } } @@ -3734,64 +4730,214 @@ warn (const char *message, ...) void free_debug_memory (void) { - enum dwarf_section_display_enum i; + unsigned int i; free_abbrevs (); for (i = 0; i < max; i++) - free_debug_section (i); + free_debug_section ((enum dwarf_section_display_enum) i); - if (debug_information) + if (debug_information != NULL) { - for (i = 0; i < num_debug_info_entries; i++) + if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE) { - if (!debug_information [i].max_loc_offsets) + for (i = 0; i < num_debug_info_entries; i++) { - free (debug_information [i].loc_offsets); - free (debug_information [i].have_frame_base); + if (!debug_information [i].max_loc_offsets) + { + free (debug_information [i].loc_offsets); + free (debug_information [i].have_frame_base); + } + if (!debug_information [i].max_range_lists) + free (debug_information [i].range_lists); } - if (!debug_information [i].max_range_lists) - free (debug_information [i].range_lists); } + free (debug_information); debug_information = NULL; num_debug_info_entries = 0; } +} +void +dwarf_select_sections_by_names (const char *names) +{ + typedef struct + { + const char * option; + int * variable; + int val; + } + debug_dump_long_opts; + + static const debug_dump_long_opts opts_table [] = + { + /* Please keep this table alpha- sorted. */ + { "Ranges", & do_debug_ranges, 1 }, + { "abbrev", & do_debug_abbrevs, 1 }, + { "aranges", & do_debug_aranges, 1 }, + { "frames", & do_debug_frames, 1 }, + { "frames-interp", & do_debug_frames_interp, 1 }, + { "info", & do_debug_info, 1 }, + { "line", & do_debug_lines, FLAG_DEBUG_LINES_RAW }, /* For backwards compatibility. */ + { "rawline", & do_debug_lines, FLAG_DEBUG_LINES_RAW }, + { "decodedline", & do_debug_lines, FLAG_DEBUG_LINES_DECODED }, + { "loc", & do_debug_loc, 1 }, + { "macro", & do_debug_macinfo, 1 }, + { "pubnames", & do_debug_pubnames, 1 }, + /* This entry is for compatability + with earlier versions of readelf. */ + { "ranges", & do_debug_aranges, 1 }, + { "str", & do_debug_str, 1 }, + { NULL, NULL, 0 } + }; + + const char *p; + + p = names; + while (*p) + { + const debug_dump_long_opts * entry; + + for (entry = opts_table; entry->option; entry++) + { + size_t len = strlen (entry->option); + + if (strncmp (p, entry->option, len) == 0 + && (p[len] == ',' || p[len] == '\0')) + { + * entry->variable |= entry->val; + + /* The --debug-dump=frames-interp option also + enables the --debug-dump=frames option. */ + if (do_debug_frames_interp) + do_debug_frames = 1; + + p += len; + break; + } + } + + if (entry->option == NULL) + { + warn (_("Unrecognized debug option '%s'\n"), p); + p = strchr (p, ','); + if (p == NULL) + break; + } + + if (*p == ',') + p++; + } +} + +void +dwarf_select_sections_by_letters (const char *letters) +{ + unsigned int index = 0; + + while (letters[index]) + switch (letters[index++]) + { + case 'i': + do_debug_info = 1; + break; + + case 'a': + do_debug_abbrevs = 1; + break; + + case 'l': + do_debug_lines |= FLAG_DEBUG_LINES_RAW; + break; + + case 'L': + do_debug_lines |= FLAG_DEBUG_LINES_DECODED; + break; + + case 'p': + do_debug_pubnames = 1; + break; + + case 'r': + do_debug_aranges = 1; + break; + + case 'R': + do_debug_ranges = 1; + break; + + case 'F': + do_debug_frames_interp = 1; + case 'f': + do_debug_frames = 1; + break; + + case 'm': + do_debug_macinfo = 1; + break; + + case 's': + do_debug_str = 1; + break; + + case 'o': + do_debug_loc = 1; + break; + + default: + warn (_("Unrecognized debug option '%s'\n"), optarg); + break; + } +} + +void +dwarf_select_sections_all (void) +{ + do_debug_info = 1; + do_debug_abbrevs = 1; + do_debug_lines = FLAG_DEBUG_LINES_RAW; + do_debug_pubnames = 1; + do_debug_aranges = 1; + do_debug_ranges = 1; + do_debug_frames = 1; + do_debug_macinfo = 1; + do_debug_str = 1; + do_debug_loc = 1; } struct dwarf_section_display debug_displays[] = { - { { ".debug_abbrev", NULL, 0, 0 }, - display_debug_abbrev, 0, 0 }, - { { ".debug_aranges", NULL, 0, 0 }, - display_debug_aranges, 0, 0 }, - { { ".debug_frame", NULL, 0, 0 }, - display_debug_frames, 1, 0 }, - { { ".debug_info", NULL, 0, 0 }, - display_debug_info, 1, 0 }, - { { ".debug_line", NULL, 0, 0 }, - display_debug_lines, 0, 0 }, - { { ".debug_pubnames", NULL, 0, 0 }, - display_debug_pubnames, 0, 0 }, - { { ".eh_frame", NULL, 0, 0 }, - display_debug_frames, 1, 1 }, - { { ".debug_macinfo", NULL, 0, 0 }, - display_debug_macinfo, 0, 0 }, - { { ".debug_str", NULL, 0, 0 }, - display_debug_str, 0, 0 }, - { { ".debug_loc", NULL, 0, 0 }, - display_debug_loc, 0, 0 }, - { { ".debug_pubtypes", NULL, 0, 0 }, - display_debug_pubnames, 0, 0 }, - { { ".debug_ranges", NULL, 0, 0 }, - display_debug_ranges, 0, 0 }, - { { ".debug_static_func", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 }, - { { ".debug_static_vars", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 }, - { { ".debug_types", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 }, - { { ".debug_weaknames", NULL, 0, 0 }, - display_debug_not_supported, 0, 0 } + { { ".debug_abbrev", ".zdebug_abbrev", NULL, NULL, 0, 0 }, + display_debug_abbrev, &do_debug_abbrevs, 0 }, + { { ".debug_aranges", ".zdebug_aranges", NULL, NULL, 0, 0 }, + display_debug_aranges, &do_debug_aranges, 1 }, + { { ".debug_frame", ".zdebug_frame", NULL, NULL, 0, 0 }, + display_debug_frames, &do_debug_frames, 1 }, + { { ".debug_info", ".zdebug_info", NULL, NULL, 0, 0 }, + display_debug_info, &do_debug_info, 1 }, + { { ".debug_line", ".zdebug_line", NULL, NULL, 0, 0 }, + display_debug_lines, &do_debug_lines, 1 }, + { { ".debug_pubnames", ".zdebug_pubnames", NULL, NULL, 0, 0 }, + display_debug_pubnames, &do_debug_pubnames, 0 }, + { { ".eh_frame", "", NULL, NULL, 0, 0 }, + display_debug_frames, &do_debug_frames, 1 }, + { { ".debug_macinfo", ".zdebug_macinfo", NULL, NULL, 0, 0 }, + display_debug_macinfo, &do_debug_macinfo, 0 }, + { { ".debug_str", ".zdebug_str", NULL, NULL, 0, 0 }, + display_debug_str, &do_debug_str, 0 }, + { { ".debug_loc", ".zdebug_loc", NULL, NULL, 0, 0 }, + display_debug_loc, &do_debug_loc, 1 }, + { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0 }, + display_debug_pubnames, &do_debug_pubnames, 0 }, + { { ".debug_ranges", ".zdebug_ranges", NULL, NULL, 0, 0 }, + display_debug_ranges, &do_debug_ranges, 1 }, + { { ".debug_static_func", ".zdebug_static_func", NULL, NULL, 0, 0 }, + display_debug_not_supported, NULL, 0 }, + { { ".debug_static_vars", ".zdebug_static_vars", NULL, NULL, 0, 0 }, + display_debug_not_supported, NULL, 0 }, + { { ".debug_types", ".zdebug_types", NULL, NULL, 0, 0 }, + display_debug_not_supported, NULL, 0 }, + { { ".debug_weaknames", ".zdebug_weaknames", NULL, NULL, 0, 0 }, + display_debug_not_supported, NULL, 0 } };