-/* Internal definitions for libdwarf.
- Copyright (C) 2002-2009 Red Hat, Inc.
- This file is part of Red Hat elfutils.
- Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+/* Internal definitions for libdw.
+ Copyright (C) 2002-2011, 2013-2018 Red Hat, Inc.
+ This file is part of 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.
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
- Red Hat elfutils is distributed in the hope that it will be useful, but
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ 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>. */
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
#ifndef _LIBDWP_H
#define _LIBDWP_H 1
#include <stdbool.h>
#include <libdw.h>
+#include <dwarf.h>
/* gettext helper macros. */
#define _(Str) dgettext ("elfutils", Str)
-/* Version of the DWARF specification we support. */
-#define DWARF_VERSION 3
-
-/* Version of the CIE format. */
-#define CIE_VERSION 1
-
-
/* Known location expressions already decoded. */
struct loc_s
{
size_t nloc;
};
+/* Known DW_OP_implicit_value blocks already decoded.
+ This overlaps struct loc_s exactly, but only the
+ first member really has to match. */
+struct loc_block_s
+{
+ void *addr;
+ unsigned char *data;
+ size_t length;
+};
+
+/* Already decoded .debug_line units. */
+struct files_lines_s
+{
+ Dwarf_Off debug_line_offset;
+ Dwarf_Files *files;
+ Dwarf_Lines *lines;
+};
+
/* Valid indeces for the section data. */
enum
{
IDX_debug_info = 0,
+ IDX_debug_types,
IDX_debug_abbrev,
IDX_debug_aranges,
+ IDX_debug_addr,
IDX_debug_line,
+ IDX_debug_line_str,
IDX_debug_frame,
- IDX_eh_frame,
IDX_debug_loc,
IDX_debug_pubnames,
IDX_debug_str,
- IDX_debug_funcnames,
- IDX_debug_typenames,
- IDX_debug_varnames,
- IDX_debug_weaknames,
+ IDX_debug_str_offsets,
IDX_debug_macinfo,
+ IDX_debug_macro,
IDX_debug_ranges,
+ IDX_gnu_debugaltlink,
IDX_last
};
DWARF_E_IO_ERROR,
DWARF_E_INVALID_ELF,
DWARF_E_NO_DWARF,
+ DWARF_E_COMPRESSED_ERROR,
DWARF_E_NOELF,
DWARF_E_GETEHDR_ERROR,
DWARF_E_NOMEM,
DWARF_E_NO_ENTRY,
DWARF_E_INVALID_DWARF,
DWARF_E_NO_STRING,
+ DWARF_E_NO_DEBUG_STR,
+ DWARF_E_NO_DEBUG_LINE_STR,
+ DWARF_E_NO_STR_OFFSETS,
DWARF_E_NO_ADDR,
DWARF_E_NO_CONSTANT,
DWARF_E_NO_REFERENCE,
DWARF_E_NO_FLAG,
DWARF_E_INVALID_OFFSET,
DWARF_E_NO_DEBUG_RANGES,
+ DWARF_E_INVALID_CFI,
+ DWARF_E_NO_ALT_DEBUGLINK,
+ DWARF_E_INVALID_OPCODE,
+ DWARF_E_NOT_CUDIE,
+ DWARF_E_UNKNOWN_LANGUAGE,
+ DWARF_E_NO_DEBUG_ADDR,
};
+#include "dwarf_sig8_hash.h"
+
/* This is the structure representing the debugging state. */
struct Dwarf
{
/* The underlying ELF file. */
Elf *elf;
+ /* dwz alternate DWARF file. */
+ Dwarf *alt_dwarf;
+
/* The section data. */
Elf_Data *sectiondata[IDX_last];
/* If true, we allocated the ELF descriptor ourselves. */
bool free_elf;
+ /* If >= 0, we allocated the alt_dwarf ourselves and must end it and
+ close this file descriptor. */
+ int alt_fd;
+
/* Information for traversing the .debug_pubnames section. This is
an array and separately allocated with malloc. */
struct pubnames_s
void *cu_tree;
Dwarf_Off next_cu_offset;
+ /* Search tree and sig8 hash table for .debug_types type units. */
+ void *tu_tree;
+ Dwarf_Off next_tu_offset;
+ Dwarf_Sig8_Hash sig8_hash;
+
+ /* Search tree for .debug_macro operator tables. */
+ void *macro_ops;
+
+ /* Search tree for decoded .debug_line units. */
+ void *files_lines;
+
/* Address ranges. */
Dwarf_Aranges *aranges;
+ /* Cached info from the CFI section. */
+ struct Dwarf_CFI_s *cfi;
+
+ /* Fake loc CU. Used when synthesizing attributes for Dwarf_Ops that
+ came from a location list entry in dwarf_getlocation_attr. */
+ struct Dwarf_CU *fake_loc_cu;
+
/* Internal memory handling. This is basically a simplified
reimplementation of obstacks. Unfortunately the standard obstack
implementation is not usable in libraries. */
/* Abbreviation representation. */
struct Dwarf_Abbrev
{
- Dwarf_Off offset;
- unsigned char *attrp;
- unsigned int attrcnt;
- unsigned int code;
- unsigned int tag;
- bool has_children;
-};
+ Dwarf_Off offset; /* Offset to start of abbrev into .debug_abbrev. */
+ unsigned char *attrp; /* Pointer to start of attribute name/form pairs. */
+ bool has_children : 1; /* Whether or not the DIE has children. */
+ unsigned int code : 31; /* The (unique) abbrev code. */
+ unsigned int tag; /* The tag of the DIE. */
+} attribute_packed;
#include "dwarf_abbrev_hash.h"
/* Files in line information records. */
struct Dwarf_Files_s
{
- struct Dwarf_CU *cu;
unsigned int ndirs;
unsigned int nfiles;
struct Dwarf_Fileinfo_s
unsigned int end_sequence:1;
unsigned int prologue_end:1;
unsigned int epilogue_begin:1;
+ /* The remaining bit fields are not flags, but hold values presumed to be
+ small. All the flags and other bit fields should add up to 48 bits
+ to give the whole struct a nice round size. */
+ unsigned int op_index:8;
+ unsigned int isa:8;
+ unsigned int discriminator:24;
};
struct Dwarf_Lines_s
uint8_t offset_size;
uint16_t version;
+ size_t sec_idx; /* Normally .debug_info, could be .debug_type or "fake". */
+
+ /* The unit type if version >= 5. Otherwise 0 for normal CUs (from
+ .debug_info) or 1 for v4 type units (from .debug_types). */
+ uint8_t unit_type;
+
+ /* Zero if the unit type doesn't support a die/type offset and/or id/sig.
+ Nonzero if it is a v4 type unit or for DWARFv5 units depending on
+ unit_type. */
+ size_t subdie_offset;
+ uint64_t unit_id8;
+
/* Hash table for the abbreviations. */
Dwarf_Abbrev_Hash abbrev_hash;
/* Offset of the first abbreviation. */
/* Known location lists. */
void *locs;
+
+ /* Base address for use with ranges and locs.
+ Don't access directly, call __libdw_cu_base_address. */
+ Dwarf_Addr base_address;
+
+ /* The offset into the .debug_addr section where index zero begins.
+ Don't access directly, call __libdw_cu_addr_base. */
+ Dwarf_Off addr_base;
+
+ /* The offset into the .debug_str_offsets section where index zero begins.
+ Don't access directly, call __libdw_cu_str_off_base. */
+ Dwarf_Off str_off_base;
+
+ /* Memory boundaries of this CU. */
+ void *startp;
+ void *endp;
};
-/* Compute the offset of a CU's first DIE from its offset. This
- is either:
+#define ISV4TU(cu) ((cu)->version == 4 && (cu)->sec_idx == IDX_debug_types)
+
+/* Compute the offset of a CU's first DIE from the CU offset.
+ CU must be a valid/known version/unit_type. */
+static inline Dwarf_Off
+__libdw_first_die_from_cu_start (Dwarf_Off cu_start,
+ uint8_t offset_size,
+ uint16_t version,
+ uint8_t unit_type)
+{
+/*
+ assert (offset_size == 4 || offset_size == 8);
+ assert (version >= 2 && version <= 5);
+ assert (version >= 5 || (unit_type == DW_UT_compile
+ || unit_type == DW_UT_partial
+ || unit_type == DW_UT_type));
+ assert (version != 5 || (unit_type == DW_UT_compile
+ || unit_type == DW_UT_partial
+ || unit_type == DW_UT_skeleton
+ || unit_type == DW_UT_split_compile
+ || unit_type == DW_UT_type
+ || unit_type == DW_UT_split_type));
+*/
+
+ Dwarf_Off off = cu_start;
+ if (version < 5)
+ {
+ /*
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
+ the '- 4' term changes the '3 *' (or '4 *') into a '2 *' (or '3 *).
+ 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)
+ if (unit_type != DW_UT_type)
+ off += 3 * offset_size - 4 + 3;
+ else
+ off += 4 * offset_size - 4 + 3 + 8;
+ }
+ else
+ {
+ /*
+ LEN VER TYPE ADDR OFFSET SIGNATURE TYPE-OFFSET
+ 4-bytes + 2-bytes + 1-byte + 1-byte + 4-bytes + 8-bytes + 4-bytes 32-bit
+ 12-bytes + 2-bytes + 1-byte + 1-byte + 8-bytes + 8-bytes + 8-bytes 64-bit
+ Both signature and type offset are optional.
+
+ Note same 4/8 offset size trick as above.
+ We explicitly ignore unknow unit types (see asserts above). */
+ off += 3 * offset_size - 4 + 4;
+ if (unit_type == DW_UT_skeleton || unit_type == DW_UT_split_compile
+ || unit_type == DW_UT_type || unit_type == DW_UT_split_type)
+ {
+ off += 8;
+ if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
+ off += offset_size;
+ }
+ }
+
+ return off;
+}
+
+static inline Dwarf_Off
+__libdw_first_die_off_from_cu (struct Dwarf_CU *cu)
+{
+ return __libdw_first_die_from_cu_start (cu->start,
+ cu->offset_size,
+ cu->version,
+ cu->unit_type);
+}
-#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), \
+ .addr = ((char *) (fromcu)->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \
+ + __libdw_first_die_off_from_cu (fromcu)) \
})
+#define SUBDIE(fromcu) \
+ ((Dwarf_Die) \
+ { \
+ .cu = (fromcu), \
+ .addr = ((char *) (fromcu)->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \
+ + (fromcu)->start + (fromcu)->subdie_offset) \
+ })
+
+
+/* Prototype of a single .debug_macro operator. */
+typedef struct
+{
+ Dwarf_Word nforms;
+ unsigned char const *forms;
+} Dwarf_Macro_Op_Proto;
+
+/* Prototype table. */
+typedef struct
+{
+ /* Offset of .debug_macro section. */
+ Dwarf_Off offset;
+
+ /* Offset of associated .debug_line section. */
+ Dwarf_Off line_offset;
+
+ /* The source file information. */
+ Dwarf_Files *files;
+
+ /* If this macro unit was opened through dwarf_getmacros or
+ dwarf_getmacros_die, this caches value of DW_AT_comp_dir, if
+ present. */
+ const char *comp_dir;
+
+ /* Header length. */
+ Dwarf_Half header_len;
+
+ uint16_t version;
+ bool is_64bit;
+ uint8_t sec_index; /* IDX_debug_macro or IDX_debug_macinfo. */
+
+ /* Shows where in TABLE each opcode is defined. Since opcode 0 is
+ never used, it stores index of opcode X in X-1'th element. The
+ value of 0xff means not stored at all. */
+ unsigned char opcodes[255];
+
+ /* Individual opcode prototypes. */
+ Dwarf_Macro_Op_Proto table[];
+} Dwarf_Macro_Op_Table;
-/* Macro information. */
struct Dwarf_Macro_s
{
- unsigned int opcode;
- Dwarf_Word param1;
- union
- {
- Dwarf_Word u;
- const char *s;
- } param2;
+ Dwarf_Macro_Op_Table *table;
+ Dwarf_Attribute *attributes;
+ uint8_t opcode;
};
+static inline Dwarf_Word
+libdw_macro_nforms (Dwarf_Macro *macro)
+{
+ return macro->table->table[macro->table->opcodes[macro->opcode - 1]].nforms;
+}
+
+/* Returns true for any allowed FORM in the opcode_operands_table as
+ mentioned in the DWARF5 spec (6.3.1 Macro Information Header).
+ Or those mentioned in DWARF5 spec (6.2.4.2 Vendor-defined Content
+ Descriptions) for the directory/file table (plus DW_FORM_strp_sup). */
+static inline bool
+libdw_valid_user_form (int form)
+{
+ switch (form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_data16:
+ case DW_FORM_flag:
+ case DW_FORM_line_strp:
+ case DW_FORM_sdata:
+ case DW_FORM_sec_offset:
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ case DW_FORM_strp_sup:
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4:
+ case DW_FORM_udata:
+ return true;
+ default:
+ return false;
+ }
+}
+
/* We have to include the file at this point because the inline
functions access internals of the Dwarf structure. */
__attribute__ ((__malloc__)) __nonnull_attribute__ (1);
/* Default OOM handler. */
-extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden")));
+extern void __libdw_oom (void) __attribute ((noreturn)) attribute_hidden;
+
+/* Read next unit (or v4 debug type) and return next offset. Doesn't
+ create an actual Dwarf_CU just provides necessary header fields. */
+extern int
+internal_function
+__libdw_next_unit (Dwarf *dbg, bool v4_debug_types, Dwarf_Off off,
+ Dwarf_Off *next_off, size_t *header_sizep,
+ Dwarf_Half *versionp, uint8_t *unit_typep,
+ Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
+ uint8_t *offset_sizep, uint64_t *unit_id8p,
+ Dwarf_Off *subdie_offsetp)
+ __nonnull_attribute__ (4) internal_function;
+
+/* 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)
+extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset, bool tu)
+ __nonnull_attribute__ (1) internal_function;
+
+/* Find CU for given DIE address. */
+extern struct Dwarf_CU *__libdw_findcu_addr (Dwarf *dbg, void *addr)
__nonnull_attribute__ (1) internal_function;
-/* Return tag of given DIE. */
+/* Get abbreviation with given code. */
extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
unsigned int code)
__nonnull_attribute__ (1) internal_function;
Dwarf_Abbrev *result)
__nonnull_attribute__ (1) internal_function;
+/* Get abbreviation of given DIE, and optionally set *READP to the DIE memory
+ just past the abbreviation code. */
+static inline Dwarf_Abbrev *
+__nonnull_attribute__ (1)
+__libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp)
+{
+ /* Do we need to get the abbreviation, or need to read after the code? */
+ if (die->abbrev == NULL || readp != NULL)
+ {
+ /* Get the abbreviation code. */
+ unsigned int code;
+ const unsigned char *addr = die->addr;
+ if (die->cu == NULL)
+ return DWARF_END_ABBREV;
+ get_uleb128 (code, addr, die->cu->endp);
+ if (readp != NULL)
+ *readp = addr;
+
+ /* Find the abbreviation. */
+ if (die->abbrev == NULL)
+ die->abbrev = __libdw_findabbrev (die->cu, code);
+ }
+ return die->abbrev;
+}
+
/* Helper functions for form handling. */
-extern size_t __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
- unsigned int form,
- const unsigned char *valp)
- __nonnull_attribute__ (1, 2, 4) internal_function;
+extern size_t __libdw_form_val_compute_len (struct Dwarf_CU *cu,
+ unsigned int form,
+ const unsigned char *valp)
+ __nonnull_attribute__ (1, 3) internal_function;
+
+/* Find the length of a form attribute in DIE/info data. */
+static inline size_t
+__nonnull_attribute__ (1, 3)
+__libdw_form_val_len (struct Dwarf_CU *cu, unsigned int form,
+ const unsigned char *valp)
+{
+ /* Small lookup table of forms with fixed lengths. Absent indexes are
+ initialized 0, so any truly desired 0 is set to 0x80 and masked. */
+ static const uint8_t form_lengths[] =
+ {
+ [DW_FORM_flag_present] = 0x80,
+ [DW_FORM_implicit_const] = 0x80, /* Value is in abbrev, not in info. */
+
+ [DW_FORM_flag] = 1,
+ [DW_FORM_data1] = 1, [DW_FORM_ref1] = 1,
+ [DW_FORM_addrx1] = 1, [DW_FORM_strx1] = 1,
+
+ [DW_FORM_data2] = 2, [DW_FORM_ref2] = 2,
+ [DW_FORM_addrx2] = 2, [DW_FORM_strx2] = 2,
+
+ [DW_FORM_addrx3] = 3, [DW_FORM_strx3] = 3,
+
+ [DW_FORM_data4] = 4, [DW_FORM_ref4] = 4, [DW_FORM_ref_sup4] = 4,
+ [DW_FORM_addrx4] = 4, [DW_FORM_strx4] = 4,
+
+ [DW_FORM_ref_sig8] = 8,
+ [DW_FORM_data8] = 8, [DW_FORM_ref8] = 8, [DW_FORM_ref_sup8] = 8,
+
+ [DW_FORM_data16] = 16,
+ };
+
+ /* Return immediately for forms with fixed lengths. */
+ if (form < sizeof form_lengths / sizeof form_lengths[0])
+ {
+ uint8_t len = form_lengths[form];
+ if (len != 0)
+ {
+ const unsigned char *endp = cu->endp;
+ len &= 0x7f; /* Mask to allow 0x80 -> 0. */
+ if (unlikely (len > (size_t) (endp - valp)))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ return len;
+ }
+ }
+
+ /* Other forms require some computation. */
+ return __libdw_form_val_compute_len (cu, form, valp);
+}
/* Helper function for DW_FORM_ref* handling. */
extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
};
extern int __libdw_visit_scopes (unsigned int depth,
struct Dwarf_Die_Chain *root,
+ struct Dwarf_Die_Chain *imports,
int (*previsit) (unsigned int depth,
struct Dwarf_Die_Chain *,
void *arg),
struct Dwarf_Die_Chain *,
void *arg),
void *arg)
- __nonnull_attribute__ (2, 3) internal_function;
+ __nonnull_attribute__ (2, 4) internal_function;
+
+/* Parse a DWARF Dwarf_Block into an array of Dwarf_Op's,
+ and cache the result (via tsearch). */
+extern int __libdw_intern_expression (Dwarf *dbg,
+ bool other_byte_order,
+ unsigned int address_size,
+ unsigned int ref_size,
+ void **cache, const Dwarf_Block *block,
+ bool cfap, bool valuep,
+ Dwarf_Op **llbuf, size_t *listlen,
+ int sec_index)
+ __nonnull_attribute__ (5, 6, 9, 10) internal_function;
+
+extern Dwarf_Die *__libdw_offdie (Dwarf *dbg, Dwarf_Off offset,
+ Dwarf_Die *result, bool debug_types)
+ internal_function;
+
/* Return error code of last failing function call. This value is kept
separately for each thread. */
if (data == NULL)
return -1;
if (unlikely (offset > data->d_size)
- || unlikely (data->d_size - offset < size))
+ || unlikely (data->d_size < size)
+ || unlikely (offset > data->d_size - size))
{
__libdw_seterrno (DWARF_E_INVALID_OFFSET);
return -1;
if (data == NULL)
return false;
if (unlikely (addr < data->d_buf)
- || unlikely (data->d_size - (addr - data->d_buf) < size))
+ || unlikely (data->d_size < size)
+ || unlikely ((size_t)(addr - data->d_buf) > data->d_size - size))
{
__libdw_seterrno (DWARF_E_INVALID_OFFSET);
return false;
}
static inline int
-__libdw_read_offset (Dwarf *dbg,
+__libdw_read_offset (Dwarf *dbg, Dwarf *dbg_ret,
int sec_index, const unsigned char *addr,
int width, Dwarf_Off *ret, int sec_ret,
size_t size)
{
READ_AND_RELOCATE (__libdw_relocate_offset, (*ret));
- return __libdw_offset_in_section (dbg, sec_ret, *ret, size);
+ return __libdw_offset_in_section (dbg_ret, sec_ret, *ret, size);
+}
+
+static inline size_t
+cu_sec_idx (struct Dwarf_CU *cu)
+{
+ return cu->sec_idx;
+}
+
+static inline bool
+is_cudie (Dwarf_Die *cudie)
+{
+ return CUDIE (cudie->cu).addr == cudie->addr;
}
/* Read up begin/end pair and increment read pointer.
- If it's end of rangelist, don't set anything and return 2
- If an error occurs, don't set anything and return <0. */
int __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
- unsigned char **addr, int width,
+ const unsigned char **readp,
+ const unsigned char *readend,
+ int width,
Dwarf_Addr *beginp, Dwarf_Addr *endp,
Dwarf_Addr *basep)
internal_function;
-unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
- int err_nodata, unsigned char **endpp,
- Dwarf_Off *offsetp)
+const unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
+ int err_nodata,
+ const unsigned char **endpp,
+ Dwarf_Off *offsetp)
internal_function;
+/* Fills in the given attribute to point at an empty location expression. */
+void __libdw_empty_loc_attr (Dwarf_Attribute *attr)
+ internal_function;
+
+/* Load .debug_line unit at DEBUG_LINE_OFFSET. COMP_DIR is a value of
+ DW_AT_comp_dir or NULL if that attribute is not available. Caches
+ the loaded unit and optionally set *LINESP and/or *FILESP (if not
+ NULL) with loaded information. Returns 0 for success or a negative
+ value for failure. */
+int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
+ const char *comp_dir, unsigned address_size,
+ Dwarf_Lines **linesp, Dwarf_Files **filesp)
+ internal_function
+ __nonnull_attribute__ (1);
+
+/* Load and return value of DW_AT_comp_dir from CUDIE. */
+const char *__libdw_getcompdir (Dwarf_Die *cudie);
+
+/* Get the base address for the CU, fetches it when not yet set.
+ This is used as initial base address for ranges and loclists. */
+Dwarf_Addr __libdw_cu_base_address (Dwarf_CU *cu);
+
+/* Get the address base for the CU, fetches it when not yet set. */
+Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu);
+
+/* Gets the .debug_str_offsets base offset to use. static inline to
+ be shared between libdw and eu-readelf. */
+static inline Dwarf_Off
+str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
+{
+ /* If we don't have a CU, then find and use the first one in the
+ debug file (when we support .dwp files, we must actually find the
+ one matching our "caller" - aka macro or line). If we (now) have
+ a cu and str_offsets_base attribute, just use that. Otherwise
+ use the first offset. But we might have to parse the header
+ first, but only if this is version 5. Assume if all else fails,
+ this is version 4, without header. */
+
+ if (cu == NULL && dbg != NULL)
+ {
+ Dwarf_CU *first_cu;
+ if (dwarf_get_units (dbg, NULL, &first_cu,
+ NULL, NULL, NULL, NULL) == 0)
+ cu = first_cu;
+ }
+
+ if (cu != NULL)
+ {
+ if (cu->str_off_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ {
+ cu->str_off_base = off;
+ return cu->str_off_base;
+ }
+ }
+ /* For older DWARF simply assume zero (no header). */
+ if (cu->version < 5)
+ {
+ cu->str_off_base = 0;
+ return cu->str_off_base;
+ }
+ }
+ else
+ return cu->str_off_base;
+ }
+
+ /* No str_offsets_base attribute, we have to assume "zero".
+ But there could be a header first. */
+ Dwarf_Off off = 0;
+ if (dbg == NULL)
+ goto no_header;
+
+ Elf_Data *data = dbg->sectiondata[IDX_debug_str_offsets];
+ if (data == NULL)
+ goto no_header;
+
+ const unsigned char *start;
+ const unsigned char *readp;
+ const unsigned char *readendp;
+ start = readp = (const unsigned char *) data->d_buf;
+ readendp = (const unsigned char *) data->d_buf + data->d_size;
+
+ uint64_t unit_length;
+ uint16_t version;
+
+ unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+ if (unlikely (unit_length == 0xffffffff))
+ {
+ if (unlikely (readendp - readp < 8))
+ goto no_header;
+ unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+ /* In theory the offset size could be different
+ between CU and str_offsets unit. But we just
+ ignore that here. */
+ }
+
+ /* We need at least 2-bytes (version) + 2-bytes (padding) =
+ 4 bytes to complete the header. And this unit cannot go
+ beyond the section data. */
+ if (readendp - readp < 4
+ || unit_length < 4
+ || (uint64_t) (readendp - readp) < unit_length)
+ goto no_header;
+
+ version = read_2ubyte_unaligned_inc (dbg, readp);
+ if (version != 5)
+ goto no_header;
+ /* padding */
+ read_2ubyte_unaligned_inc (dbg, readp);
+
+ off = (Dwarf_Off) (readp - start);
+
+ no_header:
+ if (cu != NULL)
+ cu->str_off_base = off;
+
+ return off;
+}
+
+
+/* Get the string offsets base for the CU, fetches it when not yet set. */
+static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
+{
+ return str_offsets_base_off (NULL, cu);
+}
+
+
+/* Given a file descriptor, dir and file returns a full path. If the
+ file is absolute (starts with a /) a copy of file is returned. If
+ the file isn't absolute, but dir is absolute, then a path that is
+ the concatenation of dir and file is returned. If neither file,
+ nor dir is absolute, the path will be constructed using dir (if not
+ NULL) and file relative to the path of the given file descriptor
+ (if valid).
+
+ The file descriptor may be -1 and the dir may be NULL (in which
+ case they aren't used). If file is NULL, or no full path can be
+ constructed NULL is returned.
+
+ The caller is responsible for freeing the result if not NULL. */
+char * filepath (int fd, const char *dir, const char *file)
+ internal_function;
/* Aliases to avoid PLTs. */
+INTDECL (dwarf_aggregate_size)
INTDECL (dwarf_attr)
INTDECL (dwarf_attr_integrate)
+INTDECL (dwarf_begin)
INTDECL (dwarf_begin_elf)
INTDECL (dwarf_child)
+INTDECL (dwarf_default_lower_bound)
INTDECL (dwarf_dieoffset)
INTDECL (dwarf_diename)
INTDECL (dwarf_end)
INTDECL (dwarf_formsdata)
INTDECL (dwarf_formstring)
INTDECL (dwarf_formudata)
+INTDECL (dwarf_getabbrevattr_data)
+INTDECL (dwarf_getalt)
INTDECL (dwarf_getarange_addr)
INTDECL (dwarf_getarangeinfo)
INTDECL (dwarf_getaranges)
+INTDECL (dwarf_getlocation_die)
INTDECL (dwarf_getsrcfiles)
INTDECL (dwarf_getsrclines)
INTDECL (dwarf_hasattr)
INTDECL (dwarf_highpc)
INTDECL (dwarf_lowpc)
INTDECL (dwarf_nextcu)
+INTDECL (dwarf_next_unit)
INTDECL (dwarf_offdie)
+INTDECL (dwarf_peel_type)
INTDECL (dwarf_ranges)
+INTDECL (dwarf_setalt)
INTDECL (dwarf_siblingof)
+INTDECL (dwarf_srclang)
INTDECL (dwarf_tag)
#endif /* libdwP.h */