summaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog64
-rw-r--r--libdw/Makefile.am5
-rw-r--r--libdw/dwarf_abbrev_hash.c3
-rw-r--r--libdw/dwarf_begin_elf.c5
-rw-r--r--libdw/dwarf_cuoffset.c6
-rw-r--r--libdw/dwarf_diecu.c5
-rw-r--r--libdw/dwarf_end.c4
-rw-r--r--libdw/dwarf_formref_die.c63
-rw-r--r--libdw/dwarf_formstring.c4
-rw-r--r--libdw/dwarf_formudata.c8
-rw-r--r--libdw/dwarf_getaranges.c5
-rw-r--r--libdw/dwarf_getlocation.c4
-rw-r--r--libdw/dwarf_nextcu.c80
-rw-r--r--libdw/dwarf_siblingof.c8
-rw-r--r--libdw/dwarf_sig8_hash.c62
-rw-r--r--libdw/dwarf_sig8_hash.h59
-rw-r--r--libdw/libdw.h12
-rw-r--r--libdw/libdw.map2
-rw-r--r--libdw/libdwP.h43
-rw-r--r--libdw/libdw_findcu.c89
20 files changed, 429 insertions, 102 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 277966ba..42a59d11 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,67 @@
+2010-06-16 Roland McGrath <roland@redhat.com>
+
+ * dwarf_formref_die.c: Use dwarf_offdie only for DW_FORM_ref_addr, so
+ we don't repeat a CU lookup we've already done. Handle
+ DW_FORM_ref_sig8 using sig8_hash table and __libdw_intern_next_unit.
+
+ * libdw_findcu.c (__libdw_intern_next_unit): New function,
+ broken out of ...
+ (__libdw_findcu): ... here. Call it.
+ * libdwP.h: Declare it.
+ (struct Dwarf): New member next_tu_offset.
+
+ * dwarf_sig8_hash.c: New file.
+ * dwarf_sig8_hash.h: New file.
+ * Makefile.am (libdw_a_SOURCES, noinst_HEADERS): Add them.
+ * dwarf_abbrev_hash.c: Include dwarf_sig8_hash.h before
+ defining NO_UNDEF.
+ * libdwP.h (struct Dwarf): New member sig8_hash.
+ * dwarf_begin_elf.c: Call Dwarf_Sig8_Hash_init on it.
+ * dwarf_end.c: Call Dwarf_Sig8_Hash_free on it.
+
+ * dwarf_nextcu.c (dwarf_next_unit): New function, broken out of ...
+ (dwarf_nextcu): ... here. Call it.
+ * libdw.h: Declare it.
+ * libdwP.h: Add INTDECL.
+ * libdw_findcu.c (__libdw_findcu): Use it instead of dwarf_nextcu.
+ * libdw.map (ELFUTILS_0.148): New set, add dwarf_next_unit.
+
+ * libdwP.h (cu_sec_idx, cu_data): New functions.
+ Use .debug_types when CU is a TU.
+ * dwarf_cuoffset.c: Use that instead of assuming IDX_debug_info.
+ * dwarf_siblingof.c: Likewise.
+ * dwarf_formstring.c: Likewise.
+ * dwarf_formudata.c (__libdw_formptr, dwarf_formudata): Likewise.
+ * dwarf_getlocation.c (dwarf_getlocation): Likewise.
+ (dwarf_getlocation_addr): Likewise.
+
+ * libdwP.h (struct Dwarf_CU): Add new members type_offset, type_sig8.
+ (DIE_OFFSET_FROM_CU_OFFSET): Take flag argument; if true, compute
+ .debug_types header size instead of .debug_info header size.
+ (CUDIE): Use it.
+ * dwarf_diecu.c: Update caller.
+ * dwarf_getaranges.c: Likewise.
+ * dwarf_nextcu.c: Likewise.
+ * libdw_findcu.c (__libdw_findcu): Initialize new members.
+
+ * fde.c (fde_by_offset): Renamed to ...
+ (__libdw_fde_by_offset): ... this, made global and internal_function.
+ Don't take ADDRESS argument.
+ (__libdw_find_fde): Update caller. Do address sanity check here.
+ * cfi.h: Declare __libdw_fde_by_offset.
+ * cfi.c (dwarf_cfi_validate_fde): New function.
+ * libdw.h: Declare it.
+ * libdw.map (ELFUTILS_0.148): Add it.
+
+ * cie.c (intern_new_cie): Canonicalize DW_EH_PE_absptr FDE encoding to
+ either DW_EH_PE_udata8 or DW_EH_PE_udata4.
+
+ * encoded-value.h (read_encoded_value): Handle DW_EH_PE_indirect.
+ Don't assume DW_EH_PE_aligned refers to native address size.
+
+ * cfi.c (execute_cfi): Barf on CIE initial instructions changing the
+ address.
+
2010-06-17 Roland McGrath <roland@redhat.com>
* libdwP.h (struct Dwarf_Line_s): Add members isa, discriminator, and
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 0604ac28..530cbf4b 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -44,7 +44,8 @@ pkginclude_HEADERS = libdw.h
libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \
dwarf_error.c dwarf_nextcu.c dwarf_diename.c dwarf_offdie.c \
- dwarf_attr.c dwarf_formstring.c dwarf_abbrev_hash.c \
+ dwarf_attr.c dwarf_formstring.c \
+ dwarf_abbrev_hash.c dwarf_sig8_hash.c \
dwarf_attr_integrate.c dwarf_hasattr_integrate.c \
dwarf_child.c dwarf_haschildren.c dwarf_formaddr.c \
dwarf_formudata.c dwarf_formsdata.c dwarf_lowpc.c \
@@ -127,7 +128,7 @@ endif
libdw_a_LIBADD = $(addprefix ../libdwfl/,$(shell $(AR) t ../libdwfl/libdwfl.a))
noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \
- cfi.h encoded-value.h
+ dwarf_sig8_hash.h cfi.h encoded-value.h
EXTRA_DIST = libdw.map
diff --git a/libdw/dwarf_abbrev_hash.c b/libdw/dwarf_abbrev_hash.c
index 5c5d6cb1..bec1ceb2 100644
--- a/libdw/dwarf_abbrev_hash.c
+++ b/libdw/dwarf_abbrev_hash.c
@@ -1,5 +1,5 @@
/* Implementation of hash table for DWARF .debug_abbrev section content.
- Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
+ Copyright (C) 2000-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
@@ -52,6 +52,7 @@
# include <config.h>
#endif
+#include "dwarf_sig8_hash.h"
#define NO_UNDEF
#include "libdwP.h"
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index c3a49654..b5fb7c91 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -246,8 +246,10 @@ dwarf_begin_elf (elf, cmd, scngrp)
/* Allocate the data structure. */
Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size);
- if (result == NULL)
+ if (unlikely (result == NULL)
+ || unlikely (Dwarf_Sig8_Hash_init (&result->sig8_hash, 11) < 0))
{
+ free (result);
__libdw_seterrno (DWARF_E_NOMEM);
return NULL;
}
@@ -268,7 +270,6 @@ dwarf_begin_elf (elf, cmd, scngrp)
result->mem_tail->remaining = result->mem_tail->size;
result->mem_tail->prev = NULL;
-
if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR)
{
/* If the caller provides a section group we get the DWARF
diff --git a/libdw/dwarf_cuoffset.c b/libdw/dwarf_cuoffset.c
index 10238b43..47653200 100644
--- a/libdw/dwarf_cuoffset.c
+++ b/libdw/dwarf_cuoffset.c
@@ -1,5 +1,5 @@
/* Return offset of DIE in CU.
- Copyright (C) 2003 Red Hat, Inc.
+ Copyright (C) 2003-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -62,7 +62,5 @@ dwarf_cuoffset (die)
{
return (die == NULL
? (Dwarf_Off) -1l
- : (die->addr
- - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
- - die->cu->start));
+ : (die->addr - cu_data (die->cu)->d_buf - die->cu->start));
}
diff --git a/libdw/dwarf_diecu.c b/libdw/dwarf_diecu.c
index a62b8222..e3e52521 100644
--- a/libdw/dwarf_diecu.c
+++ b/libdw/dwarf_diecu.c
@@ -1,5 +1,5 @@
/* Return CU DIE containing given DIE.
- Copyright (C) 2005, 2008 Red Hat, Inc.
+ Copyright (C) 2005-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -71,7 +71,8 @@ dwarf_diecu (die, result, address_sizep, offset_sizep)
result->addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+ DIE_OFFSET_FROM_CU_OFFSET (die->cu->start,
- die->cu->offset_size));
+ die->cu->offset_size,
+ die->cu->type_offset != 0));
result->cu = die->cu;
if (address_sizep != NULL)
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index fda37fc1..80dac7b7 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -1,5 +1,5 @@
/* Release debugging handling context.
- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009 Red Hat, Inc.
+ Copyright (C) 2002-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -86,6 +86,8 @@ dwarf_end (dwarf)
/* Clean up the CFI cache. */
__libdw_destroy_frame_cache (dwarf->cfi);
+ Dwarf_Sig8_Hash_free (&dwarf->sig8_hash);
+
/* The search tree for the CUs. NB: the CU data itself is
allocated separately, but the abbreviation hash tables need
to be handled. */
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 3ab2cb38..a684317c 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -51,56 +51,81 @@
# include <config.h>
#endif
+#include <string.h>
#include "libdwP.h"
#include <dwarf.h>
Dwarf_Die *
-dwarf_formref_die (attr, die_mem)
+dwarf_formref_die (attr, result)
Dwarf_Attribute *attr;
- Dwarf_Die *die_mem;
+ Dwarf_Die *result;
{
if (attr == NULL)
return NULL;
+ struct Dwarf_CU *cu = attr->cu;
+
Dwarf_Off offset;
if (attr->form == DW_FORM_ref_addr)
{
/* This has an absolute offset. */
- uint8_t ref_size = (attr->cu->version == 2
- ? attr->cu->address_size
- : attr->cu->offset_size);
+ uint8_t ref_size = (cu->version == 2
+ ? cu->address_size
+ : cu->offset_size);
- if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
+ if (__libdw_read_offset (cu->dbg, IDX_debug_info, attr->valp,
ref_size, &offset, IDX_debug_info, 0))
return NULL;
+
+ return INTUSE(dwarf_offdie) (cu->dbg, offset, result);
}
- else if (attr->form == DW_FORM_ref_sig8)
+
+ Elf_Data *data;
+ if (attr->form == DW_FORM_ref_sig8)
{
/* This doesn't have an offset, but instead a value we
have to match in the .debug_types type unit headers. */
- uint64_t sig = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
+ uint64_t sig = read_8ubyte_unaligned (cu->dbg, attr->valp);
+ cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig, NULL);
+ if (cu == NULL)
+ /* Not seen before. We have to scan through the type units. */
+ do
+ {
+ cu = __libdw_intern_next_unit (attr->cu->dbg, true);
+ if (cu == NULL)
+ {
+ __libdw_seterrno (INTUSE(dwarf_errno) ()
+ ?: DWARF_E_INVALID_REFERENCE);
+ return NULL;
+ }
+ Dwarf_Sig8_Hash_insert (&cu->dbg->sig8_hash, sig, cu);
+ }
+ while (cu->type_sig8 != sig);
- /* XXX We don't actually support this yet. We need to parse
- .debug_types and keep a table keyed on signature. */
-#if 0
- return INTUSE(dwarf_typeunit) (attr->cu->dbg, sig, die_mem);
-#else
- sig = sig;
- __libdw_seterrno (DWARF_E_INVALID_REFERENCE);
-#endif
- return NULL;
+ data = cu->dbg->sectiondata[IDX_debug_types];
+ offset = cu->type_offset;
}
else
{
/* Other forms produce an offset from the CU. */
if (unlikely (__libdw_formref (attr, &offset) != 0))
return NULL;
- offset += attr->cu->start;
+
+ data = cu->dbg->sectiondata[IDX_debug_info];
+ }
+
+ if (unlikely (data->d_size - cu->start <= offset))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
}
- return INTUSE(dwarf_offdie) (attr->cu->dbg, offset, die_mem);
+ memset (result, '\0', sizeof (Dwarf_Die));
+ result->addr = (char *) data->d_buf + cu->start + offset;
+ result->cu = cu;
+ return result;
}
INTDEF (dwarf_formref_die)
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index f95d31b8..1dee9b2d 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -1,5 +1,5 @@
/* Return string associated with given attribute.
- Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
+ Copyright (C) 2003-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -79,7 +79,7 @@ dwarf_formstring (attrp)
}
uint64_t off;
- if (__libdw_read_offset (dbg, IDX_debug_info, attrp->valp,
+ if (__libdw_read_offset (dbg, cu_sec_idx (attrp->cu), attrp->valp,
attrp->cu->offset_size, &off, IDX_debug_str, 1))
return NULL;
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index 63c9bcd7..573a5783 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -73,7 +73,7 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
Dwarf_Word offset;
if (attr->form == DW_FORM_sec_offset)
{
- if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
+ if (__libdw_read_offset (attr->cu->dbg, cu_sec_idx (attr->cu), attr->valp,
attr->cu->offset_size, &offset, sec_index, 0))
return NULL;
}
@@ -84,7 +84,8 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
{
case DW_FORM_data4:
case DW_FORM_data8:
- if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
+ if (__libdw_read_offset (attr->cu->dbg, cu_sec_idx (attr->cu),
+ attr->valp,
attr->form == DW_FORM_data4 ? 4 : 8,
&offset, sec_index, 0))
return NULL;
@@ -133,7 +134,8 @@ dwarf_formudata (attr, return_uval)
case DW_FORM_data4:
case DW_FORM_data8:
- if (__libdw_read_address (attr->cu->dbg, IDX_debug_info, attr->valp,
+ if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
+ attr->valp,
attr->form == DW_FORM_data4 ? 4 : 8,
return_uval))
return -1;
diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c
index 72334f5f..cced9bf8 100644
--- a/libdw/dwarf_getaranges.c
+++ b/libdw/dwarf_getaranges.c
@@ -1,5 +1,5 @@
/* Return list address ranges.
- Copyright (C) 2000-2009 Red Hat, Inc.
+ Copyright (C) 2000-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
@@ -199,7 +199,8 @@ dwarf_getaranges (dbg, aranges, naranges)
else
offset_size = 4;
new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
- offset_size);
+ offset_size,
+ false);
/* Sanity-check the data. */
if (new_arange->arange.offset
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index c89488b3..56091cd9 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -553,7 +553,7 @@ dwarf_getlocation (attr, llbuf, listlen)
if (INTUSE(dwarf_formblock) (attr, &block) != 0)
return -1;
- return getlocation (attr->cu, &block, llbuf, listlen, IDX_debug_info);
+ return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
}
int
@@ -578,7 +578,7 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
return 0;
if (llbufs != NULL &&
getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
- IDX_debug_info) != 0)
+ cu_sec_idx (attr->cu)) != 0)
return -1;
return listlens[0] == 0 ? 0 : 1;
}
diff --git a/libdw/dwarf_nextcu.c b/libdw/dwarf_nextcu.c
index e436e115..288ee95e 100644
--- a/libdw/dwarf_nextcu.c
+++ b/libdw/dwarf_nextcu.c
@@ -1,5 +1,5 @@
/* Advance to next CU header.
- Copyright (C) 2002-2009 Red Hat, Inc.
+ Copyright (C) 2002-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -57,26 +57,33 @@
int
-dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
- address_sizep, offset_sizep)
+dwarf_next_unit (dwarf, off, next_off, header_sizep, versionp, abbrev_offsetp,
+ address_sizep, offset_sizep, type_signaturep, type_offsetp)
Dwarf *dwarf;
Dwarf_Off off;
Dwarf_Off *next_off;
size_t *header_sizep;
+ uint16_t *versionp;
Dwarf_Off *abbrev_offsetp;
uint8_t *address_sizep;
uint8_t *offset_sizep;
+ uint64_t *type_signaturep;
+ Dwarf_Off *type_offsetp;
{
+ const bool debug_types = type_signaturep != NULL;
+ const size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
+
/* Maybe there has been an error before. */
if (dwarf == NULL)
return -1;
/* If we reached the end before don't do anything. */
if (off == (Dwarf_Off) -1l
+ || unlikely (dwarf->sectiondata[sec_idx] == NULL)
/* Make sure there is enough space in the .debug_info section
for at least the initial word. We cannot test the rest since
we don't know yet whether this is a 64-bit object or not. */
- || unlikely (off + 4 >= dwarf->sectiondata[IDX_debug_info]->d_size))
+ || unlikely (off + 4 >= dwarf->sectiondata[sec_idx]->d_size))
{
*next_off = (Dwarf_Off) -1l;
return 1;
@@ -84,7 +91,7 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
/* This points into the .debug_info section to the beginning of the
CU entry. */
- const unsigned char *data = dwarf->sectiondata[IDX_debug_info]->d_buf;
+ const unsigned char *data = dwarf->sectiondata[sec_idx]->d_buf;
const unsigned char *bytes = data + off;
/* The format of the CU header is described in dwarf2p1 7.5.1:
@@ -122,13 +129,14 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
&& length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
{
+ invalid:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1;
}
/* Now we know how large the header is. */
- if (unlikely (DIE_OFFSET_FROM_CU_OFFSET (off, offset_size)
- >= dwarf->sectiondata[IDX_debug_info]->d_size))
+ if (unlikely (DIE_OFFSET_FROM_CU_OFFSET (off, offset_size, debug_types)
+ >= dwarf->sectiondata[sec_idx]->d_size))
{
*next_off = -1;
return 1;
@@ -138,22 +146,47 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
/* This is a 64-bit DWARF format. */
length = read_8ubyte_unaligned_inc (dwarf, bytes);
- /* Read the version stamp. Always a 16-bit value.
- XXX Do we need the value? */
- read_2ubyte_unaligned_inc (dwarf, bytes);
+ /* Read the version stamp. Always a 16-bit value. */
+ uint_fast16_t version = read_2ubyte_unaligned_inc (dwarf, bytes);
/* Get offset in .debug_abbrev. Note that the size of the entry
depends on whether this is a 32-bit or 64-bit DWARF definition. */
uint64_t abbrev_offset;
- if (__libdw_read_offset_inc (dwarf, IDX_debug_info, &bytes, offset_size,
+ if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
&abbrev_offset, IDX_debug_abbrev, 0))
return -1;
+ /* The address size. Always an 8-bit value. */
+ uint8_t address_size = *bytes++;
+
+ if (debug_types)
+ {
+ uint64_t type_sig8 = read_8ubyte_unaligned_inc (dwarf, bytes);
+
+ Dwarf_Off type_offset;
+ if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
+ &type_offset, sec_idx, 0))
+ return -1;
+
+ /* Validate that the TYPE_OFFSET points past the header. */
+ if (unlikely (type_offset < (size_t) (bytes - (data + off))))
+ goto invalid;
+
+ *type_signaturep = type_sig8;
+ if (type_offsetp != NULL)
+ *type_offsetp = type_offset;
+ }
+
+ /* Store the header length. */
+ if (header_sizep != NULL)
+ *header_sizep = bytes - (data + off);
+
+ if (versionp != NULL)
+ *versionp = version;
+
if (abbrev_offsetp != NULL)
*abbrev_offsetp = abbrev_offset;
- /* The address size. Always an 8-bit value. */
- uint8_t address_size = *bytes++;
if (address_sizep != NULL)
*address_sizep = address_size;
@@ -161,14 +194,27 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
if (offset_sizep != NULL)
*offset_sizep = offset_size;
- /* Store the header length. */
- if (header_sizep != NULL)
- *header_sizep = bytes - (data + off);
-
/* See definition of DIE_OFFSET_FROM_CU_OFFSET macro
for an explanation of the trick in this expression. */
*next_off = off + 2 * offset_size - 4 + length;
return 0;
}
+INTDEF(dwarf_next_unit)
+
+int
+dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
+ address_sizep, offset_sizep)
+ Dwarf *dwarf;
+ Dwarf_Off off;
+ Dwarf_Off *next_off;
+ size_t *header_sizep;
+ Dwarf_Off *abbrev_offsetp;
+ uint8_t *address_sizep;
+ uint8_t *offset_sizep;
+{
+ return INTUSE(dwarf_next_unit) (dwarf, off, next_off, header_sizep, NULL,
+ abbrev_offsetp, address_sizep, offset_sizep,
+ NULL, NULL);
+}
INTDEF(dwarf_nextcu)
diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c
index 0d427175..f8e54c18 100644
--- a/libdw/dwarf_siblingof.c
+++ b/libdw/dwarf_siblingof.c
@@ -1,5 +1,5 @@
/* Return sibling of given DIE.
- Copyright (C) 2003, 2004, 2005, 2007, 2008 Red Hat, Inc.
+ Copyright (C) 2003-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -84,8 +84,7 @@ dwarf_siblingof (die, result)
unsigned char *addr = this_die.addr;
/* End of the buffer. */
unsigned char *endp
- = ((unsigned char *) sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf
- + sibattr.cu->end);
+ = ((unsigned char *) cu_data (sibattr.cu)->d_buf + sibattr.cu->end);
/* Search for the beginning of the next die on this level. We
must not return the dies for children of the given die. */
@@ -103,8 +102,7 @@ dwarf_siblingof (die, result)
return -1;
/* Compute the next address. */
- addr = ((unsigned char *)
- sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf
+ addr = ((unsigned char *) cu_data (sibattr.cu)->d_buf
+ sibattr.cu->start + offset);
}
else if (unlikely (addr == NULL)
diff --git a/libdw/dwarf_sig8_hash.c b/libdw/dwarf_sig8_hash.c
new file mode 100644
index 00000000..53c07eac
--- /dev/null
+++ b/libdw/dwarf_sig8_hash.c
@@ -0,0 +1,62 @@
+/* Implementation of hash table for DWARF .debug_types section content.
+ Copyright (C) 2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define NO_UNDEF
+#include "dwarf_sig8_hash.h"
+#undef NO_UNDEF
+
+/* This is defined in dwarf_abbrev_hash.c, we can just use it here. */
+#define next_prime __libdwarf_next_prime
+extern size_t next_prime (size_t) attribute_hidden;
+
+#include <dynamicsizehash.c>
diff --git a/libdw/dwarf_sig8_hash.h b/libdw/dwarf_sig8_hash.h
new file mode 100644
index 00000000..0d8932b5
--- /dev/null
+++ b/libdw/dwarf_sig8_hash.h
@@ -0,0 +1,59 @@
+/* Hash table for DWARF .debug_types section content.
+ Copyright (C) 2010 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifndef _DWARF_SIG8_HASH_H
+#define _DWARF_SIG8_HASH_H 1
+
+#define NAME Dwarf_Sig8_Hash
+#define TYPE struct Dwarf_CU *
+#define COMPARE(a, b) (0)
+
+#include <dynamicsizehash.h>
+
+#endif /* dwarf_sig8_hash.h */
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 766aa7ba..d244d919 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -288,12 +288,22 @@ extern int dwarf_end (Dwarf *dwarf);
/* Get the data block for the .debug_info section. */
extern Elf_Data *dwarf_getscn_info (Dwarf *dwarf);
-/* Read the header for the DWARF CU header. */
+/* Read the header for the DWARF CU. */
extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
size_t *header_sizep, Dwarf_Off *abbrev_offsetp,
uint8_t *address_sizep, uint8_t *offset_sizep)
__nonnull_attribute__ (3);
+/* Read the header of a DWARF CU or type unit. If TYPE_SIGNATUREP is not
+ null, this reads a type unit from the .debug_types section; otherwise
+ this reads a CU from the .debug_info section. */
+extern int dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
+ size_t *header_sizep, uint16_t *versionp,
+ Dwarf_Off *abbrev_offsetp,
+ uint8_t *address_sizep, uint8_t *offset_sizep,
+ uint64_t *type_signaturep, Dwarf_Off *type_offsetp)
+ __nonnull_attribute__ (3);
+
/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
The E_IDENT from the originating ELF file indicates the address
diff --git a/libdw/libdw.map b/libdw/libdw.map
index d1f48661..9cf8cd38 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -245,4 +245,6 @@ ELFUTILS_0.148 {
dwarf_lineisa;
dwarf_linediscriminator;
dwarf_lineop_index;
+
+ dwarf_next_unit;
} ELFUTILS_0.146;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index ee4d368b..14b17498 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -139,6 +139,8 @@ enum
};
+#include "dwarf_sig8_hash.h"
+
/* This is the structure representing the debugging state. */
struct Dwarf
{
@@ -169,6 +171,10 @@ struct Dwarf
void *cu_tree;
Dwarf_Off next_cu_offset;
+ /* Hash table for .debug_types type units. */
+ Dwarf_Sig8_Hash sig8_hash;
+ Dwarf_Off next_tu_offset;
+
/* Address ranges. */
Dwarf_Aranges *aranges;
@@ -279,6 +285,10 @@ struct Dwarf_CU
uint8_t offset_size;
uint16_t version;
+ /* Zero if this is a normal CU. Nonzero if it is a type unit. */
+ size_t type_offset;
+ uint64_t type_sig8;
+
/* Hash table for the abbreviations. */
Dwarf_Abbrev_Hash abbrev_hash;
/* Offset of the first abbreviation. */
@@ -301,21 +311,27 @@ struct Dwarf_CU
LEN VER OFFSET ADDR
4-bytes + 2-bytes + 4-bytes + 1-byte for 32-bit dwarf
12-bytes + 2-bytes + 8-bytes + 1-byte for 64-bit dwarf
+ or in .debug_types, SIGNATURE TYPE-OFFSET
+ 4-bytes + 2-bytes + 4-bytes + 1-byte + 8-bytes + 4-bytes for 32-bit
+ 12-bytes + 2-bytes + 8-bytes + 1-byte + 8-bytes + 8-bytes for 64-bit
Note the trick in the computation. If the offset_size is 4
the '- 4' term changes the '3 *' into a '2 *'. If the
offset_size is 8 it accounts for the 4-byte escape value
used at the start of the length. */
-#define DIE_OFFSET_FROM_CU_OFFSET(cu_offset, offset_size) \
- ((cu_offset) + 3 * (offset_size) - 4 + 3)
+#define DIE_OFFSET_FROM_CU_OFFSET(cu_offset, offset_size, type_unit) \
+ ((type_unit) ? ((cu_offset) + 4 * (offset_size) - 4 + 3 + 8) \
+ : ((cu_offset) + 3 * (offset_size) - 4 + 3))
-#define CUDIE(fromcu) \
+#define CUDIE(fromcu) \
((Dwarf_Die) \
{ \
.cu = (fromcu), \
.addr = ((char *) (fromcu)->dbg->sectiondata[IDX_debug_info]->d_buf \
- + (fromcu)->start + 3 * (fromcu)->offset_size - 4 + 3), \
- })
+ + DIE_OFFSET_FROM_CU_OFFSET ((fromcu)->start, \
+ (fromcu)->offset_size, \
+ (fromcu)->type_offset != 0)) \
+ }) \
/* Macro information. */
@@ -368,6 +384,10 @@ extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
/* Default OOM handler. */
extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden")));
+/* Allocate the internal data for a unit not seen before. */
+extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
+ __nonnull_attribute__ (1) internal_function;
+
/* Find CU for given offset. */
extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset)
__nonnull_attribute__ (1) internal_function;
@@ -573,6 +593,18 @@ __libdw_read_offset (Dwarf *dbg,
return __libdw_offset_in_section (dbg, sec_ret, *ret, size);
}
+static inline size_t
+cu_sec_idx (struct Dwarf_CU *cu)
+{
+ return cu->type_offset == 0 ? IDX_debug_info : IDX_debug_types;
+}
+
+static inline Elf_Data *
+cu_data (struct Dwarf_CU *cu)
+{
+ return cu->dbg->sectiondata[cu_sec_idx (cu)];
+}
+
/* Read up begin/end pair and increment read pointer.
- If it's normal range record, set up *BEGINP and *ENDP and return 0.
- If it's base address selection record, set up *BASEP and return 1.
@@ -619,6 +651,7 @@ INTDECL (dwarf_haspc)
INTDECL (dwarf_highpc)
INTDECL (dwarf_lowpc)
INTDECL (dwarf_nextcu)
+INTDECL (dwarf_next_unit)
INTDECL (dwarf_offdie)
INTDECL (dwarf_ranges)
INTDECL (dwarf_siblingof)
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index cf79c639..7e0b3568 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -57,6 +57,58 @@
#include "libdwP.h"
+struct Dwarf_CU *
+internal_function
+__libdw_intern_next_unit (dbg, debug_types)
+ Dwarf *dbg;
+ bool debug_types;
+{
+ Dwarf_Off *const offsetp
+ = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
+
+ Dwarf_Off oldoff = *offsetp;
+ uint16_t version;
+ uint8_t address_size;
+ uint8_t offset_size;
+ Dwarf_Off abbrev_offset;
+ uint64_t type_sig8 = 0;
+ Dwarf_Off type_offset = 0;
+
+ if (INTUSE(dwarf_next_unit) (dbg, oldoff, offsetp, NULL,
+ &version, &abbrev_offset,
+ &address_size, &offset_size,
+ debug_types ? &type_sig8 : NULL,
+ debug_types ? &type_offset : NULL) != 0)
+ /* No more entries. */
+ return NULL;
+
+ /* We only know how to handle the DWARF version 2 through 4 formats. */
+ if (unlikely (version < 2) || unlikely (version > 4))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
+
+ /* Create an entry for this CU. */
+ struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
+
+ newp->dbg = dbg;
+ newp->start = oldoff;
+ newp->end = *offsetp;
+ newp->address_size = address_size;
+ newp->offset_size = offset_size;
+ newp->version = version;
+ newp->type_sig8 = type_sig8;
+ newp->type_offset = type_offset;
+ Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
+ newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
+ newp->lines = NULL;
+ newp->locs = NULL;
+
+ return newp;
+}
+
+
static int
findcu_cb (const void *arg1, const void *arg2)
{
@@ -83,7 +135,6 @@ findcu_cb (const void *arg1, const void *arg2)
return 0;
}
-
struct Dwarf_CU *
__libdw_findcu (dbg, start)
Dwarf *dbg;
@@ -97,7 +148,6 @@ __libdw_findcu (dbg, start)
if (start < dbg->next_cu_offset)
{
- invalid:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
}
@@ -106,43 +156,14 @@ __libdw_findcu (dbg, start)
while (1)
{
Dwarf_Off oldoff = dbg->next_cu_offset;
- uint8_t address_size;
- uint8_t offset_size;
- Dwarf_Off abbrev_offset;
-
- if (INTUSE(dwarf_nextcu) (dbg, oldoff, &dbg->next_cu_offset, NULL,
- &abbrev_offset, &address_size, &offset_size)
- != 0)
- /* No more entries. */
+ struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, false);
+ if (newp == NULL)
return NULL;
- /* XXX We need the version number but dwarf_nextcu swallows it. */
- const char *bytes = (dbg->sectiondata[IDX_debug_info]->d_buf + oldoff
- + (2 * offset_size - 4));
- uint16_t version = read_2ubyte_unaligned (dbg, bytes);
-
- /* We only know how to handle the DWARF version 2 through 4 formats. */
- if (unlikely (version < 2) || unlikely (version > 4))
- goto invalid;
-
- /* Create an entry for this CU. */
- struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
-
- newp->dbg = dbg;
- newp->start = oldoff;
- newp->end = dbg->next_cu_offset;
- newp->address_size = address_size;
- newp->offset_size = offset_size;
- newp->version = version;
- Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
- newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
- newp->lines = NULL;
- newp->locs = NULL;
-
/* Add the new entry to the search tree. */
if (tsearch (newp, &dbg->cu_tree, findcu_cb) == NULL)
{
- /* Something went wrong. Unfo the operation. */
+ /* Something went wrong. Undo the operation. */
dbg->next_cu_offset = oldoff;
__libdw_seterrno (DWARF_E_NOMEM);
return NULL;