initial implementation of DWARF Expression state machine parsing and

it's usage for retrieve arguments/variables of function
This commit is contained in:
2020-01-13 17:21:46 +04:00
parent 08ba87ce98
commit 50bebda6a1
5 changed files with 719 additions and 335 deletions
+147 -27
View File
@@ -20,6 +20,73 @@
extern SC_LogBase* logger; extern SC_LogBase* logger;
bool dwarf_value::get_int(int64_t& v)
{
switch (size) {
case 1:
v = *((int8_t*)value);
break;
case 2:
v = *((int16_t*)value);
break;
case 4:
v = *((int32_t*)value);
break;
case 8:
v = *((int64_t*)value);
break;
default:
return false;
break;
}
return true;
}
bool dwarf_value::get_uint(uint64_t& v)
{
if(type & DWARF_TYPE_SIGNED) {
int64_t sig;
if(!get_int(sig)) {
return false;
}
v = llabs(sig);
} else {
return get_generic(v);
}
return true;
}
__dwarf_value& dwarf_value::operator+=(const __dwarf_value& rhs)
{
return *this;
}
bool dwarf_value::get_generic(uint64_t& v)
{
switch (size) {
case 1:
v = *((uint8_t*)value);
break;
case 2:
v = *((uint16_t*)value);
break;
case 4:
v = *((uint32_t*)value);
break;
case 8:
v = *((uint64_t*)value);
break;
default:
return false;
break;
}
return true;
}
bool __pst_context::print(const char* fmt, ...) bool __pst_context::print(const char* fmt, ...)
{ {
bool nret = true; bool nret = true;
@@ -58,16 +125,17 @@ uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff,
if(map) { if(map) {
if(map->op_num >= DW_OP_breg0 && map->op_num <= DW_OP_breg16) { if(map->op_num >= DW_OP_breg0 && map->op_num <= DW_OP_breg16) {
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number); int32_t off = decode_sleb128((unsigned char*)&exprs[i].number);
int regno = map->op_num - DW_OP_breg0;
unw_word_t ptr = 0; unw_word_t ptr = 0;
unw_get_reg(&cursor, map->regno, &ptr); unw_get_reg(&cursor, regno, &ptr);
//ptr += off; //ptr += off;
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s%s%d) reg_value: 0x%lX ", map->op_name, map->regname, off >=0 ? "+" : "", off, ptr); offset += snprintf(buff + offset, buff_size - offset, "%s(*%s%s%d) reg_value: 0x%lX ", map->op_name, unw_regname(regno), off >=0 ? "+" : "", off, ptr);
} else if(map->op_num >= DW_OP_reg0 && map->op_num <= DW_OP_reg16) { } else if(map->op_num >= DW_OP_reg0 && map->op_num <= DW_OP_reg16) {
unw_word_t value = 0; unw_word_t value = 0;
unw_get_reg(&cursor, map->regno, &value); int regno = map->op_num - DW_OP_reg0;
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s) value: 0x%lX", map->op_name, map->regname, value); unw_get_reg(&cursor, regno, &value);
offset += snprintf(buff + offset, buff_size - offset, "%s(*%s) value: 0x%lX", map->op_name, unw_regname(regno), value);
} else if(map->op_num == DW_OP_GNU_entry_value) { } else if(map->op_num == DW_OP_GNU_entry_value) {
uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number); uint32_t value = decode_uleb128((unsigned char*)&exprs[i].number);
offset += snprintf(buff + offset, buff_size - offset, "%s(%u, ", map->op_name, value); offset += snprintf(buff + offset, buff_size - offset, "%s(%u, ", map->op_name, value);
@@ -76,7 +144,7 @@ uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff,
Dwarf_Op *expr; Dwarf_Op *expr;
size_t exprlen; size_t exprlen;
if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) { if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) {
offset += print_expr_block (expr, exprlen, buff + offset, buff_size - offset, attr); offset += print_expr_block (expr, exprlen, buff + offset, buff_size - offset, &attr_mem);
offset += snprintf(buff + offset, buff_size - offset, ") "); offset += snprintf(buff + offset, buff_size - offset, ") ");
} else { } else {
log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location"); log(SEVERITY_ERROR, "Failed to get DW_OP_GNU_entry_value attr location");
@@ -94,7 +162,7 @@ uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff,
int32_t off = decode_sleb128((unsigned char*)&exprs[i].number2); int32_t off = decode_sleb128((unsigned char*)&exprs[i].number2);
unw_word_t ptr = 0; unw_word_t ptr = 0;
unw_get_reg(&cursor, map->regno, &ptr); unw_get_reg(&cursor, regno, &ptr);
//ptr += off; //ptr += off;
offset += snprintf(buff + offset, buff_size - offset, "%s(%s%s%d) reg_value = 0x%lX", map->op_name, unw_regname(regno), off >= 0 ? "+" : "", off, ptr); offset += snprintf(buff + offset, buff_size - offset, "%s(%s%s%d) reg_value = 0x%lX", map->op_name, unw_regname(regno), off >= 0 ? "+" : "", off, ptr);
@@ -121,6 +189,58 @@ uint32_t __pst_context::print_expr_block (Dwarf_Op *exprs, int len, char* buff,
return offset; return offset;
} }
bool __pst_context::calc_expression(Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr)
{
stack.clear();
for (int i = 0; i < expr_len; i++) {
const dwarf_op_map* map = find_op_map(exprs[i].atom);
if(!map) {
log(SEVERITY_ERROR, "Unknown operation type 0x%hhX(0x%lX, 0x%lX)", exprs[i].atom, exprs[i].number, exprs[i].number2);
return false;
}
dwarf_value* v = stack.get();
if(v && v->type == DWARF_TYPE_REGISTER_LOC) {
// dereference register location
unw_word_t value = 0;
uint64_t regno = *((uint64_t*)v->value);
if(unw_get_reg(&cursor, regno, &value)) {
log(SEVERITY_ERROR, "Failed to ger value of register 0x%lX", regno);
return false;
}
v->replace(&value, sizeof(value), DWARF_TYPE_GENERIC);
}
if(!map->operation(this, map, exprs[i].number, exprs[i].number2)) {
log(SEVERITY_ERROR, "Failed to calculate %s(0x%lX, 0x%lX) operation", map->op_name, exprs[i].number, exprs[i].number2);
return false;
}
}
if(stack.Size()) {
unw_word_t value = 0;
dwarf_value* v = stack.get();
v->get_uint(value);
if(v->type & DWARF_TYPE_REGISTER_LOC) {
// dereference register location
uint64_t regno;
v->get_uint(regno);
if(unw_get_reg(&cursor, regno, &value)) {
log(SEVERITY_ERROR, "Failed to get value of register 0x%lX", regno);
return false;
}
}
log(SEVERITY_INFO, "Found 0x%X value of location expression", value);
return true;
} else {
log(SEVERITY_ERROR, "No value found for location expression");
return false;
}
return true;
}
bool is_location_form(int form) bool is_location_form(int form)
{ {
if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block || if (form == DW_FORM_block1 || form == DW_FORM_block2 || form == DW_FORM_block4 || form == DW_FORM_block ||
@@ -157,22 +277,22 @@ uint32_t decode_uleb128(uint8_t *uleb128)
// Utility function to encode a ULEB128 value to a buffer. Returns // Utility function to encode a ULEB128 value to a buffer. Returns
// the length in bytes of the encoded value. // the length in bytes of the encoded value.
inline unsigned encodeULEB128(uint64_t Value, uint8_t *p, unsigned PadTo = 0) inline unsigned encode_uleb128(uint64_t value, uint8_t *p, unsigned PadTo = 0)
{ {
uint8_t *orig_p = p; uint8_t *orig_p = p;
unsigned Count = 0; unsigned count = 0;
do { do {
uint8_t Byte = Value & 0x7f; uint8_t Byte = value & 0x7f;
Value >>= 7; value >>= 7;
Count++; count++;
if (Value != 0 || Count < PadTo) if (value != 0 || count < PadTo)
Byte |= 0x80; // Mark this byte to show that more bytes will follow. Byte |= 0x80; // Mark this byte to show that more bytes will follow.
*p++ = Byte; *p++ = Byte;
} while (Value != 0); } while (value != 0);
// Pad with 0x80 and emit a null byte at the end. // Pad with 0x80 and emit a null byte at the end.
if (Count < PadTo) { if (count < PadTo) {
for (; Count < PadTo - 1; ++Count) for (; count < PadTo - 1; ++count)
*p++ = '\x80'; *p++ = '\x80';
*p++ = '\x00'; *p++ = '\x00';
} }
@@ -182,27 +302,27 @@ inline unsigned encodeULEB128(uint64_t Value, uint8_t *p, unsigned PadTo = 0)
// Utility function to encode a SLEB128 value to a buffer. Returns // Utility function to encode a SLEB128 value to a buffer. Returns
// the length in bytes of the encoded value. // the length in bytes of the encoded value.
inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) inline unsigned encode_sleb128(int64_t value, uint8_t *p, unsigned PadTo = 0)
{ {
uint8_t *orig_p = p; uint8_t *orig_p = p;
unsigned Count = 0; unsigned count = 0;
bool More; bool More;
do { do {
uint8_t Byte = Value & 0x7f; uint8_t Byte = value & 0x7f;
// NOTE: this assumes that this signed shift is an arithmetic right shift. // NOTE: this assumes that this signed shift is an arithmetic right shift.
Value >>= 7; value >>= 7;
More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || More = !((((value == 0 ) && ((Byte & 0x40) == 0)) ||
((Value == -1) && ((Byte & 0x40) != 0)))); ((value == -1) && ((Byte & 0x40) != 0))));
Count++; count++;
if (More || Count < PadTo) if (More || count < PadTo)
Byte |= 0x80; // Mark this byte to show that more bytes will follow. Byte |= 0x80; // Mark this byte to show that more bytes will follow.
*p++ = Byte; *p++ = Byte;
} while (More); } while (More);
// Pad with 0x80 and emit a terminating byte at the end. // Pad with 0x80 and emit a terminating byte at the end.
if (Count < PadTo) { if (count < PadTo) {
uint8_t PadValue = Value < 0 ? 0x7f : 0x00; uint8_t PadValue = value < 0 ? 0x7f : 0x00;
for (; Count < PadTo - 1; ++Count) for (; count < PadTo - 1; ++count)
*p++ = (PadValue | 0x80); *p++ = (PadValue | 0x80);
*p++ = PadValue; *p++ = PadValue;
} }
+22 -68
View File
@@ -10,21 +10,22 @@
typedef enum { typedef enum {
DWARF_TYPE_INVALID = 0, DWARF_TYPE_INVALID = 0,
DWARF_TYPE_UNSIGNED, DWARF_TYPE_SIGNED = 1,
DWARF_TYPE_SIGNED, DWARF_TYPE_UNSIGNED = 2,
DWARF_TYPE_ADDRESS, DWARF_TYPE_CONST = 4,
DWARF_TYPE_GENERIC DWARF_TYPE_GENERIC = 8,
DWARF_TYPE_CHAR = 16,
DWARF_TYPE_FLOAT = 32,
DWARF_TYPE_REGISTER_LOC = 64,
DWARF_TYPE_MEMORY_LOC = 128,
DWARF_TYPE_PIECE = 256,
DWARF_TYPE_SHORT = 512,
DWARF_TYPE_INT = 1024,
DWARF_TYPE_LONG = 2048
} dwarf_value_type; } dwarf_value_type;
typedef struct __dwarf_value : public SC_ListNode { typedef struct __dwarf_value : public SC_ListNode {
__dwarf_value(uint32_t s) __dwarf_value(char*v, uint32_t s, int t)
{
size = s;
value = (char*)malloc(s);
type = DWARF_TYPE_INVALID;
}
__dwarf_value(char*v, uint32_t s, dwarf_value_type t)
{ {
size = s; size = s;
value = (char*)malloc(s); value = (char*)malloc(s);
@@ -32,13 +33,6 @@ typedef struct __dwarf_value : public SC_ListNode {
type = t; type = t;
} }
__dwarf_value()
{
value = NULL;
size = 0;
type = DWARF_TYPE_INVALID;
}
~__dwarf_value() ~__dwarf_value()
{ {
if(value) { if(value) {
@@ -48,7 +42,7 @@ typedef struct __dwarf_value : public SC_ListNode {
} }
} }
void replace(void* v, uint32_t s, dwarf_value_type t) void replace(void* v, uint32_t s, int t)
{ {
if(value) { if(value) {
free(value); free(value);
@@ -62,55 +56,14 @@ typedef struct __dwarf_value : public SC_ListNode {
type = t; type = t;
} }
bool get_uint(uint64_t v) bool get_uint(uint64_t& v);
{ bool get_int(int64_t& v);
switch (size) { bool get_generic(uint64_t& v);
case 1: __dwarf_value& operator+=(const __dwarf_value& rhs);
v = (uint8_t)*((uint8_t*)value);
break;
case 2:
v = (uint16_t)*((uint16_t*)value);
break;
case 4:
v = (uint32_t)*((uint32_t*)value);
break;
case 8:
v = (uint64_t)*((uint64_t*)value);
break;
default:
return false;
break;
}
return true;
}
bool get_int(int64_t v)
{
switch (size) {
case 1:
v = (int8_t)*((int8_t*)value);
break;
case 2:
v = (int16_t)*((int16_t*)value);
break;
case 4:
v = (int32_t)*((int32_t*)value);
break;
case 8:
v = (int64_t)*((int64_t*)value);
break;
default:
return false;
break;
}
return true;
}
char* value; char* value;
uint32_t size; uint32_t size; // size in bytes except of 'DWARF_TYPE_PIECE', in such case in bits
dwarf_value_type type; int type; // bitmask of DWARF_TYPE_XXX
} dwarf_value; } dwarf_value;
typedef struct __dwarf_stack : public SC_ListHead { typedef struct __dwarf_stack : public SC_ListHead {
@@ -121,7 +74,7 @@ typedef struct __dwarf_stack : public SC_ListHead {
} }
} }
void push(void* v, uint32_t s, dwarf_value_type t) { void push(void* v, uint32_t s, int t) {
dwarf_value* value = new dwarf_value((char*)v, s, t); dwarf_value* value = new dwarf_value((char*)v, s, t);
InsertFirst(value); InsertFirst(value);
} }
@@ -160,6 +113,7 @@ typedef struct __pst_context {
bool print(const char* fmt, ...); bool print(const char* fmt, ...);
void log(SC_LogSeverity severity, const char*fmt, ...); void log(SC_LogSeverity severity, const char*fmt, ...);
uint32_t print_expr_block(Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr = 0); uint32_t print_expr_block(Dwarf_Op *exprs, int len, char* buff, uint32_t buff_size, Dwarf_Attribute* attr = 0);
bool calc_expression(Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr);
ucontext_t* hcontext; // context of signal handler ucontext_t* hcontext; // context of signal handler
unw_context_t context; // context of stack trace unw_context_t context; // context of stack trace
+508 -190
View File
@@ -6,12 +6,53 @@
*/ */
#include <dwarf.h> #include <dwarf.h>
#include <inttypes.h>
#include "dwarf_operations.h" #include "dwarf_operations.h"
#include "common.h" #include "common.h"
dwarf_reg_map reg_map[] = {
// GP Registers
{0x0, "RAX", "DW_OP_reg0"},
{0x1, "RDX", "DW_OP_reg1"},
{0x2, "RCX", "DW_OP_reg2"},
{0x3, "RBX", "DW_OP_reg3"},
{0x4, "RSI", "DW_OP_reg4"},
{0x5, "RDI", "DW_OP_reg5"},
{0x6, "RBP", "DW_OP_reg6"},
{0x7, "RSP", "DW_OP_reg7"},
// Extended GP Registers
{0x8, "R8", "DW_OP_reg8"},
{0x9, "R9", "DW_OP_reg9"},
{0xA, "R10", "DW_OP_reg10"},
{0xB, "R11", "DW_OP_reg11"},
{0xC, "R12", "DW_OP_reg12"},
{0xD, "R13", "DW_OP_reg13"},
{0xE, "R14", "DW_OP_reg14"},
{0xF, "R15", "DW_OP_reg15"},
{0x10, "RIP", "DW_OP_reg16"}, // Return Address (RA) mapped to RIP
// SSE Vector Registers
{0x11, "XMM0", "DW_OP_reg17"},
{0x12, "XMM1", "DW_OP_reg18"},
{0x13, "XMM2", "DW_OP_reg19"},
{0x14, "XMM3", "DW_OP_reg20"},
{0x15, "XMM4", "DW_OP_reg21"},
{0x16, "XMM5", "DW_OP_reg22"},
{0x17, "XMM6", "DW_OP_reg23"},
{0x18, "XMM7", "DW_OP_reg24"},
{0x19, "XMM8", "DW_OP_reg25"},
{0x1a, "XMM9", "DW_OP_reg26"},
{0x1b, "XMM10", "DW_OP_reg27"},
{0x1c, "XMM11", "DW_OP_reg28"},
{0x1d, "XMM12", "DW_OP_reg29"},
{0x1e, "XMM13", "DW_OP_reg30"},
{0x1f, "XMM14", "DW_OP_reg31"},
};
// not implemented operations
bool dw_op_notimpl(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) bool dw_op_notimpl(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
{ {
ctx->log(SEVERITY_ERROR, "0x%lX => %s(0x%lX, 0x%lX) operation is not implemented", map->op_num, map->op_name, op1, op2); ctx->log(SEVERITY_ERROR, "%s(0x%lX, 0x%lX) operation is not implemented", map->op_name, op1, op2);
return false; return false;
} }
@@ -19,7 +60,7 @@ bool dw_op_addr(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf
{ {
// The DW_OP_addr operation has a single operand that encodes a machine // The DW_OP_addr operation has a single operand that encodes a machine
// address and whose size is the size of an address on the target machine. // address and whose size is the size of an address on the target machine.
ctx->stack.push(&op1, sizeof(op1), DWARF_TYPE_ADDRESS); ctx->stack.push(&op1, sizeof(op1), DWARF_TYPE_MEMORY_LOC | DWARF_TYPE_GENERIC);
return true; return true;
} }
@@ -42,25 +83,31 @@ bool dw_op_deref(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwar
bool dw_op_const_x_u(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) bool dw_op_const_x_u(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
{ {
// DW_OP_const1u, DW_OP_const2u, DW_OP_const4u, DW_OP_const8u. The single operand of a DW_OP_const<n>u operation provides a 1, 2, 4, or 8-byte unsigned integer constant, respectively. // DW_OP_const1u, DW_OP_const2u, DW_OP_const4u, DW_OP_const8u. The single operand of a DW_OP_const<n>u operation provides a 1, 2, 4, or 8-byte unsigned integer constant, respectively.
// These operations push a value with the generic type
uint8_t size = 0; uint8_t size = 0;
dwarf_value_type type = DWARF_TYPE_UNSIGNED;
switch (map->op_num) { switch (map->op_num) {
case DW_OP_const1u: case DW_OP_const1u:
size = 1; size = 1;
type = DWARF_TYPE_CHAR;
break; break;
case DW_OP_const2u: case DW_OP_const2u:
size = 2; size = 2;
type = DWARF_TYPE_SHORT;
break; break;
case DW_OP_const4u: case DW_OP_const4u:
size = 4; size = 4;
type = DWARF_TYPE_INT;
break; break;
case DW_OP_const8u: case DW_OP_const8u:
size = 1; size = 8;
type = DWARF_TYPE_LONG;
break; break;
default: default:
return false; return false;
} }
ctx->stack.push(&op1, size, DWARF_TYPE_UNSIGNED); ctx->stack.push(&op1, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
return true; return true;
} }
@@ -68,25 +115,35 @@ bool dw_op_const_x_u(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1,
bool dw_op_const_x_s(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) bool dw_op_const_x_s(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
{ {
// DW_OP_const1s, DW_OP_const2s, DW_OP_const4s, DW_OP_const8s. The single operand of a DW_OP_const<n>s operation provides a 1, 2, 4, or 8-byte signed integer constant, respectively. // DW_OP_const1s, DW_OP_const2s, DW_OP_const4s, DW_OP_const8s. The single operand of a DW_OP_const<n>s operation provides a 1, 2, 4, or 8-byte signed integer constant, respectively.
uint8_t size = 0; // These operations push a value with the generic type
uint8_t size; int64_t v;
dwarf_value_type type = DWARF_TYPE_SIGNED;
switch (map->op_num) { switch (map->op_num) {
case DW_OP_const1u: case DW_OP_const1s:
size = 1; *((int8_t*)(&v)) = (int8_t)op1;
size = sizeof(int8_t);
type = DWARF_TYPE_CHAR;
break; break;
case DW_OP_const2u: case DW_OP_const2s:
size = 2; *((int16_t*)(&v)) = (int16_t)op1;
size = sizeof(int16_t);
type = DWARF_TYPE_SHORT;
break; break;
case DW_OP_const4u: case DW_OP_const4s:
size = 4; *((int32_t*)(&v)) = (int32_t)op1;
size = sizeof(int32_t);
type = DWARF_TYPE_INT;
break; break;
case DW_OP_const8u: case DW_OP_const8s:
size = 1; v = (int64_t)op1;
size = sizeof(int64_t);
type = DWARF_TYPE_LONG;
break; break;
default: default:
return false; return false;
} }
ctx->stack.push(&op1, size, DWARF_TYPE_SIGNED); ctx->stack.push(&op1, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
return true; return true;
} }
@@ -95,7 +152,7 @@ bool dw_op_constu(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwa
{ {
// The single operand of the DW_OP_constu operation provides an unsigned LEB128 integer constant. // The single operand of the DW_OP_constu operation provides an unsigned LEB128 integer constant.
uint64_t value = decode_uleb128((unsigned char*)&op1); uint64_t value = decode_uleb128((unsigned char*)&op1);
ctx->stack.push(&value, sizeof(value), DWARF_TYPE_UNSIGNED); ctx->stack.push(&value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_UNSIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
return true; return true;
} }
@@ -103,7 +160,7 @@ bool dw_op_consts(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwa
{ {
// The single operand of the DW_OP_consts operation provides a signed LEB128 integer constant. // The single operand of the DW_OP_consts operation provides a signed LEB128 integer constant.
uint64_t value = decode_sleb128((unsigned char*)&op1); uint64_t value = decode_sleb128((unsigned char*)&op1);
ctx->stack.push(&value, sizeof(value), DWARF_TYPE_SIGNED); ctx->stack.push(&value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_SIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
return true; return true;
} }
@@ -163,6 +220,13 @@ bool dw_op_swap(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf
return true; return true;
} }
if(value1) {
free(value1);
}
if(value2) {
free(value2);
}
return false; return false;
} }
@@ -183,6 +247,16 @@ bool dw_op_rot(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
return true; return true;
} }
if(value1) {
free(value1);
}
if(value2) {
free(value2);
}
if(value3) {
free(value3);
}
return false; return false;
} }
@@ -193,13 +267,13 @@ bool dw_op_abs(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
dwarf_value* value = ctx->stack.get(); dwarf_value* value = ctx->stack.get();
if(value) { if(value) {
uint64_t v; int64_t v;
if(!value->get_int(v)) { if(!value->get_int(v)) {
ctx->log(SEVERITY_ERROR, "Wrong %d size of stack value", value->size); ctx->log(SEVERITY_ERROR, "Wrong %d size of stack value", value->size);
return false; return false;
} }
uint64_t res = llabs(v);
value->replace(&v, value->size, DWARF_TYPE_SIGNED); value->replace(&res, value->size, DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC | DWARF_TYPE_LONG);
} }
return false; return false;
@@ -209,25 +283,26 @@ bool dw_op_and(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
{ {
// The DW_OP_and operation pops the top two stack values, performs a bitwise and operation on the two, and pushes the result. // The DW_OP_and operation pops the top two stack values, performs a bitwise and operation on the two, and pushes the result.
dwarf_value* value1 = ctx->stack.pop(); dwarf_value* value1 = ctx->stack.get(0);
dwarf_value* value2 = ctx->stack.pop(); dwarf_value* value2 = ctx->stack.get(1);
if(value1 && value2) { if(value1 && value2) {
if(value1->type != value2->type) { if(!(value1->type & value2->type)) {
ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type);
return false; return false;
} }
uint64_t v1 = 0, v2 = 0; uint64_t v1 = 0, v2 = 0;
if(!value1->get_uint(v1)) { if(!value1->get_generic(v1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
if(!value2->get_uint(v2)) { if(!value2->get_generic(v2)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
uint64_t res = v1 & v2; uint64_t res = v1 & v2;
ctx->stack.push(&res, value1->size, value1->type); ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, value1->size, DWARF_TYPE_GENERIC);
return true; return true;
} }
@@ -238,27 +313,85 @@ bool dw_op_div(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
{ {
// The DW_OP_div operation pops the top two stack values, divides the former second entry by the former top of the stack using signed division, and pushes the result. // The DW_OP_div operation pops the top two stack values, divides the former second entry by the former top of the stack using signed division, and pushes the result.
dwarf_value* value1 = ctx->stack.pop(); dwarf_value* value1 = ctx->stack.get(0);
dwarf_value* value2 = ctx->stack.pop(); dwarf_value* value2 = ctx->stack.get(1);
if(value1 && value2) { if(value1 && value2) {
if(value1->type != value2->type) { if(!(value1->type & value2->type)) {
ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type);
return false;
}
int64_t v1 = 0, v2 = 0;
if(!value1->get_int(v1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
if(!value2->get_int(v2)) { if(value2->type & DWARF_TYPE_SIGNED) {
int64_t sig2;
if(!value2->get_int(sig2)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
if(value1->type & DWARF_TYPE_SIGNED) {
int64_t res = v2 / v1; int64_t sig1;
ctx->stack.push(&res, value1->size, value1->type); if(!value1->get_int(sig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(sig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig2);
return false;
}
uint64_t res = sig2 / sig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
return true; return true;
} else {
uint64_t unsig1;
if(!value1->get_uint(unsig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(unsig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, sig2);
return false;
}
int64_t res = sig2 / unsig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
return true;
}
} else {
uint64_t unsig2;
if(!value2->get_uint(unsig2)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(value1->type & DWARF_TYPE_SIGNED) {
int64_t sig1;
if(!value1->get_int(sig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(sig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig1);
return false;
}
int64_t res = unsig2 / sig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
return true;
} else {
uint64_t unsig1;
if(!value1->get_uint(unsig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(unsig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, unsig2);
return false;
}
uint64_t res = unsig2 / unsig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
return true;
}
}
} }
return false; return false;
@@ -268,26 +401,32 @@ bool dw_op_minus(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwar
{ {
// The DW_OP_minus operation pops the top two stack values, subtracts the former top of the stack from the former second entry, and pushes the result. // The DW_OP_minus operation pops the top two stack values, subtracts the former top of the stack from the former second entry, and pushes the result.
dwarf_value* value1 = ctx->stack.pop(); dwarf_value* value1 = ctx->stack.get(0);
dwarf_value* value2 = ctx->stack.pop(); dwarf_value* value2 = ctx->stack.get(1);
uint64_t unres; int64_t sigres; void* res;
if(value1 && value2) { if(value1 && value2) {
if(value1->type != value2->type) { if(!(value1->type & value2->type)) {
ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type);
return false; return false;
} }
int64_t v1 = 0, v2 = 0; // use arithmetic by modulo 1 plus
if(!value1->get_int(v1)) { uint64_t unsig1; uint64_t unsig2;
if(!value1->get_uint(unsig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
if(!value2->get_uint(unsig2)) {
if(!value2->get_int(v2)) { ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value2->size);
ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
int res_type = DWARF_TYPE_GENERIC;
if(value2->type & DWARF_TYPE_MEMORY_LOC) {
res_type |= DWARF_TYPE_MEMORY_LOC;
}
uint64_t res = unsig2 - unsig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), res_type);
int64_t res = v2 - v1;
ctx->stack.push(&res, value1->size, value1->type);
return true; return true;
} }
@@ -298,26 +437,32 @@ bool dw_op_mod(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
{ {
// The DW_OP_mod operation pops the top two stack values and pushes the result of the calculation: former second stack entry modulo the former top of the stack. // The DW_OP_mod operation pops the top two stack values and pushes the result of the calculation: former second stack entry modulo the former top of the stack.
dwarf_value* value1 = ctx->stack.pop(); dwarf_value* value1 = ctx->stack.get(0);
dwarf_value* value2 = ctx->stack.pop(); dwarf_value* value2 = ctx->stack.get(1);
if(value1 && value2) { if(value1 && value2) {
if(value1->type != value2->type) { if(!(value1->type & value2->type)) {
ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type);
return false; return false;
} }
int64_t v1 = 0, v2 = 0; uint64_t v1 = 0, v2 = 0;
if(!value1->get_int(v1)) { if(!value1->get_uint(v1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size); ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
if(!value2->get_int(v2)) { if(v1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero requested, aborting.");
return false;
}
if(!value2->get_uint(v2)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
int64_t res = v2 % v1; uint64_t res = v2 % v1;
ctx->stack.push(&res, value1->size, value1->type); ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, value1->size, DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
return true; return true;
} }
@@ -328,27 +473,85 @@ bool dw_op_mul(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
{ {
// The DW_OP_mul operation pops the top two stack entries, multiplies them together, and pushes the result. // The DW_OP_mul operation pops the top two stack entries, multiplies them together, and pushes the result.
dwarf_value* value1 = ctx->stack.pop(); dwarf_value* value1 = ctx->stack.get(0);
dwarf_value* value2 = ctx->stack.pop(); dwarf_value* value2 = ctx->stack.get(1);
if(value1 && value2) { if(value1 && value2) {
if(value1->type != value2->type) { if(!(value1->type & value2->type)) {
ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type);
return false;
}
int64_t v1 = 0, v2 = 0;
if(!value1->get_int(v1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
if(!value2->get_int(v2)) { if(value2->type & DWARF_TYPE_SIGNED) {
int64_t sig2;
if(!value2->get_int(sig2)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size); ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size);
return false; return false;
} }
if(value1->type & DWARF_TYPE_SIGNED) {
int64_t res = v2 * v1; int64_t sig1;
ctx->stack.push(&res, value1->size, value1->type); if(!value1->get_int(sig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(sig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig2);
return false;
}
uint64_t res = sig2 * sig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
return true; return true;
} else {
uint64_t unsig1;
if(!value1->get_uint(unsig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(unsig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, sig2);
return false;
}
int64_t res = sig2 * unsig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
return true;
}
} else {
uint64_t unsig2;
if(!value2->get_uint(unsig2)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 2nd stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(value1->type & DWARF_TYPE_SIGNED) {
int64_t sig1;
if(!value1->get_int(sig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(sig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, sig1, sig1);
return false;
}
int64_t res = unsig2 * sig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
return true;
} else {
uint64_t unsig1;
if(!value1->get_uint(unsig1)) {
ctx->log(SEVERITY_ERROR, "Wrong size of 1st stack value for operation %s(%d)", map->op_name, value1->size);
return false;
}
if(unsig1 == 0) {
ctx->log(SEVERITY_ERROR, "Division by zero for operation %s(0x%lX, 0x%lX)", map->op_name, unsig1, unsig2);
return false;
}
uint64_t res = unsig2 * unsig1;
ctx->stack.pop(); ctx->stack.pop();
ctx->stack.push(&res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
return true;
}
}
} }
return false; return false;
@@ -402,8 +605,8 @@ bool dw_op_neg(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
bool dw_op_not(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2) bool dw_op_not(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
{ {
// The DW_OP_neg operation pops the top stack entry, interprets it as a signed value and pushes its negation. // The DW_OP_not operation pops the top stack entry, and pushes its bitwise complement.
// If the negation cannot be represented, the result is undefined.
dwarf_value* value = ctx->stack.get(); dwarf_value* value = ctx->stack.get();
if(value) { if(value) {
@@ -412,7 +615,7 @@ bool dw_op_not(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_
ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size); ctx->log(SEVERITY_ERROR, "Wrong size of stack value for operation %s(%d)", map->op_name, value->size);
return false; return false;
} }
v = !v; v = ~v;
value->replace(&v, value->size, value->type); value->replace(&v, value->size, value->type);
@@ -429,7 +632,7 @@ bool dw_op_or(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_W
dwarf_value* value1 = ctx->stack.pop(); dwarf_value* value1 = ctx->stack.pop();
dwarf_value* value2 = ctx->stack.pop(); dwarf_value* value2 = ctx->stack.pop();
if(value1 && value2) { if(value1 && value2) {
if(value1->type != value2->type) { if(!(value1->type & value2->type)) {
ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type);
return false; return false;
} }
@@ -459,7 +662,7 @@ bool dw_op_plus(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf
dwarf_value* value1 = ctx->stack.pop(); dwarf_value* value1 = ctx->stack.pop();
dwarf_value* value2 = ctx->stack.pop(); dwarf_value* value2 = ctx->stack.pop();
if(value1 && value2) { if(value1 && value2) {
if(value1->type != value2->type) { if(!(value1->type & value2->type)) {
ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type); ctx->log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%d, %d)", map->op_name, value1->type, value2->type);
return false; return false;
} }
@@ -521,137 +724,252 @@ bool dw_op_plus_uconst(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1
return false; return false;
} }
dwarf_op_map dw_op[] = {
{DW_OP_addr, -1, 0, "DW_OP_addr", dw_op_addr},
{DW_OP_deref, -1, 0, "DW_OP_deref", dw_op_deref},
// Constant operations
{DW_OP_const1u, -1, 0, "DW_OP_const1u", dw_op_const_x_u},
{DW_OP_const1s, -1, 0, "DW_OP_const1s", dw_op_const_x_s},
{DW_OP_const2u, -1, 0, "DW_OP_const2u", dw_op_const_x_u},
{DW_OP_const2s, -1, 0, "DW_OP_const2s", dw_op_const_x_s},
{DW_OP_const4u, -1, 0, "DW_OP_const4u", dw_op_const_x_u},
{DW_OP_const4s, -1, 0, "DW_OP_const4s", dw_op_const_x_s},
{DW_OP_const8u, -1, 0, "DW_OP_const8u", dw_op_const_x_u},
{DW_OP_const8s, -1, 0, "DW_OP_const8s", dw_op_const_x_s},
{DW_OP_constu, -1, 0, "DW_OP_constu", dw_op_constu},
{DW_OP_consts, -1, 0, "DW_OP_consts", dw_op_consts},
// DWARF expression stack operations
{DW_OP_dup, -1, 0, "DW_OP_dup", dw_op_dup},
{DW_OP_drop, -1, 0, "DW_OP_drop", dw_op_drop},
{DW_OP_over, -1, 0, "DW_OP_over", dw_op_over},
{DW_OP_pick, -1, 0, "DW_OP_pick", dw_op_pick},
{DW_OP_swap, -1, 0, "DW_OP_swap", dw_op_swap},
{DW_OP_rot, -1, 0, "DW_OP_rot", dw_op_rot},
{DW_OP_xderef, -1, 0, "DW_OP_xderef", dw_op_notimpl},
// Arithmetic and Logical Operations
{DW_OP_abs, -1, 0, "DW_OP_abs", dw_op_abs},
{DW_OP_and, -1, 0, "DW_OP_and", dw_op_and},
{DW_OP_div, -1, 0, "DW_OP_div", dw_op_div},
{DW_OP_minus, -1, 0, "DW_OP_minus", dw_op_minus},
{DW_OP_mod, -1, 0, "DW_OP_mod", dw_op_mod},
{DW_OP_mul, -1, 0, "DW_OP_mul", dw_op_mul},
{DW_OP_neg, -1, 0, "DW_OP_neg", dw_op_neg},
{DW_OP_not, -1, 0, "DW_OP_not", dw_op_not},
{DW_OP_or, -1, 0, "DW_OP_or", dw_op_or},
{DW_OP_plus, -1, 0, "DW_OP_plus", dw_op_plus},
{DW_OP_plus_uconst, 0x0, 0, "DW_OP_plus_uconst", dw_op_plus_uconst},
// Register location descriptions. From DWARF 5, section 2.6.1.1.3: // Register location descriptions. From DWARF 5, section 2.6.1.1.3:
// Register location descriptions describe an object (or a piece of an object) that resides in a register. // Register location descriptions describe an object (or a piece of an object) that resides in a register.
// A register location description must stand alone as the entire description of an object or a piece of an object. // A register location description must stand alone as the entire description of an object or a piece of an object.
bool dw_op_reg_x(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
{
// The DW_OP_regx operation has a single unsigned LEB128 literal operand that encodes the name of a register
if(map->op_num != DW_OP_regx && (map->op_num < DW_OP_reg0 || map->op_num > DW_OP_reg31)) {
return false;
}
// GP Registers uint64_t regno = 0;
{0x50, 0x0, "RAX", "DW_OP_reg0"}, if(map->op_num == DW_OP_regx) {
{0x51, 0x1, "RDX", "DW_OP_reg1"}, regno = decode_uleb128((unsigned char*)&op1);
{0x52, 0x2, "RCX", "DW_OP_reg2"}, } else {
{0x53, 0x3, "RBX", "DW_OP_reg3"}, regno = map->op_num - DW_OP_reg0;
{0x54, 0x4, "RSI", "DW_OP_reg4"}, }
{0x55, 0x5, "RDI", "DW_OP_reg5"},
{0x56, 0x6, "RBP", "DW_OP_reg6"}, ctx->stack.push(&regno, sizeof(regno), DWARF_TYPE_REGISTER_LOC);
{0x57, 0x7, "RSP", "DW_OP_reg7"},
// Extended GP Registers return true;
{0x58, 0x8, "R8", "DW_OP_reg8"}, }
{0x59, 0x9, "R9", "DW_OP_reg9"},
{0x5A, 0xA, "R10", "DW_OP_reg10"},
{0x5B, 0xB, "R11", "DW_OP_reg11"},
{0x5C, 0xC, "R12", "DW_OP_reg12"},
{0x5D, 0xD, "R13", "DW_OP_reg13"},
{0x5E, 0xE, "R14", "DW_OP_reg14"},
{0x5F, 0xF, "R15", "DW_OP_reg15"},
{0x60, 0x10, "RIP", "DW_OP_reg16"}, // Return Address (RA) mapped to RIP
// SSE Vector Registers
{0x61, 0x11, "XMM0", "DW_OP_reg17"},
{0x62, 0x12, "XMM1", "DW_OP_reg18"},
{0x63, 0x13, "XMM2", "DW_OP_reg19"},
{0x64, 0x14, "XMM3", "DW_OP_reg20"},
{0x65, 0x15, "XMM4", "DW_OP_reg21"},
{0x66, 0x16, "XMM5", "DW_OP_reg22"},
{0x67, 0x17, "XMM6", "DW_OP_reg23"},
{0x68, 0x18, "XMM7", "DW_OP_reg24"},
{0x69, 0x19, "XMM8", "DW_OP_reg25"},
{0x6a, 0x1a, "XMM9", "DW_OP_reg26"},
{0x6b, 0x1b, "XMM10", "DW_OP_reg27"},
{0x6c, 0x1c, "XMM11", "DW_OP_reg28"},
{0x6d, 0x1d, "XMM12", "DW_OP_reg29"},
{0x6e, 0x1e, "XMM13", "DW_OP_reg30"},
{0x6f, 0x1f, "XMM14", "DW_OP_reg31"},
// Register values. DWARF5, section 2.5.1.2 // Register values. DWARF5, section 2.5.1.2
// Register values are used to describe an object (or a piece of an object) that is located in memory at an address that is contained in // Register values are used to describe an object (or a piece of an object) that is located in memory at an address that is contained in
// a register (possibly offset by some constant) // a register (possibly offset by some constant)
bool dw_op_breg_x(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
// GP Registers {
{0x70, 0x0, "RAX", "DW_OP_breg0"},
{0x71, 0x1, "RDX", "DW_OP_breg1"},
{0x72, 0x2, "RCX", "DW_OP_breg2"},
{0x73, 0x3, "RBX", "DW_OP_breg3"},
{0x74, 0x4, "RSI", "DW_OP_breg4"},
{0x75, 0x5, "RDI", "DW_OP_breg5"},
{0x76, 0x6, "RBP", "DW_OP_breg6"},
{0x77, 0x7, "RSP", "DW_OP_breg7"},
// Extended GP Registers
{0x78, 0x8, "R8", "DW_OP_breg8"},
{0x79, 0x9, "R9", "DW_OP_breg9"},
{0x7A, 0xA, "R10", "DW_OP_breg10"},
{0x7B, 0xB, "R11", "DW_OP_breg11"},
{0x7C, 0xC, "R12", "DW_OP_breg12"},
{0x7D, 0xD, "R13", "DW_OP_breg13"},
{0x7E, 0xE, "R14", "DW_OP_breg14"},
{0x7F, 0xF, "R15", "DW_OP_breg15"},
{0x80, 0x10, "RIP", "DW_OP_breg16"}, // Return Address (RA) mapped to RIP
// SSE Vector Registers
{0x81, 0x11, "XMM0", "DW_OP_breg17"},
{0x82, 0x12, "XMM1", "DW_OP_breg18"},
{0x83, 0x13, "XMM2", "DW_OP_breg19"},
{0x84, 0x14, "XMM3", "DW_OP_breg20"},
{0x85, 0x15, "XMM4", "DW_OP_breg21"},
{0x86, 0x16, "XMM5", "DW_OP_breg22"},
{0x87, 0x17, "XMM6", "DW_OP_breg23"},
{0x88, 0x18, "XMM7", "DW_OP_breg24"},
{0x89, 0x19, "XMM8", "DW_OP_breg25"},
{0x8a, 0x1a, "XMM9", "DW_OP_breg26"},
{0x8b, 0x1b, "XMM10", "DW_OP_breg27"},
{0x8c, 0x1c, "XMM11", "DW_OP_breg28"},
{0x8d, 0x1d, "XMM12", "DW_OP_breg29"},
{0x8e, 0x1e, "XMM13", "DW_OP_breg30"},
{0x8f, 0x1f, "XMM14", "DW_OP_breg31"},
// The DW_OP_regx operation has a single unsigned LEB128 literal operand that encodes the name of a register
{0x90, -1, 0, "DW_OP_regx"},
// The DW_OP_fbreg operation provides a signed LEB128 offset from the address specified by the location description in the DW_AT_frame_base
// attribute of the current function. This is typically a stack pointer register plus or minus some offset
{0x91, -1, 0, "DW_OP_fbreg"},
// The DW_OP_bregx operation provides the sum of two values specified by its two operands. // The DW_OP_bregx operation provides the sum of two values specified by its two operands.
// The first operand is a register number which is specified by an unsigned LEB128 number. The second operand is a signed LEB128 offset. // The first operand is a register number which is specified by an unsigned LEB128 number. The second operand is a signed LEB128 offset.
{0x92, -1, 0, "DW_OP_bregx"}, if(map->op_num != DW_OP_bregx && (map->op_num < DW_OP_breg0 || map->op_num > DW_OP_breg31)) {
{0x9C, -1, 0, "DW_OP_call_frame_cfa"}, return false;
}
uint64_t regno = 0; int64_t off = 0;
if(map->op_num == DW_OP_bregx) {
regno = decode_uleb128((unsigned char*)&op1);
off = decode_sleb128((unsigned char*)&op2);
} else {
regno = map->op_num - DW_OP_breg0;
off = decode_sleb128((unsigned char*)&op1);
}
unw_word_t val = 0;
if(unw_get_reg(&ctx->cursor, regno, &val)) {
return false;
}
val += off;
ctx->stack.push(&val, sizeof(val), DWARF_TYPE_MEMORY_LOC | DWARF_TYPE_GENERIC);
return true;
}
bool dw_op_lit_x(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
{
// The DW_OP_lit<n> operations encode the unsigned literal values from 0 through 31, inclusive.
// Operations other than DW_OP_const_type push a value with the generic type.
if(map->op_num < DW_OP_lit0 || map->op_num > DW_OP_lit31) {
return false;
}
uint64_t val = map->op_num - DW_OP_lit0;
ctx->stack.push(&val, sizeof(val), DWARF_TYPE_GENERIC);
return true;
}
bool dw_op_stack_value(pst_context* ctx, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
{
// DWARF5, Section 2.6.1.1.4: // DWARF5, Section 2.6.1.1.4:
// The DW_OP_stack_value operation specifies that the object does not exist in memory but its value is nonetheless known and is at the top of the DWARF // The DW_OP_stack_value operation specifies that the object does not exist in memory but its value is nonetheless known and is at the top of the DWARF
// expression stack. In this form of location description, the DWARF expression represents the actual value of the object, rather than its location. // expression stack. In this form of location description, the DWARF expression represents the actual value of the object, rather than its location.
// The DW_OP_stack_value operation terminates the expression. // The DW_OP_stack_value operation terminates the expression.
{0x9F, -1, 0, "DW_OP_stack_value"},
dwarf_value* v = ctx->stack.get();
if(v) {
v->type = DWARF_TYPE_GENERIC;
return true;
}
return false;
}
dwarf_op_map dw_op[] = {
{DW_OP_addr, "DW_OP_addr", dw_op_addr},
{DW_OP_deref, "DW_OP_deref", dw_op_deref},
// Constant operations
{DW_OP_const1u, "DW_OP_const1u", dw_op_const_x_u},
{DW_OP_const1s, "DW_OP_const1s", dw_op_const_x_s},
{DW_OP_const2u, "DW_OP_const2u", dw_op_const_x_u},
{DW_OP_const2s, "DW_OP_const2s", dw_op_const_x_s},
{DW_OP_const4u, "DW_OP_const4u", dw_op_const_x_u},
{DW_OP_const4s, "DW_OP_const4s", dw_op_const_x_s},
{DW_OP_const8u, "DW_OP_const8u", dw_op_const_x_u},
{DW_OP_const8s, "DW_OP_const8s", dw_op_const_x_s},
{DW_OP_constu, "DW_OP_constu", dw_op_constu},
{DW_OP_consts, "DW_OP_consts", dw_op_consts},
// DWARF expression stack operations
{DW_OP_dup, "DW_OP_dup", dw_op_dup},
{DW_OP_drop, "DW_OP_drop", dw_op_drop},
{DW_OP_over, "DW_OP_over", dw_op_over},
{DW_OP_pick, "DW_OP_pick", dw_op_pick},
{DW_OP_swap, "DW_OP_swap", dw_op_swap},
{DW_OP_rot, "DW_OP_rot", dw_op_rot},
{DW_OP_xderef, "DW_OP_xderef", dw_op_notimpl},
// Arithmetic and Logical Operations
{DW_OP_abs, "DW_OP_abs", dw_op_abs},
{DW_OP_and, "DW_OP_and", dw_op_and},
{DW_OP_div, "DW_OP_div", dw_op_div},
{DW_OP_minus, "DW_OP_minus", dw_op_minus},
{DW_OP_mod, "DW_OP_mod", dw_op_mod},
{DW_OP_mul, "DW_OP_mul", dw_op_mul},
{DW_OP_neg, "DW_OP_neg", dw_op_neg},
{DW_OP_not, "DW_OP_not", dw_op_not},
{DW_OP_or, "DW_OP_or", dw_op_or},
{DW_OP_plus, "DW_OP_plus", dw_op_plus},
{DW_OP_plus_uconst, "DW_OP_plus_uconst",dw_op_plus_uconst},
// not implemented for now
{DW_OP_shl, "DW_OP_shl", dw_op_notimpl},
{DW_OP_shr, "DW_OP_shr", dw_op_notimpl},
{DW_OP_shra, "DW_OP_shra", dw_op_notimpl},
{DW_OP_xor, "DW_OP_xor", dw_op_notimpl},
{DW_OP_bra, "DW_OP_bra", dw_op_notimpl},
{DW_OP_eq, "DW_OP_eq", dw_op_notimpl},
{DW_OP_ge, "DW_OP_ge", dw_op_notimpl},
{DW_OP_gt, "DW_OP_gt", dw_op_notimpl},
{DW_OP_le, "DW_OP_le", dw_op_notimpl},
{DW_OP_lt, "DW_OP_lt", dw_op_notimpl},
{DW_OP_ne, "DW_OP_ne", dw_op_notimpl},
{DW_OP_skip, "DW_OP_skip", dw_op_notimpl},
//DWARF5 2.5.1.1 Literal Encodings
{DW_OP_lit0, "DW_OP_lit0", dw_op_lit_x},
{DW_OP_lit1, "DW_OP_lit1", dw_op_lit_x},
{DW_OP_lit2, "DW_OP_lit2", dw_op_lit_x},
{DW_OP_lit3, "DW_OP_lit3", dw_op_lit_x},
{DW_OP_lit4, "DW_OP_lit4", dw_op_lit_x},
{DW_OP_lit5, "DW_OP_lit5", dw_op_lit_x},
{DW_OP_lit6, "DW_OP_lit6", dw_op_lit_x},
{DW_OP_lit7, "DW_OP_lit7", dw_op_lit_x},
{DW_OP_lit8, "DW_OP_lit8", dw_op_lit_x},
{DW_OP_lit9, "DW_OP_lit9", dw_op_lit_x},
{DW_OP_lit10, "DW_OP_lit10", dw_op_lit_x},
{DW_OP_lit11, "DW_OP_lit11", dw_op_lit_x},
{DW_OP_lit12, "DW_OP_lit12", dw_op_lit_x},
{DW_OP_lit13, "DW_OP_lit13", dw_op_lit_x},
{DW_OP_lit14, "DW_OP_lit14", dw_op_lit_x},
{DW_OP_lit15, "DW_OP_lit15", dw_op_lit_x},
{DW_OP_lit16, "DW_OP_lit16", dw_op_lit_x},
{DW_OP_lit17, "DW_OP_lit17", dw_op_lit_x},
{DW_OP_lit18, "DW_OP_lit18", dw_op_lit_x},
{DW_OP_lit19, "DW_OP_lit19", dw_op_lit_x},
{DW_OP_lit20, "DW_OP_lit20", dw_op_lit_x},
{DW_OP_lit21, "DW_OP_lit21", dw_op_lit_x},
{DW_OP_lit22, "DW_OP_lit22", dw_op_lit_x},
{DW_OP_lit23, "DW_OP_lit23", dw_op_lit_x},
{DW_OP_lit24, "DW_OP_lit24", dw_op_lit_x},
{DW_OP_lit25, "DW_OP_lit25", dw_op_lit_x},
{DW_OP_lit26, "DW_OP_lit26", dw_op_lit_x},
{DW_OP_lit27, "DW_OP_lit27", dw_op_lit_x},
{DW_OP_lit28, "DW_OP_lit28", dw_op_lit_x},
{DW_OP_lit29, "DW_OP_lit29", dw_op_lit_x},
{DW_OP_lit30, "DW_OP_lit30", dw_op_lit_x},
{DW_OP_lit31, "DW_OP_lit31", dw_op_lit_x},
// Register location descriptions.
// GP Registers
{DW_OP_reg0, "DW_OP_reg0", dw_op_reg_x},
{DW_OP_reg1, "DW_OP_reg1", dw_op_reg_x},
{DW_OP_reg2, "DW_OP_reg2", dw_op_reg_x},
{DW_OP_reg3, "DW_OP_reg3", dw_op_reg_x},
{DW_OP_reg4, "DW_OP_reg4", dw_op_reg_x},
{DW_OP_reg5, "DW_OP_reg5", dw_op_reg_x},
{DW_OP_reg6, "DW_OP_reg6", dw_op_reg_x},
{DW_OP_reg7, "DW_OP_reg7", dw_op_reg_x},
// Extended GP Registers
{DW_OP_reg8, "DW_OP_reg8", dw_op_reg_x},
{DW_OP_reg9, "DW_OP_reg9", dw_op_reg_x},
{DW_OP_reg10, "DW_OP_reg10", dw_op_reg_x},
{DW_OP_reg11, "DW_OP_reg11", dw_op_reg_x},
{DW_OP_reg12, "DW_OP_reg12", dw_op_reg_x},
{DW_OP_reg13, "DW_OP_reg13", dw_op_reg_x},
{DW_OP_reg14, "DW_OP_reg14", dw_op_reg_x},
{DW_OP_reg15, "DW_OP_reg15", dw_op_reg_x},
{DW_OP_reg16, "DW_OP_reg16", dw_op_reg_x}, // Return Address (RA) mapped to RIP
// SSE Vector Registers
{DW_OP_reg17, "DW_OP_reg17", dw_op_reg_x},
{DW_OP_reg18, "DW_OP_reg18", dw_op_reg_x},
{DW_OP_reg19, "DW_OP_reg19", dw_op_reg_x},
{DW_OP_reg20, "DW_OP_reg20", dw_op_reg_x},
{DW_OP_reg21, "DW_OP_reg21", dw_op_reg_x},
{DW_OP_reg22, "DW_OP_reg22", dw_op_reg_x},
{DW_OP_reg23, "DW_OP_reg23", dw_op_reg_x},
{DW_OP_reg24, "DW_OP_reg24", dw_op_reg_x},
{DW_OP_reg25, "DW_OP_reg25", dw_op_reg_x},
{DW_OP_reg26, "DW_OP_reg26", dw_op_reg_x},
{DW_OP_reg27, "DW_OP_reg27", dw_op_reg_x},
{DW_OP_reg28, "DW_OP_reg28", dw_op_reg_x},
{DW_OP_reg29, "DW_OP_reg29", dw_op_reg_x},
{DW_OP_reg30, "DW_OP_reg30", dw_op_reg_x},
{DW_OP_reg31, "DW_OP_reg31", dw_op_reg_x},
// Register values.
// GP Registers
{DW_OP_breg0, "DW_OP_breg0", dw_op_breg_x},
{DW_OP_breg1, "DW_OP_breg1", dw_op_breg_x},
{DW_OP_breg2, "DW_OP_breg2", dw_op_breg_x},
{DW_OP_breg3, "DW_OP_breg3", dw_op_breg_x},
{DW_OP_breg4, "DW_OP_breg4", dw_op_breg_x},
{DW_OP_breg5, "DW_OP_breg5", dw_op_breg_x},
{DW_OP_breg6, "DW_OP_breg6", dw_op_breg_x},
{DW_OP_breg7, "DW_OP_breg7", dw_op_breg_x},
// Extended GP Registers
{DW_OP_breg8, "DW_OP_breg8", dw_op_breg_x},
{DW_OP_breg9, "DW_OP_breg9", dw_op_breg_x},
{DW_OP_breg10, "DW_OP_breg10", dw_op_breg_x},
{DW_OP_breg11, "DW_OP_breg11", dw_op_breg_x},
{DW_OP_breg12, "DW_OP_breg12", dw_op_breg_x},
{DW_OP_breg13, "DW_OP_breg13", dw_op_breg_x},
{DW_OP_breg14, "DW_OP_breg14", dw_op_breg_x},
{DW_OP_breg15, "DW_OP_breg15", dw_op_breg_x},
{DW_OP_breg16, "DW_OP_breg16", dw_op_breg_x}, // Return Address (RA) mapped to RIP
// SSE Vector Registers
{DW_OP_breg17, "DW_OP_breg17", dw_op_breg_x},
{DW_OP_breg18, "DW_OP_breg18", dw_op_breg_x},
{DW_OP_breg19, "DW_OP_breg19", dw_op_breg_x},
{DW_OP_breg20, "DW_OP_breg20", dw_op_breg_x},
{DW_OP_breg21, "DW_OP_breg21", dw_op_breg_x},
{DW_OP_breg22, "DW_OP_breg22", dw_op_breg_x},
{DW_OP_breg23, "DW_OP_breg23", dw_op_breg_x},
{DW_OP_breg24, "DW_OP_breg24", dw_op_breg_x},
{DW_OP_breg25, "DW_OP_breg25", dw_op_breg_x},
{DW_OP_breg26, "DW_OP_breg26", dw_op_breg_x},
{DW_OP_breg27, "DW_OP_breg27", dw_op_breg_x},
{DW_OP_breg28, "DW_OP_breg28", dw_op_breg_x},
{DW_OP_breg29, "DW_OP_breg29", dw_op_breg_x},
{DW_OP_breg30, "DW_OP_breg30", dw_op_breg_x},
{DW_OP_breg31, "DW_OP_breg31", dw_op_breg_x},
{DW_OP_regx, "DW_OP_regx", dw_op_reg_x},
// The DW_OP_fbreg operation provides a signed LEB128 offset from the address specified by the location description in the DW_AT_frame_base
// attribute of the current function. This is typically a stack pointer register plus or minus some offset
{DW_OP_fbreg, "DW_OP_fbreg", dw_op_notimpl},
{DW_OP_bregx, "DW_OP_bregx", dw_op_breg_x},
{DW_OP_call_frame_cfa, "DW_OP_call_frame_cfa", dw_op_notimpl},
{DW_OP_stack_value, "DW_OP_stack_value", dw_op_stack_value},
// This opcode has two operands, the first one is uleb128 length and the second is block of that length, containing either a // This opcode has two operands, the first one is uleb128 length and the second is block of that length, containing either a
// simple register or DWARF expression // simple register or DWARF expression
{0xF3, -1, 0, "DW_OP_GNU_entry_value"}, {DW_OP_GNU_entry_value, "DW_OP_GNU_entry_value", dw_op_notimpl},
}; };
const dwarf_op_map* find_op_map(int op) const dwarf_op_map* find_op_map(int op)
+8 -2
View File
@@ -10,10 +10,16 @@ typedef bool (*dwarf_operation)(pst_context* ctx, const dwarf_op_map* map, Dwarf
typedef struct __dwarf_op_map { typedef struct __dwarf_op_map {
int op_num; // DWARF Operation DW_OP_XXX int op_num; // DWARF Operation DW_OP_XXX
int regno; // platform-dependent register number if present // int regno; // platform-dependent register number if present
const char* regname; // register name if 'regno' specified // const char* regname; // register name if 'regno' specified
const char* op_name; // string representation of an operation const char* op_name; // string representation of an operation
dwarf_operation operation; // function which handles operation dwarf_operation operation; // function which handles operation
} dwarf_op_map; } dwarf_op_map;
typedef struct __dwarf_reg_map {
int regno; // platform-dependent register number
const char* regname; // register name if
const char* dwarf_name; // name of DWARF operation
} dwarf_reg_map;
const dwarf_op_map* find_op_map(int op); const dwarf_op_map* find_op_map(int op);
+15 -29
View File
@@ -111,29 +111,6 @@ void print_framereg(int regno)
} }
*/ */
bool __pst_handler::calc_expression(Dwarf_Op *exprs, int expr_len, dwarf_stack* stack, Dwarf_Attribute* attr)
{
for (int i = 0; i < expr_len; i++) {
const dwarf_op_map* map = find_op_map(exprs[i].atom);
if(!map) {
ctx.log(SEVERITY_ERROR, "Unknown operation type 0x%hhX(0x%lX, 0x%lX)", exprs[i].atom, exprs[i].number, exprs[i].number2);
return false;
}
if(map->op_num == DW_OP_stack_value && stack->Size() > 0) {
return true;
}
if(!map->operation(&ctx, map, exprs[i].number, exprs[i].number2)) {
ctx.log(SEVERITY_ERROR, "Failed to calculate %s(0x%lX, 0x%lX) operation", map->op_name, exprs[i].number, exprs[i].number2);
return false;
}
}
return true;
}
bool __pst_parameter::handle_type(Dwarf_Attribute* param, bool is_return) bool __pst_parameter::handle_type(Dwarf_Attribute* param, bool is_return)
{ {
Dwarf_Attribute attr_mem; Dwarf_Attribute attr_mem;
@@ -221,6 +198,10 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
handle_type(attr); handle_type(attr);
} }
Dwarf_Addr pc;
unw_get_reg(&ctx->cursor, UNW_REG_IP, &pc);
Dwarf_Addr offset = pc - ctx->base_addr;
// determine location of parameter in stack/heap or CPU registers // determine location of parameter in stack/heap or CPU registers
attr = dwarf_attr(result, DW_AT_location, &attr_mem); attr = dwarf_attr(result, DW_AT_location, &attr_mem);
if(attr) { if(attr) {
@@ -230,10 +211,8 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
if (dwarf_getlocation(attr, &expr, &exprlen) == 0) { if (dwarf_getlocation(attr, &expr, &exprlen) == 0) {
char str[1024]; str[0] = 0; char str[1024]; str[0] = 0;
ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr); ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
ctx->log(SEVERITY_DEBUG, "Found DW_AT_location expression: %s", str); ctx->log(SEVERITY_DEBUG, "DW_AT_location expression: %s", str);
// if(expr[0].atom >= DW_OP_reg0 && expr[0].atom <= DW_OP_bregx) { ctx->calc_expression(expr, exprlen, attr);
// print_framereg(expr[0].atom);
// }
} }
} else if(dwarf_hasform(attr, DW_FORM_sec_offset)) { } else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
Dwarf_Addr base, start, end; Dwarf_Addr base, start, end;
@@ -241,10 +220,17 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
Dwarf_Op *expr; Dwarf_Op *expr;
size_t exprlen; size_t exprlen;
// handle list of possible locations of parameter
for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) { for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) {
if(offset >= start && offset <= end) {
// actual location, try to calculate Location expression and retrieve value of parameter
char str[1024]; str[0] = 0; char str[1024]; str[0] = 0;
ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr); ctx->print_expr_block (expr, exprlen, str, sizeof(str), attr);
ctx->log(SEVERITY_DEBUG, "[%d] low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 " ==> %s", i, start, end, str); ctx->log(SEVERITY_DEBUG, "Location list expression: [%d] low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 " ==> %s", i, start, end, str);
ctx->calc_expression(expr, exprlen, attr);
} else {
// Location skipped due to don't match current PC offset
}
} }
} else { } else {
@@ -561,7 +547,7 @@ bool __pst_handler::unwind()
ctx.print("[%-2d] ", idx); ctx.print("[%-2d] ", idx);
#endif #endif
module = dwfl_addrmodule(dwfl, addr); module = dwfl_addrmodule(dwfl, addr);
get_frame(); //get_frame();
pst_function fun(&ctx); pst_function fun(&ctx);
if(fun.unwind(dwfl, module, pc)) { if(fun.unwind(dwfl, module, pc)) {
if(get_dwarf_function(fun)) { if(get_dwarf_function(fun)) {