#ifndef _LIBDWP_H
#define _LIBDWP_H 1
#include <stdbool.h>
#include <pthread.h>
#include <libdw.h>
#include <dwarf.h>
struct loc_s
{
void *addr;
Dwarf_Op *loc;
size_t nloc;
};
struct loc_block_s
{
void *addr;
unsigned char *data;
size_t length;
};
struct files_lines_s
{
Dwarf_Off debug_line_offset;
Dwarf_Files *files;
Dwarf_Lines *lines;
};
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_debug_loc,
IDX_debug_loclists,
IDX_debug_pubnames,
IDX_debug_str,
IDX_debug_str_offsets,
IDX_debug_macinfo,
IDX_debug_macro,
IDX_debug_ranges,
IDX_debug_rnglists,
IDX_debug_cu_index,
IDX_debug_tu_index,
IDX_gnu_debugaltlink,
IDX_last
};
enum string_section_index
{
STR_SCN_IDX_debug_line_str,
STR_SCN_IDX_debug_str,
STR_SCN_IDX_last
};
enum
{
DWARF_E_NOERROR = 0,
DWARF_E_UNKNOWN_ERROR,
DWARF_E_INVALID_ACCESS,
DWARF_E_NO_REGFILE,
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_UNIMPL,
DWARF_E_INVALID_CMD,
DWARF_E_INVALID_VERSION,
DWARF_E_INVALID_FILE,
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_INVALID_REFERENCE,
DWARF_E_NO_DEBUG_LINE,
DWARF_E_INVALID_DEBUG_LINE,
DWARF_E_TOO_BIG,
DWARF_E_VERSION,
DWARF_E_INVALID_DIR_IDX,
DWARF_E_ADDR_OUTOFRANGE,
DWARF_E_NO_DEBUG_LOC,
DWARF_E_NO_DEBUG_LOCLISTS,
DWARF_E_NO_LOC_VALUE,
DWARF_E_NO_BLOCK,
DWARF_E_INVALID_LINE_IDX,
DWARF_E_INVALID_ARANGE_IDX,
DWARF_E_NO_MATCH,
DWARF_E_NO_FLAG,
DWARF_E_INVALID_OFFSET,
DWARF_E_NO_DEBUG_RANGES,
DWARF_E_NO_DEBUG_RNGLISTS,
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,
DWARF_E_UNKNOWN_SECTION,
};
#include "dwarf_sig8_hash.h"
enum dwarf_type
{
TYPE_UNKNOWN = 0,
TYPE_GNU_LTO = 16,
TYPE_DWO = 32,
TYPE_PLAIN = 64,
};
struct Dwarf
{
Elf *elf;
char *elfpath;
char *debugdir;
Dwarf *alt_dwarf;
Dwarf *dwp_dwarf;
Elf_Data *sectiondata[IDX_last];
size_t string_section_size[STR_SCN_IDX_last];
bool other_byte_order;
bool free_elf;
int alt_fd;
int dwp_fd;
struct pubnames_s
{
Dwarf_Off cu_offset;
Dwarf_Off set_start;
unsigned int cu_header_size;
int address_len;
} *pubnames_sets;
size_t pubnames_nsets;
void *cu_tree;
Dwarf_Off next_cu_offset;
void *tu_tree;
Dwarf_Off next_tu_offset;
Dwarf_Sig8_Hash sig8_hash;
void *split_tree;
void *macro_ops;
void *files_lines;
Dwarf_Aranges *aranges;
Dwarf_Aranges *dieranges;
struct Dwarf_CFI_s *cfi;
struct Dwarf_Package_Index_s *cu_index;
struct Dwarf_Package_Index_s *tu_index;
struct Dwarf_CU *fake_loc_cu;
struct Dwarf_CU *fake_loclists_cu;
struct Dwarf_CU *fake_addr_cu;
enum dwarf_type type;
pthread_rwlock_t mem_rwl;
size_t mem_stacks;
struct libdw_memblock
{
size_t size;
size_t remaining;
struct libdw_memblock *prev;
char mem[0];
} **mem_tails;
size_t mem_default_size;
Dwarf_OOM oom_handler;
};
struct Dwarf_Abbrev
{
Dwarf_Off offset;
unsigned char *attrp;
bool has_children : 1;
unsigned int code : 31;
unsigned int tag;
} attribute_packed;
#include "dwarf_abbrev_hash.h"
struct Dwarf_Files_s
{
unsigned int ndirs;
unsigned int nfiles;
struct Dwarf_Fileinfo_s
{
char *name;
Dwarf_Word mtime;
Dwarf_Word length;
} info[0];
};
typedef struct Dwarf_Fileinfo_s Dwarf_Fileinfo;
struct Dwarf_Line_s
{
Dwarf_Files *files;
Dwarf_Addr addr;
unsigned int file;
int line;
unsigned short int column;
unsigned int is_stmt:1;
unsigned int basic_block:1;
unsigned int end_sequence:1;
unsigned int prologue_end:1;
unsigned int epilogue_begin:1;
unsigned int op_index:8;
unsigned int isa:8;
unsigned int discriminator:24;
unsigned int context;
unsigned int function_name;
};
struct Dwarf_Lines_s
{
size_t nlines;
struct Dwarf_Line_s info[0];
};
struct Dwarf_Aranges_s
{
Dwarf *dbg;
size_t naranges;
struct Dwarf_Arange_s
{
Dwarf_Addr addr;
Dwarf_Word length;
Dwarf_Off offset;
} info[0];
};
typedef struct Dwarf_Package_Index_s
{
Dwarf *dbg;
uint32_t section_count;
uint32_t unit_count;
uint32_t slot_count;
uint32_t sections[DW_SECT_RNGLISTS];
uint32_t last_unit_found;
const unsigned char *hash_table;
const unsigned char *indices;
const unsigned char *section_offsets;
const unsigned char *section_sizes;
Dwarf_Off *debug_info_offsets;
} Dwarf_Package_Index;
struct Dwarf_CU
{
Dwarf *dbg;
Dwarf_Off start;
Dwarf_Off end;
uint32_t dwp_row;
uint8_t address_size;
uint8_t offset_size;
uint16_t version;
size_t sec_idx;
uint8_t unit_type;
size_t subdie_offset;
uint64_t unit_id8;
struct Dwarf_CU *split;
Dwarf_Abbrev_Hash abbrev_hash;
size_t orig_abbrev_offset;
size_t last_abbrev_offset;
Dwarf_Lines *lines;
Dwarf_Files *files;
void *locs;
Dwarf_Addr base_address;
Dwarf_Off addr_base;
Dwarf_Off str_off_base;
Dwarf_Off ranges_base;
Dwarf_Off locs_base;
void *startp;
void *endp;
};
INTDECL (dwarf_aggregate_size)
INTDECL (dwarf_attr)
INTDECL (dwarf_attr_integrate)
INTDECL (dwarf_begin)
INTDECL (dwarf_begin_elf)
INTDECL (dwarf_child)
INTDECL (dwarf_cu_dwp_section_info)
INTDECL (dwarf_default_lower_bound)
INTDECL (dwarf_dieoffset)
INTDECL (dwarf_diename)
INTDECL (dwarf_end)
INTDECL (dwarf_entrypc)
INTDECL (dwarf_errmsg)
INTDECL (dwarf_formaddr)
INTDECL (dwarf_formblock)
INTDECL (dwarf_formref_die)
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_get_units)
INTDECL (dwarf_hasattr)
INTDECL (dwarf_haschildren)
INTDECL (dwarf_haspc)
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)
#define ISV4TU(cu) ((cu)->version == 4 && (cu)->sec_idx == IDX_debug_types)
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)
{
Dwarf_Off off = cu_start;
if (version < 5)
{
if (unit_type != DW_UT_type)
off += 3 * offset_size - 4 + 3;
else
off += 4 * offset_size - 4 + 3 + 8;
}
else
{
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) \
((Dwarf_Die) \
{ \
.cu = (fromcu), \
.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) \
})
typedef struct
{
Dwarf_Word nforms;
unsigned char const *forms;
} Dwarf_Macro_Op_Proto;
typedef struct
{
Dwarf *dbg;
Dwarf_Off offset;
Dwarf_Off line_offset;
Dwarf_Files *files;
const char *comp_dir;
Dwarf_Half header_len;
uint16_t version;
uint8_t address_size;
uint8_t offset_size;
uint8_t sec_index;
unsigned char opcodes[255];
Dwarf_Macro_Op_Proto table[];
} Dwarf_Macro_Op_Table;
struct Dwarf_Macro_s
{
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;
}
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;
}
}
#include "memory-access.h"
extern void __libdw_seterrno (int value) internal_function;
#define libdw_alloc(dbg, type, tsize, cnt) \
({ struct libdw_memblock *_tail = __libdw_alloc_tail(dbg); \
size_t _required = (tsize) * (cnt); \
type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\
size_t _padding = ((__alignof (type) \
- ((uintptr_t) _result & (__alignof (type) - 1))) \
& (__alignof (type) - 1)); \
if (unlikely (_tail->remaining < _required + _padding)) \
_result = (type *) __libdw_allocate (dbg, _required, __alignof (type));\
else \
{ \
_required += _padding; \
_result = (type *) ((char *) _result + _padding); \
_tail->remaining -= _required; \
} \
_result; })
#define libdw_typed_alloc(dbg, type) \
libdw_alloc (dbg, type, sizeof (type), 1)
#define libdw_unalloc(dbg, type, tsize, cnt) \
({ struct libdw_memblock *_tail = __libdw_thread_tail (dbg); \
size_t _required = (tsize) * (cnt); \
\
_tail->remaining += _required; }) \
#define libdw_typed_unalloc(dbg, type) \
libdw_unalloc (dbg, type, sizeof (type), 1)
extern struct libdw_memblock *__libdw_alloc_tail (Dwarf* dbg)
__nonnull_attribute__ (1);
extern struct libdw_memblock *__libdw_thread_tail (Dwarf* dbg)
__nonnull_attribute__ (1);
extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
__attribute__ ((__malloc__)) __nonnull_attribute__ (1);
extern void __libdw_oom (void) __attribute ((noreturn)) attribute_hidden;
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;
extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
__nonnull_attribute__ (1) internal_function;
extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset, bool tu)
__nonnull_attribute__ (1) internal_function;
extern struct Dwarf_CU *__libdw_findcu_addr (Dwarf *dbg, void *addr)
__nonnull_attribute__ (1) internal_function;
extern struct Dwarf *__libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
__nonnull_attribute__ (1) internal_function;
extern struct Dwarf_CU *__libdw_find_split_unit (Dwarf_CU *cu)
internal_function;
extern int __libdw_dwp_find_unit (Dwarf *dbg, bool debug_types, Dwarf_Off off,
uint16_t version, uint8_t unit_type,
uint64_t unit_id8, uint32_t *unit_rowp,
Dwarf_Off *abbrev_offsetp)
__nonnull_attribute__ (1, 7, 8) internal_function;
extern Dwarf_CU *__libdw_dwp_findcu_id (Dwarf *dbg, uint64_t unit_id8)
__nonnull_attribute__ (1) internal_function;
extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
unsigned int code)
__nonnull_attribute__ (1) internal_function;
extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
Dwarf_Off offset, size_t *lengthp,
Dwarf_Abbrev *result)
__nonnull_attribute__ (1) internal_function;
static inline Dwarf_Abbrev *
__nonnull_attribute__ (1)
__libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp)
{
if (die->abbrev == NULL || readp != NULL)
{
unsigned int code;
const unsigned char *addr = die->addr;
if (unlikely (die->cu == NULL
|| addr >= (const unsigned char *) die->cu->endp))
return die->abbrev = DWARF_END_ABBREV;
get_uleb128 (code, addr, die->cu->endp);
if (readp != NULL)
*readp = addr;
if (die->abbrev == NULL)
die->abbrev = __libdw_findabbrev (die->cu, code);
}
return die->abbrev;
}
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;
static inline size_t
__nonnull_attribute__ (1, 3)
__libdw_form_val_len (struct Dwarf_CU *cu, unsigned int form,
const unsigned char *valp)
{
static const uint8_t form_lengths[] =
{
[DW_FORM_flag_present] = 0x80,
[DW_FORM_implicit_const] = 0x80,
[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,
};
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;
if (unlikely (len > (size_t) (endp - valp)))
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1;
}
return len;
}
}
return __libdw_form_val_compute_len (cu, form, valp);
}
extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
__nonnull_attribute__ (1, 2) internal_function;
extern unsigned char *__libdw_find_attr (Dwarf_Die *die,
unsigned int search_name,
unsigned int *codep,
unsigned int *formp)
__nonnull_attribute__ (1) internal_function;
extern int __libdw_attr_intval (Dwarf_Die *die, int *valp, int attval)
__nonnull_attribute__ (1, 2) internal_function;
struct Dwarf_Die_Chain
{
Dwarf_Die die;
struct Dwarf_Die_Chain *parent;
bool prune;
};
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),
int (*postvisit) (unsigned int depth,
struct Dwarf_Die_Chain *,
void *arg),
void *arg)
__nonnull_attribute__ (2, 4) internal_function;
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;
extern int __dwarf_errno_internal (void);
static inline int
__libdw_relocate_address (Dwarf *dbg __attribute__ ((unused)),
int sec_index __attribute__ ((unused)),
const void *addr __attribute__ ((unused)),
int width __attribute__ ((unused)),
Dwarf_Addr *val __attribute__ ((unused)))
{
return 0;
}
static inline int
__libdw_relocate_offset (Dwarf *dbg __attribute__ ((unused)),
int sec_index __attribute__ ((unused)),
const void *addr __attribute__ ((unused)),
int width __attribute__ ((unused)),
Dwarf_Off *val __attribute__ ((unused)))
{
return 0;
}
static inline Elf_Data *
__libdw_checked_get_data (Dwarf *dbg, int sec_index)
{
Elf_Data *data = dbg->sectiondata[sec_index];
if (unlikely (data == NULL)
|| unlikely (data->d_buf == NULL))
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
}
return data;
}
static inline int
__libdw_offset_in_section (Dwarf *dbg, int sec_index,
Dwarf_Off offset, size_t size)
{
Elf_Data *data = __libdw_checked_get_data (dbg, sec_index);
if (data == NULL)
return -1;
if (unlikely (offset > data->d_size)
|| unlikely (data->d_size < size)
|| unlikely (offset > data->d_size - size))
{
__libdw_seterrno (DWARF_E_INVALID_OFFSET);
return -1;
}
return 0;
}
static inline bool
__libdw_in_section (Dwarf *dbg, int sec_index,
const void *addr, size_t size)
{
Elf_Data *data = __libdw_checked_get_data (dbg, sec_index);
if (data == NULL)
return false;
if (unlikely (addr < data->d_buf)
|| unlikely (data->d_size < size)
|| unlikely ((size_t)(addr - data->d_buf) > data->d_size - size))
{
__libdw_seterrno (DWARF_E_INVALID_OFFSET);
return false;
}
return true;
}
#define READ_AND_RELOCATE(RELOC_HOOK, VAL) \
({ \
if (!__libdw_in_section (dbg, sec_index, addr, width)) \
return -1; \
\
const unsigned char *orig_addr = addr; \
if (width == 4) \
VAL = read_4ubyte_unaligned_inc (dbg, addr); \
else \
VAL = read_8ubyte_unaligned_inc (dbg, addr); \
\
int status = RELOC_HOOK (dbg, sec_index, orig_addr, width, &VAL); \
if (status < 0) \
return status; \
status > 0; \
})
static inline int
__libdw_read_address_inc (Dwarf *dbg,
int sec_index, const unsigned char **addrp,
int width, Dwarf_Addr *ret)
{
const unsigned char *addr = *addrp;
READ_AND_RELOCATE (__libdw_relocate_address, (*ret));
*addrp = addr;
return 0;
}
static inline int
__libdw_read_address (Dwarf *dbg,
int sec_index, const unsigned char *addr,
int width, Dwarf_Addr *ret)
{
READ_AND_RELOCATE (__libdw_relocate_address, (*ret));
return 0;
}
static inline int
__libdw_read_offset_inc (Dwarf *dbg,
int sec_index, const unsigned char **addrp,
int width, Dwarf_Off *ret, int sec_ret,
size_t size)
{
const unsigned char *addr = *addrp;
READ_AND_RELOCATE (__libdw_relocate_offset, (*ret));
*addrp = addr;
return __libdw_offset_in_section (dbg, sec_ret, *ret, size);
}
static inline int
__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_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->cu != NULL && CUDIE (cudie->cu).addr == cudie->addr;
}
int __libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
const unsigned char **readp,
const unsigned char *readend,
int width,
Dwarf_Addr *beginp, Dwarf_Addr *endp,
Dwarf_Addr *basep)
internal_function;
const unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
int err_nodata,
const unsigned char **endpp,
Dwarf_Off *offsetp)
internal_function;
void __libdw_empty_loc_attr (Dwarf_Attribute *attr)
internal_function;
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);
const char *__libdw_getcompdir (Dwarf_Die *cudie);
Dwarf_Addr __libdw_cu_base_address (Dwarf_CU *cu);
static inline Dwarf_Off
__libdw_cu_addr_base (Dwarf_CU *cu)
{
if (cu->addr_base == (Dwarf_Off) -1)
{
Dwarf_Die cu_die = CUDIE(cu);
Dwarf_Attribute attr;
Dwarf_Off offset = 0;
if (dwarf_attr (&cu_die, DW_AT_GNU_addr_base, &attr) != NULL
|| dwarf_attr (&cu_die, DW_AT_addr_base, &attr) != NULL)
{
Dwarf_Word off;
if (dwarf_formudata (&attr, &off) == 0)
offset = off;
}
cu->addr_base = offset;
}
return cu->addr_base;
}
static inline Dwarf_Off
str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
{
if (cu == NULL && dbg != NULL)
{
Dwarf_CU *first_cu;
if (INTUSE(dwarf_get_units) (dbg, NULL, &first_cu,
NULL, NULL, NULL, NULL) == 0)
cu = first_cu;
}
Dwarf_Off off = 0;
if (cu != NULL)
{
if (cu->str_off_base == (Dwarf_Off) -1)
{
Dwarf_Off dwp_offset;
if (dwarf_cu_dwp_section_info (cu, DW_SECT_STR_OFFSETS, &dwp_offset,
NULL) == 0)
off = dwp_offset;
Dwarf_Die cu_die = CUDIE(cu);
Dwarf_Attribute attr;
if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
{
Dwarf_Word base;
if (dwarf_formudata (&attr, &base) == 0)
{
cu->str_off_base = off + base;
return cu->str_off_base;
}
}
if (cu->version < 5)
{
cu->str_off_base = off;
return cu->str_off_base;
}
if (dbg == NULL)
dbg = cu->dbg;
}
else
return cu->str_off_base;
}
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);
}
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;
read_2ubyte_unaligned_inc (dbg, readp);
off += (Dwarf_Off) (readp - start);
no_header:
if (cu != NULL)
cu->str_off_base = off;
return off;
}
static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
{
return str_offsets_base_off (NULL, cu);
}
static inline Dwarf_Off
__libdw_cu_ranges_base (Dwarf_CU *cu)
{
if (cu->ranges_base == (Dwarf_Off) -1)
{
Dwarf_Off offset = 0;
Dwarf_Die cu_die = CUDIE(cu);
Dwarf_Attribute attr;
if (cu->version < 5)
{
if (dwarf_attr (&cu_die, DW_AT_GNU_ranges_base, &attr) != NULL)
{
Dwarf_Word off;
if (dwarf_formudata (&attr, &off) == 0)
offset = off;
}
}
else
{
Dwarf_Off dwp_offset;
if (dwarf_cu_dwp_section_info (cu, DW_SECT_RNGLISTS, &dwp_offset,
NULL) == 0)
offset = dwp_offset;
if (dwarf_attr (&cu_die, DW_AT_rnglists_base, &attr) != NULL)
{
Dwarf_Word off;
if (dwarf_formudata (&attr, &off) == 0)
offset += off;
}
Elf_Data *data = cu->dbg->sectiondata[IDX_debug_rnglists];
if (offset == dwp_offset && data != NULL)
{
Dwarf *dbg = cu->dbg;
const unsigned char *readp = data->d_buf;
const unsigned char *const dataend
= (unsigned char *) data->d_buf + data->d_size;
uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
unsigned int offset_size = 4;
if (unlikely (unit_length == 0xffffffff))
{
if (unlikely (readp > dataend - 8))
goto no_header;
unit_length = read_8ubyte_unaligned_inc (dbg, readp);
offset_size = 8;
}
if (readp > dataend - 8
|| unit_length < 8
|| unit_length > (uint64_t) (dataend - readp))
goto no_header;
uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
if (version != 5)
goto no_header;
uint8_t address_size = *readp++;
if (address_size != 4 && address_size != 8)
goto no_header;
uint8_t segment_size = *readp++;
if (segment_size != 0)
goto no_header;
uint32_t offset_entry_count;
offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp);
const unsigned char *offset_array_start = readp;
if (offset_entry_count <= 0)
goto no_header;
uint64_t needed = offset_entry_count * offset_size;
if (unit_length - 8 < needed)
goto no_header;
offset += (Dwarf_Off) (offset_array_start
- (unsigned char *) data->d_buf);
}
}
no_header:
cu->ranges_base = offset;
}
return cu->ranges_base;
}
static inline Dwarf_Off
__libdw_cu_locs_base (Dwarf_CU *cu)
{
if (cu->locs_base == (Dwarf_Off) -1)
{
Dwarf_Off offset = 0;
Dwarf_Off dwp_offset;
if (dwarf_cu_dwp_section_info (cu, DW_SECT_LOCLISTS, &dwp_offset, NULL)
== 0)
offset = dwp_offset;
Dwarf_Die cu_die = CUDIE(cu);
Dwarf_Attribute attr;
if (dwarf_attr (&cu_die, DW_AT_loclists_base, &attr) != NULL)
{
Dwarf_Word off;
if (dwarf_formudata (&attr, &off) == 0)
offset += off;
}
Elf_Data *data = cu->dbg->sectiondata[IDX_debug_loclists];
if (offset == dwp_offset && data != NULL)
{
Dwarf *dbg = cu->dbg;
const unsigned char *readp = data->d_buf;
const unsigned char *const dataend
= (unsigned char *) data->d_buf + data->d_size;
uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
unsigned int offset_size = 4;
if (unlikely (unit_length == 0xffffffff))
{
if (unlikely (readp > dataend - 8))
goto no_header;
unit_length = read_8ubyte_unaligned_inc (dbg, readp);
offset_size = 8;
}
if (readp > dataend - 8
|| unit_length < 8
|| unit_length > (uint64_t) (dataend - readp))
goto no_header;
uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
if (version != 5)
goto no_header;
uint8_t address_size = *readp++;
if (address_size != 4 && address_size != 8)
goto no_header;
uint8_t segment_size = *readp++;
if (segment_size != 0)
goto no_header;
uint32_t offset_entry_count;
offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp);
const unsigned char *offset_array_start = readp;
if (offset_entry_count <= 0)
goto no_header;
uint64_t needed = offset_entry_count * offset_size;
if (unit_length - 8 < needed)
goto no_header;
offset += (Dwarf_Off) (offset_array_start
- (unsigned char *) data->d_buf);
}
no_header:
cu->locs_base = offset;
}
return cu->locs_base;
}
int __libdw_finddbg_cb (const void *arg1, const void *arg2);
static inline void
__libdw_link_skel_split (Dwarf_CU *skel, Dwarf_CU *split)
{
skel->split = split;
split->split = skel;
Dwarf *dbg = skel->dbg;
Dwarf *sdbg = split->dbg;
if (dbg->sectiondata[IDX_debug_addr] != NULL
&& (sdbg->sectiondata[IDX_debug_addr] == NULL
|| (sdbg->sectiondata[IDX_debug_addr]
== dbg->sectiondata[IDX_debug_addr])))
{
sdbg->sectiondata[IDX_debug_addr]
= dbg->sectiondata[IDX_debug_addr];
split->addr_base = __libdw_cu_addr_base (skel);
sdbg->fake_addr_cu = dbg->fake_addr_cu;
}
}
int __libdw_addrx (Dwarf_CU *cu, Dwarf_Word idx, Dwarf_Addr *addr);
char * __libdw_elfpath (int fd);
void __libdw_set_debugdir (Dwarf *dbg);
char * __libdw_filepath (const char *debugdir, const char *dir,
const char *file)
internal_function;
int __libdw_getdieranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges);
#endif