#include "config.h"
#include <stdio.h>
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarfstring.h"
#include "dwarf_global.h"
#ifdef __sgi
void
_dwarf_fix_up_offset_irix(Dwarf_Debug dbg,
Dwarf_Unsigned * varp, char *caller_site_name)
{
Dwarf_Unsigned var = *varp;
#define UPPER33 0xffffffff80000000LL
#define LOWER32 0xffffffffLL
if ((var & UPPER33) == UPPER33) {
var &= LOWER32;
*varp = var;
}
#undef UPPER33
#undef LOWER32
return;
}
#endif
static void
dealloc_globals_chain(Dwarf_Debug dbg,
Dwarf_Chain head_chain)
{
Dwarf_Chain curr_chain = 0;
Dwarf_Chain prev_chain = 0;
int chaintype = DW_DLA_CHAIN;
curr_chain = head_chain;
for (; curr_chain; ) {
void *item = curr_chain->ch_item;
int itemtype = curr_chain->ch_itemtype;
prev_chain = curr_chain;
dwarf_dealloc(dbg, item,itemtype);
prev_chain->ch_item = 0;
curr_chain = curr_chain->ch_next;
dwarf_dealloc(dbg, prev_chain, chaintype);
}
}
int
dwarf_get_globals(Dwarf_Debug dbg,
Dwarf_Global ** globals,
Dwarf_Signed * return_count, Dwarf_Error * error)
{
int res = _dwarf_load_section(dbg, &dbg->de_debug_pubnames,error);
if (res != DW_DLV_OK) {
return res;
}
if (!dbg->de_debug_pubnames.dss_size) {
return DW_DLV_NO_ENTRY;
}
res = _dwarf_internal_get_pubnames_like_data(dbg,
dbg->de_debug_pubnames.dss_data,
dbg->de_debug_pubnames.dss_size,
globals,
return_count,
error,
DW_DLA_GLOBAL_CONTEXT,
DW_DLA_GLOBAL,
DW_DLE_PUBNAMES_LENGTH_BAD,
DW_DLE_PUBNAMES_VERSION_ERROR);
return res;
}
void
dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
Dwarf_Signed count)
{
_dwarf_internal_globals_dealloc(dbg, dwgl,
count,
DW_DLA_GLOBAL_CONTEXT,
DW_DLA_GLOBAL, DW_DLA_LIST);
return;
}
void
_dwarf_internal_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
Dwarf_Signed count,
int context_DLA_code,
int global_DLA_code, int list_DLA_code)
{
Dwarf_Signed i;
struct Dwarf_Global_Context_s *glcp = 0;
struct Dwarf_Global_Context_s *lastglcp = 0;
if(!dwgl) {
return;
}
for (i = 0; i < count; i++) {
Dwarf_Global dgb = dwgl[i];
if (!dgb) {
continue;
}
glcp = dgb->gl_context;
if (lastglcp != glcp) {
lastglcp = glcp;
dwarf_dealloc(dbg, glcp, context_DLA_code);
}
dwarf_dealloc(dbg, dgb, global_DLA_code);
}
dwarf_dealloc(dbg, dwgl, list_DLA_code);
return;
}
int
_dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
Dwarf_Small * section_data_ptr,
Dwarf_Unsigned section_length,
Dwarf_Global ** globals,
Dwarf_Signed * return_count,
Dwarf_Error * error,
int context_DLA_code,
int global_DLA_code,
int length_err_num,
int version_err_num)
{
Dwarf_Small *pubnames_like_ptr = 0;
Dwarf_Off pubnames_section_offset = 0;
Dwarf_Small *section_end_ptr = section_data_ptr +section_length;
Dwarf_Global_Context pubnames_context = 0;
Dwarf_Unsigned version = 0;
Dwarf_Off die_offset_in_cu = 0;
Dwarf_Unsigned global_count = 0;
Dwarf_Global global = 0;
Dwarf_Chain curr_chain = 0;
Dwarf_Chain prev_chain = 0;
Dwarf_Chain head_chain = 0;
Dwarf_Global *ret_globals = 0;
int mres = 0;
Dwarf_Unsigned i = 0;
if (dbg == NULL) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
return (DW_DLV_ERROR);
}
if (!dbg->de_debug_info.dss_data) {
int res = _dwarf_load_debug_info(dbg, error);
if (res != DW_DLV_OK) {
return res;
}
}
if (section_data_ptr == NULL) {
return (DW_DLV_NO_ENTRY);
}
pubnames_like_ptr = section_data_ptr;
do {
Dwarf_Unsigned length = 0;
int local_extension_size = 0;
int local_length_size = 0;
Dwarf_Small *pubnames_ptr_past_end_cu = 0;
pubnames_context = (Dwarf_Global_Context)
_dwarf_get_alloc(dbg, context_DLA_code, 1);
if (pubnames_context == NULL) {
dealloc_globals_chain(dbg,head_chain);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
mres = _dwarf_read_area_length_ck_wrapper(dbg,
&length,&pubnames_like_ptr,&local_length_size,
&local_extension_size,section_length,section_end_ptr,
error);
if (mres != DW_DLV_OK) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return mres;
}
pubnames_context->pu_length_size = local_length_size;
pubnames_context->pu_length = length;
pubnames_context->pu_extension_size = local_extension_size;
pubnames_context->pu_dbg = dbg;
pubnames_context->pu_pub_offset = pubnames_section_offset;
pubnames_ptr_past_end_cu = pubnames_like_ptr + length;
mres = _dwarf_read_unaligned_ck_wrapper(dbg,
&version,pubnames_like_ptr,DWARF_HALF_SIZE,
section_end_ptr,error);
if (mres != DW_DLV_OK) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return mres;
}
pubnames_context->pu_version = version;
pubnames_like_ptr += DWARF_HALF_SIZE;
if (version != DW_PUBNAMES_VERSION2) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, version_err_num);
return DW_DLV_ERROR;
}
mres = _dwarf_read_unaligned_ck_wrapper(dbg,
&pubnames_context->pu_offset_of_cu_header,
pubnames_like_ptr,
pubnames_context->pu_length_size,
section_end_ptr,error);
if (mres != DW_DLV_OK) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return mres;
}
pubnames_like_ptr += pubnames_context->pu_length_size;
FIX_UP_OFFSET_IRIX_BUG(dbg,
pubnames_context->pu_offset_of_cu_header,
"pubnames cu header offset");
mres = _dwarf_read_unaligned_ck_wrapper(dbg,
&pubnames_context->pu_info_length,
pubnames_like_ptr,
pubnames_context->pu_length_size,
section_end_ptr,error);
if (mres != DW_DLV_OK) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return mres;
}
pubnames_like_ptr += pubnames_context->pu_length_size;
if (pubnames_like_ptr > (section_data_ptr + section_length)) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, length_err_num);
return (DW_DLV_ERROR);
}
mres = _dwarf_read_unaligned_ck_wrapper(dbg,
&die_offset_in_cu,
pubnames_like_ptr,
pubnames_context->pu_length_size,
section_end_ptr,error);
if (mres != DW_DLV_OK) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return mres;
}
pubnames_like_ptr += pubnames_context->pu_length_size;
FIX_UP_OFFSET_IRIX_BUG(dbg,
die_offset_in_cu, "offset of die in cu");
if (pubnames_like_ptr > (section_data_ptr + section_length)) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, length_err_num);
return DW_DLV_ERROR;
}
if (dbg->de_return_empty_pubnames && die_offset_in_cu == 0) {
global =
(Dwarf_Global) _dwarf_get_alloc(dbg, global_DLA_code, 1);
if (global == NULL) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
global_count++;
global->gl_context = pubnames_context;
global->gl_named_die_offset_within_cu = 0;
global->gl_name = (Dwarf_Small *)"";
curr_chain =
(Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (curr_chain == NULL) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
curr_chain->ch_itemtype = global_DLA_code;
curr_chain->ch_item = (Dwarf_Global) global;
if (head_chain == NULL)
head_chain = prev_chain = curr_chain;
else {
prev_chain->ch_next = curr_chain;
prev_chain = curr_chain;
}
} else if (!die_offset_in_cu) {
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
pubnames_context = 0;
continue;
}
while (die_offset_in_cu) {
int res = 0;
global =
(Dwarf_Global) _dwarf_get_alloc(dbg, global_DLA_code, 1);
if (global == NULL) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
global_count++;
global->gl_context = pubnames_context;
global->gl_named_die_offset_within_cu = die_offset_in_cu;
global->gl_name = pubnames_like_ptr;
res = _dwarf_check_string_valid(dbg,section_data_ptr,
pubnames_like_ptr,section_end_ptr,
DW_DLE_STRING_OFF_END_PUBNAMES_LIKE,error);
if (res != DW_DLV_OK) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return res;
}
pubnames_like_ptr = pubnames_like_ptr +
strlen((char *) pubnames_like_ptr) + 1;
curr_chain =
(Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
if (curr_chain == NULL) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return (DW_DLV_ERROR);
}
curr_chain->ch_item = (Dwarf_Global) global;
curr_chain->ch_itemtype = global_DLA_code;
if (head_chain == NULL)
head_chain = prev_chain = curr_chain;
else {
prev_chain->ch_next = curr_chain;
prev_chain = curr_chain;
}
mres = _dwarf_read_unaligned_ck_wrapper(dbg,
&die_offset_in_cu,
pubnames_like_ptr,
pubnames_context->pu_length_size,
section_end_ptr,error);
if (mres != DW_DLV_OK) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return mres;
}
pubnames_like_ptr += pubnames_context->pu_length_size;
FIX_UP_OFFSET_IRIX_BUG(dbg,
die_offset_in_cu, "offset of next die in cu");
if (pubnames_like_ptr > (section_data_ptr + section_length)) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, length_err_num);
return DW_DLV_ERROR;
}
}
if (pubnames_like_ptr > pubnames_ptr_past_end_cu) {
_dwarf_error(dbg, error, length_err_num);
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
return DW_DLV_ERROR;
}
{
Dwarf_Unsigned increment =
pubnames_context->pu_length_size +
pubnames_context->pu_length +
pubnames_context->pu_extension_size;
pubnames_section_offset += increment;
}
pubnames_like_ptr = pubnames_ptr_past_end_cu;
} while (pubnames_like_ptr < section_end_ptr);
ret_globals = (Dwarf_Global *)
_dwarf_get_alloc(dbg, DW_DLA_LIST, global_count);
if (ret_globals == NULL) {
dealloc_globals_chain(dbg,head_chain);
dwarf_dealloc(dbg,pubnames_context,context_DLA_code);
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
return DW_DLV_ERROR;
}
curr_chain = head_chain;
for (i = 0; i < global_count; i++) {
*(ret_globals + i) = curr_chain->ch_item;
prev_chain = curr_chain;
curr_chain = curr_chain->ch_next;
prev_chain->ch_item = 0;
dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
}
*globals = ret_globals;
*return_count = (Dwarf_Signed) global_count;
return DW_DLV_OK;
}
int
dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error)
{
if (glob == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
return (DW_DLV_ERROR);
}
*ret_name = (char *) (glob->gl_name);
return DW_DLV_OK;
}
int
dwarf_global_die_offset(Dwarf_Global global,
Dwarf_Off * ret_off, Dwarf_Error * error)
{
if (global == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
return (DW_DLV_ERROR);
}
if (global->gl_context == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
return (DW_DLV_ERROR);
}
*ret_off = (global->gl_named_die_offset_within_cu +
global->gl_context->pu_offset_of_cu_header);
return DW_DLV_OK;
}
int
dwarf_global_cu_offset(Dwarf_Global global,
Dwarf_Off * cu_header_offset,
Dwarf_Error * error)
{
Dwarf_Global_Context con = 0;
if (global == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
return (DW_DLV_ERROR);
}
con = global->gl_context;
if (con == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
return (DW_DLV_ERROR);
}
*cu_header_offset = con->pu_offset_of_cu_header;
return DW_DLV_OK;
}
static void
build_off_end_msg(Dwarf_Unsigned offval,
Dwarf_Unsigned withincr,
Dwarf_Unsigned secsize,
dwarfstring *m)
{
const char *msg = "past";
if (offval < secsize){
msg = "too near";
}
dwarfstring_append_printf_u(m,"DW_DLE_OFFSET_BAD: "
"The CU header offset of %u in a pubnames-like entry ",
withincr);
dwarfstring_append_printf_s(m,
"would put us %s the end of .debug_info. "
"No room for a DIE there... "
"Corrupt Dwarf.",(char *)msg);
return;
}
int
dwarf_global_name_offsets(Dwarf_Global global,
char **ret_name,
Dwarf_Off * die_offset,
Dwarf_Off * cu_die_offset,
Dwarf_Error * error)
{
Dwarf_Global_Context con = 0;
Dwarf_Debug dbg = 0;
Dwarf_Off cuhdr_off = 0;
if (global == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
return (DW_DLV_ERROR);
}
con = global->gl_context;
if (con == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
return (DW_DLV_ERROR);
}
cuhdr_off = con->pu_offset_of_cu_header;
#define MIN_CU_HDR_SIZE 10
dbg = con->pu_dbg;
if (dbg == NULL) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
return (DW_DLV_ERROR);
}
if (dbg->de_debug_info.dss_size &&
((cuhdr_off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) {
dwarfstring m;
dwarfstring_constructor(&m);
build_off_end_msg(cuhdr_off,cuhdr_off+MIN_CU_HDR_SIZE,
dbg->de_debug_info.dss_size,&m);
_dwarf_error_string(dbg, error, DW_DLE_OFFSET_BAD,
dwarfstring_string(&m));
dwarfstring_destructor(&m);
return (DW_DLV_ERROR);
}
#undef MIN_CU_HDR_SIZE
if (die_offset) {
if(global->gl_named_die_offset_within_cu) {
*die_offset = global->gl_named_die_offset_within_cu + cuhdr_off;
} else {
*die_offset = 0;
}
}
*ret_name = (char *) global->gl_name;
if (cu_die_offset) {
int cres = 0;
Dwarf_Unsigned headerlen = 0;
int res = _dwarf_load_debug_info(dbg, error);
if (res != DW_DLV_OK) {
return res;
}
if ((cuhdr_off + 10) >= dbg->de_debug_info.dss_size) {
dwarfstring m;
dwarfstring_constructor(&m);
build_off_end_msg(cuhdr_off,cuhdr_off+10,
dbg->de_debug_info.dss_size,&m);
_dwarf_error_string(dbg, error, DW_DLE_OFFSET_BAD,
dwarfstring_string(&m));
dwarfstring_destructor(&m);
return (DW_DLV_ERROR);
}
cres = _dwarf_length_of_cu_header(dbg, cuhdr_off,true,
&headerlen,error);
if(cres != DW_DLV_OK) {
return cres;
}
*cu_die_offset = cuhdr_off + headerlen;
}
return DW_DLV_OK;
}
int
dwarf_get_globals_header(Dwarf_Global global,
Dwarf_Off *pub_section_hdr_offset,
Dwarf_Unsigned *pub_offset_size,
Dwarf_Unsigned *pub_cu_length,
Dwarf_Unsigned *version,
Dwarf_Off *info_header_offset,
Dwarf_Unsigned *info_length,
Dwarf_Error* error)
{
Dwarf_Global_Context con = 0;
Dwarf_Debug dbg = 0;
if (global == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
return DW_DLV_ERROR;
}
con = global->gl_context;
if (con == NULL) {
_dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
return DW_DLV_ERROR;
}
dbg = con->pu_dbg;
if (dbg == NULL) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
return DW_DLV_ERROR;
}
if(pub_section_hdr_offset) {
*pub_section_hdr_offset = con->pu_pub_offset;
}
if (pub_offset_size) {
*pub_offset_size = con->pu_length_size;
}
if (pub_cu_length) {
*pub_cu_length = con->pu_length;
}
if (version) {
*version = con->pu_version;
}
if(info_header_offset) {
*info_header_offset = con->pu_offset_of_cu_header;
}
if (info_length) {
*info_length = con->pu_info_length;
}
return DW_DLV_OK;
}
int
dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
Dwarf_Off in_cu_header_offset,
Dwarf_Off * out_cu_die_offset,
UNUSEDARG Dwarf_Error * err)
{
Dwarf_Off headerlen = 0;
int cres = 0;
cres = _dwarf_length_of_cu_header(dbg, in_cu_header_offset,true,
&headerlen,err);
if (cres != DW_DLV_OK) {
return cres;
}
*out_cu_die_offset = in_cu_header_offset + headerlen;
return DW_DLV_OK;
}
int
dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug dbg,
Dwarf_Off in_cu_header_offset,
Dwarf_Bool is_info,
Dwarf_Off * out_cu_die_offset,
UNUSEDARG Dwarf_Error * err)
{
Dwarf_Off headerlen = 0;
int cres = 0;
cres = _dwarf_length_of_cu_header(dbg, in_cu_header_offset,is_info,
&headerlen,err);
if (cres != DW_DLV_OK) {
return cres;
}
*out_cu_die_offset = in_cu_header_offset + headerlen;
return DW_DLV_OK;
}
int
dwarf_CU_dieoffset_given_die(Dwarf_Die die,
Dwarf_Off* return_offset,
Dwarf_Error* error)
{
Dwarf_Off dieoff = 0;
Dwarf_CU_Context cucontext = 0;
CHECK_DIE(die, DW_DLV_ERROR);
cucontext = die->di_cu_context;
dieoff = cucontext->cc_debug_offset;
dwarf_get_cu_die_offset_given_cu_header_offset_b(
cucontext->cc_dbg, dieoff,
die->di_is_info, return_offset,error);
return DW_DLV_OK;
}
int dwarf_return_empty_pubnames(Dwarf_Debug dbg,
int flag, UNUSEDARG Dwarf_Error *err )
{
if (dbg == NULL) {
return DW_DLV_OK;
}
if (flag && flag != 1) {
return DW_DLV_OK;
}
dbg->de_return_empty_pubnames = (unsigned char)flag;
return DW_DLV_OK;
}