|
|
@ -146,6 +146,514 @@ abbrev_entry_offset(u8 *file, u64 abbrev_offset, u32 requested_code) |
|
|
|
return(0); |
|
|
|
return(0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static s64 |
|
|
|
|
|
|
|
compute_dwarf_expression_value(u8 *at, u32 length) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
s64 result = 0; |
|
|
|
|
|
|
|
s64 stack[128] = { 0 }; |
|
|
|
|
|
|
|
u32 stack_head = 0; |
|
|
|
|
|
|
|
u8 *original_at = at; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum dwarf_expression_op op; |
|
|
|
|
|
|
|
u32 increment; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (at - original_at < length) { |
|
|
|
|
|
|
|
op = *at++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
increment = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (op) { |
|
|
|
|
|
|
|
case DW_OP_addr: { |
|
|
|
|
|
|
|
u64 address; |
|
|
|
|
|
|
|
memcpy(&address, at, 8); |
|
|
|
|
|
|
|
stack[stack_head++] = address; |
|
|
|
|
|
|
|
increment = 8; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_deref: { |
|
|
|
|
|
|
|
u64 address = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 value; |
|
|
|
|
|
|
|
memcpy(&value, (void *) address, 8); // TODO: surely not this...
|
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const1u: { |
|
|
|
|
|
|
|
u8 const_value = *at; |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const1s: { |
|
|
|
|
|
|
|
s8 const_value = *((s8 *) at); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const2u: { |
|
|
|
|
|
|
|
u16 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 2); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 2; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const2s: { |
|
|
|
|
|
|
|
s16 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 2); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 2; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const4u: { |
|
|
|
|
|
|
|
u32 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 4); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 4; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const4s: { |
|
|
|
|
|
|
|
s32 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 4); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 4; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const8u: { |
|
|
|
|
|
|
|
u64 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 8); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 8; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_const8s: { |
|
|
|
|
|
|
|
s64 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 8); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
increment = 8; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_constu: { |
|
|
|
|
|
|
|
u32 const_value; |
|
|
|
|
|
|
|
increment = decode_leb128(at, &const_value); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_consts: { |
|
|
|
|
|
|
|
s32 const_value; |
|
|
|
|
|
|
|
increment = decode_leb128s(at, &const_value); |
|
|
|
|
|
|
|
stack[stack_head++] = const_value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_dup: { |
|
|
|
|
|
|
|
s64 top = stack[stack_head - 1]; |
|
|
|
|
|
|
|
stack[stack_head++] = top; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_drop: { |
|
|
|
|
|
|
|
--stack_head; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_over: { |
|
|
|
|
|
|
|
s64 value = stack[stack_head - 2]; |
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_pick: { |
|
|
|
|
|
|
|
u8 stack_index = *at; |
|
|
|
|
|
|
|
increment = 1; |
|
|
|
|
|
|
|
// NOTE: 0 means top of stack
|
|
|
|
|
|
|
|
s64 value = stack[stack_head - 1 - stack_index]; |
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_swap: { |
|
|
|
|
|
|
|
s64 top = stack[stack_head - 1]; |
|
|
|
|
|
|
|
s64 second_from_top = stack[stack_head - 2]; |
|
|
|
|
|
|
|
stack[stack_head - 2] = top; |
|
|
|
|
|
|
|
stack[stack_head - 1] = second_from_top; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_rot: { |
|
|
|
|
|
|
|
s64 top = stack[stack_head - 1]; |
|
|
|
|
|
|
|
s64 second = stack[stack_head - 2]; |
|
|
|
|
|
|
|
s64 third = stack[stack_head - 3]; |
|
|
|
|
|
|
|
stack[stack_head - 1] = second; |
|
|
|
|
|
|
|
stack[stack_head - 2] = third; |
|
|
|
|
|
|
|
stack[stack_head - 3] = top; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_xderef: { |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
TODO: The top two stack elements are popped, and a data item is retrieved through an implementation-defined address calculation and pushed as the new stack top. The size of the data retrieved from the dereferenced address is the size of an address on the target machine. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
stack_head -= 2; |
|
|
|
|
|
|
|
s64 value = 0xdeadbeef; |
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_abs: { |
|
|
|
|
|
|
|
stack[stack_head - 1] = ABS(stack[stack_head - 1]); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_and: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b & a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_div: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b / a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_minus: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b - a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_mod: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b % a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_mul: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b * a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_neg: { |
|
|
|
|
|
|
|
stack[stack_head - 1] = -stack[stack_head - 1]; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_not: { |
|
|
|
|
|
|
|
stack[stack_head - 1] = ~stack[stack_head - 1]; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_or: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b | a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_plus: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b + a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_plus_uconst: { |
|
|
|
|
|
|
|
u32 const_value; |
|
|
|
|
|
|
|
increment = decode_leb128(at, &const_value); |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = a + const_value; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_shl: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b << a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_shr: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b >> a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_shra: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (b > 0) { |
|
|
|
|
|
|
|
result = b >> a; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
result = ~(~b >> a); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_xor: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 result = b ^ a; |
|
|
|
|
|
|
|
stack[stack_head++] = result; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_skip: { |
|
|
|
|
|
|
|
s16 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 2); |
|
|
|
|
|
|
|
increment = 2; |
|
|
|
|
|
|
|
increment += const_value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_bra: { |
|
|
|
|
|
|
|
s16 const_value; |
|
|
|
|
|
|
|
memcpy(&const_value, at, 2); |
|
|
|
|
|
|
|
increment = 2; |
|
|
|
|
|
|
|
s64 top = stack[--stack_head]; |
|
|
|
|
|
|
|
if (top) { |
|
|
|
|
|
|
|
increment += const_value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_eq: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
stack[stack_head++] = (b == a ? 1 : 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_ge: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
stack[stack_head++] = (b >= a ? 1 : 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_gt: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
stack[stack_head++] = (b > a ? 1 : 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_le: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
stack[stack_head++] = (b <= a ? 1 : 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_lt: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
stack[stack_head++] = (b < a ? 1 : 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_ne: { |
|
|
|
|
|
|
|
s64 a = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 b = stack[--stack_head]; |
|
|
|
|
|
|
|
stack[stack_head++] = (b != a ? 1 : 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_lit0 ... DW_OP_lit31: { |
|
|
|
|
|
|
|
u32 value = op - DW_OP_lit0; |
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_reg0 ... DW_OP_reg31: { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_breg0 ... DW_OP_breg31: { |
|
|
|
|
|
|
|
s32 offset; |
|
|
|
|
|
|
|
increment = decode_leb128s(at, &offset); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_regx: { |
|
|
|
|
|
|
|
u32 reg; |
|
|
|
|
|
|
|
increment = decode_leb128(at, ®); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_fbreg: { |
|
|
|
|
|
|
|
s32 offset; |
|
|
|
|
|
|
|
increment = decode_leb128s(at, &offset); |
|
|
|
|
|
|
|
stack[stack_head++] = offset; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_bregx: { |
|
|
|
|
|
|
|
u32 reg; |
|
|
|
|
|
|
|
s32 offset; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
increment = decode_leb128(at, ®); |
|
|
|
|
|
|
|
increment += decode_leb128s(at, &offset); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_piece: { |
|
|
|
|
|
|
|
u32 size; |
|
|
|
|
|
|
|
increment = decode_leb128(at, &size); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_deref_size: { |
|
|
|
|
|
|
|
u8 size = *at; |
|
|
|
|
|
|
|
increment = 1; |
|
|
|
|
|
|
|
u64 address = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 value; |
|
|
|
|
|
|
|
memcpy(&value, (void *) address, size); // TODO: surely not this..
|
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_xderef_size: { |
|
|
|
|
|
|
|
u8 size = *at; |
|
|
|
|
|
|
|
increment = 1; |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
TODO: The top two stack elements are popped, and a data item is retrieved through an implementation-defined address calculation and pushed as the new stack top. The size of the data retrieved from the dereferenced address is the size of an address on the target machine. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
stack_head -= 2; |
|
|
|
|
|
|
|
s64 value = 0xdeadbeef; |
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_nop: { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_push_object_address: { |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
TODO: The DW_OP_push_object_address operation pushes the address of the object currently being evaluated as part of evaluation of a user presented expression. This object may correspond to an independent variable described by its own debugging information entry or it may be a component of an array, structure, or class whose address has been dynamically determined by an earlier step during user expression evaluation. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
s64 value = 0xdeadbeef; |
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_call2: { |
|
|
|
|
|
|
|
u16 offset; |
|
|
|
|
|
|
|
memcpy(&offset, at, 2); |
|
|
|
|
|
|
|
increment = 2; |
|
|
|
|
|
|
|
DIE("i can't call2\n"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_call4: { |
|
|
|
|
|
|
|
u32 offset; |
|
|
|
|
|
|
|
memcpy(&offset, at, 4); |
|
|
|
|
|
|
|
increment = 4; |
|
|
|
|
|
|
|
DIE("i can't call4\n"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_call_ref: { |
|
|
|
|
|
|
|
u32 offset; // u64 on 64-bit dwarf !
|
|
|
|
|
|
|
|
memcpy(&offset, at, 4); |
|
|
|
|
|
|
|
increment = 4; |
|
|
|
|
|
|
|
DIE("i can't call_ref\n"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_form_tls_address: { |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
TODO: The DW_OP_form_tls_address operation pops a value from the stack, translates it into an address in the current thread's thread-local storage block, and pushes the address. If the DWARF expression containing the DW_OP_form_tls_address operation belongs to the main executable's DWARF info, the operation uses the main executable's thread-local storage block; if the expression belongs to a shared library's DWARF info, then it uses that shared library's thread-local storage block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
s64 top = stack[--stack_head]; |
|
|
|
|
|
|
|
s64 value = 0xdeadbeef; |
|
|
|
|
|
|
|
stack[stack_head++] = value; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_call_frame_cfa: { |
|
|
|
|
|
|
|
s64 address = 0xdeadbeef; // TODO: get CFA address
|
|
|
|
|
|
|
|
stack[stack_head++] = address; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_bit_piece: { |
|
|
|
|
|
|
|
u32 size; |
|
|
|
|
|
|
|
u32 offset; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
increment = decode_leb128(at, &size); |
|
|
|
|
|
|
|
increment += decode_leb128(at, &offset); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_implicit_value: { |
|
|
|
|
|
|
|
u32 size; |
|
|
|
|
|
|
|
increment = decode_leb128(at, &size); |
|
|
|
|
|
|
|
increment += size; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_stack_value: { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_lo_user: { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case DW_OP_hi_user: { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default: { |
|
|
|
|
|
|
|
printf("unknown dwarf op %d\n", op); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
at += increment; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = stack[stack_head - 1]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(result); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static u32 |
|
|
|
static u32 |
|
|
|
read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_data_offset, u32 form, u64 data_offset, u64 *value) |
|
|
|
read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_data_offset, u32 form, u64 data_offset, u64 *value) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -189,10 +697,12 @@ read_actual_debug_data(u8 *file, u64 string_offset, u32 address_size, u64 base_d |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case DW_FORM_exprloc: { |
|
|
|
case DW_FORM_exprloc: { |
|
|
|
// TODO: return value to caller
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u32 length; |
|
|
|
u32 length; |
|
|
|
increment = decode_leb128(file + data_offset, &length); |
|
|
|
increment = decode_leb128(file + data_offset, &length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s64 expression_value = compute_dwarf_expression_value(file + data_offset + increment, length); |
|
|
|
|
|
|
|
*value = expression_value; |
|
|
|
|
|
|
|
|
|
|
|
increment += length; |
|
|
|
increment += length; |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
@ -262,11 +772,26 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, |
|
|
|
|
|
|
|
|
|
|
|
struct mi_function *func = dest->functions + dest->func_count; |
|
|
|
struct mi_function *func = dest->functions + dest->func_count; |
|
|
|
struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count; |
|
|
|
struct mi_compunit *comp_unit = dest->compilation_units + dest->cu_count; |
|
|
|
|
|
|
|
struct mi_block *block = comp_unit->blocks; |
|
|
|
|
|
|
|
struct mi_variable *variable = block->variables; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum dwarf_die_tag parent = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: make this not bad
|
|
|
|
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
for (;;) { |
|
|
|
data_offset += decode_leb128(file + data_offset, &code); |
|
|
|
data_offset += decode_leb128(file + data_offset, &code); |
|
|
|
|
|
|
|
|
|
|
|
if (code == 0) { |
|
|
|
if (code == 0) { |
|
|
|
|
|
|
|
// NOTE: finalize parent
|
|
|
|
|
|
|
|
if (parent == DW_TAG_lexical_block) { |
|
|
|
|
|
|
|
block->high_pc = block->low_pc + block->high_pc; |
|
|
|
|
|
|
|
++block; |
|
|
|
|
|
|
|
++comp_unit->block_count; |
|
|
|
|
|
|
|
variable = block->variables; |
|
|
|
|
|
|
|
__builtin_trap(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (depth > 1) { |
|
|
|
if (depth > 1) { |
|
|
|
--depth; |
|
|
|
--depth; |
|
|
|
continue; |
|
|
|
continue; |
|
|
@ -283,6 +808,7 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, |
|
|
|
|
|
|
|
|
|
|
|
u32 has_children = file[schema_offset++]; |
|
|
|
u32 has_children = file[schema_offset++]; |
|
|
|
if (has_children) { |
|
|
|
if (has_children) { |
|
|
|
|
|
|
|
parent = tag; |
|
|
|
++depth; |
|
|
|
++depth; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -312,16 +838,27 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, |
|
|
|
} else if (attribute == DW_AT_high_pc) { |
|
|
|
} else if (attribute == DW_AT_high_pc) { |
|
|
|
func->high_pc = value; |
|
|
|
func->high_pc = value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else if (tag == DW_TAG_lexical_block) { |
|
|
|
|
|
|
|
if (attribute == DW_AT_low_pc) { |
|
|
|
|
|
|
|
block->low_pc = value; |
|
|
|
|
|
|
|
} else if (attribute == DW_AT_high_pc) { |
|
|
|
|
|
|
|
block->high_pc = value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (tag == DW_TAG_variable) { |
|
|
|
|
|
|
|
if (attribute == DW_AT_name) { |
|
|
|
|
|
|
|
variable->name = (char *) value; |
|
|
|
|
|
|
|
} else if (attribute == DW_AT_location) { |
|
|
|
|
|
|
|
variable->location = value; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} while (attribute != 0 || form != 0); |
|
|
|
} while (attribute != 0 || form != 0); |
|
|
|
|
|
|
|
|
|
|
|
if (tag == DW_TAG_compile_unit) { |
|
|
|
if (parent == DW_TAG_variable) { |
|
|
|
comp_unit->high_pc = comp_unit->low_pc + comp_unit->high_pc; |
|
|
|
++variable; |
|
|
|
++comp_unit; |
|
|
|
++block->var_count; |
|
|
|
++dest->cu_count; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (tag == DW_TAG_subprogram) { |
|
|
|
if (parent == DW_TAG_subprogram) { |
|
|
|
func->high_pc = func->low_pc + func->high_pc; |
|
|
|
func->high_pc = func->low_pc + func->high_pc; |
|
|
|
func->comp_unit = dest->cu_count; |
|
|
|
func->comp_unit = dest->cu_count; |
|
|
|
++func; |
|
|
|
++func; |
|
|
@ -329,6 +866,9 @@ read_debug_info_for_compilation_unit(u8 *file, struct mi_debuginfo *dest, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
comp_unit->high_pc = comp_unit->low_pc + comp_unit->high_pc; |
|
|
|
|
|
|
|
++dest->cu_count; |
|
|
|
|
|
|
|
|
|
|
|
return(di_header.length + 4); |
|
|
|
return(di_header.length + 4); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|