#include "config.h"
#include "libdwarfdefs.h"
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#ifdef HAVE_STDINT_H
#include <stdint.h> /* For uintptr_t */
#endif /* HAVE_STDINT_H */
#include "pro_incl.h"
#include "dwarf.h"
#include "libdwarf.h"
#include "pro_opaque.h"
#include "pro_error.h"
#include "pro_encode_nm.h"
#include "pro_alloc.h"
#include "pro_line.h"
#include "memcpy_swap.h"
#include "pro_section.h" /* for MAGIC_SECT_NO */
#include "pro_reloc_symbolic.h"
#include "pro_reloc_stream.h"
#include "dwarf_tsearch.h"
#include "dwarfstring.h"
#define IS_64BITPTR(dbg) ((dbg)->de_flags & DW_DLC_POINTER64 ? 1 : 0)
#define ISA_IA64(dbg) ((dbg)->de_flags & DW_DLC_ISA_IA64 ? 1 : 0)
struct
isa_relocs_s {
const
char
*name_;
int
reloc32_;
int
reloc64_;
int
segrel_;
};
#ifndef TRUE
#define TRUE 1
#endif /*TRUE*/
#ifndef FALSE
#define FALSE 0
#endif /*FALSE*/
#define R_MIPS_32 2
#define R_MIPS_64 18
#define R_MIPS_SCN_DISP 32
#define R_386_32 1
#define R_386_64 0 /* impossible */
#define R_X86_64_32 10
#define R_X86_64_64 1
#define R_SPARC_UA32 23
#define R_SPARC_UA64 54
#define R_ARM_ABS32 2
#define R_ARM_ABS64 0 /* impossible */
#define R_AARCH64_ABS32 258
#define R_AARCH64_ABS64 257
#define R_IA64_DIR32LSB 0x25
#define R_IA64_DIR64LSB 0x27
#define R_PPC_REL32 26
#define R_PPC_REL64 44
#define R_PPC64_REL32 R_PPC_REL32
#define R_PPC64_REL64 44
static
struct
isa_relocs_s isa_relocs[] = {
{
"irix"
, R_MIPS_32,R_MIPS_64,R_MIPS_SCN_DISP},
{
"mips"
, R_MIPS_32,R_MIPS_64,0},
{
"x86"
, R_386_32, R_386_64,0},
{
"x86_64"
,R_X86_64_32,R_X86_64_64,0},
{
"ia64"
, R_IA64_DIR32LSB,R_IA64_DIR64LSB,0},
{
"arm64"
, R_AARCH64_ABS32,R_AARCH64_ABS64,0},
{
"arm"
, R_ARM_ABS32,R_ARM_ABS64,0},
{
"ppc"
, R_PPC_REL32,R_PPC_REL64,0},
{
"ppc64"
, R_PPC64_REL32,R_PPC64_REL64,0},
{
"sparc"
, R_SPARC_UA32,R_SPARC_UA64,0},
{0,0,0,0}
};
static
int
common_init(Dwarf_P_Debug dbg, Dwarf_Unsigned flags,
const
char
*abiname,
const
char
*dwarf_version,
const
char
*extrainfo,
int
*error_ret);
static
struct
Dwarf_P_Section_Data_s init_sect = {
MAGIC_SECT_NO, 0, 0, 0, 0
};
static
struct
Dwarf_P_Section_Data_s init_sect_debug_str = {
MAGIC_SECT_NO, 0, 0, 0, 0
};
static
struct
Dwarf_P_Section_Data_s init_sect_debug_line_str = {
MAGIC_SECT_NO, 0, 0, 0, 0
};
int
dwarf_producer_init(Dwarf_Unsigned flags,
Dwarf_Callback_Func func,
Dwarf_Handler errhand,
Dwarf_Ptr errarg,
void
* user_data,
const
char
*isa_name,
const
char
*dwarf_version,
const
char
*extra,
Dwarf_P_Debug *dbg_returned,
Dwarf_Error * error)
{
Dwarf_P_Debug dbg = 0;
int
res = 0;
int
err_ret = 0;
dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL,
sizeof
(
struct
Dwarf_P_Debug_s));
if
(dbg == NULL) {
DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC,
DW_DLV_ERROR);
}
memset
((
void
*) dbg, 0,
sizeof
(
struct
Dwarf_P_Debug_s));
if
(func == NULL) {
DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC,
DW_DLV_ERROR);
}
dbg->de_callback_func = func;
dbg->de_errhand = errhand;
dbg->de_errarg = errarg;
dbg->de_user_data = user_data;
res = common_init(dbg, flags,isa_name,dwarf_version,
extra,&err_ret);
if
(res != DW_DLV_OK) {
DWARF_P_DBG_ERROR(dbg, err_ret, DW_DLV_ERROR);
}
*dbg_returned = dbg;
return
DW_DLV_OK;
}
int
dwarf_pro_set_default_string_form(Dwarf_P_Debug dbg,
int
form,
UNUSEDARG Dwarf_Error * error)
{
if
(form != DW_FORM_string &&
form != DW_FORM_strp) {
_dwarf_p_error(dbg, error, DW_DLE_BAD_STRING_FORM);
return
DW_DLV_ERROR;
}
dbg->de_debug_default_str_form = form;
return
DW_DLV_OK;
}
static
int
set_reloc_numbers(Dwarf_P_Debug dbg,
UNUSEDARG Dwarf_Unsigned flags,
const
char
*abiname)
{
struct
isa_relocs_s *isap = 0;
if
(!abiname) {
return
DW_DLV_NO_ENTRY;
}
for
(isap = &isa_relocs[0]; ;isap++) {
if
(!isap->name_) {
return
DW_DLV_NO_ENTRY;
}
if
(!
strcmp
(abiname,isap->name_)) {
if
(dbg->de_pointer_size == 4) {
dbg->de_ptr_reloc = isap->reloc32_;
}
else
{
dbg->de_ptr_reloc = isap->reloc64_;
}
if
(dbg->de_dwarf_offset_size == 4) {
dbg->de_offset_reloc = isap->reloc32_;
}
else
{
dbg->de_offset_reloc = isap->reloc64_;
}
dbg->de_exc_reloc = isap->segrel_;
return
DW_DLV_OK;
}
}
}
static
DW_TSHASHTYPE
_dwarf_string_hashfunc(
const
char
*str)
{
DW_TSHASHTYPE up = 0;
DW_TSHASHTYPE hash = 5381;
int
c = 0;
while
((c = *str++)) {
hash = hash * 33 + c ;
}
up = hash;
return
up;
}
static
DW_TSHASHTYPE
key_simple_string_hashfunc(
const
void
*keyp)
{
struct
Dwarf_P_debug_str_entry_s* mt =
(
struct
Dwarf_P_debug_str_entry_s*) keyp;
const
char
*str = 0;
if
(mt->dse_has_table_offset) {
str = (
const
char
*)mt->dse_dbg->de_debug_str->ds_data +
mt->dse_table_offset;
}
else
{
str = (
const
char
*)mt->dse_name;
}
return
_dwarf_string_hashfunc(str);
}
static
int
common_init(Dwarf_P_Debug dbg,
Dwarf_Unsigned flags,
const
char
*abiname,
const
char
*dwarf_version,
const
char
*extra,
int
*err_ret)
{
unsigned
int
k = 0;
int
res = 0;
dbg->de_version_magic_number = PRO_VERSION_MAGIC;
dbg->de_n_debug_sect = 0;
dbg->de_debug_sects = &init_sect;
dbg->de_debug_str = &init_sect_debug_str;
dbg->de_debug_line_str = &init_sect_debug_line_str;
dbg->de_current_active_section = &init_sect;
dbg->de_flags = flags;
dbg->de_pointer_size = 4;
dbg->de_dwarf_offset_size = 4;
dbg->de_elf_offset_size = 4;
dbg->de_64bit_extension = 0;
dbg->de_big_endian = (dbg->de_flags&DW_DLC_TARGET_BIGENDIAN)?
TRUE:FALSE;
if
(dbg->de_flags & DW_DLC_POINTER64) {
dbg->de_pointer_size = 8;
}
if
(dbg->de_flags & DW_DLC_OFFSET64) {
dbg->de_pointer_size = 8;
dbg->de_dwarf_offset_size = 4;
dbg->de_64bit_extension = 0;
dbg->de_elf_offset_size = 8;
}
else
{
if
(dbg->de_flags & DW_DLC_IRIX_OFFSET64) {
dbg->de_pointer_size = 8;
dbg->de_big_endian = TRUE;
dbg->de_dwarf_offset_size = 8;
dbg->de_64bit_extension = 0;
dbg->de_elf_offset_size = 8;
}
}
if
(abiname && (!
strcmp
(abiname,
"irix"
))) {
dbg->de_irix_exc_augmentation = 1;
}
else
{
dbg->de_irix_exc_augmentation = 0;
}
res = set_reloc_numbers(dbg,flags,abiname);
if
(res != DW_DLV_OK) {
*err_ret = DW_DLE_BAD_ABINAME;
return
DW_DLV_ERROR;
}
dbg->de_output_version = 2;
if
(dwarf_version) {
if
(!
strcmp
(dwarf_version,
"V2"
)) {
dbg->de_output_version = 2;
}
else
if
(!
strcmp
(dwarf_version,
"V3"
)) {
dbg->de_output_version = 3;
}
else
if
(!
strcmp
(dwarf_version,
"V4"
)) {
dbg->de_output_version = 4;
}
else
if
(!
strcmp
(dwarf_version,
"V5"
)) {
dbg->de_output_version = 5;
}
else
{
*err_ret = DW_DLE_VERSION_STAMP_ERROR;
return
DW_DLV_ERROR;
}
}
_dwarf_init_default_line_header_vals(dbg);
res = _dwarf_log_extra_flagstrings(dbg,extra,err_ret);
if
(res == DW_DLV_ERROR) {
return
res;
}
if
(flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
dbg->de_relocation_record_size =
sizeof
(
struct
Dwarf_Relocation_Data_s);
}
else
{
#ifdef DWARF_WITH_LIBELF
#if HAVE_ELF64_GETEHDR
dbg->de_relocation_record_size =
((dbg->de_pointer_size == 8)?
sizeof
(REL64) :
sizeof
(REL32));
#else
dbg->de_relocation_record_size =
sizeof
(REL32);
#endif
#else /* DWARF_WITH_LIBELF */
*err_ret = DW_DLE_NO_STREAM_RELOC_SUPPORT;
return
DW_DLV_ERROR;
#endif /* DWARF_WITH_LIBELF */
}
dwarf_initialize_search_hash(&dbg->de_debug_str_hashtab,
key_simple_string_hashfunc,0);
dbg->de_debug_default_str_form = DW_FORM_string;
dwarf_initialize_search_hash(&dbg->de_debug_line_str_hashtab,
key_simple_string_hashfunc,0);
if
(dbg->de_dwarf_offset_size == 8) {
if
(dbg->de_output_version <= 3) {
dbg->de_ar_data_attribute_form = DW_FORM_data8;
}
else
{
dbg->de_ar_data_attribute_form = DW_FORM_sec_offset;
}
dbg->de_ar_ref_attr_form = DW_FORM_ref8;
}
else
{
if
(dbg->de_output_version <= 3) {
dbg->de_ar_data_attribute_form = DW_FORM_data4;
}
else
{
dbg->de_ar_data_attribute_form = DW_FORM_sec_offset;
}
dbg->de_ar_ref_attr_form = DW_FORM_ref4;
}
if
(flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
dbg->de_relocate_by_name_symbol =
_dwarf_pro_reloc_name_symbolic;
dbg->de_relocate_pair_by_symbol =
_dwarf_pro_reloc_length_symbolic;
dbg->de_transform_relocs_to_disk =
_dwarf_symbolic_relocs_to_disk;
}
else
{
#ifdef DWARF_WITH_LIBELF
if
(IS_64BITPTR(dbg)) {
dbg->de_relocate_by_name_symbol =
_dwarf_pro_reloc_name_stream64;
}
else
{
dbg->de_relocate_by_name_symbol =
_dwarf_pro_reloc_name_stream32;
}
dbg->de_relocate_pair_by_symbol = 0;
dbg->de_transform_relocs_to_disk = _dwarf_stream_relocs_to_disk;
#else /* DWARF_WITH_LIBELF */
*err_ret = DW_DLE_NO_STREAM_RELOC_SUPPORT;
return
DW_DLV_ERROR;
#endif /* DWARF_WITH_LIBELF */
}
for
(k = 0; k < NUM_DEBUG_SECTIONS; ++k) {
Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[k];
prel->pr_slots_per_block_to_alloc = DEFAULT_SLOTS_PER_BLOCK;
}
dbg->de_same_endian = 1;
dbg->de_copy_word = _dwarf_memcpy_noswap_bytes;
#ifdef WORDS_BIGENDIAN
if
(flags & DW_DLC_TARGET_LITTLEENDIAN) {
dbg->de_same_endian = 0;
dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
}
#else /* little endian */
if
(flags & DW_DLC_TARGET_BIGENDIAN) {
dbg->de_same_endian = 0;
dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
}
#endif /* !WORDS_BIGENDIAN */
return
DW_DLV_OK;
}