summaryrefslogtreecommitdiffstats
path: root/trunk/src/dwarf2.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/dwarf2.c')
-rw-r--r--trunk/src/dwarf2.c310
1 files changed, 188 insertions, 122 deletions
diff --git a/trunk/src/dwarf2.c b/trunk/src/dwarf2.c
index e831a18..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);
@@ -392,6 +395,7 @@ adjust_location_list (DSO *dso, unsigned char *ptr, size_t len,
uint32_t len = read_uleb128 (ptr);
ptr += len;
}
+ break;
default:
error (0, 0, "%s: Unknown DWARF DW_OP_%d", dso->filename, op);
return 1;
@@ -537,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;
@@ -586,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:
@@ -597,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:
@@ -639,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);
@@ -653,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
@@ -669,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;
}
@@ -706,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);
@@ -722,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)
@@ -731,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);
@@ -746,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;
@@ -855,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);
@@ -868,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)
@@ -958,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)
{
@@ -974,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)
@@ -1010,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;
}
}
}
@@ -1038,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. */