/* Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. Portions Copyright (C) 2007-2018 David Anderson. All Rights Reserved. Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2.1 of the GNU Lesser General Public License as published by the Free Software Foundation. This program is distributed in the hope that it would be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, this software is distributed without any warranty that it is free of the rightful claim of any third person regarding infringement or the like. Any license provided herein, whether implied or otherwise, applies only to this software file. Patent licenses, if any, provided herein do not apply to combinations of this program with other software, or any other product whatsoever. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, USA. */ #include #include /* memset() */ #if defined(_WIN32) && defined(HAVE_STDAFX_H) #include "stdafx.h" #endif /* HAVE_STDAFX_H */ #include "dwarf.h" #include "libdwarf.h" #include "libdwarf_private.h" #include "dwarf_base_types.h" #include "dwarf_opaque.h" #include "dwarf_alloc.h" #include "dwarf_error.h" #include "dwarf_util.h" #include "dwarf_loc.h" #include "dwarf_string.h" static int _dwarf_read_loc_section_dwo(Dwarf_Debug dbg, Dwarf_Block_c * return_block, Dwarf_Addr * lowpc, Dwarf_Addr * highpc, Dwarf_Bool * at_end, Dwarf_Half * lle_op, Dwarf_Off sec_offset, Dwarf_Half address_size, Dwarf_Half lkind, Dwarf_Error *error); /* Used to enable sanity checking of these data items before we return to caller. */ int _dwarf_locdesc_c_constructor(Dwarf_Debug dbg, void *locd) { Dwarf_Locdesc_c ldp = (Dwarf_Locdesc_c)locd; if (!dbg) { return DW_DLV_ERROR; } ldp->ld_lle_value = DW_LLE_VALUE_BOGUS; ldp->ld_kind = DW_LKIND_unknown; return DW_DLV_OK; } static void _dwarf_lkind_name(unsigned lkind, dwarfstring *m) { switch(lkind) { case DW_LKIND_expression: dwarfstring_append(m,"DW_LKIND_expression"); return; case DW_LKIND_loclist: dwarfstring_append(m,"DW_LKIND_loclist"); return; case DW_LKIND_GNU_exp_list: dwarfstring_append(m,"DW_LKIND_GNU_exp_list"); return; case DW_LKIND_loclists: dwarfstring_append(m,"DW_LKIND_loclists"); return; case DW_LKIND_unknown: dwarfstring_append(m,"DW_LKIND_unknown"); return; default: break; } dwarfstring_append_printf_u(m, ".", lkind); } static int determine_location_lkind(unsigned int version, unsigned int form, Dwarf_Bool is_dwo) { switch(form) { case DW_FORM_exprloc: /* only defined for DW_CFA_def_cfa_expression */ case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: return DW_LKIND_expression; break; case DW_FORM_data4: case DW_FORM_data8: if (version > 1 && version < 4) { return DW_LKIND_loclist; } break; case DW_FORM_sec_offset: if (version == 5 ) { return DW_LKIND_loclists; } if (version == 4 && is_dwo ) { return DW_LKIND_GNU_exp_list; } return DW_LKIND_loclist; break; case DW_FORM_loclistx: if (version == 5 ) { return DW_LKIND_loclists; } break; default: break; } return DW_LKIND_unknown; } static void _dwarf_free_op_chain(Dwarf_Debug dbg, Dwarf_Loc_Chain headloc) { Dwarf_Loc_Chain cur = headloc; while (cur) { Dwarf_Loc_Chain next = cur->lc_next; dwarf_dealloc(dbg, cur, DW_DLA_LOC_CHAIN); cur = next; } } /* Using a loclist offset to get the in-memory address of .debug_loc data to read, returns the loclist 'header' info in return_block. */ #define MAX_ADDR \ ((address_size == 8)?0xffffffffffffffffULL:0xffffffff) static int _dwarf_read_loc_section(Dwarf_Debug dbg, Dwarf_Block_c * return_block, Dwarf_Addr * lowpc, Dwarf_Addr * hipc, Dwarf_Half * lle_val, Dwarf_Off sec_offset, Dwarf_Half address_size, Dwarf_Error * error) { Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset; Dwarf_Small *loc_section_end = dbg->de_debug_loc.dss_data + dbg->de_debug_loc.dss_size; /* start_addr and end_addr are actually offsets of the applicable base address of the CU. They are address-size. */ Dwarf_Addr start_addr = 0; Dwarf_Addr end_addr = 0; Dwarf_Half exprblock_size = 0; Dwarf_Unsigned exprblock_off = 2 * address_size + DWARF_HALF_SIZE; if (sec_offset >= dbg->de_debug_loc.dss_size) { /* We're at the end. No more present. */ return DW_DLV_NO_ENTRY; } /* If it goes past end, error */ if (exprblock_off > dbg->de_debug_loc.dss_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); return DW_DLV_ERROR; } READ_UNALIGNED_CK(dbg, start_addr, Dwarf_Addr, beg, address_size, error,loc_section_end); READ_UNALIGNED_CK(dbg, end_addr, Dwarf_Addr, beg + address_size, address_size, error,loc_section_end); if (start_addr == 0 && end_addr == 0) { /* If start_addr and end_addr are 0, it's the end and no exprblock_size field follows. */ exprblock_size = 0; exprblock_off -= DWARF_HALF_SIZE; *lle_val = DW_LLE_end_of_list; } else if (start_addr == MAX_ADDR) { /* End address is a base address, no exprblock_size field here either */ exprblock_size = 0; exprblock_off -= DWARF_HALF_SIZE; *lle_val = DW_LLE_base_address; } else { /* Here we note the address and length of the expression operators, DW_OP_reg0 etc */ READ_UNALIGNED_CK(dbg, exprblock_size, Dwarf_Half, beg + 2 * address_size, DWARF_HALF_SIZE, error,loc_section_end); /* exprblock_size can be zero, means no expression */ if ( exprblock_size >= dbg->de_debug_loc.dss_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); return DW_DLV_ERROR; } if ((sec_offset +exprblock_off + exprblock_size) > dbg->de_debug_loc.dss_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); return DW_DLV_ERROR; } *lle_val = DW_LLE_start_end; } *lowpc = start_addr; *hipc = end_addr; return_block->bl_len = exprblock_size; return_block->bl_kind = DW_LKIND_loclist; return_block->bl_data = beg + exprblock_off; return_block->bl_section_offset = ((Dwarf_Small *) return_block->bl_data) - dbg->de_debug_loc.dss_data; return DW_DLV_OK; } static int _dwarf_get_loclist_lle_count_dwo(Dwarf_Debug dbg, Dwarf_Off loclist_offset, Dwarf_Half address_size, Dwarf_Half lkind, int *loclist_count, Dwarf_Error * error) { int count = 0; Dwarf_Off offset = loclist_offset; for (;;) { Dwarf_Block_c b; Dwarf_Bool at_end = FALSE; Dwarf_Addr lowpc = 0; Dwarf_Addr highpc = 0; Dwarf_Half lle_op = 0; int res = _dwarf_read_loc_section_dwo(dbg, &b, &lowpc, &highpc, &at_end, &lle_op, offset, address_size, lkind, error); if (res != DW_DLV_OK) { return res; } if (at_end) { count++; break; } offset = b.bl_len + b.bl_section_offset; count++; } *loclist_count = count; return DW_DLV_OK; } static int _dwarf_get_loclist_lle_count(Dwarf_Debug dbg, Dwarf_Off loclist_offset, Dwarf_Half address_size, int *loclist_count, Dwarf_Error * error) { int count = 0; Dwarf_Off offset = loclist_offset; for (;;) { Dwarf_Block_c b; Dwarf_Addr lowpc = 0; Dwarf_Addr highpc = 0; Dwarf_Half lle_val = DW_LLE_VALUE_BOGUS; int res = _dwarf_read_loc_section(dbg, &b, &lowpc, &highpc, &lle_val, offset, address_size,error); if (res != DW_DLV_OK) { return res; } offset = b.bl_len + b.bl_section_offset; if (lowpc == 0 && highpc == 0) { break; } count++; } *loclist_count = count; return DW_DLV_OK; } /* Helper routine to avoid code duplication. */ static int _dwarf_setup_loc(Dwarf_Attribute attr, Dwarf_Debug * dbg_ret, Dwarf_CU_Context *cucontext_ret, Dwarf_Half *form_ret, Dwarf_Error *error) { Dwarf_Debug dbg = 0; Dwarf_Half form = 0; int blkres = DW_DLV_ERROR; /* Creating an error with NULL dbg is not a good thing. These won't be freed if we later call dealloc with a non-NULL dbg. */ if (!attr) { _dwarf_error_string(NULL, error, DW_DLE_ATTR_NULL, "DW_DLE_ATTR_NULL: the attribute passed to " "dwarf_get_loclist_c() is a NULL pointer"); return DW_DLV_ERROR; } if (attr->ar_cu_context == NULL) { _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); return DW_DLV_ERROR; } *cucontext_ret = attr->ar_cu_context; dbg = attr->ar_cu_context->cc_dbg; if (!dbg || dbg->de_magic != DBG_IS_VALID) { _dwarf_error_string(NULL, error, DW_DLE_ATTR_DBG_NULL, "DW_DLE_ATTR_DBG_NULL The Attribute passed to " "dwarf_get_loclist_c() " "points to an invalid Dwarf_Debug"); return DW_DLV_ERROR; } *dbg_ret = dbg; blkres = dwarf_whatform(attr, &form, error); if (blkres != DW_DLV_OK) { return blkres; } *form_ret = form; return DW_DLV_OK; } /* Helper routine to avoid code duplication. */ static int _dwarf_get_loclist_header_start(Dwarf_Debug dbg, Dwarf_Attribute attr, Dwarf_Unsigned * loclist_offset_out, Dwarf_Error * error) { Dwarf_Unsigned loc_sec_size = 0; Dwarf_Unsigned loclist_offset = 0; int blkres = dwarf_global_formref(attr, &loclist_offset, error); if (blkres != DW_DLV_OK) { return blkres; } if (!dbg->de_debug_loc.dss_data) { int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error); if (secload != DW_DLV_OK) { return secload; } if (!dbg->de_debug_loc.dss_size) { return DW_DLV_NO_ENTRY; } } loc_sec_size = dbg->de_debug_loc.dss_size; if (loclist_offset >= loc_sec_size) { _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD); return DW_DLV_ERROR; } { int fisres = 0; Dwarf_Unsigned fissoff = 0; Dwarf_Unsigned size = 0; fisres = _dwarf_get_fission_addition_die(attr->ar_die, DW_SECT_LOCLISTS, &fissoff, &size,error); if (fisres != DW_DLV_OK) { return fisres; } if (fissoff >= loc_sec_size) { _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD); return DW_DLV_ERROR; } loclist_offset += fissoff; if (loclist_offset >= loc_sec_size) { _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD); return DW_DLV_ERROR; } } *loclist_offset_out = loclist_offset; return DW_DLV_OK; } static int context_is_cu_not_tu(Dwarf_CU_Context context, Dwarf_Bool *r) { int ut = context->cc_unit_type; if (ut == DW_UT_type || ut == DW_UT_split_type ) { *r =FALSE; return DW_DLV_OK; } *r = TRUE; return DW_DLV_OK; } /* Handles only a location expression. It returns the location expression as a loclist with a single entry. Usable to access dwarf expressions from any source, but specifically from DW_CFA_def_cfa_expression DW_CFA_expression DW_CFA_val_expression expression_in must point to a valid dwarf expression */ /* ============== the October 2015 interfaces. */ int _dwarf_loc_block_sanity_check(Dwarf_Debug dbg, Dwarf_Block_c *loc_block,Dwarf_Error* error) { unsigned lkind = loc_block->bl_kind; if (lkind == DW_LKIND_loclist) { Dwarf_Small *loc_ptr = 0; Dwarf_Unsigned loc_len = 0; Dwarf_Small *end_ptr = 0; loc_ptr = loc_block->bl_data; loc_len = loc_block->bl_len; end_ptr = dbg->de_debug_loc.dss_size + dbg->de_debug_loc.dss_data; if ((loc_ptr +loc_len) > end_ptr) { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append(&m, "DW_DLE_DEBUG_LOC_SECTION_SHORT kind: "); _dwarf_lkind_name(lkind, &m); _dwarf_error_string(dbg,error, DW_DLE_DEBUG_LOC_SECTION_SHORT, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } return DW_DLV_OK; } if (lkind == DW_LKIND_loclists) { Dwarf_Small *loc_ptr = 0; Dwarf_Unsigned loc_len = 0; Dwarf_Small *end_ptr = 0; loc_ptr = loc_block->bl_data; loc_len = loc_block->bl_len; end_ptr = dbg->de_debug_loclists.dss_size + dbg->de_debug_loclists.dss_data; if ((loc_ptr +loc_len) > end_ptr) { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append(&m, "DW_DLE_DEBUG_LOC_SECTION_SHORT " "(the .debug_loclists section is short), kind: "); _dwarf_lkind_name(lkind, &m); _dwarf_error_string(dbg,error, DW_DLE_DEBUG_LOC_SECTION_SHORT, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } } return DW_DLV_OK; } /* ld_kind was checked before calling this, so we know its value is an intended value. */ static const char *kindset[] = { "DW_LKIND_expression", "DW_LKIND_loclist", "DW_LKIND_GNU_exp_list", "DW_LKIND_unknown3", "DW_LKIND_unknown4", "DW_LKIND_loclists" }; static const char * get_loc_kind_str(Dwarf_Small lkind) { if (lkind <= DW_LKIND_loclists) { return kindset[lkind]; } if (lkind == DW_LKIND_unknown) { return "DW_LKIND_unknown"; } return "UNKNOWN DW_LKIND!"; } static int validate_lle_value(Dwarf_Debug dbg, Dwarf_Locdesc_c locdesc, Dwarf_Error *error) { dwarfstring m; if (locdesc->ld_kind != DW_LKIND_GNU_exp_list) { switch(locdesc->ld_lle_value) { case DW_LLE_end_of_list: case DW_LLE_base_addressx: case DW_LLE_startx_endx: case DW_LLE_startx_length: case DW_LLE_offset_pair: case DW_LLE_default_location: case DW_LLE_base_address: case DW_LLE_start_end: case DW_LLE_start_length: return DW_DLV_OK; default: break; } dwarfstring_constructor(&m); dwarfstring_append_printf_s(&m, "DW_DLE_LOCATION_ERROR: For location kind %s (", (char *)get_loc_kind_str(locdesc->ld_kind)); dwarfstring_append_printf_u(&m,"%u) the DW_LLE value is " "not properly set", locdesc->ld_kind); dwarfstring_append_printf_u(&m," but is %u " " which is a libdwarf bug", locdesc->ld_lle_value); _dwarf_error_string(dbg,error,DW_DLE_LOCATION_ERROR, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } switch(locdesc->ld_lle_value) { case DW_LLEX_end_of_list_entry: case DW_LLEX_base_address_selection_entry: case DW_LLEX_start_end_entry: case DW_LLEX_start_length_entry: case DW_LLEX_offset_pair_entry: return DW_DLV_OK; default: break; /* ERROR */ } { dwarfstring_constructor(&m); dwarfstring_append_printf_s(&m, "DW_DLE_LOCATION_ERROR: For location kind %s (", (char *)get_loc_kind_str(locdesc->ld_kind)); dwarfstring_append_printf_u(&m,"%u) the DW_LLEX value is " "not properly set", locdesc->ld_kind); dwarfstring_append_printf_u(&m," but is %u " " which is a libdwarf bug", locdesc->ld_lle_value); _dwarf_error_string(dbg,error,DW_DLE_LOCATION_ERROR, dwarfstring_string(&m)); dwarfstring_destructor(&m); } return DW_DLV_ERROR; } /* Sets locdesc operator list information in locdesc. Sets the locdesc values (rawlow, rawhigh etc). This synthesizes the ld_lle_value of the locdesc if it's not already provided. Not passing in locdesc pointer, the locdesc_index suffices to index to the relevant locdesc pointer. See also dwarf_loclists.c: build_array_of_lle*/ int _dwarf_fill_in_locdesc_op_c(Dwarf_Debug dbg, Dwarf_Unsigned locdesc_index, Dwarf_Loc_Head_c loc_head, Dwarf_Block_c * loc_block, Dwarf_Half address_size, Dwarf_Half offset_size, Dwarf_Small version_stamp, Dwarf_Addr lowpc, Dwarf_Addr highpc, Dwarf_Half lle_op, Dwarf_Error * error) { /* Offset of current operator from start of block. */ Dwarf_Unsigned offset = 0; /* Chain the DW_OPerator structs. */ Dwarf_Loc_Chain new_loc = NULL; Dwarf_Loc_Chain prev_loc = NULL; Dwarf_Loc_Chain head_loc = NULL; Dwarf_Loc_Chain *plast = &head_loc; Dwarf_Unsigned op_count = 0; /* Contiguous block of Dwarf_Loc_Expr_Op_s for Dwarf_Locdesc. */ Dwarf_Loc_Expr_Op block_loc = 0; Dwarf_Locdesc_c locdesc = loc_head->ll_locdesc + locdesc_index; Dwarf_Unsigned i = 0; int res = 0; Dwarf_Small *section_start = 0; Dwarf_Unsigned section_size = 0; Dwarf_Small *section_end = 0; const char *section_name = 0; Dwarf_Small *blockdataptr = 0; unsigned lkind = loc_head->ll_kind; /* ***** BEGIN CODE ***** */ blockdataptr = loc_block->bl_data; if (!blockdataptr || !loc_block->bl_len) { /* an empty block has no operations so no section or tests need be done.. */ } else { res = _dwarf_what_section_are_we(dbg, blockdataptr,§ion_name,§ion_start, §ion_size,§ion_end); if (res != DW_DLV_OK) { _dwarf_error(dbg, error,DW_DLE_POINTER_SECTION_UNKNOWN); return DW_DLV_ERROR; } res = _dwarf_loc_block_sanity_check(dbg,loc_block,error); if (res != DW_DLV_OK) { return res; } } /* New loop getting Loc operators. Non DWO */ while (offset <= loc_block->bl_len) { Dwarf_Unsigned nextoffset = 0; struct Dwarf_Loc_Expr_Op_s temp_loc; /* This call is ok even if bl_data NULL and bl_len 0 */ res = _dwarf_read_loc_expr_op(dbg,loc_block, op_count, version_stamp, offset_size, address_size, offset, section_end, &nextoffset, &temp_loc, error); if (res == DW_DLV_ERROR) { _dwarf_free_op_chain(dbg,head_loc); return res; } if (res == DW_DLV_NO_ENTRY) { /* Normal end. Also the end for an empty loc_block. */ break; } op_count++; new_loc = (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN, 1); if (new_loc == NULL) { _dwarf_free_op_chain(dbg,head_loc); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return DW_DLV_ERROR; } /* Copying all the fields. DWARF 2,3,4,5. */ new_loc->lc_atom = temp_loc.lr_atom; new_loc->lc_opnumber= temp_loc.lr_opnumber; new_loc->lc_number = temp_loc.lr_number; new_loc->lc_number2 = temp_loc.lr_number2; new_loc->lc_number3 = temp_loc.lr_number3; new_loc->lc_offset = temp_loc.lr_offset; *plast = new_loc; plast= &(new_loc->lc_next); offset = nextoffset; } block_loc = (Dwarf_Loc_Expr_Op ) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK_C, op_count); new_loc = head_loc; if (!block_loc) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); for (i = 0; i < op_count; i++) { prev_loc = new_loc; new_loc = prev_loc->lc_next; dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN); } return DW_DLV_ERROR; } /* op_count could be zero. */ new_loc = head_loc; for (i = 0; i < op_count; i++) { /* Copying only the fields needed by DWARF 2,3,4 */ (block_loc + i)->lr_atom = new_loc->lc_atom; (block_loc + i)->lr_number = new_loc->lc_number; (block_loc + i)->lr_number2 = new_loc->lc_number2; (block_loc + i)->lr_number3 = new_loc->lc_number3; (block_loc + i)->lr_offset = new_loc->lc_offset; (block_loc + i)->lr_opnumber = new_loc->lc_opnumber; prev_loc = new_loc; new_loc = prev_loc->lc_next; dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN); } /* Synthesizing the DW_LLE values for the old loclist versions. */ switch(loc_head->ll_kind) { case DW_LKIND_loclist: { if (highpc == 0 && lowpc == 0) { locdesc->ld_lle_value = DW_LLE_end_of_list; } else if (lowpc == MAX_ADDR) { locdesc->ld_lle_value = DW_LLE_base_address; } else { locdesc->ld_lle_value = DW_LLE_offset_pair; } } break; case DW_LKIND_GNU_exp_list: /* DW_LKIND_GNU_exp_list */ locdesc->ld_lle_value = lle_op; break; case DW_LKIND_expression: /* This is a kind of fake, but better than 0 */ locdesc->ld_lle_value = DW_LLE_start_end; break; case DW_LKIND_loclists: /* ld_lle_value already set */ break; default: { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append_printf_u(&m, "DW_DLE_LOCATION_ERROR: An impossible DW_LKIND" " value of %u encountered, likely internal " "libdwarf error or data corruption", (unsigned)loc_head->ll_kind); _dwarf_error_string(dbg,error, DW_DLE_LOCATION_ERROR, dwarfstring_string(&m)); dwarfstring_destructor(&m); dwarf_dealloc(dbg,block_loc,DW_DLA_LOC_BLOCK_C); return DW_DLV_ERROR; } } locdesc->ld_cents = op_count; locdesc->ld_s = block_loc; locdesc->ld_kind = lkind; locdesc->ld_section_offset = loc_block->bl_section_offset; locdesc->ld_locdesc_offset = loc_block->bl_locdesc_offset; locdesc->ld_rawlow = lowpc; locdesc->ld_rawhigh = highpc; res = validate_lle_value(dbg,locdesc,error); if (res != DW_DLV_OK) { dwarf_dealloc(dbg,block_loc,DW_DLA_LOC_BLOCK_C); locdesc->ld_s = 0; return res; } /* Leaving the cooked values zero. Filled in later. */ /* We have not yet looked for debug_addr, so we'll set it as not-missing. */ locdesc->ld_index_failed = FALSE; return DW_DLV_OK; } /* Non-standard DWARF4 dwo loclist */ static int _dwarf_read_loc_section_dwo(Dwarf_Debug dbg, Dwarf_Block_c * return_block, Dwarf_Addr * lowpc, Dwarf_Addr * highpc, Dwarf_Bool *at_end, Dwarf_Half * lle_op, Dwarf_Off sec_offset, Dwarf_Half address_size, Dwarf_Half lkind, Dwarf_Error * error) { Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset; Dwarf_Small *locptr = 0; Dwarf_Small llecode = 0; Dwarf_Unsigned expr_offset = sec_offset; Dwarf_Byte_Ptr section_end = dbg->de_debug_loc.dss_data + dbg->de_debug_loc.dss_size; if (sec_offset >= dbg->de_debug_loc.dss_size) { /* We're at the end. No more present. */ return DW_DLV_NO_ENTRY; } memset(return_block,0,sizeof(*return_block)); /* not the same as non-split loclist, but still a list. */ return_block->bl_kind = lkind; /* This is non-standard GNU Dwarf4 loclist */ return_block->bl_locdesc_offset = sec_offset; llecode = *beg; locptr = beg +1; expr_offset++; switch(llecode) { case DW_LLEX_end_of_list_entry: *at_end = TRUE; return_block->bl_section_offset = expr_offset; expr_offset++; break; case DW_LLEX_base_address_selection_entry: { Dwarf_Unsigned addr_index = 0; DECODE_LEB128_UWORD_CK(locptr,addr_index, dbg,error,section_end); return_block->bl_section_offset = expr_offset; /* So this behaves much like non-dwo loclist */ *lowpc=MAX_ADDR; *highpc=addr_index; } break; case DW_LLEX_start_end_entry: { Dwarf_Unsigned addr_indexs = 0; Dwarf_Unsigned addr_indexe= 0; Dwarf_Unsigned exprlen = 0; Dwarf_Unsigned leb128_length = 0; DECODE_LEB128_UWORD_LEN_CK(locptr,addr_indexs, leb128_length, dbg,error,section_end); expr_offset += leb128_length; DECODE_LEB128_UWORD_LEN_CK(locptr,addr_indexe, leb128_length, dbg,error,section_end); expr_offset +=leb128_length; *lowpc=addr_indexs; *highpc=addr_indexe; READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr, DWARF_HALF_SIZE, error,section_end); locptr += DWARF_HALF_SIZE; expr_offset += DWARF_HALF_SIZE; return_block->bl_len = exprlen; return_block->bl_data = locptr; return_block->bl_section_offset = expr_offset; expr_offset += exprlen; if (expr_offset > dbg->de_debug_loc.dss_size) { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append(&m, "DW_DLE_DEBUG_LOC_SECTION_SHORT:"); dwarfstring_append_printf_u(&m, " in DW_LLEX_start_end_entry " "The expression offset is 0x%x", expr_offset); dwarfstring_append_printf_u(&m, " which is greater than the section size" " of 0x%x. Corrupt Dwarf.", dbg->de_debug_loc.dss_size); _dwarf_error_string(dbg,error, DW_DLE_DEBUG_LOC_SECTION_SHORT, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } } break; case DW_LLEX_start_length_entry: { Dwarf_Unsigned addr_index = 0; Dwarf_Unsigned range_length = 0; Dwarf_Unsigned exprlen = 0; Dwarf_Unsigned leb128_length = 0; DECODE_LEB128_UWORD_LEN_CK(locptr,addr_index, leb128_length, dbg,error,section_end); expr_offset +=leb128_length; READ_UNALIGNED_CK(dbg, range_length, Dwarf_Unsigned, locptr, DWARF_32BIT_SIZE, error,section_end); locptr += DWARF_32BIT_SIZE; expr_offset += DWARF_32BIT_SIZE; READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr, DWARF_HALF_SIZE, error,section_end); locptr += DWARF_HALF_SIZE; expr_offset += DWARF_HALF_SIZE; *lowpc = addr_index; *highpc = range_length; return_block->bl_len = exprlen; return_block->bl_data = locptr; return_block->bl_section_offset = expr_offset; /* exprblock_size can be zero, means no expression */ expr_offset += exprlen; if (expr_offset > dbg->de_debug_loc.dss_size) { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append(&m, "DW_DLE_DEBUG_LOC_SECTION_SHORT:"); dwarfstring_append_printf_u(&m, " in DW_LLEX_start_length_entry " "The expression offset is 0x%x", expr_offset); dwarfstring_append_printf_u(&m, " which is greater than the section size" " of 0x%x. Corrupt Dwarf.", dbg->de_debug_loc.dss_size); _dwarf_error_string(dbg,error, DW_DLE_DEBUG_LOC_SECTION_SHORT, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } } break; case DW_LLEX_offset_pair_entry: { Dwarf_Unsigned startoffset = 0; Dwarf_Unsigned endoffset = 0; Dwarf_Unsigned exprlen = 0; READ_UNALIGNED_CK(dbg, startoffset, Dwarf_Unsigned, locptr, DWARF_32BIT_SIZE, error,section_end); locptr += DWARF_32BIT_SIZE; expr_offset += DWARF_32BIT_SIZE; READ_UNALIGNED_CK(dbg, endoffset, Dwarf_Unsigned, locptr, DWARF_32BIT_SIZE, error,section_end); locptr += DWARF_32BIT_SIZE; expr_offset += DWARF_32BIT_SIZE; *lowpc= startoffset; *highpc = endoffset; READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr, DWARF_HALF_SIZE, error,section_end); locptr += DWARF_HALF_SIZE; expr_offset += DWARF_HALF_SIZE; return_block->bl_len = exprlen; return_block->bl_data = locptr; return_block->bl_section_offset = expr_offset; expr_offset += exprlen; if (expr_offset > dbg->de_debug_loc.dss_size) { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append(&m, "DW_DLE_DEBUG_LOC_SECTION_SHORT:"); dwarfstring_append_printf_u(&m, " in DW_LLEX_offset_pair_entry " "The expression offset is 0x%x", expr_offset); dwarfstring_append_printf_u(&m, " which is greater than the section size" " of 0x%x. Corrupt Dwarf.", dbg->de_debug_loc.dss_size); _dwarf_error_string(dbg,error, DW_DLE_DEBUG_LOC_SECTION_SHORT, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } } break; default: { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append(&m, "DW_DLE_LLE_CODE_UNKNOWN:"); dwarfstring_append_printf_u(&m, " in DW_LLEX_ code value " " is 0x%x ,not an expected value.", llecode); _dwarf_error_string(dbg,error, DW_DLE_LLE_CODE_UNKNOWN, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } } *lle_op = llecode; return DW_DLV_OK; } int dwarf_get_loclist_head_kind(Dwarf_Loc_Head_c ll_header, unsigned int * kind, Dwarf_Error * error) { if (!ll_header) { _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, "DW_DLE_DBG_NULL: " "NULL Dwarf_Loc_Head_c " "argument passed to " "dwarf_get_loclist_head_kind()"); return DW_DLV_ERROR; } *kind = ll_header->ll_kind; return DW_DLV_OK; } static int _dwarf_original_loclist_build(Dwarf_Debug dbg, Dwarf_Loc_Head_c llhead, Dwarf_Attribute attr, Dwarf_Error *error) { Dwarf_Unsigned loclist_offset = 0; Dwarf_Unsigned starting_loclist_offset = 0; int off_res = DW_DLV_ERROR; int count_res = DW_DLV_ERROR; int loclist_count = 0; Dwarf_Unsigned lli = 0; unsigned lkind = llhead->ll_kind; unsigned address_size = llhead->ll_address_size; Dwarf_Unsigned listlen = 0; Dwarf_Locdesc_c llbuf = 0; Dwarf_CU_Context cucontext; off_res = _dwarf_get_loclist_header_start(dbg, attr, &loclist_offset, error); if (off_res != DW_DLV_OK) { return off_res; } starting_loclist_offset = loclist_offset; if (lkind == DW_LKIND_GNU_exp_list) { count_res = _dwarf_get_loclist_lle_count_dwo(dbg, loclist_offset, address_size, lkind, &loclist_count, error); } else { count_res = _dwarf_get_loclist_lle_count(dbg, loclist_offset, address_size, &loclist_count, error); } if (count_res != DW_DLV_OK) { return count_res; } if (loclist_count == 0) { return DW_DLV_NO_ENTRY; } listlen = loclist_count; llbuf = (Dwarf_Locdesc_c) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen); if (!llbuf) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return DW_DLV_ERROR; } llbuf->ld_magic = LOCLISTS_MAGIC; llhead->ll_locdesc = llbuf; llhead->ll_locdesc_count = listlen; cucontext = llhead->ll_context; llhead->ll_llearea_offset = loclist_offset; /* Now get loc ops */ for (lli = 0; lli < listlen; ++lli) { int lres = 0; Dwarf_Half lle_op = 0; Dwarf_Bool at_end = 0; Dwarf_Block_c loc_block; Dwarf_Unsigned rawlowpc = 0; Dwarf_Unsigned rawhighpc = 0; int blkres = 0; memset(&loc_block,0,sizeof(loc_block)); if (lkind == DW_LKIND_GNU_exp_list) { blkres = _dwarf_read_loc_section_dwo(dbg, &loc_block, &rawlowpc, &rawhighpc, &at_end, &lle_op, loclist_offset, address_size, lkind, error); } else { blkres = _dwarf_read_loc_section(dbg, &loc_block, &rawlowpc, &rawhighpc, &lle_op, loclist_offset, address_size, error); } if (blkres != DW_DLV_OK) { return blkres; } /* Fills in the locdesc and its operators list at index lli */ lres = _dwarf_fill_in_locdesc_op_c(dbg, lli, llhead, &loc_block, address_size, cucontext->cc_length_size, cucontext->cc_version_stamp, rawlowpc, rawhighpc, lle_op, error); if (lres != DW_DLV_OK) { return lres; } /* Now get to next loclist entry offset. */ loclist_offset = loc_block.bl_section_offset + loc_block.bl_len; } /* We need to calculate the cooked values for each locldesc entry, that will be done in dwarf_get_loclist_c(). */ llhead->ll_bytes_total = loclist_offset - starting_loclist_offset; return DW_DLV_OK; } static int _dwarf_original_expression_build(Dwarf_Debug dbg, Dwarf_Loc_Head_c llhead, Dwarf_Attribute attr, Dwarf_Error *error) { Dwarf_Block_c loc_blockc; Dwarf_Unsigned rawlowpc = 0; Dwarf_Unsigned rawhighpc = 0; unsigned form = llhead->ll_attrform; int blkres = 0; Dwarf_Locdesc_c llbuf = 0; unsigned listlen = 1; Dwarf_CU_Context cucontext = llhead->ll_context; unsigned address_size = llhead->ll_address_size; memset(&loc_blockc,0,sizeof(loc_blockc)); if (form == DW_FORM_exprloc) { /* A bit ugly. dwarf_formexprloc should use a Dwarf_Block argument. */ blkres = dwarf_formexprloc(attr,&loc_blockc.bl_len, (Dwarf_Ptr)&loc_blockc.bl_data,error); if (blkres != DW_DLV_OK) { return blkres; } loc_blockc.bl_kind = llhead->ll_kind; loc_blockc.bl_section_offset = (char *)loc_blockc.bl_data - (char *)dbg->de_debug_info.dss_data; loc_blockc.bl_locdesc_offset = 0; /* not relevant */ } else { Dwarf_Block loc_block; memset(&loc_block,0,sizeof(loc_block)); blkres = _dwarf_formblock_internal(dbg,attr, llhead->ll_context, &loc_block, error); if (blkres != DW_DLV_OK) { return blkres; } loc_blockc.bl_len = loc_block.bl_len; loc_blockc.bl_data = loc_block.bl_data; loc_blockc.bl_kind = llhead->ll_kind; loc_blockc.bl_section_offset = loc_block.bl_section_offset; loc_blockc.bl_locdesc_offset = 0; /* not relevant */ } /* We will mark the Locdesc_c DW_LLE_start_end shortly. Here we fake the address range as 'all addresses'. */ rawlowpc = 0; rawhighpc = MAX_ADDR; llbuf = (Dwarf_Locdesc_c) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen); if (!llbuf) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return DW_DLV_ERROR; } llbuf->ld_magic = LOCLISTS_MAGIC; llhead->ll_locdesc = llbuf; /* Count is one by definition of a location entry. */ llhead->ll_locdesc_count = listlen; llbuf = 0; /* An empty location description (block length 0) means the code generator emitted no variable, the variable was not generated, it was unused or perhaps never tested after being set. Dwarf2, section 2.4.1 In other words, it is not an error, and we don't test for block length 0 specially here. */ /* Fills in the locdesc and its operators list at index 0 */ blkres = _dwarf_fill_in_locdesc_op_c(dbg, 0, /* fake locdesc is index 0 */ llhead, &loc_blockc, llhead->ll_address_size, cucontext->cc_length_size, cucontext->cc_version_stamp, rawlowpc, rawhighpc, 0, error); llhead->ll_bytes_total += loc_blockc.bl_len; if (blkres != DW_DLV_OK) { /* low level error already set: let problem be passed back */ dwarf_dealloc(dbg,llhead->ll_locdesc,DW_DLA_LOCDESC_C); llhead->ll_locdesc = 0; llhead->ll_locdesc_count = 0; return blkres; } return DW_DLV_OK; } /* Following the original loclist definition the low value is all one bits, the high value is the base address. */ static int cook_original_loclist_contents(Dwarf_Debug dbg, Dwarf_Loc_Head_c llhead, Dwarf_Error *error) { Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address; Dwarf_Unsigned count = llhead->ll_locdesc_count; Dwarf_Unsigned i = 0; for ( i = 0 ; i < count; ++i) { Dwarf_Locdesc_c llc = 0; llc = llhead->ll_locdesc +i; switch(llc->ld_lle_value) { case DW_LLE_end_of_list: { /* nothing to do */ break; } case DW_LLE_base_address: { llc->ld_lopc = llc->ld_rawhigh; llc->ld_highpc = llc->ld_rawhigh; baseaddress = llc->ld_rawhigh; break; } case DW_LLE_offset_pair: { llc->ld_lopc = llc->ld_rawlow + baseaddress; llc->ld_highpc = llc->ld_rawhigh + baseaddress; break; } default: { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append_printf_u(&m, "DW_DLE_LOCLISTS_ERROR: " "improper synthesized LLE code " "of 0x%x is unknown. In standard DWARF3/4 loclist", llc->ld_lle_value); _dwarf_error_string(dbg,error, DW_DLE_LOCLISTS_ERROR, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } } } return DW_DLV_OK; } static int cook_gnu_loclist_contents(Dwarf_Debug dbg, Dwarf_Loc_Head_c llhead, Dwarf_Error *error) { Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address; Dwarf_Unsigned count = llhead->ll_locdesc_count; Dwarf_Unsigned i = 0; Dwarf_CU_Context cucontext = llhead->ll_context; int res = 0; for (i = 0 ; i < count ; ++i) { Dwarf_Locdesc_c llc = 0; llc = llhead->ll_locdesc +i; switch(llc->ld_lle_value) { case DW_LLEX_base_address_selection_entry:{ Dwarf_Addr targaddr = 0; res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawhigh,&targaddr, error); if (res != DW_DLV_OK) { llc->ld_index_failed = TRUE; llc->ld_lopc = 0; llc->ld_highpc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { llc->ld_lopc = targaddr; llc->ld_highpc = targaddr; } break; } case DW_LLEX_end_of_list_entry:{ /* Nothing to do. */ break; } case DW_LLEX_start_length_entry:{ Dwarf_Addr targaddr = 0; res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawlow,&targaddr, error); if (res != DW_DLV_OK) { llc->ld_index_failed = TRUE; llc->ld_lopc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { llc->ld_lopc = targaddr; llc->ld_highpc = llc->ld_lopc +llc->ld_rawhigh; } break; } case DW_LLEX_offset_pair_entry:{ llc->ld_lopc = llc->ld_rawlow + baseaddress; llc->ld_highpc = llc->ld_rawhigh + baseaddress; break; } case DW_LLEX_start_end_entry:{ Dwarf_Addr targaddr = 0; res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawlow,&targaddr, error); if (res != DW_DLV_OK) { llc->ld_index_failed = TRUE; llc->ld_lopc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { llc->ld_lopc = targaddr; } res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawlow,&targaddr, error); if (res != DW_DLV_OK) { llc->ld_index_failed = TRUE; llc->ld_highpc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { llc->ld_highpc = targaddr; } break; } default:{ dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append_printf_u(&m, "DW_DLE_LOCLISTS_ERROR: improper LLEX code " "of 0x%x is unknown. GNU LLEX dwo loclists error", llc->ld_lle_value); _dwarf_error_string(dbg,error, DW_DLE_LOCLISTS_ERROR, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; break; } } } return DW_DLV_OK; } /* DWARF5 */ static int cook_loclists_contents(Dwarf_Debug dbg, Dwarf_Loc_Head_c llhead, Dwarf_Error *error) { Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address; Dwarf_Unsigned count = llhead->ll_locdesc_count; Dwarf_Unsigned i = 0; Dwarf_CU_Context cucontext = llhead->ll_context; int res = 0; Dwarf_Bool base_address_fail = FALSE; Dwarf_Bool debug_addr_fail = FALSE; if (!llhead->ll_cu_base_address_present) { base_address_fail = TRUE; } for (i = 0 ; i < count ; ++i) { Dwarf_Locdesc_c llc = 0; llc = llhead->ll_locdesc +i; switch(llc->ld_lle_value) { case DW_LLE_base_addressx: { Dwarf_Addr targaddr = 0; if (debug_addr_fail) { res = DW_DLV_NO_ENTRY; } else { res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawlow,&targaddr, error); } if (res != DW_DLV_OK) { debug_addr_fail = TRUE; base_address_fail = TRUE; llc->ld_index_failed = TRUE; llc->ld_lopc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { base_address_fail = FALSE; baseaddress = targaddr; llc->ld_lopc = targaddr; } break; } case DW_LLE_startx_endx:{ /* two indexes into debug_addr */ Dwarf_Addr targaddr = 0; if (debug_addr_fail) { res = DW_DLV_NO_ENTRY; } else { res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawlow,&targaddr, error); } if (res != DW_DLV_OK) { debug_addr_fail = TRUE; llc->ld_index_failed = TRUE; llc->ld_lopc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { llc->ld_lopc = targaddr; } if (debug_addr_fail) { res = DW_DLV_NO_ENTRY; } else { res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawhigh,&targaddr, error); } if (res != DW_DLV_OK) { debug_addr_fail = TRUE; llc->ld_index_failed = TRUE; llc->ld_highpc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { llc->ld_highpc = targaddr; } break; } case DW_LLE_startx_length:{ /* one index to debug_addr other a length */ Dwarf_Addr targaddr = 0; if (debug_addr_fail) { res = DW_DLV_NO_ENTRY; } else { res = _dwarf_look_in_local_and_tied_by_index( dbg,cucontext,llc->ld_rawlow,&targaddr, error); } if (res != DW_DLV_OK) { debug_addr_fail = TRUE; llc->ld_index_failed = TRUE; llc->ld_lopc = 0; if (res == DW_DLV_ERROR && error) { dwarf_dealloc_error(dbg, *error); *error = 0; } } else { llc->ld_lopc = targaddr; llc->ld_highpc = targaddr + llc->ld_rawhigh; } break; } case DW_LLE_offset_pair:{ if (base_address_fail) { llc->ld_index_failed = TRUE; llc->ld_lopc = 0; llc->ld_highpc = 0; } else { /*offsets of the current base address*/ llc->ld_lopc = llc->ld_rawlow +baseaddress; llc->ld_highpc = llc->ld_rawhigh +baseaddress; } break; } case DW_LLE_default_location:{ /* nothing to do here, just has a counted location description */ break; } case DW_LLE_base_address:{ llc->ld_lopc = llc->ld_rawlow; llc->ld_highpc = llc->ld_rawlow; baseaddress = llc->ld_rawlow; base_address_fail = FALSE; break; } case DW_LLE_start_end:{ llc->ld_lopc = llc->ld_rawlow; llc->ld_highpc = llc->ld_rawhigh; break; } case DW_LLE_start_length:{ llc->ld_lopc = llc->ld_rawlow; llc->ld_highpc = llc->ld_rawlow + llc->ld_rawhigh; break; } case DW_LLE_end_of_list:{ /* do nothing */ break; } default: { dwarfstring m; dwarfstring_constructor(&m); dwarfstring_append_printf_u(&m, "DW_DLE_LOCLISTS_ERROR: improper DW_LLE code " "of 0x%x is unknown. DWARF5 loclists error", llc->ld_lle_value); _dwarf_error_string(dbg,error, DW_DLE_LOCLISTS_ERROR, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } } } return DW_DLV_OK; } /* New October 2015 This interface requires the use of interface functions to get data from Dwarf_Locdesc_c. The structures are not visible to callers. */ int dwarf_get_loclist_c(Dwarf_Attribute attr, Dwarf_Loc_Head_c * ll_header_out, Dwarf_Unsigned * listlen_out, Dwarf_Error * error) { Dwarf_Debug dbg = 0; Dwarf_Half form = 0; Dwarf_Loc_Head_c llhead = 0; Dwarf_CU_Context cucontext = 0; unsigned address_size = 0; int cuversionstamp = 0; Dwarf_Bool is_cu = FALSE; Dwarf_Unsigned attrnum = 0; Dwarf_Bool is_dwo = 0; int setup_res = DW_DLV_ERROR; int lkind = 0; if (!attr) { _dwarf_error_string(dbg, error,DW_DLE_ATTR_NULL, "DW_DLE_ATTR_NULL" "NULL Dwarf_Attribute " "argument passed to " "dwarf_get_loclist_c()"); return DW_DLV_ERROR; } dbg = attr->ar_dbg; if (!dbg || dbg->de_magic != DBG_IS_VALID) { _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, "DW_DLE_DBG_NULL" "NULL Dwarf_Debug, improper Dwarf_Attribute " "argument passed to " "dwarf_get_loclist_c()"); return DW_DLV_ERROR; } /* ***** BEGIN CODE ***** */ setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error); if (setup_res != DW_DLV_OK) { return setup_res; } attrnum = attr->ar_attribute; cuversionstamp = cucontext->cc_version_stamp; address_size = cucontext->cc_address_size; is_dwo = cucontext->cc_is_dwo; lkind = determine_location_lkind(cuversionstamp, form, is_dwo); if (lkind == DW_LKIND_unknown) { dwarfstring m; const char * formname = ""; const char * attrname = ""; dwarfstring_constructor(&m); dwarf_get_FORM_name(form,&formname); dwarf_get_AT_name(attrnum,&attrname); dwarfstring_append_printf_u(&m, "DW_DLE_LOC_EXPR_BAD: For Compilation Unit " "version %u",cuversionstamp); dwarfstring_append_printf_u(&m, ", attribute 0x%x (",attrnum); dwarfstring_append(&m,(char *)attrname); dwarfstring_append_printf_u(&m, ") form 0x%x (",form); dwarfstring_append(&m,(char *)formname); if (is_dwo) { dwarfstring_append(&m,") (the CU is a .dwo) "); } else { dwarfstring_append(&m,") (the CU is not a .dwo) "); } dwarfstring_append(&m," we don't understand the location"); _dwarf_error_string(dbg,error,DW_DLE_LOC_EXPR_BAD, dwarfstring_string(&m)); dwarfstring_destructor(&m); return DW_DLV_ERROR; } /* Doing this early (first) to avoid repeating the alloc code for each type */ llhead = (Dwarf_Loc_Head_c) _dwarf_get_alloc(dbg, DW_DLA_LOC_HEAD_C, 1); if (!llhead) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return DW_DLV_ERROR; } llhead->ll_cuversion = cuversionstamp; llhead->ll_kind = lkind; llhead->ll_attrnum = attrnum; llhead->ll_attrform = form; llhead->ll_dbg = dbg; llhead->ll_address_size = address_size; llhead->ll_offset_size = cucontext->cc_length_size; llhead->ll_context = cucontext; llhead->ll_magic = LOCLISTS_MAGIC; llhead->ll_at_loclists_base_present = cucontext->cc_loclists_base_present; llhead->ll_at_loclists_base = cucontext->cc_loclists_base; llhead->ll_cu_base_address_present = cucontext->cc_low_pc_present; llhead->ll_cu_base_address = cucontext->cc_low_pc; llhead->ll_cu_addr_base = cucontext->cc_addr_base; llhead->ll_cu_addr_base_present = cucontext->cc_addr_base_present; if (lkind == DW_LKIND_loclist || lkind == DW_LKIND_GNU_exp_list) { int ores = 0; /* Here we have a loclist to deal with. */ ores = context_is_cu_not_tu(cucontext,&is_cu); if (ores != DW_DLV_OK) { dwarf_dealloc_loc_head_c(llhead); return setup_res; } ores = _dwarf_original_loclist_build(dbg, llhead, attr, error); if (ores != DW_DLV_OK) { dwarf_dealloc_loc_head_c(llhead); return ores; } if (lkind == DW_LKIND_loclist) { ores = cook_original_loclist_contents(dbg,llhead, error); } else { ores = cook_gnu_loclist_contents(dbg,llhead,error); } if (ores != DW_DLV_OK) { dwarf_dealloc_loc_head_c(llhead); return ores; } } else if (lkind == DW_LKIND_expression) { /* DWARF2,3,4,5 */ int eres = 0; eres = _dwarf_original_expression_build(dbg, llhead, attr, error); if (eres != DW_DLV_OK) { dwarf_dealloc_loc_head_c(llhead); return eres; } } else if (lkind == DW_LKIND_loclists) { /* DWARF5! */ int leres = 0; leres = _dwarf_loclists_fill_in_lle_head(dbg, attr,llhead,error); if (leres != DW_DLV_OK) { dwarf_dealloc_loc_head_c(llhead); return leres; } leres = cook_loclists_contents(dbg,llhead,error); if (leres != DW_DLV_OK) { dwarf_dealloc_loc_head_c(llhead); return leres; } } /* ASSERT else impossible */ *ll_header_out = llhead; *listlen_out = llhead->ll_locdesc_count; return DW_DLV_OK; } /* An interface giving us no cu context! This is not going to be quite right. */ int dwarf_loclist_from_expr_c(Dwarf_Debug dbg, Dwarf_Ptr expression_in, Dwarf_Unsigned expression_length, Dwarf_Half address_size, Dwarf_Half offset_size, Dwarf_Small dwarf_version, Dwarf_Loc_Head_c *loc_head, Dwarf_Unsigned * listlen, Dwarf_Error * error) { /* Dwarf_Block that describes a single location expression. */ Dwarf_Block_c loc_block; Dwarf_Loc_Head_c llhead = 0; Dwarf_Locdesc_c llbuf = 0; int local_listlen = 1; Dwarf_Addr rawlowpc = 0; Dwarf_Addr rawhighpc = MAX_ADDR; Dwarf_Small version_stamp = dwarf_version; int res = 0; if (!dbg || dbg->de_magic != DBG_IS_VALID) { _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, "DW_DLE_DBG_NULL" "NULL or bad Dwarf_Debug " "argument passed to " "dwarf_loclist_from_expr_c()"); return DW_DLV_ERROR; } llhead = (Dwarf_Loc_Head_c)_dwarf_get_alloc(dbg, DW_DLA_LOC_HEAD_C, 1); if (!llhead) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return DW_DLV_ERROR; } llhead->ll_magic = LOCLISTS_MAGIC; memset(&loc_block,0,sizeof(loc_block)); loc_block.bl_len = expression_length; loc_block.bl_data = expression_in; loc_block.bl_kind = DW_LKIND_expression; /* Not from loclist. */ loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */ loc_block.bl_locdesc_offset = 0; /* Fake. Not meaningful. */ llbuf = (Dwarf_Locdesc_c) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, local_listlen); if (!llbuf) { dwarf_dealloc_loc_head_c(llhead); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return DW_DLV_ERROR; } llbuf->ld_magic = LOCLISTS_MAGIC; llhead->ll_locdesc = llbuf; llhead->ll_locdesc_count = local_listlen; llhead->ll_context = 0; /* Not available! */ llhead->ll_dbg = dbg; llhead->ll_kind = DW_LKIND_expression; /* An empty location description (block length 0) means the code generator emitted no variable, the variable was not generated, it was unused or perhaps never tested after being set. Dwarf2, section 2.4.1 In other words, it is not an error, and we don't test for block length 0 specially here. */ /* Fills in the locdesc and its operators list at index 0 */ res = _dwarf_fill_in_locdesc_op_c(dbg, 0, llhead, &loc_block, address_size, offset_size, version_stamp, rawlowpc, rawhighpc, DW_LKIND_expression, error); if (res != DW_DLV_OK) { /* low level error already set: let it be passed back */ dwarf_dealloc(dbg,llbuf,DW_DLA_LOCDESC_C); llhead->ll_locdesc = 0; llhead->ll_locdesc_count = 0; dwarf_dealloc_loc_head_c(llhead); return DW_DLV_ERROR; } *loc_head = llhead; *listlen = local_listlen; return DW_DLV_OK; } /* New June 2020 Supports all versions of DWARF. Distinguishes location entry values as in the file directly (raw) from the computed value (lowpc_out,hipc_out) after applying base values (if any). */ int dwarf_get_locdesc_entry_d(Dwarf_Loc_Head_c loclist_head, Dwarf_Unsigned index, Dwarf_Small * lle_value_out, Dwarf_Unsigned * rawval1, Dwarf_Unsigned * rawval2, Dwarf_Bool * debug_addr_unavailable, Dwarf_Addr * lowpc_out, /* 'cooked' value */ Dwarf_Addr * hipc_out, /* 'cooked' value */ Dwarf_Unsigned * loclist_expr_op_count_out, /* Returns pointer to the specific locdesc of the index; */ Dwarf_Locdesc_c* locdesc_entry_out, Dwarf_Small * loclist_source_out, /* 0,1, or 2 */ Dwarf_Unsigned * expression_offset_out, Dwarf_Unsigned * locdesc_offset_out, Dwarf_Error * error) { Dwarf_Locdesc_c descs_base = 0; Dwarf_Locdesc_c desc = 0; Dwarf_Unsigned desc_count = 0; Dwarf_Debug dbg = 0; if (!loclist_head || loclist_head->ll_magic != LOCLISTS_MAGIC) { _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, "DW_DLE_DBG_NULL: " "Dwarf_Loc_Head_c NULL or not " "marked LOCLISTS_MAGIC " "in calling " "dwarf_get_locdesc_entry_d()"); return DW_DLV_ERROR; } desc_count = loclist_head->ll_locdesc_count; descs_base = loclist_head->ll_locdesc; dbg = loclist_head->ll_dbg; if (index >= desc_count) { _dwarf_error(dbg, error, DW_DLE_LOCLIST_INDEX_ERROR); return DW_DLV_ERROR; } desc = descs_base + index; *lle_value_out = desc->ld_lle_value; *rawval1 = desc->ld_rawlow; *rawval2 = desc->ld_rawhigh; *lowpc_out = desc->ld_lopc; *hipc_out = desc->ld_highpc; *debug_addr_unavailable = desc->ld_index_failed; *loclist_expr_op_count_out = desc->ld_cents; *locdesc_entry_out = desc; *loclist_source_out = desc->ld_kind; *expression_offset_out = desc->ld_section_offset; *locdesc_offset_out = desc->ld_locdesc_offset; return DW_DLV_OK; } int dwarf_get_location_op_value_c(Dwarf_Locdesc_c locdesc, Dwarf_Unsigned index, Dwarf_Small * atom_out, Dwarf_Unsigned * operand1, Dwarf_Unsigned * operand2, Dwarf_Unsigned * operand3, Dwarf_Unsigned * offset_for_branch, Dwarf_Error* error) { Dwarf_Loc_Expr_Op op = 0; Dwarf_Unsigned max = 0; if (!locdesc) { _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, "DW_DLE_DBG_NULL" "Dwarf_Locdesc_c_Head_c NULL " "in calling " "dwarf_get_location_op_value_c()"); return DW_DLV_ERROR; } max = locdesc->ld_cents; if (index >= max) { Dwarf_Debug dbg = locdesc->ld_loclist_head->ll_dbg; _dwarf_error(dbg, error, DW_DLE_LOCLIST_INDEX_ERROR); return DW_DLV_ERROR; } op = locdesc->ld_s + index; *atom_out = op->lr_atom; *operand1 = op->lr_number; *operand2 = op->lr_number2; *operand3 = op->lr_number3; *offset_for_branch = op->lr_offset; return DW_DLV_OK; } /* ============== End of the October 2015 interfaces. */