#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarf_loc.h"
#include "dwarfstring.h"
#define TRUE 1
#define FALSE 0
static int
read_encoded_addr(Dwarf_Small *loc_ptr,
Dwarf_Debug dbg,
Dwarf_Small *section_end_ptr,
Dwarf_Unsigned * val_out,
int * len_out,
Dwarf_Error *error)
{
int len = 0;
Dwarf_Small op = *loc_ptr;
Dwarf_Unsigned operand = 0;
len++;
if (op == 0) {
op = dbg->de_pointer_size;
}
switch (op) {
case 1:
*val_out = *loc_ptr;
len++;
break;
case 2:
READ_UNALIGNED_CK(dbg, operand, Dwarf_Unsigned, loc_ptr, 2,
error,section_end_ptr);
*val_out = operand;
len +=2;
break;
case 4:
READ_UNALIGNED_CK(dbg, operand, Dwarf_Unsigned, loc_ptr, 4,
error,section_end_ptr);
*val_out = operand;
len +=4;
break;
case 8:
READ_UNALIGNED_CK(dbg, operand, Dwarf_Unsigned, loc_ptr, 8,
error,section_end_ptr);
*val_out = operand;
len +=8;
break;
default:
_dwarf_error(dbg, error, DW_DLE_GNU_OPCODE_ERROR);
return DW_DLV_ERROR;
};
*len_out = len;
return DW_DLV_OK;
}
int
_dwarf_read_loc_expr_op(Dwarf_Debug dbg,
Dwarf_Block_c * loc_block,
Dwarf_Signed opnumber,
Dwarf_Half version_stamp,
Dwarf_Half offset_size,
Dwarf_Half address_size,
Dwarf_Signed startoffset_in,
Dwarf_Small *section_end,
Dwarf_Unsigned *nextoffset_out,
Dwarf_Loc_Expr_Op curr_loc,
Dwarf_Error * error)
{
Dwarf_Small *loc_ptr = 0;
Dwarf_Unsigned loc_len = 0;
Dwarf_Unsigned offset = startoffset_in;
Dwarf_Unsigned operand1 = 0;
Dwarf_Unsigned operand2 = 0;
Dwarf_Unsigned operand3 = 0;
Dwarf_Small atom = 0;
Dwarf_Unsigned leb128_length = 0;
if (offset > loc_block->bl_len) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
loc_len = loc_block->bl_len;
if (offset == loc_len) {
return DW_DLV_NO_ENTRY;
}
loc_ptr = (Dwarf_Small*)loc_block->bl_data + offset;
if ((loc_ptr+1) > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
memset(curr_loc,0,sizeof(*curr_loc));
curr_loc->lr_opnumber = opnumber;
curr_loc->lr_offset = offset;
atom = *(Dwarf_Small *) loc_ptr;
loc_ptr++;
offset++;
curr_loc->lr_atom = atom;
switch (atom) {
case DW_OP_reg0:
case DW_OP_reg1:
case DW_OP_reg2:
case DW_OP_reg3:
case DW_OP_reg4:
case DW_OP_reg5:
case DW_OP_reg6:
case DW_OP_reg7:
case DW_OP_reg8:
case DW_OP_reg9:
case DW_OP_reg10:
case DW_OP_reg11:
case DW_OP_reg12:
case DW_OP_reg13:
case DW_OP_reg14:
case DW_OP_reg15:
case DW_OP_reg16:
case DW_OP_reg17:
case DW_OP_reg18:
case DW_OP_reg19:
case DW_OP_reg20:
case DW_OP_reg21:
case DW_OP_reg22:
case DW_OP_reg23:
case DW_OP_reg24:
case DW_OP_reg25:
case DW_OP_reg26:
case DW_OP_reg27:
case DW_OP_reg28:
case DW_OP_reg29:
case DW_OP_reg30:
case DW_OP_reg31:
break;
case DW_OP_regx:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_lit0:
case DW_OP_lit1:
case DW_OP_lit2:
case DW_OP_lit3:
case DW_OP_lit4:
case DW_OP_lit5:
case DW_OP_lit6:
case DW_OP_lit7:
case DW_OP_lit8:
case DW_OP_lit9:
case DW_OP_lit10:
case DW_OP_lit11:
case DW_OP_lit12:
case DW_OP_lit13:
case DW_OP_lit14:
case DW_OP_lit15:
case DW_OP_lit16:
case DW_OP_lit17:
case DW_OP_lit18:
case DW_OP_lit19:
case DW_OP_lit20:
case DW_OP_lit21:
case DW_OP_lit22:
case DW_OP_lit23:
case DW_OP_lit24:
case DW_OP_lit25:
case DW_OP_lit26:
case DW_OP_lit27:
case DW_OP_lit28:
case DW_OP_lit29:
case DW_OP_lit30:
case DW_OP_lit31:
operand1 = atom - DW_OP_lit0;
break;
case DW_OP_addr:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned,
loc_ptr, address_size,
error,section_end);
loc_ptr += address_size;
offset += address_size;
break;
case DW_OP_const1u:
if (loc_ptr >= section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
operand1 = *(Dwarf_Small *) loc_ptr;
loc_ptr = loc_ptr + 1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + 1;
break;
case DW_OP_const1s:
if (loc_ptr >= section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
operand1 = *(Dwarf_Sbyte *) loc_ptr;
SIGN_EXTEND(operand1,1);
loc_ptr = loc_ptr + 1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + 1;
break;
case DW_OP_const2u:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2,
error,section_end);
loc_ptr = loc_ptr + 2;
offset = offset + 2;
break;
case DW_OP_const2s:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2,
error, section_end);
SIGN_EXTEND(operand1,2);
loc_ptr = loc_ptr + 2;
offset = offset + 2;
break;
case DW_OP_const4u:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4,
error, section_end);
loc_ptr = loc_ptr + 4;
offset = offset + 4;
break;
case DW_OP_const4s:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4,
error, section_end);
SIGN_EXTEND(operand1,4);
loc_ptr = loc_ptr + 4;
offset = offset + 4;
break;
case DW_OP_const8u:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8,
error, section_end);
loc_ptr = loc_ptr + 8;
offset = offset + 8;
break;
case DW_OP_const8s:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8,
error, section_end);
loc_ptr = loc_ptr + 8;
offset = offset + 8;
break;
case DW_OP_constu:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_consts:
DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_fbreg:
DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_bregx:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand2,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_dup:
case DW_OP_drop:
break;
case DW_OP_pick:
if (loc_ptr >= section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
operand1 = *(Dwarf_Small *) loc_ptr;
loc_ptr = loc_ptr + 1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + 1;
break;
case DW_OP_over:
case DW_OP_swap:
case DW_OP_rot:
case DW_OP_deref:
break;
case DW_OP_deref_size:
if (loc_ptr >= section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
operand1 = *(Dwarf_Small *) loc_ptr;
loc_ptr = loc_ptr + 1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + 1;
break;
case DW_OP_xderef:
break;
case DW_OP_xderef_type:
if (loc_ptr >= section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
operand1 = *(Dwarf_Small *) loc_ptr;
loc_ptr = loc_ptr + 1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + 1;
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_xderef_size:
if (loc_ptr >= section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
operand1 = *(Dwarf_Small *) loc_ptr;
loc_ptr = loc_ptr + 1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + 1;
break;
case DW_OP_abs:
case DW_OP_and:
case DW_OP_div:
case DW_OP_minus:
case DW_OP_mod:
case DW_OP_mul:
case DW_OP_neg:
case DW_OP_not:
case DW_OP_or:
case DW_OP_plus:
break;
case DW_OP_plus_uconst:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_shl:
case DW_OP_shr:
case DW_OP_shra:
case DW_OP_xor:
break;
case DW_OP_le:
case DW_OP_ge:
case DW_OP_eq:
case DW_OP_lt:
case DW_OP_gt:
case DW_OP_ne:
break;
case DW_OP_skip:
case DW_OP_bra:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2,
error,section_end);
loc_ptr = loc_ptr + 2;
offset = offset + 2;
break;
case DW_OP_piece:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_nop:
break;
case DW_OP_push_object_address:
break;
case DW_OP_call2:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2,
error,section_end);
loc_ptr = loc_ptr + 2;
offset = offset + 2;
break;
case DW_OP_call4:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4,
error,section_end);
loc_ptr = loc_ptr + 4;
offset = offset + 4;
break;
case DW_OP_call_ref:
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr,
offset_size,
error,section_end);
loc_ptr = loc_ptr + offset_size;
offset = offset + offset_size;
break;
case DW_OP_form_tls_address:
break;
case DW_OP_call_frame_cfa:
break;
case DW_OP_bit_piece:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_GNU_push_tls_address:
break;
case DW_OP_deref_type:
case DW_OP_GNU_deref_type:
if (loc_ptr >= section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
operand1 = *(Dwarf_Small *) loc_ptr;
loc_ptr = loc_ptr + 1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + 1;
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_implicit_value:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr;
offset = offset + operand1;
loc_ptr = loc_ptr + operand1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
break;
case DW_OP_stack_value:
break;
case DW_OP_GNU_uninit:
break;
case DW_OP_GNU_encoded_addr: {
int length = 0;
int reares = read_encoded_addr(loc_ptr,dbg,
section_end,
&operand1, &length,error);
if (reares != DW_DLV_OK) {
return reares;
}
loc_ptr += length;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset += length;
}
break;
case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:{
Dwarf_Small iplen = offset_size;
if (version_stamp == DW_CU_VERSION2 ) {
iplen = address_size;
}
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr,
iplen,error,section_end);
loc_ptr = loc_ptr + iplen;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + iplen;
DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand2,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
}
break;
case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr;
offset = offset + operand1;
loc_ptr = loc_ptr + operand1;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
break;
case DW_OP_const_type:
case DW_OP_GNU_const_type:
{
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
operand2 = *loc_ptr;
loc_ptr = loc_ptr + 1;
offset = offset + 1;
operand3 = (Dwarf_Unsigned)(uintptr_t)loc_ptr;
loc_ptr = loc_ptr + operand2;
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
offset = offset + operand2;
}
break;
case DW_OP_regval_type:
case DW_OP_GNU_regval_type:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_convert:
case DW_OP_GNU_convert:
case DW_OP_reinterpret:
case DW_OP_GNU_reinterpret:
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_GNU_parameter_ref :
READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4,
error,section_end);;
loc_ptr = loc_ptr + 4;
offset = offset + 4;
break;
case DW_OP_addrx :
case DW_OP_GNU_addr_index :
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
case DW_OP_constx :
case DW_OP_GNU_const_index :
DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length,
dbg,error,section_end);
offset = offset + leb128_length;
break;
default:
_dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
return DW_DLV_ERROR;
}
if (loc_ptr > section_end) {
_dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END);
return DW_DLV_ERROR;
}
if (offset > loc_len) {
_dwarf_error(dbg, error, DW_DLE_LOC_BAD_TERMINATION);
return DW_DLV_ERROR;
}
curr_loc->lr_atom = atom;
curr_loc->lr_raw1 = operand1;
curr_loc->lr_number = operand1;
curr_loc->lr_raw2 = operand2;
curr_loc->lr_number2 = operand2;
curr_loc->lr_raw3 = operand3;
curr_loc->lr_number3 = operand3;
*nextoffset_out = offset;
return DW_DLV_OK;
}