diff options
Diffstat (limited to 'libdw')
-rw-r--r-- | libdw/ChangeLog | 64 | ||||
-rw-r--r-- | libdw/Makefile.am | 5 | ||||
-rw-r--r-- | libdw/dwarf_abbrev_hash.c | 3 | ||||
-rw-r--r-- | libdw/dwarf_begin_elf.c | 5 | ||||
-rw-r--r-- | libdw/dwarf_cuoffset.c | 6 | ||||
-rw-r--r-- | libdw/dwarf_diecu.c | 5 | ||||
-rw-r--r-- | libdw/dwarf_end.c | 4 | ||||
-rw-r--r-- | libdw/dwarf_formref_die.c | 63 | ||||
-rw-r--r-- | libdw/dwarf_formstring.c | 4 | ||||
-rw-r--r-- | libdw/dwarf_formudata.c | 8 | ||||
-rw-r--r-- | libdw/dwarf_getaranges.c | 5 | ||||
-rw-r--r-- | libdw/dwarf_getlocation.c | 4 | ||||
-rw-r--r-- | libdw/dwarf_nextcu.c | 80 | ||||
-rw-r--r-- | libdw/dwarf_siblingof.c | 8 | ||||
-rw-r--r-- | libdw/dwarf_sig8_hash.c | 62 | ||||
-rw-r--r-- | libdw/dwarf_sig8_hash.h | 59 | ||||
-rw-r--r-- | libdw/libdw.h | 12 | ||||
-rw-r--r-- | libdw/libdw.map | 2 | ||||
-rw-r--r-- | libdw/libdwP.h | 43 | ||||
-rw-r--r-- | libdw/libdw_findcu.c | 89 |
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; |