diff options
-rw-r--r-- | trunk/ChangeLog | 31 | ||||
-rw-r--r-- | trunk/src/dwarf2.c | 309 | ||||
-rw-r--r-- | trunk/src/dwarf2.h | 37 |
3 files changed, 254 insertions, 123 deletions
diff --git a/trunk/ChangeLog b/trunk/ChangeLog index cc0ef4d..bcb27ad 100644 --- a/trunk/ChangeLog +++ b/trunk/ChangeLog @@ -1,5 +1,36 @@ 2010-04-13 Jakub Jelinek <jakub@redhat.com> + * src/dwarf2.c (DEBUG_TYPES): Define. + (debug_sections): Add .debug_types entry. + (read_abbrev): Handle new DWARF4 forms. + (adjust_attributes): DW_AT_segment can be a loclistptr. + DW_AT_byte_size, DW_AT_bit_offset, DW_AT_bit_size, + DW_AT_string_length, DW_AT_lower_bound, DW_AT_return_addr, + DW_AT_bit_stride, DW_AT_upper_bound, DW_AT_count, + DW_AT_segment, DW_AT_static_link, DW_AT_use_location, + DW_AT_allocated, DW_AT_associated, DW_AT_data_location + and DW_AT_byte_stride can be exprloc. Handle new DWARF4 forms. + (adjust_dwarf2_line): Handle adjusting DWARF4 .debug_line + sections. + (adjust_dwarf2_frame): Handle adjusting DWARF4 .debug_frame + section. + (adjust_dwarf2_info): New function, moved from adjust_dwarf2. + Handle DWARF4 .debug_info and handle .debug_types too. + (adjust_dwarf2): Call it for .debug_info and .debug_types + sections. + * src/dwarf2.h (DW_TAG_type_unit, DW_TAG_rvalue_reference_type, + DW_TAG_template_alias, DW_FORM_sec_offset, DW_FORM_exprloc, + DW_FORM_flag_present, DW_FORM_ref_sig8, DW_AT_bit_stride, + DW_AT_byte_stride, DW_AT_description, DW_AT_binary_scale, + DW_AT_decimal_scale, DW_AT_small, DW_AT_decimal_sign, + DW_AT_digit_count, DW_AT_picture_string, DW_AT_mutable, + DW_AT_threads_scaled, DW_AT_explicit, DW_AT_object_pointer, + DW_AT_endianity, DW_AT_elemental, DW_AT_pure, DW_AT_recursive, + DW_AT_signature, DW_AT_main_subprogram, DW_AT_data_bit_offset, + DW_AT_const_expr, DW_AT_enum_class, DW_AT_linkage_name, + DW_LNS_set_prologue_end, DW_LNS_set_epilogue_begin, + DW_LNS_set_isa, DW_LNE_set_discriminator, DW_LANG_Python): Define. + * src/prelink.h (send_file): New prototype. * src/execstack.c (send_file): New dummy function. * src/verify.c (send_file): No longer static. Don't loop forever diff --git a/trunk/src/dwarf2.c b/trunk/src/dwarf2.c index 1e7596c..802d9ad 100644 --- a/trunk/src/dwarf2.c +++ b/trunk/src/dwarf2.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Red Hat, Inc. +/* Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009, 2010 Red Hat, Inc. Written by Jakub Jelinek <jakub@redhat.com>, 2001. This program is free software; you can redistribute it and/or modify @@ -161,6 +161,7 @@ static struct #define DEBUG_STR 8 #define DEBUG_FRAME 9 #define DEBUG_RANGES 10 +#define DEBUG_TYPES 11 { ".debug_info", NULL, 0, 0 }, { ".debug_abbrev", NULL, 0, 0 }, { ".debug_line", NULL, 0, 0 }, @@ -172,6 +173,7 @@ static struct { ".debug_str", NULL, 0, 0 }, { ".debug_frame", NULL, 0, 0 }, { ".debug_ranges", NULL, 0, 0 }, + { ".debug_types", NULL, 0, 0 }, { NULL, NULL, 0 } }; @@ -271,7 +273,8 @@ no_memory: goto no_memory; } form = read_uleb128 (ptr); - if (form == 2 || form > DW_FORM_indirect) + if (form == 2 + || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8)) { error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form); htab_delete (h); @@ -538,11 +541,12 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, case DW_AT_return_addr: case DW_AT_data_member_location: case DW_AT_frame_base: + case DW_AT_segment: case DW_AT_static_link: case DW_AT_use_location: case DW_AT_vtable_elem_location: case DW_AT_ranges: - if (form == DW_FORM_data4) + if (form == DW_FORM_data4 || form == DW_FORM_sec_offset) addr = read_32 (ptr), ptr -= 4; else if (form == DW_FORM_data8) addr = read_64 (ptr), ptr -= 8; @@ -587,6 +591,8 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, if (addr >= start && addr_to_sec (dso, addr) != -1) write_ptr (ptr - ptr_size, addr + adjust); break; + case DW_FORM_flag_present: + break; case DW_FORM_ref1: case DW_FORM_flag: case DW_FORM_data1: @@ -598,10 +604,12 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, break; case DW_FORM_ref4: case DW_FORM_data4: + case DW_FORM_sec_offset: ptr += 4; break; case DW_FORM_ref8: case DW_FORM_data8: + case DW_FORM_ref_sig8: ptr += 8; break; case DW_FORM_sdata: @@ -640,6 +648,10 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, form = DW_FORM_block1; assert (len < UINT_MAX); break; + case DW_FORM_exprloc: + len = read_uleb128 (ptr); + assert (len < UINT_MAX); + break; default: error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form); @@ -654,11 +666,27 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, case DW_AT_location: case DW_AT_data_member_location: case DW_AT_vtable_elem_location: + case DW_AT_byte_size: + case DW_AT_bit_offset: + case DW_AT_bit_size: + case DW_AT_string_length: + case DW_AT_lower_bound: + case DW_AT_return_addr: + case DW_AT_bit_stride: + case DW_AT_upper_bound: + case DW_AT_count: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_byte_stride: if (adjust_location_list (dso, ptr, len, start, adjust)) return NULL; break; default: - if (t->attr[i].attr <= DW_AT_call_line + if (t->attr[i].attr <= DW_AT_linkage_name || (t->attr[i].attr >= DW_AT_MIPS_fde && t->attr[i].attr <= DW_AT_MIPS_has_inlines) || (t->attr[i].attr >= DW_AT_sf_names @@ -670,6 +698,12 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, } ptr += len; } + else if (form == DW_FORM_exprloc) + { + if (adjust_location_list (dso, ptr, len, start, adjust)) + return NULL; + ptr += len; + } break; } @@ -707,7 +741,7 @@ adjust_dwarf2_line (DSO *dso, GElf_Addr start, GElf_Addr adjust) } value = read_16 (ptr); - if (value != 2 && value != 3) + if (value != 2 && value != 3 && value != 4) { error (0, 0, "%s: DWARF version %d unhandled", dso->filename, value); @@ -723,8 +757,8 @@ adjust_dwarf2_line (DSO *dso, GElf_Addr start, GElf_Addr adjust) return 1; } - opcode_base = ptr[4]; - opcode_lengths = ptr + 4; + opcode_base = ptr[4 + (value >= 4)]; + opcode_lengths = ptr + 4 + (value >= 4); ptr = endprol; while (ptr < endcu) @@ -732,7 +766,7 @@ adjust_dwarf2_line (DSO *dso, GElf_Addr start, GElf_Addr adjust) op = *ptr++; if (op >= opcode_base) continue; - if (op == 0) + if (op == DW_LNS_extended_op) { unsigned int len = read_uleb128 (ptr); @@ -747,6 +781,7 @@ adjust_dwarf2_line (DSO *dso, GElf_Addr start, GElf_Addr adjust) break; case DW_LNE_end_sequence: case DW_LNE_define_file: + case DW_LNE_set_discriminator: default: ptr += len - 1; break; @@ -856,7 +891,7 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust) { /* CIE. */ uint32_t version = *ptr++; - if (version != 1 && version != 3) + if (version != 1 && version != 3 && version != 4) { error (0, 0, "%s: unhandled .debug_frame version %d", dso->filename, version); @@ -869,6 +904,22 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust) return 1; } ptr++; /* Skip augmentation. */ + if (version >= 4) + { + if (ptr[0] != ptr_size) + { + error (0, 0, "%s: .debug_frame unhandled pointer size %d", + dso->filename, ptr[0]); + return 1; + } + if (ptr[1] != 0) + { + error (0, 0, "%s: .debug_frame unhandled non-zero segment size", + dso->filename); + return 1; + } + ptr += 2; + } read_uleb128 (ptr); /* Skip code_alignment factor. */ read_uleb128 (ptr); /* Skip data_alignment factor. */ if (version >= 3) @@ -959,13 +1010,132 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust) return 0; } +static int +adjust_dwarf2_info (DSO *dso, GElf_Addr start, GElf_Addr adjust, int type) +{ + unsigned char *ptr, *endcu, *endsec; + uint32_t value; + htab_t abbrev; + struct abbrev_tag tag, *t; + struct cu_data cu; + + memset (&cu, 0, sizeof(cu)); + ptr = debug_sections[type].data; + endsec = ptr + debug_sections[type].size; + while (ptr < endsec) + { + if (ptr + 11 > endsec) + { + error (0, 0, "%s: .debug_info CU header too small", dso->filename); + return 1; + } + + endcu = ptr + 4; + endcu += read_32 (ptr); + if (endcu == ptr + 0xffffffff) + { + error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); + return 1; + } + + if (endcu > endsec) + { + error (0, 0, "%s: .debug_info too small", dso->filename); + return 1; + } + + value = read_16 (ptr); + if (value != 2 && value != 3 && value != 4) + { + error (0, 0, "%s: DWARF version %d unhandled", dso->filename, value); + return 1; + } + cu.cu_version = value; + + value = read_32 (ptr); + if (value >= debug_sections[DEBUG_ABBREV].size) + { + if (debug_sections[DEBUG_ABBREV].data == NULL) + error (0, 0, "%s: .debug_abbrev not present", dso->filename); + else + error (0, 0, "%s: DWARF CU abbrev offset too large", + dso->filename); + return 1; + } + + if (ptr_size == 0) + { + ptr_size = read_1 (ptr); + if (ptr_size == 4) + { + do_read_ptr = do_read_32_64; + write_ptr = write_32; + } + else if (ptr_size == 8) + { + do_read_ptr = do_read_64; + write_ptr = write_64; + } + else + { + error (0, 0, "%s: Invalid DWARF pointer size %d", + dso->filename, ptr_size); + return 1; + } + } + else if (read_1 (ptr) != ptr_size) + { + error (0, 0, "%s: DWARF pointer size differs between CUs", + dso->filename); + return 1; + } + + abbrev = read_abbrev (dso, debug_sections[DEBUG_ABBREV].data + value); + if (abbrev == NULL) + return 1; + + cu.cu_entry_pc = ~ (GElf_Addr) 0; + cu.cu_low_pc = ~ (GElf_Addr) 0; + + if (type == DEBUG_TYPES) + { + ptr += 8; /* Skip type_signature. */ + ptr += 4; /* Skip type_offset. */ + } + + while (ptr < endcu) + { + tag.entry = read_uleb128 (ptr); + if (tag.entry == 0) + continue; + t = htab_find_with_hash (abbrev, &tag, tag.entry); + if (t == NULL) + { + error (0, 0, "%s: Could not find DWARF abbreviation %d", + dso->filename, tag.entry); + htab_delete (abbrev); + return 1; + } + + ptr = adjust_attributes (dso, ptr, t, &cu, start, adjust); + if (ptr == NULL) + { + htab_delete (abbrev); + return 1; + } + } + + htab_delete (abbrev); + } + return 0; +} + int adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust) { Elf_Data *data; Elf_Scn *scn; int i, j; - struct cu_data cu; for (i = 0; debug_sections[i].name; ++i) { @@ -975,7 +1145,6 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust) } ptr_size = 0; - memset (&cu, 0, sizeof(cu)); for (i = 1; i < dso->ehdr.e_shnum; ++i) if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) && dso->shdr[i].sh_size) @@ -1011,6 +1180,7 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust) { error (0, 0, "%s: Unknown debugging section %s", dso->filename, name); + return 1; } } } @@ -1039,118 +1209,13 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust) return 1; } - if (debug_sections[DEBUG_INFO].data != NULL) - { - unsigned char *ptr, *endcu, *endsec; - uint32_t value; - htab_t abbrev; - struct abbrev_tag tag, *t; - - ptr = debug_sections[DEBUG_INFO].data; - endsec = ptr + debug_sections[DEBUG_INFO].size; - while (ptr < endsec) - { - if (ptr + 11 > endsec) - { - error (0, 0, "%s: .debug_info CU header too small", - dso->filename); - return 1; - } - - endcu = ptr + 4; - endcu += read_32 (ptr); - if (endcu == ptr + 0xffffffff) - { - error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); - return 1; - } - - if (endcu > endsec) - { - error (0, 0, "%s: .debug_info too small", dso->filename); - return 1; - } - - value = read_16 (ptr); - if (value != 2 && value != 3) - { - error (0, 0, "%s: DWARF version %d unhandled", dso->filename, - value); - return 1; - } - cu.cu_version = value; - - value = read_32 (ptr); - if (value >= debug_sections[DEBUG_ABBREV].size) - { - if (debug_sections[DEBUG_ABBREV].data == NULL) - error (0, 0, "%s: .debug_abbrev not present", dso->filename); - else - error (0, 0, "%s: DWARF CU abbrev offset too large", - dso->filename); - return 1; - } - - if (ptr_size == 0) - { - ptr_size = read_1 (ptr); - if (ptr_size == 4) - { - do_read_ptr = do_read_32_64; - write_ptr = write_32; - } - else if (ptr_size == 8) - { - do_read_ptr = do_read_64; - write_ptr = write_64; - } - else - { - error (0, 0, "%s: Invalid DWARF pointer size %d", - dso->filename, ptr_size); - return 1; - } - } - else if (read_1 (ptr) != ptr_size) - { - error (0, 0, "%s: DWARF pointer size differs between CUs", - dso->filename); - return 1; - } - - abbrev = read_abbrev (dso, - debug_sections[DEBUG_ABBREV].data + value); - if (abbrev == NULL) - return 1; - - cu.cu_entry_pc = ~ (GElf_Addr) 0; - cu.cu_low_pc = ~ (GElf_Addr) 0; - - while (ptr < endcu) - { - tag.entry = read_uleb128 (ptr); - if (tag.entry == 0) - continue; - t = htab_find_with_hash (abbrev, &tag, tag.entry); - if (t == NULL) - { - error (0, 0, "%s: Could not find DWARF abbreviation %d", - dso->filename, tag.entry); - htab_delete (abbrev); - return 1; - } - - ptr = adjust_attributes (dso, ptr, t, &cu, start, adjust); - if (ptr == NULL) - { - htab_delete (abbrev); - return 1; - } - } + if (debug_sections[DEBUG_INFO].data != NULL + && adjust_dwarf2_info (dso, start, adjust, DEBUG_INFO)) + return 1; - htab_delete (abbrev); - } - } + if (debug_sections[DEBUG_TYPES].data != NULL + && adjust_dwarf2_info (dso, start, adjust, DEBUG_TYPES)) + return 1; if (ptr_size == 0) /* Should not happen. */ diff --git a/trunk/src/dwarf2.h b/trunk/src/dwarf2.h index 143a00b..7870c28 100644 --- a/trunk/src/dwarf2.h +++ b/trunk/src/dwarf2.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2002, 2009 Red Hat, Inc. +/* Copyright (C) 2001, 2002, 2009, 2010 Red Hat, Inc. Written by Jakub Jelinek <jakub@redhat.com>, 2001. This program is free software; you can redistribute it and/or modify @@ -73,6 +73,9 @@ #define DW_TAG_imported_unit 0x3d #define DW_TAG_condition 0x3f #define DW_TAG_shared_type 0x40 +#define DW_TAG_type_unit 0x41 +#define DW_TAG_rvalue_reference_type 0x42 +#define DW_TAG_template_alias 0x43 #define DW_TAG_MIPS_loop 0x4081 #define DW_TAG_format_label 0x4101 #define DW_TAG_function_template 0x4102 @@ -106,6 +109,10 @@ #define DW_FORM_ref8 0x14 #define DW_FORM_ref_udata 0x15 #define DW_FORM_indirect 0x16 +#define DW_FORM_sec_offset 0x17 +#define DW_FORM_exprloc 0x18 +#define DW_FORM_flag_present 0x19 +#define DW_FORM_ref_sig8 0x20 #define DW_AT_sibling 0x01 #define DW_AT_location 0x02 @@ -139,6 +146,7 @@ #define DW_AT_return_addr 0x2a #define DW_AT_start_scope 0x2c #define DW_AT_stride_size 0x2e +#define DW_AT_bit_stride 0x2e #define DW_AT_upper_bound 0x2f #define DW_AT_abstract_origin 0x31 #define DW_AT_accessibility 0x32 @@ -173,6 +181,7 @@ #define DW_AT_associated 0x4f #define DW_AT_data_location 0x50 #define DW_AT_stride 0x51 +#define DW_AT_byte_stride 0x51 #define DW_AT_entry_pc 0x52 #define DW_AT_use_UTF8 0x53 #define DW_AT_extension 0x54 @@ -181,6 +190,27 @@ #define DW_AT_call_column 0x57 #define DW_AT_call_file 0x58 #define DW_AT_call_line 0x59 +#define DW_AT_description 0x5a +#define DW_AT_binary_scale 0x5b +#define DW_AT_decimal_scale 0x5c +#define DW_AT_small 0x5d +#define DW_AT_decimal_sign 0x5e +#define DW_AT_digit_count 0x5f +#define DW_AT_picture_string 0x60 +#define DW_AT_mutable 0x61 +#define DW_AT_threads_scaled 0x62 +#define DW_AT_explicit 0x63 +#define DW_AT_object_pointer 0x64 +#define DW_AT_endianity 0x65 +#define DW_AT_elemental 0x66 +#define DW_AT_pure 0x67 +#define DW_AT_recursive 0x68 +#define DW_AT_signature 0x69 +#define DW_AT_main_subprogram 0x6a +#define DW_AT_data_bit_offset 0x6b +#define DW_AT_const_expr 0x6c +#define DW_AT_enum_class 0x6d +#define DW_AT_linkage_name 0x6e #define DW_AT_MIPS_fde 0x2001 #define DW_AT_MIPS_loop_begin 0x2002 #define DW_AT_MIPS_tail_loop_begin 0x2003 @@ -424,10 +454,14 @@ #define DW_LNS_set_basic_block 0x7 #define DW_LNS_const_add_pc 0x8 #define DW_LNS_fixed_advance_pc 0x9 +#define DW_LNS_set_prologue_end 0xa +#define DW_LNS_set_epilogue_begin 0xb +#define DW_LNS_set_isa 0xc #define DW_LNE_end_sequence 0x1 #define DW_LNE_set_address 0x2 #define DW_LNE_define_file 0x3 +#define DW_LNE_set_discriminator 0x4 #define DW_CFA_advance_loc 0x40 #define DW_CFA_offset 0x80 @@ -491,6 +525,7 @@ #define DW_LANG_ObjC_plus_plus 0x0011 #define DW_LANG_UPC 0x0012 #define DW_LANG_D 0x0013 +#define DW_LANG_Python 0x0014 #define DW_LANG_Mips_Assembler 0x8001 #define DW_LANG_lo_user 0x8000 #define DW_LANG_hi_user 0xffff |