From: Roland McGrath Date: Mon, 21 Jun 2010 10:18:44 +0000 (-0700) Subject: Add libdw APIs for relocatable address values. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ebe0138980089cf698ecbfb63df3912fd581529e;p=thirdparty%2Felfutils.git Add libdw APIs for relocatable address values. --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index b6fe88502..986427795 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,5 +1,13 @@ 2010-06-21 Roland McGrath + * relocate.c (__libdw_relocatable): New function. + * libdwP.h: Declare it. + * dwarf_form_relocatable.c: New file. + * dwarf_lineaddr_relocatable.c: New file. + * Makefile.am (libdw_a_SOURCES): Add them. + * libdw.map (ELFUTILS_0.149): New set; add those. + * libdw.h: Declare them. + * libdwP.h (struct Dwarf_Line_s): Replace files with cu. (struct Dwarf_Lines_s): New member reloc. * dwarf_linesrc.c: Update usage. diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 6b0c0734b..067eec0d1 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -85,7 +85,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ dwarf_cfi_addrframe.c \ dwarf_getcfi.c dwarf_getcfi_elf.c dwarf_cfi_end.c \ dwarf_aggregate_size.c \ - relocate.c + relocate.c \ + dwarf_form_relocatable.c dwarf_lineaddr_relocatable.c if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h diff --git a/libdw/dwarf_form_relocatable.c b/libdw/dwarf_form_relocatable.c new file mode 100644 index 000000000..f01b1375a --- /dev/null +++ b/libdw/dwarf_form_relocatable.c @@ -0,0 +1,91 @@ +/* Return relocatable address from attribute. + 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" +#include + + +int +dwarf_form_relocatable (attr, sym, name, addend) + Dwarf_Attribute *attr; + GElf_Sym *sym; + const char **name; + GElf_Sxword *addend; +{ + if (attr == NULL) + return -1; + + int width; + switch (attr->form) + { + default: + return ((addend != NULL && INTUSE(dwarf_formsdata) (attr, addend)) ? -1 + : __libdw_relocatable (attr->cu->dbg, IDX_last, NULL, 0, + sym, name, addend, 0)); + + case DW_FORM_addr: + width = attr->cu->address_size; + break; + + case DW_FORM_data4: + width = 4; + break; + + case DW_FORM_data8: + width = 8; + break; + } + + return __libdw_relocatable (attr->cu->dbg, cu_sec_idx (attr->cu), + attr->valp, width, sym, name, addend, 0); +} diff --git a/libdw/dwarf_lineaddr_relocatable.c b/libdw/dwarf_lineaddr_relocatable.c new file mode 100644 index 000000000..2b4a7a67f --- /dev/null +++ b/libdw/dwarf_lineaddr_relocatable.c @@ -0,0 +1,73 @@ +/* Return relocatable line address. + Copyright (C) 2010 Red Hat, Inc. + Written by Ulrich Drepper , 2004. + + 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" + + +int +dwarf_lineaddr_relocatable (line, sym, name, addend) + Dwarf_Line *line; + GElf_Sym *sym; + const char **name; + GElf_Sxword *addend; +{ + if (line == NULL) + return -1; + + return __libdw_relocatable (line->cu->dbg, IDX_debug_line, + line->cu->lines->reloc == NULL ? NULL + : line->cu->lines->reloc[line + - line->cu->lines->info], + line->cu->address_size, sym, name, addend, + line->addr); +} diff --git a/libdw/libdw.h b/libdw/libdw.h index d3e7a5abe..0ba51972a 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -512,6 +512,31 @@ extern int dwarf_arrayorder (Dwarf_Die *die); extern int dwarf_srclang (Dwarf_Die *die); +/* Relocatable address access functions. + + These retrieve an address that might require relocation in an ET_REL + file. They return -1 for errors. If successful, they fill in SYM (if + not null) with the ELF symbol describing the address fetched. If NAME + is not null, it is filled with the symbol name, or with NULL if there is + no named symbol involved. If ADDEND is not null, it is filled with the + offset relative to that symbol. If the symbol refers to a normal + section, the return value is that section index (which might be above + SHN_LORESERVE). If the symbol does not refer to a normal section, + the return value is zero and SYM->st_shndx has a special SHN_* value. + An address that required no relocation appears as a SHN_ABS symbol + with st_value 0 and the whole address in the addend. */ + +/* Like dwarf_formaddr, but as described above. */ +extern int dwarf_form_relocatable (Dwarf_Attribute *attr, + GElf_Sym *sym, const char **name, + GElf_Sxword *addend); + +/* Like dwarf_lineaddr, but as described above. */ +extern int dwarf_lineaddr_relocatable (Dwarf_Line *line, + GElf_Sym *sym, const char **name, + GElf_Sxword *addend); + + /* Get abbreviation at given offset for given DIE. */ extern Dwarf_Abbrev *dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp); diff --git a/libdw/libdw.map b/libdw/libdw.map index 954fff67d..d3d51af3e 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -249,3 +249,9 @@ ELFUTILS_0.148 { dwarf_next_unit; dwarf_offdie_types; } ELFUTILS_0.146; + +ELFUTILS_0.149 { + global: + dwarf_form_relocatable; + dwarf_lineaddr_relocatable; +} ELFUTILS_0.148; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 6b22d6ee7..60ca016bf 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -619,6 +619,13 @@ __libdw_read_offset (Dwarf *dbg, ret, sec_ret, size); } +extern int __libdw_relocatable (Dwarf *dbg, int sec_idx, + const unsigned char *valp, unsigned int width, + GElf_Sym *sym, const char **name, + GElf_Sxword *addend, GElf_Sxword offset) + __nonnull_attribute__ (1) internal_function; + + static inline size_t cu_sec_idx (struct Dwarf_CU *cu) { diff --git a/libdw/relocate.c b/libdw/relocate.c index a7d57a483..27a05eff9 100644 --- a/libdw/relocate.c +++ b/libdw/relocate.c @@ -544,3 +544,56 @@ __libdw_relocate_offset (Dwarf *dbg, int sec_index, *val = addend; return result; } + +int +internal_function +__libdw_relocatable (Dwarf *dbg, int sec_idx, + const unsigned char *valp, unsigned int width, + GElf_Sym *sym, const char **name, GElf_Sxword *addend, + GElf_Sxword offset) +{ + struct dwarf_section_reloc *const r = dbg->relocate->sectionrel[sec_idx]; + int symndx; + int result = relocatable_datum (dbg, sec_idx, r, valp, width, + &symndx, addend); + if (result == 0) + { + if (sym != NULL) + *sym = (GElf_Sym) { .st_shndx = SHN_ABS }; + if (name != NULL) + *name = NULL; + if (addend != NULL) + *addend = offset + (width == 8 + ? read_8ubyte_unaligned (dbg, valp) + : read_4ubyte_unaligned (dbg, valp)); + } + else if (likely (result > 0)) + { + GElf_Sym sym_mem; + GElf_Word shndx; + if (sym == NULL) + sym = &sym_mem; + result = reloc_getsym (r, symndx, sym, &shndx); + if (likely (result > 0)) + { + if (name != NULL) + { + if (sym->st_name == 0) + *name = NULL; + else if (unlikely (sym->st_name >= r->symstrdata->d_size)) + { + __libdw_seterrno (DWARF_E_RELBADSYM); + return -1; + } + else + *name = (const char *) r->symstrdata->d_buf + sym->st_name; + } + if (addend != NULL) + *addend += offset; + result = (sym->st_shndx < SHN_LORESERVE ? sym->st_shndx + : sym->st_shndx == SHN_XINDEX ? shndx : SHN_UNDEF); + } + } + + return result; +}