summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--trunk/ChangeLog31
-rw-r--r--trunk/src/dwarf2.c309
-rw-r--r--trunk/src/dwarf2.h37
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