blob: bc18841395adbf059e81ce1b5581ce516bc074d2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2016 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
/*
* A virtual machine that executes DWARF expressions.
*/
#include <tcf/config.h>
#if ENABLE_DebugContext
#include <errno.h>
#include <tcf/framework/trace.h>
#include <tcf/framework/myalloc.h>
#include <tcf/framework/exceptions.h>
#include <tcf/services/stacktrace.h>
#include <tcf/services/symbols.h>
#include <tcf/services/dwarf.h>
#include <tcf/services/vm.h>
#define check_e_stack(n) { if (state->stk_pos < n) inv_dwarf("Invalid location expression stack"); }
static LocationExpressionState * state = NULL;
static RegisterDefinition * reg_def = NULL;
static void * value_addr = NULL;
static size_t value_size = 0;
static unsigned implicit_pointer = 0;
static uint8_t * code = NULL;
static size_t code_pos = 0;
static size_t code_len = 0;
static void inv_dwarf(const char * msg) {
str_exception(ERR_INV_DWARF, msg);
}
static uint64_t read_memory(uint64_t addr, size_t size) {
size_t i;
uint64_t n = 0;
uint8_t buf[8];
if (context_read_mem(state->ctx, (ContextAddress)addr, buf, size) < 0) exception(errno);
for (i = 0; i < size; i++) {
n = (n << 8) | buf[state->reg_id_scope.big_endian ? i : size - i - 1];
}
return n;
}
static uint8_t read_u1(void) {
if (code_pos >= code_len) inv_dwarf("Invalid command");
return code[code_pos++];
}
static uint16_t read_u2(void) {
uint16_t x0 = read_u1();
uint16_t x1 = read_u1();
return state->reg_id_scope.big_endian ? (x0 << 8) | x1 : x0 | (x1 << 8);
}
static uint32_t read_u4(void) {
uint32_t x0 = read_u2();
uint32_t x1 = read_u2();
return state->reg_id_scope.big_endian ? (x0 << 16) | x1 : x0 | (x1 << 16);
}
static uint64_t read_u8(void) {
uint64_t x0 = read_u4();
uint64_t x1 = read_u4();
return state->reg_id_scope.big_endian ? (x0 << 32) | x1 : x0 | (x1 << 32);
}
static uint32_t read_u4leb128(void) {
uint32_t res = 0;
int i = 0;
for (;; i += 7) {
uint8_t n = read_u1();
res |= (uint32_t)(n & 0x7Fu) << i;
if ((n & 0x80) == 0) break;
}
return res;
}
static uint64_t read_u8leb128(void) {
uint64_t res = 0;
int i = 0;
for (;; i += 7) {
uint8_t n = read_u1();
res |= (uint64_t)(n & 0x7Fu) << i;
if ((n & 0x80) == 0) break;
}
return res;
}
static int64_t read_i8leb128(void) {
uint64_t res = 0;
int i = 0;
for (;; i += 7) {
uint8_t n = read_u1();
res |= (uint64_t)(n & 0x7Fu) << i;
if ((n & 0x80) == 0) {
res |= -(int64_t)(n & 0x40) << i;
break;
}
}
return (int64_t)res;
}
static uint64_t read_ia(void) {
switch (state->addr_size) {
case 1: return (int8_t)read_u1();
case 2: return (int16_t)read_u2();
case 4: return (int32_t)read_u4();
case 8: return (int64_t)read_u8();
default: inv_dwarf("Invalid address size");
}
return 0;
}
static uint64_t read_ua(void) {
switch (state->addr_size) {
case 1: return read_u1();
case 2: return read_u2();
case 4: return read_u4();
case 8: return read_u8();
default: inv_dwarf("Invalid address size");
}
return 0;
}
static LocationPiece * add_piece(void) {
LocationPiece * piece = NULL;
if (state->pieces_cnt >= state->pieces_max) {
state->pieces_max += 4;
state->pieces = (LocationPiece *)tmp_realloc(state->pieces, state->pieces_max * sizeof(LocationPiece));
}
piece = state->pieces + state->pieces_cnt++;
memset(piece, 0, sizeof(LocationPiece));
if (reg_def != NULL) {
piece->reg = reg_def;
piece->size = reg_def->size;
}
else if (value_addr != NULL) {
piece->value = value_addr;
piece->size = value_size;
}
else if (state->stk_pos == 0) {
/* An empty location description represents a piece or all of an object that is
* present in the source but not in the object code (perhaps due to optimization). */
piece->optimized_away = 1;
}
else {
state->stk_pos--;
piece->addr = (ContextAddress)state->stk[state->stk_pos];
}
piece->implicit_pointer = implicit_pointer;
implicit_pointer = 0;
value_addr = NULL;
reg_def = NULL;
return piece;
}
static void set_state(LocationExpressionState * s) {
state = s;
code = state->code;
code_pos = state->code_pos;
code_len = state->code_len;
}
static void get_state(LocationExpressionState * s) {
s->code_pos = code_pos;
state = NULL;
code = NULL;
code_pos = 0;
code_len = 0;
}
static int is_end_of_loc_expr(void) {
return
code_pos >= code_len ||
code[code_pos] == OP_piece ||
code[code_pos] == OP_bit_piece ||
code[code_pos] == OP_TCF_offset;
}
static void evaluate_expression(void) {
uint64_t data = 0;
uint8_t type = 0;
if (code_len == 0) inv_dwarf("location expression size = 0");
while (code_pos < code_len) {
LocationPiece * piece = NULL;
uint8_t op = code[code_pos++];
if (state->stk_pos + 4 > state->stk_max) {
state->stk_max += 8;
state->stk = (uint64_t *)tmp_realloc(state->stk, sizeof(uint64_t) * state->stk_max);
state->type_stk = (uint8_t *)tmp_realloc(state->type_stk, sizeof(uint8_t) * state->stk_max);
}
switch (op) {
case OP_deref:
check_e_stack(1);
state->stk[state->stk_pos - 1] = read_memory(state->stk[state->stk_pos - 1], state->addr_size);
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_deref2:
check_e_stack(1);
state->stk[state->stk_pos - 1] = (int16_t)read_memory(state->stk[state->stk_pos - 1], 2);
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_deref_size:
check_e_stack(1);
state->stk[state->stk_pos - 1] = read_memory(state->stk[state->stk_pos - 1], read_u1());
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_const:
state->stk[state->stk_pos++] = read_ia();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_const1u:
state->stk[state->stk_pos++] = read_u1();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_const1s:
state->stk[state->stk_pos++] = (int8_t)read_u1();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER;
break;
case OP_const2u:
state->stk[state->stk_pos++] = read_u2();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_const2s:
state->stk[state->stk_pos++] = (int16_t)read_u2();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER;
break;
case OP_const4u:
state->stk[state->stk_pos++] = read_u4();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_const4s:
state->stk[state->stk_pos++] = (int32_t)read_u4();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER;
break;
case OP_const8u:
state->stk[state->stk_pos++] = read_u8();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_const8s:
state->stk[state->stk_pos++] = (int64_t)read_u8();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER;
break;
case OP_constu:
state->stk[state->stk_pos++] = read_u8leb128();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_consts:
state->stk[state->stk_pos++] = read_i8leb128();
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_INTEGER;
break;
case OP_dup:
check_e_stack(1);
state->stk[state->stk_pos] = state->stk[state->stk_pos - 1];
state->type_stk[state->stk_pos] = state->type_stk[state->stk_pos - 1];
state->stk_pos++;
break;
case OP_drop:
check_e_stack(1);
state->stk_pos--;
break;
case OP_over:
check_e_stack(2);
state->stk[state->stk_pos] = state->stk[state->stk_pos - 2];
state->type_stk[state->stk_pos] = state->type_stk[state->stk_pos - 2];
state->stk_pos++;
break;
case OP_pick:
{
unsigned n = read_u1();
check_e_stack(n + 1);
state->stk[state->stk_pos] = state->stk[state->stk_pos - n - 1];
state->type_stk[state->stk_pos] = state->type_stk[state->stk_pos - n - 1];
state->stk_pos++;
}
break;
case OP_swap:
check_e_stack(2);
data = state->stk[state->stk_pos - 1];
type = state->type_stk[state->stk_pos - 1];
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 2];
state->type_stk[state->stk_pos - 1] = state->type_stk[state->stk_pos - 2];
state->stk[state->stk_pos - 2] = data;
state->type_stk[state->stk_pos - 2] = type;
break;
case OP_rot:
check_e_stack(3);
data = state->stk[state->stk_pos - 1];
type = state->type_stk[state->stk_pos - 1];
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 2];
state->type_stk[state->stk_pos - 1] = state->type_stk[state->stk_pos - 2];
state->stk[state->stk_pos - 2] = state->stk[state->stk_pos - 3];
state->type_stk[state->stk_pos - 2] = state->type_stk[state->stk_pos - 3];
state->stk[state->stk_pos - 3] = data;
state->type_stk[state->stk_pos - 2] = type;
break;
case OP_xderef:
check_e_stack(2);
state->stk[state->stk_pos - 2] = read_memory(state->stk[state->stk_pos - 1], state->addr_size);
state->type_stk[state->stk_pos - 2] = TYPE_CLASS_CARDINAL;
state->stk_pos--;
break;
case OP_xderef_size:
check_e_stack(2);
state->stk[state->stk_pos - 2] = read_memory(state->stk[state->stk_pos - 1], read_u1());
state->type_stk[state->stk_pos - 2] = TYPE_CLASS_CARDINAL;
state->stk_pos--;
break;
case OP_abs:
check_e_stack(1);
if ((int64_t)state->stk[state->stk_pos - 1] < 0) {
state->stk[state->stk_pos - 1] = ~state->stk[state->stk_pos - 1] + 1;
}
break;
case OP_and:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] & state->stk[state->stk_pos];
break;
case OP_div:
check_e_stack(2);
state->stk_pos--;
if (state->stk[state->stk_pos] == 0) inv_dwarf("Division by zero in location expression");
state->stk[state->stk_pos - 1] /= state->stk[state->stk_pos];
break;
case OP_minus:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] -= state->stk[state->stk_pos];
break;
case OP_mod:
check_e_stack(2);
state->stk_pos--;
if (state->stk[state->stk_pos] == 0) inv_dwarf("Division by zero in location expression");
state->stk[state->stk_pos - 1] %= state->stk[state->stk_pos];
break;
case OP_mul:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] *= state->stk[state->stk_pos];
break;
case OP_neg:
check_e_stack(1);
state->stk[state->stk_pos - 1] = ~state->stk[state->stk_pos - 1] + 1;
break;
case OP_not:
check_e_stack(1);
state->stk[state->stk_pos - 1] = ~state->stk[state->stk_pos - 1];
break;
case OP_or:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] | state->stk[state->stk_pos];
break;
case OP_add:
case OP_plus:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] += state->stk[state->stk_pos];
break;
case OP_plus_uconst:
check_e_stack(1);
state->stk[state->stk_pos - 1] += read_u8leb128();
break;
case OP_shl:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] <<= state->stk[state->stk_pos];
break;
case OP_shr:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] >>= state->stk[state->stk_pos];
break;
case OP_shra:
{
uint64_t cnt;
check_e_stack(2);
data = state->stk[state->stk_pos - 2];
cnt = state->stk[state->stk_pos - 1];
if (cnt >= 64) {
data = data & ((uint64_t)1 << 63) ? ~(uint64_t)0 : 0;
}
else {
while (cnt > 0) {
int s = (data & ((uint64_t)1 << 63)) != 0;
data >>= 1;
if (s) data |= (uint64_t)1 << 63;
cnt--;
}
}
state->stk[state->stk_pos - 2] = data;
state->stk_pos--;
}
break;
case OP_xor:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] ^ state->stk[state->stk_pos];
break;
case OP_bra:
check_e_stack(1);
{
size_t offs = (int16_t)read_u2();
if (state->stk[state->stk_pos - 1]) {
code_pos += offs;
if (code_pos > code_len) inv_dwarf("Invalid command");
}
state->stk_pos--;
}
break;
case OP_eq:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] == state->stk[state->stk_pos];
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_ge:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] >= state->stk[state->stk_pos];
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_gt:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] > state->stk[state->stk_pos];
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_le:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] <= state->stk[state->stk_pos];
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_lt:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] < state->stk[state->stk_pos];
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_ne:
check_e_stack(2);
state->stk_pos--;
state->stk[state->stk_pos - 1] = state->stk[state->stk_pos - 1] != state->stk[state->stk_pos];
state->type_stk[state->stk_pos - 1] = TYPE_CLASS_CARDINAL;
break;
case OP_skip:
{
size_t offs = (int16_t)read_u2();
code_pos += offs;
if (code_pos > code_len) inv_dwarf("Invalid command");
}
break;
case OP_lit0:
case OP_lit1:
case OP_lit2:
case OP_lit3:
case OP_lit4:
case OP_lit5:
case OP_lit6:
case OP_lit7:
case OP_lit8:
case OP_lit9:
case OP_lit10:
case OP_lit11:
case OP_lit12:
case OP_lit13:
case OP_lit14:
case OP_lit15:
case OP_lit16:
case OP_lit17:
case OP_lit18:
case OP_lit19:
case OP_lit20:
case OP_lit21:
case OP_lit22:
case OP_lit23:
case OP_lit24:
case OP_lit25:
case OP_lit26:
case OP_lit27:
case OP_lit28:
case OP_lit29:
case OP_lit30:
case OP_lit31:
state->stk[state->stk_pos] = op - OP_lit0;
state->type_stk[state->stk_pos++] = TYPE_CLASS_CARDINAL;
break;
case OP_reg0:
case OP_reg1:
case OP_reg2:
case OP_reg3:
case OP_reg4:
case OP_reg5:
case OP_reg6:
case OP_reg7:
case OP_reg8:
case OP_reg9:
case OP_reg10:
case OP_reg11:
case OP_reg12:
case OP_reg13:
case OP_reg14:
case OP_reg15:
case OP_reg16:
case OP_reg17:
case OP_reg18:
case OP_reg19:
case OP_reg20:
case OP_reg21:
case OP_reg22:
case OP_reg23:
case OP_reg24:
case OP_reg25:
case OP_reg26:
case OP_reg27:
case OP_reg28:
case OP_reg29:
case OP_reg30:
case OP_reg31:
{
unsigned n = op - OP_reg0;
if (!is_end_of_loc_expr()) inv_dwarf("OP_reg* must be last instruction");
reg_def = get_reg_by_id(state->ctx, n, &state->reg_id_scope);
if (reg_def == NULL) exception(errno);
}
break;
case OP_regx:
{
unsigned n = (unsigned)read_u4leb128();
if (!is_end_of_loc_expr()) inv_dwarf("OP_regx must be last instruction");
reg_def = get_reg_by_id(state->ctx, n, &state->reg_id_scope);
if (reg_def == NULL) exception(errno);
}
break;
case OP_reg:
{
unsigned n = (unsigned)read_ua();
if (!is_end_of_loc_expr()) inv_dwarf("OP_reg must be last instruction");
reg_def = get_reg_by_id(state->ctx, n, &state->reg_id_scope);
if (reg_def == NULL) exception(errno);
}
break;
case OP_breg0:
case OP_breg1:
case OP_breg2:
case OP_breg3:
case OP_breg4:
case OP_breg5:
case OP_breg6:
case OP_breg7:
case OP_breg8:
case OP_breg9:
case OP_breg10:
case OP_breg11:
case OP_breg12:
case OP_breg13:
case OP_breg14:
case OP_breg15:
case OP_breg16:
case OP_breg17:
case OP_breg18:
case OP_breg19:
case OP_breg20:
case OP_breg21:
case OP_breg22:
case OP_breg23:
case OP_breg24:
case OP_breg25:
case OP_breg26:
case OP_breg27:
case OP_breg28:
case OP_breg29:
case OP_breg30:
case OP_breg31:
{
RegisterDefinition * def = get_reg_by_id(state->ctx, op - OP_breg0, &state->reg_id_scope);
if (def == NULL) exception(errno);
if (read_reg_value(state->stack_frame, def, state->stk + state->stk_pos) < 0) exception(errno);
state->type_stk[state->stk_pos] = TYPE_CLASS_CARDINAL;
state->stk[state->stk_pos++] += read_i8leb128();
}
break;
case OP_bregx:
{
RegisterDefinition * def = get_reg_by_id(state->ctx, (unsigned)read_u4leb128(), &state->reg_id_scope);
if (def == NULL) exception(errno);
if (read_reg_value(state->stack_frame, def, state->stk + state->stk_pos) < 0) exception(errno);
state->type_stk[state->stk_pos] = TYPE_CLASS_CARDINAL;
state->stk[state->stk_pos++] += read_i8leb128();
}
break;
case OP_basereg:
{
RegisterDefinition * def = get_reg_by_id(state->ctx, (unsigned)read_ua(), &state->reg_id_scope);
if (def == NULL) exception(errno);
if (read_reg_value(state->stack_frame, def, state->stk + state->stk_pos) < 0) exception(errno);
state->type_stk[state->stk_pos++] = TYPE_CLASS_CARDINAL;
}
break;
case OP_call_frame_cfa:
{
StackFrame * frame = state->stack_frame;
if (frame == NULL) str_exception(ERR_INV_ADDRESS, "Stack frame address not available");
state->type_stk[state->stk_pos] = TYPE_CLASS_CARDINAL;
state->stk[state->stk_pos++] = frame->fp;
}
break;
case OP_nop:
break;
case OP_push_object_address:
if (state->args_cnt == 0) exception(ERR_INV_CONT_OBJ);
state->type_stk[state->stk_pos] = TYPE_CLASS_CARDINAL;
state->stk[state->stk_pos++] = state->args[0];
break;
case OP_piece:
piece = add_piece();
piece->size = read_u4leb128();
break;
case OP_bit_piece:
piece = add_piece();
piece->bit_size = read_u4leb128();
piece->bit_offs = read_u4leb128();
break;
case OP_implicit_value:
value_size = read_u4leb128();
if (code_pos + value_size > code_len) inv_dwarf("Invalid command");
value_addr = tmp_alloc(value_size);
memcpy(value_addr, code + code_pos, value_size);
code_pos += value_size;
if (!is_end_of_loc_expr()) inv_dwarf("OP_implicit_value must be last instruction");
break;
case OP_stack_value:
check_e_stack(1);
value_size = state->addr_size;
value_addr = tmp_alloc(value_size);
{
unsigned i;
uint8_t * buf = (uint8_t *)value_addr;
uint64_t n = state->stk[--state->stk_pos];
for (i = 0; i < value_size; i++) {
buf[state->reg_id_scope.big_endian ? value_size - i - 1 : i] = (uint8_t)n;
n >>= 8;
}
}
if (!is_end_of_loc_expr()) inv_dwarf("OP_stack_value must be last instruction");
break;
case OP_GNU_const_type:
inv_dwarf("Unsupported type in OP_GNU_const_type");
break;
case OP_GNU_regval_type:
inv_dwarf("Unsupported type in OP_GNU_regval_type");
break;
case OP_GNU_deref_type:
inv_dwarf("Unsupported type in OP_GNU_deref_type");
break;
case OP_GNU_convert:
inv_dwarf("Unsupported type in OP_GNU_convert");
break;
case OP_TCF_switch:
check_e_stack(1);
{
uint64_t n = state->stk[--state->stk_pos];
size_t end_pos = read_u2();
end_pos += code_pos;
if (end_pos > code_len) inv_dwarf("Invalid command");
for (;;) {
uint64_t addr, size;
size_t nxt_pos = read_u2();
nxt_pos += code_pos;
if (nxt_pos > end_pos) inv_dwarf("Invalid command");
if (nxt_pos == code_pos) {
str_exception(ERR_OTHER, "Object is not available at this location in the code");
}
addr = read_u8leb128();
size = read_u8leb128();
if (size == 0 || (n >= addr && n - addr < size)) {
Trap trap;
size_t code_len_org = code_len;
if (set_trap(&trap)) {
code_len = state->code_len = nxt_pos;
evaluate_expression();
clear_trap(&trap);
}
code_len = state->code_len = code_len_org;
if (trap.error) exception(trap.error);
break;
}
code_pos = nxt_pos;
}
code_pos = end_pos;
}
break;
case OP_TCF_offset:
if (reg_def != NULL || value_addr != NULL) add_piece();
if (state->pieces_cnt) {
unsigned cnt = 0;
uint32_t bit_offs = 0;
uint32_t offs = read_u4leb128();
LocationPiece * pieces = state->pieces;
unsigned pieces_cnt = state->pieces_cnt;
state->pieces = NULL;
state->pieces_cnt = state->pieces_max = 0;
while (cnt < pieces_cnt) {
LocationPiece * org_piece = pieces + cnt++;
if (org_piece->bit_size == 0) org_piece->bit_size = org_piece->size * 8;
if (bit_offs + org_piece->bit_size > offs * 8) {
LocationPiece * piece = NULL;
if (state->pieces_cnt >= state->pieces_max) {
state->pieces_max += 4;
state->pieces = (LocationPiece *)tmp_realloc(state->pieces, state->pieces_max * sizeof(LocationPiece));
}
piece = state->pieces + state->pieces_cnt++;
*piece = *org_piece;
if (bit_offs < offs * 8) {
piece->bit_offs += offs * 8 - bit_offs;
piece->bit_size -= offs * 8 - bit_offs;
}
if (piece->bit_offs == 0 && piece->bit_size % 8 == 0) {
piece->size = piece->bit_size / 8;
piece->bit_size = 0;
}
piece->implicit_pointer++;
}
bit_offs += org_piece->bit_size;
}
if (state->pieces_cnt == 0) inv_dwarf("Invalid size of implicit value");
}
else {
check_e_stack(1);
state->stk[state->stk_pos - 1] += read_u8leb128();
implicit_pointer++;
}
break;
case OP_GNU_entry_value:
{
#if SERVICE_StackTrace || ENABLE_ContextProxy
LocationExpressionState * s = state;
LocationExpressionState entry_state;
int frame = get_prev_frame(s->ctx, get_info_frame(s->ctx, s->stack_frame));
uint32_t size = read_u4leb128();
Trap trap;
get_state(s);
if (set_trap(&trap)) {
memset(&entry_state, 0, sizeof(entry_state));
entry_state.ctx = s->ctx;
if (get_frame_info(s->ctx, frame, &entry_state.stack_frame) < 0) exception(errno);
entry_state.reg_id_scope = s->reg_id_scope;
entry_state.addr_size = s->addr_size;
entry_state.code = s->code + s->code_pos;
entry_state.code_len = size;
entry_state.client_op = s->client_op;
if (evaluate_vm_expression(&entry_state) < 0) exception(errno);
if (entry_state.pieces_cnt > 0) {
size_t i;
uint64_t value = 0;
void * value_addr = NULL;
size_t value_size = 0;
read_location_pieces(entry_state.ctx, entry_state.stack_frame,
entry_state.pieces, entry_state.pieces_cnt, 0,
&value_addr, &value_size);
if (value_size > sizeof(value)) inv_dwarf("Invalid OP_entry_value expression");
for (i = 0; i < value_size; i++) {
value |= ((uint8_t *)value_addr)[i] << (i * 8);
}
s->type_stk[s->stk_pos] = TYPE_CLASS_CARDINAL;
s->stk[s->stk_pos++] = value;
}
else if (entry_state.stk_pos == 1) {
s->type_stk[s->stk_pos] = entry_state.type_stk[entry_state.stk_pos - 1];
s->stk[s->stk_pos++] = entry_state.stk[entry_state.stk_pos - 1];
}
else {
inv_dwarf("Invalid OP_entry_value expression");
}
clear_trap(&trap);
}
s->code_pos += size;
set_state(s);
if (trap.error) exception(trap.error);
#else
inv_dwarf("Cannot execute OP_entry_value: stack trace not available");
#endif
}
break;
case OP_call2:
case OP_call4:
case OP_call_ref:
default:
if (state->client_op != NULL) {
LocationExpressionState * s = state;
Trap trap;
get_state(s);
if (set_trap(&trap)) {
s->client_op(op);
clear_trap(&trap);
}
set_state(s);
if (trap.error) exception(trap.error);
}
else {
str_fmt_exception(ERR_UNSUPPORTED, "Unsupported location expression op 0x%02x", op);
}
}
}
}
int evaluate_vm_expression(LocationExpressionState * vm_state) {
int error = 0;
Trap trap;
implicit_pointer = 0;
value_addr = NULL;
reg_def = NULL;
set_state(vm_state);
if (set_trap(&trap)) {
evaluate_expression();
if (reg_def != NULL || value_addr != NULL || implicit_pointer) add_piece();
clear_trap(&trap);
}
else {
error = trap.error;
}
get_state(vm_state);
if (!error) return 0;
errno = error;
return -1;
}
#endif /* ENABLE_DebugContext */