2N/A/*
2N/A
2N/A Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
2N/A Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
2N/A
2N/A This program is free software; you can redistribute it and/or modify it
2N/A under the terms of version 2.1 of the GNU Lesser General Public License
2N/A as published by the Free Software Foundation.
2N/A
2N/A This program is distributed in the hope that it would be useful, but
2N/A WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2N/A
2N/A Further, this software is distributed without any warranty that it is
2N/A free of the rightful claim of any third person regarding infringement
2N/A or the like. Any license provided herein, whether implied or
2N/A otherwise, applies only to this software file. Patent licenses, if
2N/A any, provided herein do not apply to combinations of this program with
2N/A other software, or any other product whatsoever.
2N/A
2N/A You should have received a copy of the GNU Lesser General Public
2N/A License along with this program; if not, write the Free Software
2N/A Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
2N/A USA.
2N/A
2N/A Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
2N/A Mountain View, CA 94043, or:
2N/A
2N/A http://www.sgi.com
2N/A
2N/A For further information regarding this notice, see:
2N/A
2N/A http://oss.sgi.com/projects/GenInfo/NoticeExplan
2N/A
2N/A*/
2N/A/* The address of the Free Software Foundation is
2N/A Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
2N/A Boston, MA 02110-1301, USA.
2N/A SGI has moved from the Crittenden Lane address.
2N/A*/
2N/A
2N/A
2N/A
2N/A
2N/A#include "config.h"
2N/A#include "dwarf_incl.h"
2N/A#include "dwarf_loc.h"
2N/A#include <stdio.h> /* for debugging only. */
2N/A#include <sys/types.h>
2N/A
2N/A/*
2N/A Given a Dwarf_Block that represents a location expression,
2N/A this function returns a pointer to a Dwarf_Locdesc struct
2N/A that has its ld_cents field set to the number of location
2N/A operators in the block, and its ld_s field pointing to a
2N/A contiguous block of Dwarf_Loc structs. However, the
2N/A ld_lopc and ld_hipc values are uninitialized. Returns
2N/A NULL on error. This function assumes that the length of
2N/A the block is greater than 0. Zero length location expressions
2N/A to represent variables that have been optimized away are
2N/A handled in the calling function.
2N/A*/
2N/Astatic Dwarf_Locdesc *
2N/A_dwarf_get_locdesc(Dwarf_Debug dbg,
2N/A Dwarf_Block * loc_block,
2N/A Dwarf_Half address_size,
2N/A Dwarf_Addr lowpc,
2N/A Dwarf_Addr highpc,
2N/A Dwarf_Error * error)
2N/A{
2N/A /* Size of the block containing the location expression. */
2N/A Dwarf_Unsigned loc_len = 0;
2N/A
2N/A /* Sweeps the block containing the location expression. */
2N/A Dwarf_Small *loc_ptr = 0;
2N/A
2N/A /* Current location operator. */
2N/A Dwarf_Small atom = 0;
2N/A
2N/A /* Offset of current operator from start of block. */
2N/A Dwarf_Unsigned offset = 0;
2N/A
2N/A /* Operands of current location operator. */
2N/A Dwarf_Unsigned operand1, operand2;
2N/A
2N/A /* Used to chain the Dwarf_Loc_Chain_s structs. */
2N/A Dwarf_Loc_Chain curr_loc = NULL;
2N/A Dwarf_Loc_Chain prev_loc = NULL;
2N/A Dwarf_Loc_Chain head_loc = NULL;
2N/A
2N/A /* Count of the number of location operators. */
2N/A Dwarf_Unsigned op_count = 0;
2N/A
2N/A /* Contiguous block of Dwarf_Loc's for Dwarf_Locdesc. */
2N/A Dwarf_Loc *block_loc = 0;
2N/A
2N/A /* Dwarf_Locdesc pointer to be returned. */
2N/A Dwarf_Locdesc *locdesc = 0;
2N/A
2N/A Dwarf_Word leb128_length = 0;
2N/A Dwarf_Unsigned i = 0;
2N/A
2N/A /* ***** BEGIN CODE ***** */
2N/A
2N/A loc_len = loc_block->bl_len;
2N/A loc_ptr = loc_block->bl_data;
2N/A
2N/A offset = 0;
2N/A op_count = 0;
2N/A while (offset < loc_len) {
2N/A
2N/A operand1 = 0;
2N/A operand2 = 0;
2N/A op_count++;
2N/A
2N/A atom = *(Dwarf_Small *) loc_ptr;
2N/A loc_ptr++;
2N/A offset++;
2N/A
2N/A curr_loc =
2N/A (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN,
2N/A 1);
2N/A if (curr_loc == NULL) {
2N/A _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
2N/A return (NULL);
2N/A }
2N/A curr_loc->lc_offset = offset;
2N/A curr_loc->lc_atom = atom;
2N/A switch (atom) {
2N/A
2N/A case DW_OP_reg0:
2N/A case DW_OP_reg1:
2N/A case DW_OP_reg2:
2N/A case DW_OP_reg3:
2N/A case DW_OP_reg4:
2N/A case DW_OP_reg5:
2N/A case DW_OP_reg6:
2N/A case DW_OP_reg7:
2N/A case DW_OP_reg8:
2N/A case DW_OP_reg9:
2N/A case DW_OP_reg10:
2N/A case DW_OP_reg11:
2N/A case DW_OP_reg12:
2N/A case DW_OP_reg13:
2N/A case DW_OP_reg14:
2N/A case DW_OP_reg15:
2N/A case DW_OP_reg16:
2N/A case DW_OP_reg17:
2N/A case DW_OP_reg18:
2N/A case DW_OP_reg19:
2N/A case DW_OP_reg20:
2N/A case DW_OP_reg21:
2N/A case DW_OP_reg22:
2N/A case DW_OP_reg23:
2N/A case DW_OP_reg24:
2N/A case DW_OP_reg25:
2N/A case DW_OP_reg26:
2N/A case DW_OP_reg27:
2N/A case DW_OP_reg28:
2N/A case DW_OP_reg29:
2N/A case DW_OP_reg30:
2N/A case DW_OP_reg31:
2N/A break;
2N/A
2N/A case DW_OP_regx:
2N/A operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_lit0:
2N/A case DW_OP_lit1:
2N/A case DW_OP_lit2:
2N/A case DW_OP_lit3:
2N/A case DW_OP_lit4:
2N/A case DW_OP_lit5:
2N/A case DW_OP_lit6:
2N/A case DW_OP_lit7:
2N/A case DW_OP_lit8:
2N/A case DW_OP_lit9:
2N/A case DW_OP_lit10:
2N/A case DW_OP_lit11:
2N/A case DW_OP_lit12:
2N/A case DW_OP_lit13:
2N/A case DW_OP_lit14:
2N/A case DW_OP_lit15:
2N/A case DW_OP_lit16:
2N/A case DW_OP_lit17:
2N/A case DW_OP_lit18:
2N/A case DW_OP_lit19:
2N/A case DW_OP_lit20:
2N/A case DW_OP_lit21:
2N/A case DW_OP_lit22:
2N/A case DW_OP_lit23:
2N/A case DW_OP_lit24:
2N/A case DW_OP_lit25:
2N/A case DW_OP_lit26:
2N/A case DW_OP_lit27:
2N/A case DW_OP_lit28:
2N/A case DW_OP_lit29:
2N/A case DW_OP_lit30:
2N/A case DW_OP_lit31:
2N/A operand1 = atom - DW_OP_lit0;
2N/A break;
2N/A
2N/A case DW_OP_addr:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned,
2N/A loc_ptr, address_size);
2N/A loc_ptr += address_size;
2N/A offset += address_size;
2N/A break;
2N/A
2N/A case DW_OP_const1u:
2N/A operand1 = *(Dwarf_Small *) loc_ptr;
2N/A loc_ptr = loc_ptr + 1;
2N/A offset = offset + 1;
2N/A break;
2N/A
2N/A case DW_OP_const1s:
2N/A operand1 = *(Dwarf_Sbyte *) loc_ptr;
2N/A SIGN_EXTEND(operand1,1);
2N/A loc_ptr = loc_ptr + 1;
2N/A offset = offset + 1;
2N/A break;
2N/A
2N/A case DW_OP_const2u:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
2N/A loc_ptr = loc_ptr + 2;
2N/A offset = offset + 2;
2N/A break;
2N/A
2N/A case DW_OP_const2s:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
2N/A SIGN_EXTEND(operand1,2);
2N/A loc_ptr = loc_ptr + 2;
2N/A offset = offset + 2;
2N/A break;
2N/A
2N/A case DW_OP_const4u:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
2N/A loc_ptr = loc_ptr + 4;
2N/A offset = offset + 4;
2N/A break;
2N/A
2N/A case DW_OP_const4s:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
2N/A SIGN_EXTEND(operand1,4);
2N/A loc_ptr = loc_ptr + 4;
2N/A offset = offset + 4;
2N/A break;
2N/A
2N/A case DW_OP_const8u:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
2N/A loc_ptr = loc_ptr + 8;
2N/A offset = offset + 8;
2N/A break;
2N/A
2N/A case DW_OP_const8s:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
2N/A loc_ptr = loc_ptr + 8;
2N/A offset = offset + 8;
2N/A break;
2N/A
2N/A case DW_OP_constu:
2N/A operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_consts:
2N/A operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_fbreg:
2N/A operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_breg0:
2N/A case DW_OP_breg1:
2N/A case DW_OP_breg2:
2N/A case DW_OP_breg3:
2N/A case DW_OP_breg4:
2N/A case DW_OP_breg5:
2N/A case DW_OP_breg6:
2N/A case DW_OP_breg7:
2N/A case DW_OP_breg8:
2N/A case DW_OP_breg9:
2N/A case DW_OP_breg10:
2N/A case DW_OP_breg11:
2N/A case DW_OP_breg12:
2N/A case DW_OP_breg13:
2N/A case DW_OP_breg14:
2N/A case DW_OP_breg15:
2N/A case DW_OP_breg16:
2N/A case DW_OP_breg17:
2N/A case DW_OP_breg18:
2N/A case DW_OP_breg19:
2N/A case DW_OP_breg20:
2N/A case DW_OP_breg21:
2N/A case DW_OP_breg22:
2N/A case DW_OP_breg23:
2N/A case DW_OP_breg24:
2N/A case DW_OP_breg25:
2N/A case DW_OP_breg26:
2N/A case DW_OP_breg27:
2N/A case DW_OP_breg28:
2N/A case DW_OP_breg29:
2N/A case DW_OP_breg30:
2N/A case DW_OP_breg31:
2N/A operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_bregx:
2N/A /* uleb reg num followed by sleb offset */
2N/A operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A
2N/A operand2 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_dup:
2N/A case DW_OP_drop:
2N/A break;
2N/A
2N/A case DW_OP_pick:
2N/A operand1 = *(Dwarf_Small *) loc_ptr;
2N/A loc_ptr = loc_ptr + 1;
2N/A offset = offset + 1;
2N/A break;
2N/A
2N/A case DW_OP_over:
2N/A case DW_OP_swap:
2N/A case DW_OP_rot:
2N/A case DW_OP_deref:
2N/A break;
2N/A
2N/A case DW_OP_deref_size:
2N/A operand1 = *(Dwarf_Small *) loc_ptr;
2N/A loc_ptr = loc_ptr + 1;
2N/A offset = offset + 1;
2N/A break;
2N/A
2N/A case DW_OP_xderef:
2N/A break;
2N/A
2N/A case DW_OP_xderef_size:
2N/A operand1 = *(Dwarf_Small *) loc_ptr;
2N/A loc_ptr = loc_ptr + 1;
2N/A offset = offset + 1;
2N/A break;
2N/A
2N/A case DW_OP_abs:
2N/A case DW_OP_and:
2N/A case DW_OP_div:
2N/A case DW_OP_minus:
2N/A case DW_OP_mod:
2N/A case DW_OP_mul:
2N/A case DW_OP_neg:
2N/A case DW_OP_not:
2N/A case DW_OP_or:
2N/A case DW_OP_plus:
2N/A break;
2N/A
2N/A case DW_OP_plus_uconst:
2N/A operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_shl:
2N/A case DW_OP_shr:
2N/A case DW_OP_shra:
2N/A case DW_OP_xor:
2N/A break;
2N/A
2N/A case DW_OP_le:
2N/A case DW_OP_ge:
2N/A case DW_OP_eq:
2N/A case DW_OP_lt:
2N/A case DW_OP_gt:
2N/A case DW_OP_ne:
2N/A break;
2N/A
2N/A case DW_OP_skip:
2N/A case DW_OP_bra:
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
2N/A loc_ptr = loc_ptr + 2;
2N/A offset = offset + 2;
2N/A break;
2N/A
2N/A case DW_OP_piece:
2N/A operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A
2N/A case DW_OP_nop:
2N/A break;
2N/A case DW_OP_push_object_address: /* DWARF3 */
2N/A break;
2N/A case DW_OP_call2: /* DWARF3 */
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
2N/A loc_ptr = loc_ptr + 2;
2N/A offset = offset + 2;
2N/A break;
2N/A
2N/A case DW_OP_call4: /* DWARF3 */
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
2N/A loc_ptr = loc_ptr + 4;
2N/A offset = offset + 4;
2N/A break;
2N/A case DW_OP_call_ref: /* DWARF3 */
2N/A READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr,
2N/A dbg->de_length_size);
2N/A loc_ptr = loc_ptr + dbg->de_length_size;
2N/A offset = offset + dbg->de_length_size;
2N/A break;
2N/A
2N/A case DW_OP_form_tls_address: /* DWARF3f */
2N/A break;
2N/A case DW_OP_call_frame_cfa: /* DWARF3f */
2N/A break;
2N/A case DW_OP_bit_piece: /* DWARF3f */
2N/A /* uleb size in bits followed by uleb offset in bits */
2N/A operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A
2N/A operand2 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A break;
2N/A case DW_OP_implicit_value: /* DWARF4 */
2N/A /* uleb length of value bytes followed by that
2N/A number of bytes of the value. */
2N/A operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
2N/A loc_ptr = loc_ptr + leb128_length;
2N/A offset = offset + leb128_length;
2N/A
2N/A /* Second operand is block of 'operand1' bytes of stuff. */
2N/A /* This using the second operand as a pointer
2N/A is quite ugly. */
2N/A /* This gets an ugly compiler warning. Sorry. */
2N/A operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr;
2N/A offset = offset + operand1;
2N/A loc_ptr = loc_ptr + operand1;
2N/A break;
2N/A case DW_OP_stack_value: /* DWARF4 */
2N/A break;
2N/A
2N/A
2N/A default:
2N/A _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
2N/A return (NULL);
2N/A }
2N/A
2N/A
2N/A curr_loc->lc_number = operand1;
2N/A curr_loc->lc_number2 = operand2;
2N/A
2N/A if (head_loc == NULL)
2N/A head_loc = prev_loc = curr_loc;
2N/A else {
2N/A prev_loc->lc_next = curr_loc;
2N/A prev_loc = curr_loc;
2N/A }
2N/A }
2N/A
2N/A block_loc =
2N/A (Dwarf_Loc *) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK, op_count);
2N/A if (block_loc == NULL) {
2N/A _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
2N/A return (NULL);
2N/A }
2N/A
2N/A curr_loc = head_loc;
2N/A for (i = 0; i < op_count; i++) {
2N/A (block_loc + i)->lr_atom = curr_loc->lc_atom;
2N/A (block_loc + i)->lr_number = curr_loc->lc_number;
2N/A (block_loc + i)->lr_number2 = curr_loc->lc_number2;
2N/A (block_loc + i)->lr_offset = curr_loc->lc_offset;
2N/A
2N/A prev_loc = curr_loc;
2N/A curr_loc = curr_loc->lc_next;
2N/A dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
2N/A }
2N/A
2N/A locdesc =
2N/A (Dwarf_Locdesc *) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC, 1);
2N/A if (locdesc == NULL) {
2N/A _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
2N/A return (NULL);
2N/A }
2N/A
2N/A locdesc->ld_cents = op_count;
2N/A locdesc->ld_s = block_loc;
2N/A locdesc->ld_from_loclist = loc_block->bl_from_loclist;
2N/A locdesc->ld_section_offset = loc_block->bl_section_offset;
2N/A locdesc->ld_lopc = lowpc;
2N/A locdesc->ld_hipc = highpc;
2N/A
2N/A return (locdesc);
2N/A}
2N/A
2N/A/* Using a loclist offset to get the in-memory
2N/A address of .debug_loc data to read, returns the loclist
2N/A 'header' info in return_block.
2N/A*/
2N/A
2N/A#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)
2N/A
2N/Astatic int
2N/A_dwarf_read_loc_section(Dwarf_Debug dbg,
2N/A Dwarf_Block * return_block,
2N/A Dwarf_Addr * lowpc, Dwarf_Addr * hipc,
2N/A Dwarf_Off sec_offset,
2N/A Dwarf_Half address_size,
2N/A Dwarf_Error * error)
2N/A{
2N/A Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset;
2N/A
2N/A Dwarf_Addr start_addr = 0;
2N/A Dwarf_Addr end_addr = 0;
2N/A Dwarf_Half exprblock_size = 0;
2N/A Dwarf_Unsigned exprblock_off =
2N/A 2 * address_size + sizeof(Dwarf_Half);
2N/A
2N/A if (sec_offset >= dbg->de_debug_loc.dss_size) {
2N/A /* We're at the end. No more present. */
2N/A return DW_DLV_NO_ENTRY;
2N/A }
2N/A
2N/A /* If it goes past end, error */
2N/A if (exprblock_off > dbg->de_debug_loc.dss_size) {
2N/A _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
2N/A return DW_DLV_ERROR;
2N/A }
2N/A
2N/A READ_UNALIGNED(dbg, start_addr, Dwarf_Addr, beg, address_size);
2N/A READ_UNALIGNED(dbg, end_addr, Dwarf_Addr,
2N/A beg + address_size, address_size);
2N/A if (start_addr == 0 && end_addr == 0) {
2N/A /* If start_addr and end_addr are 0, it's the end and no
2N/A exprblock_size field follows. */
2N/A exprblock_size = 0;
2N/A exprblock_off -= sizeof(Dwarf_Half);
2N/A } else if (start_addr == MAX_ADDR) {
2N/A /* end address is a base address, no exprblock_size field here
2N/A either */
2N/A exprblock_size = 0;
2N/A exprblock_off -= sizeof(Dwarf_Half);
2N/A } else {
2N/A
2N/A READ_UNALIGNED(dbg, exprblock_size, Dwarf_Half,
2N/A beg + 2 * address_size, sizeof(Dwarf_Half));
2N/A /* exprblock_size can be zero, means no expression */
2N/A if ((exprblock_off + exprblock_size) > dbg->de_debug_loc.dss_size) {
2N/A _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
2N/A return DW_DLV_ERROR;
2N/A }
2N/A }
2N/A#undef MAX_ADDR
2N/A *lowpc = start_addr;
2N/A *hipc = end_addr;
2N/A
2N/A return_block->bl_len = exprblock_size;
2N/A return_block->bl_from_loclist = 1;
2N/A return_block->bl_data = beg + exprblock_off;
2N/A return_block->bl_section_offset =
2N/A ((Dwarf_Small *) return_block->bl_data) - dbg->de_debug_loc.dss_data;
2N/A
2N/A return DW_DLV_OK;
2N/A
2N/A}
2N/Astatic int
2N/A_dwarf_get_loclist_count(Dwarf_Debug dbg,
2N/A Dwarf_Off loclist_offset,
2N/A Dwarf_Half address_size,
2N/A int *loclist_count, Dwarf_Error * error)
2N/A{
2N/A int count = 0;
2N/A Dwarf_Off offset = loclist_offset;
2N/A
2N/A
2N/A for (;;) {
2N/A Dwarf_Block b;
2N/A Dwarf_Addr lowpc;
2N/A Dwarf_Addr highpc;
2N/A int res = _dwarf_read_loc_section(dbg, &b,
2N/A &lowpc, &highpc,
2N/A offset, address_size,error);
2N/A
2N/A if (res != DW_DLV_OK) {
2N/A return res;
2N/A }
2N/A offset = b.bl_len + b.bl_section_offset;
2N/A if (lowpc == 0 && highpc == 0) {
2N/A break;
2N/A }
2N/A count++;
2N/A }
2N/A *loclist_count = count;
2N/A return DW_DLV_OK;
2N/A}
2N/A
2N/A/* Helper routine to avoid code duplication.
2N/A*/
2N/Astatic int
2N/A_dwarf_setup_loc(Dwarf_Attribute attr,
2N/A Dwarf_Debug * dbg_ret,
2N/A Dwarf_CU_Context *cucontext_ret,
2N/A Dwarf_Half * form_ret, Dwarf_Error * error)
2N/A{
2N/A Dwarf_Debug dbg = 0;
2N/A Dwarf_Half form = 0;
2N/A int blkres = DW_DLV_ERROR;
2N/A
2N/A if (attr == NULL) {
2N/A _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A if (attr->ar_cu_context == NULL) {
2N/A _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A *cucontext_ret = attr->ar_cu_context;
2N/A
2N/A dbg = attr->ar_cu_context->cc_dbg;
2N/A if (dbg == NULL) {
2N/A _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A *dbg_ret = dbg;
2N/A blkres = dwarf_whatform(attr, &form, error);
2N/A if (blkres != DW_DLV_OK) {
2N/A _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
2N/A return blkres;
2N/A }
2N/A *form_ret = form;
2N/A return DW_DLV_OK;
2N/A}
2N/A
2N/A/* Helper routine to avoid code duplication.
2N/A*/
2N/Astatic int
2N/A_dwarf_get_loclist_header_start(Dwarf_Debug dbg,
2N/A Dwarf_Attribute attr,
2N/A Dwarf_Unsigned * loclist_offset,
2N/A Dwarf_Error * error)
2N/A{
2N/A int blkres = dwarf_formudata(attr, loclist_offset, error);
2N/A if (blkres != DW_DLV_OK) {
2N/A return (blkres);
2N/A }
2N/A
2N/A if (!dbg->de_debug_loc.dss_data) {
2N/A int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
2N/A if (secload != DW_DLV_OK) {
2N/A return secload;
2N/A }
2N/A }
2N/A return DW_DLV_OK;
2N/A}
2N/A
2N/A/* When llbuf (see dwarf_loclist_n) is partially set up
2N/A and an error is encountered, tear it down as it
2N/A won't be used.
2N/A*/
2N/Astatic void
2N/A_dwarf_cleanup_llbuf(Dwarf_Debug dbg, Dwarf_Locdesc ** llbuf, int count)
2N/A{
2N/A int i;
2N/A for (i = 0; i < count; ++i) {
2N/A dwarf_dealloc(dbg, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
2N/A dwarf_dealloc(dbg, llbuf[i], DW_DLA_LOCDESC);
2N/A }
2N/A dwarf_dealloc(dbg, llbuf, DW_DLA_LIST);
2N/A}
2N/A
2N/A/*
2N/A Handles simple location entries and loclists.
2N/A Returns all the Locdesc's thru llbuf.
2N/A
2N/A*/
2N/Aint
2N/Adwarf_loclist_n(Dwarf_Attribute attr,
2N/A Dwarf_Locdesc *** llbuf_out,
2N/A Dwarf_Signed * listlen_out, Dwarf_Error * error)
2N/A{
2N/A Dwarf_Debug dbg;
2N/A
2N/A /*
2N/A Dwarf_Attribute that describes the DW_AT_location in die, if
2N/A present. */
2N/A Dwarf_Attribute loc_attr = attr;
2N/A
2N/A /* Dwarf_Block that describes a single location expression. */
2N/A Dwarf_Block loc_block;
2N/A
2N/A /* A pointer to the current Dwarf_Locdesc read. */
2N/A Dwarf_Locdesc *locdesc = 0;
2N/A
2N/A Dwarf_Half form = 0;
2N/A Dwarf_Addr lowpc = 0;
2N/A Dwarf_Addr highpc = 0;
2N/A Dwarf_Signed listlen = 0;
2N/A Dwarf_Locdesc **llbuf = 0;
2N/A Dwarf_CU_Context cucontext = 0;
2N/A unsigned address_size = 0;
2N/A
2N/A int blkres = DW_DLV_ERROR;
2N/A int setup_res = DW_DLV_ERROR;
2N/A
2N/A /* ***** BEGIN CODE ***** */
2N/A setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
2N/A if (setup_res != DW_DLV_OK) {
2N/A return setup_res;
2N/A }
2N/A address_size = cucontext->cc_address_size;
2N/A /* If this is a form_block then it's a location expression. If it's
2N/A DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */
2N/A if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP ||
2N/A cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) &&
2N/A (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
2N/A (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 &&
2N/A form == DW_FORM_sec_offset))
2N/A {
2N/A
2N/A
2N/A /* A reference to .debug_loc, with an offset in .debug_loc of a
2N/A loclist */
2N/A Dwarf_Unsigned loclist_offset = 0;
2N/A int off_res = DW_DLV_ERROR;
2N/A int count_res = DW_DLV_ERROR;
2N/A int loclist_count;
2N/A int lli;
2N/A
2N/A off_res = _dwarf_get_loclist_header_start(dbg,
2N/A attr, &loclist_offset,
2N/A error);
2N/A if (off_res != DW_DLV_OK) {
2N/A return off_res;
2N/A }
2N/A count_res = _dwarf_get_loclist_count(dbg, loclist_offset,
2N/A address_size,
2N/A &loclist_count, error);
2N/A listlen = loclist_count;
2N/A if (count_res != DW_DLV_OK) {
2N/A return count_res;
2N/A }
2N/A if (loclist_count == 0) {
2N/A return DW_DLV_NO_ENTRY;
2N/A }
2N/A
2N/A llbuf = (Dwarf_Locdesc **)
2N/A _dwarf_get_alloc(dbg, DW_DLA_LIST, loclist_count);
2N/A if (!llbuf) {
2N/A _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A
2N/A for (lli = 0; lli < loclist_count; ++lli) {
2N/A blkres = _dwarf_read_loc_section(dbg, &loc_block,
2N/A &lowpc,
2N/A &highpc,
2N/A loclist_offset,
2N/A address_size,
2N/A error);
2N/A if (blkres != DW_DLV_OK) {
2N/A _dwarf_cleanup_llbuf(dbg, llbuf, lli);
2N/A return (blkres);
2N/A }
2N/A locdesc = _dwarf_get_locdesc(dbg, &loc_block,
2N/A address_size,
2N/A lowpc, highpc, error);
2N/A if (locdesc == NULL) {
2N/A _dwarf_cleanup_llbuf(dbg, llbuf, lli);
2N/A /* low level error already set: let it be passed back */
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A llbuf[lli] = locdesc;
2N/A
2N/A /* Now get to next loclist entry offset. */
2N/A loclist_offset = loc_block.bl_section_offset +
2N/A loc_block.bl_len;
2N/A }
2N/A
2N/A
2N/A } else {
2N/A Dwarf_Block *tblock = 0;
2N/A
2N/A blkres = dwarf_formblock(loc_attr, &tblock, error);
2N/A if (blkres != DW_DLV_OK) {
2N/A return (blkres);
2N/A }
2N/A loc_block = *tblock;
2N/A /* We copied tblock contents to the stack var, so can dealloc
2N/A tblock now. Avoids leaks. */
2N/A dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
2N/A listlen = 1; /* One by definition of a location entry. */
2N/A lowpc = 0; /* HACK */
2N/A highpc = (Dwarf_Unsigned) (-1LL); /* HACK */
2N/A
2N/A /* An empty location description (block length 0) means the
2N/A code generator emitted no variable, the variable was not
2N/A generated, it was unused or perhaps never tested after being
2N/A set. Dwarf2, section 2.4.1 In other words, it is not an
2N/A error, and we don't test for block length 0 specially here. */
2N/A locdesc = _dwarf_get_locdesc(dbg, &loc_block,
2N/A address_size,
2N/A lowpc, highpc, error);
2N/A if (locdesc == NULL) {
2N/A /* low level error already set: let it be passed back */
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A llbuf = (Dwarf_Locdesc **)
2N/A _dwarf_get_alloc(dbg, DW_DLA_LIST, listlen);
2N/A if (!llbuf) {
2N/A /* Free the locdesc we allocated but won't use. */
2N/A dwarf_dealloc(dbg, locdesc, DW_DLA_LOCDESC);
2N/A _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A llbuf[0] = locdesc;
2N/A }
2N/A
2N/A *llbuf_out = llbuf;
2N/A *listlen_out = listlen;
2N/A return (DW_DLV_OK);
2N/A}
2N/A
2N/A
2N/A/*
2N/A Handles only a location expression.
2N/A If called on a loclist, just returns one of those.
2N/A Cannot not handle a real loclist.
2N/A It returns the location expression as a loclist with
2N/A a single entry.
2N/A See dwarf_loclist_n() which handles any number
2N/A of location list entries.
2N/A
2N/A This is the original definition, and it simply
2N/A does not work for loclists. Kept for compatibility.
2N/A*/
2N/Aint
2N/Adwarf_loclist(Dwarf_Attribute attr,
2N/A Dwarf_Locdesc ** llbuf,
2N/A Dwarf_Signed * listlen, Dwarf_Error * error)
2N/A{
2N/A Dwarf_Debug dbg;
2N/A
2N/A /* Dwarf_Attribute that describes the DW_AT_location in die, if
2N/A present. */
2N/A Dwarf_Attribute loc_attr = attr;
2N/A
2N/A /* Dwarf_Block that describes a single location expression. */
2N/A Dwarf_Block loc_block;
2N/A
2N/A /* A pointer to the current Dwarf_Locdesc read. */
2N/A Dwarf_Locdesc *locdesc = 0;
2N/A
2N/A Dwarf_Half form = 0;
2N/A Dwarf_Addr lowpc = 0;
2N/A Dwarf_Addr highpc = 0;
2N/A Dwarf_CU_Context cucontext = 0;
2N/A unsigned address_size = 0;
2N/A
2N/A int blkres = DW_DLV_ERROR;
2N/A int setup_res = DW_DLV_ERROR;
2N/A
2N/A /* ***** BEGIN CODE ***** */
2N/A setup_res = _dwarf_setup_loc(attr, &dbg, &cucontext, &form, error);
2N/A if (setup_res != DW_DLV_OK) {
2N/A return setup_res;
2N/A }
2N/A address_size = cucontext->cc_address_size;
2N/A /* If this is a form_block then it's a location expression. If it's
2N/A DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */
2N/A if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP ||
2N/A cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) &&
2N/A (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
2N/A (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 &&
2N/A form == DW_FORM_sec_offset))
2N/A {
2N/A
2N/A /* A reference to .debug_loc, with an offset in .debug_loc of a
2N/A loclist */
2N/A Dwarf_Unsigned loclist_offset = 0;
2N/A int off_res = DW_DLV_ERROR;
2N/A
2N/A off_res = _dwarf_get_loclist_header_start(dbg,
2N/A attr, &loclist_offset,
2N/A error);
2N/A if (off_res != DW_DLV_OK) {
2N/A return off_res;
2N/A }
2N/A
2N/A /* With dwarf_loclist, just read a single entry */
2N/A blkres = _dwarf_read_loc_section(dbg, &loc_block,
2N/A &lowpc,
2N/A &highpc,
2N/A loclist_offset,
2N/A address_size,
2N/A error);
2N/A if (blkres != DW_DLV_OK) {
2N/A return (blkres);
2N/A }
2N/A } else {
2N/A Dwarf_Block *tblock = 0;
2N/A
2N/A blkres = dwarf_formblock(loc_attr, &tblock, error);
2N/A if (blkres != DW_DLV_OK) {
2N/A return (blkres);
2N/A }
2N/A loc_block = *tblock;
2N/A /* We copied tblock contents to the stack var, so can dealloc
2N/A tblock now. Avoids leaks. */
2N/A dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
2N/A lowpc = 0; /* HACK */
2N/A highpc = (Dwarf_Unsigned) (-1LL); /* HACK */
2N/A }
2N/A
2N/A /* An empty location description (block length 0) means the code
2N/A generator emitted no variable, the variable was not generated,
2N/A it was unused or perhaps never tested after being set. Dwarf2,
2N/A section 2.4.1 In other words, it is not an error, and we don't
2N/A test for block length 0 specially here.
2N/A See *dwarf_loclist_n() which handles the general case, this case
2N/A handles only a single location expression. */
2N/A locdesc = _dwarf_get_locdesc(dbg, &loc_block,
2N/A address_size,
2N/A lowpc, highpc, error);
2N/A if (locdesc == NULL) {
2N/A /* low level error already set: let it be passed back */
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A
2N/A *llbuf = locdesc;
2N/A *listlen = 1;
2N/A return (DW_DLV_OK);
2N/A}
2N/A
2N/A
2N/A
2N/A/*
2N/A Handles only a location expression.
2N/A It returns the location expression as a loclist with
2N/A a single entry.
2N/A
2N/A Usable to access dwarf expressions from any source, but
2N/A specifically from
2N/A DW_CFA_def_cfa_expression
2N/A DW_CFA_expression
2N/A DW_CFA_val_expression
2N/A
2N/A expression_in must point to a valid dwarf expression
2N/A set of bytes of length expression_length. Not
2N/A a DW_FORM_block*, just the expression bytes.
2N/A
2N/A If the address_size != de_pointer_size this will not work
2N/A right. FIXME.
2N/A*/
2N/Aint
2N/Adwarf_loclist_from_expr(Dwarf_Debug dbg,
2N/A Dwarf_Ptr expression_in,
2N/A Dwarf_Unsigned expression_length,
2N/A Dwarf_Locdesc ** llbuf,
2N/A Dwarf_Signed * listlen, Dwarf_Error * error)
2N/A{
2N/A int res = 0;
2N/A Dwarf_Half addr_size = dbg->de_pointer_size;
2N/A res = dwarf_loclist_from_expr_a(dbg,expression_in,
2N/A expression_length, addr_size,llbuf,listlen,error);
2N/A return res;
2N/A}
2N/A/* New April 27 2009. Adding addr_size argument for the rare
2N/A * cases where an object has CUs with a different address_size. */
2N/Aint
2N/Adwarf_loclist_from_expr_a(Dwarf_Debug dbg,
2N/A Dwarf_Ptr expression_in,
2N/A Dwarf_Unsigned expression_length,
2N/A Dwarf_Half addr_size,
2N/A Dwarf_Locdesc ** llbuf,
2N/A Dwarf_Signed * listlen, Dwarf_Error * error)
2N/A{
2N/A /* Dwarf_Block that describes a single location expression. */
2N/A Dwarf_Block loc_block;
2N/A
2N/A /* A pointer to the current Dwarf_Locdesc read. */
2N/A Dwarf_Locdesc *locdesc = 0;
2N/A Dwarf_Addr lowpc = 0;
2N/A Dwarf_Addr highpc = (Dwarf_Unsigned) (-1LL);
2N/A
2N/A memset(&loc_block,0,sizeof(loc_block));
2N/A loc_block.bl_len = expression_length;
2N/A loc_block.bl_data = expression_in;
2N/A loc_block.bl_from_loclist = 0; /* Not from loclist. */
2N/A loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */
2N/A
2N/A /* An empty location description (block length 0) means the code
2N/A generator emitted no variable, the variable was not generated,
2N/A it was unused or perhaps never tested after being set. Dwarf2,
2N/A section 2.4.1 In other words, it is not an error, and we don't
2N/A test for block length 0 specially here. */
2N/A locdesc = _dwarf_get_locdesc(dbg, &loc_block,
2N/A addr_size,lowpc, highpc, error);
2N/A if (locdesc == NULL) {
2N/A /* low level error already set: let it be passed back */
2N/A return (DW_DLV_ERROR);
2N/A }
2N/A
2N/A *llbuf = locdesc;
2N/A *listlen = 1;
2N/A return (DW_DLV_OK);
2N/A}
2N/A
2N/A/* Usable to read a single loclist or to read a block of them
2N/A or to read an entire section's loclists.
2N/A
2N/A It's broken because it's not safe to read a loclist entry
2N/A when we do not know the address size (in any object where
2N/A address size can vary by compilation unit).
2N/A*/
2N/A
2N/A /*ARGSUSED*/ int
2N/Adwarf_get_loclist_entry(Dwarf_Debug dbg,
2N/A Dwarf_Unsigned offset,
2N/A Dwarf_Addr * hipc_offset,
2N/A Dwarf_Addr * lopc_offset,
2N/A Dwarf_Ptr * data,
2N/A Dwarf_Unsigned * entry_len,
2N/A Dwarf_Unsigned * next_entry,
2N/A Dwarf_Error * error)
2N/A{
2N/A Dwarf_Block b;
2N/A Dwarf_Addr lowpc = 0;
2N/A Dwarf_Addr highpc = 0;
2N/A Dwarf_Half address_size = 0;
2N/A int res = DW_DLV_ERROR;
2N/A
2N/A if (!dbg->de_debug_loc.dss_data) {
2N/A int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
2N/A if (secload != DW_DLV_OK) {
2N/A return secload;
2N/A }
2N/A }
2N/A
2N/A /* FIXME: address_size is not necessarily the same in every frame. */
2N/A address_size = dbg->de_pointer_size;
2N/A res = _dwarf_read_loc_section(dbg,
2N/A &b, &lowpc, &highpc, offset,
2N/A address_size,error);
2N/A if (res != DW_DLV_OK) {
2N/A return res;
2N/A }
2N/A *hipc_offset = highpc;
2N/A *lopc_offset = lowpc;
2N/A *entry_len = b.bl_len;
2N/A *data = b.bl_data;
2N/A *next_entry = b.bl_len + b.bl_section_offset;
2N/A return DW_DLV_OK;
2N/A}
2N/A
2N/A
2N/A