Implemented interpretation of most of the DWARF expression operations. A few

are still missing. And everything is still utterly untested.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31578 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-07-15 02:12:03 +00:00
parent 460f6b3e73
commit ca38af4c2b
2 changed files with 295 additions and 18 deletions
@@ -12,13 +12,23 @@
#include <algorithm> #include <algorithm>
#include <new> #include <new>
#include <Variant.h>
#include "DataReader.h" #include "DataReader.h"
#include "Dwarf.h" #include "Dwarf.h"
#include "DwarfTargetInterface.h"
static const size_t kMaxStackCapacityIncrement = 64; // number of elements to increase the stack capacity when the stack is full
static const size_t kStackCapacityIncrement = 64;
// maximum number of elements we allow to be pushed on the stack
static const size_t kMaxStackCapacity = 1024; static const size_t kMaxStackCapacity = 1024;
// maximum number of operations we allow to be performed for a single expression
// (to avoid running infinite loops forever)
static const uint32 kMaxOperationCount = 10000;
// #pragma mark - EvaluationException // #pragma mark - EvaluationException
@@ -46,7 +56,7 @@ DwarfExpressionEvaluator::_Push(target_addr_t value)
if (fStackCapacity >= kMaxStackCapacity) if (fStackCapacity >= kMaxStackCapacity)
throw EvaluationException(); throw EvaluationException();
size_t newCapacity = fStackCapacity + kMaxStackCapacityIncrement; size_t newCapacity = fStackCapacity + kStackCapacityIncrement;
target_addr_t* newStack = (target_addr_t*)realloc(fStack, target_addr_t* newStack = (target_addr_t*)realloc(fStack,
newCapacity * sizeof(target_addr_t)); newCapacity * sizeof(target_addr_t));
if (newStack == NULL) if (newStack == NULL)
@@ -68,12 +78,18 @@ DwarfExpressionEvaluator::_Pop()
} }
DwarfExpressionEvaluator::DwarfExpressionEvaluator(uint8 addressSize) DwarfExpressionEvaluator::DwarfExpressionEvaluator(
DwarfTargetInterface* targetInterface, uint8 addressSize)
: :
fTargetInterface(targetInterface),
fStack(NULL), fStack(NULL),
fStackSize(0), fStackSize(0),
fStackCapacity(0), fStackCapacity(0),
fAddressSize(addressSize) fObjectAddress(0),
fFrameAddress(0),
fAddressSize(addressSize),
fObjectAddressValid(false),
fFrameAddressValid(false)
{ {
} }
@@ -84,6 +100,22 @@ DwarfExpressionEvaluator::~DwarfExpressionEvaluator()
} }
void
DwarfExpressionEvaluator::SetObjectAddress(target_addr_t address)
{
fObjectAddress = address;
fObjectAddressValid = true;
}
void
DwarfExpressionEvaluator::SetFrameAddress(target_addr_t address)
{
fFrameAddress = address;
fFrameAddressValid = true;
}
status_t status_t
DwarfExpressionEvaluator::Evaluate(const void* expression, size_t size) DwarfExpressionEvaluator::Evaluate(const void* expression, size_t size)
{ {
@@ -102,6 +134,8 @@ DwarfExpressionEvaluator::Evaluate(const void* expression, size_t size)
status_t status_t
DwarfExpressionEvaluator::_Evaluate() DwarfExpressionEvaluator::_Evaluate()
{ {
uint32 operationsExecuted = 0;
while (fDataReader.BytesRemaining() > 0) { while (fDataReader.BytesRemaining() > 0) {
uint8 opcode = fDataReader.Read<uint8>(0); uint8 opcode = fDataReader.Read<uint8>(0);
@@ -172,67 +206,293 @@ DwarfExpressionEvaluator::_Evaluate()
fStack[fStackSize - 3] = tmp; fStack[fStackSize - 3] = tmp;
break; break;
} }
case DW_OP_deref: case DW_OP_deref:
// TODO:... _DereferenceAddress(fAddressSize);
break;
case DW_OP_deref_size:
_DereferenceAddress(fDataReader.Read<uint8>(0));
break; break;
case DW_OP_xderef: case DW_OP_xderef:
// TODO:... _DereferenceAddressSpaceAddress(fAddressSize);
break; break;
case DW_OP_xderef_size:
_DereferenceAddressSpaceAddress(fDataReader.Read<uint8>(0));
break;
case DW_OP_abs: case DW_OP_abs:
{
target_addr_t value = _Pop();
if (fAddressSize == 4) {
int32 signedValue = (int32)value;
_Push(signedValue >= 0 ? signedValue : -signedValue);
} else {
int64 signedValue = (int64)value;
_Push(signedValue >= 0 ? signedValue : -signedValue);
}
break;
}
case DW_OP_and: case DW_OP_and:
_Push(_Pop() & _Pop());
break;
case DW_OP_div: case DW_OP_div:
{
int64 top = (int64)_Pop();
int64 second = (int64)_Pop();
_Push(top != 0 ? second / top : 0);
break;
}
case DW_OP_minus: case DW_OP_minus:
{
target_addr_t top = _Pop();
_Push(_Pop() - top);
break;
}
case DW_OP_mod: case DW_OP_mod:
{
// While the specs explicitly speak of signed integer division
// for "div", nothing is mentioned for "mod".
target_addr_t top = _Pop();
target_addr_t second = _Pop();
_Push(top != 0 ? second % top : 0);
break;
}
case DW_OP_mul: case DW_OP_mul:
_Push(_Pop() * _Pop());
break;
case DW_OP_neg: case DW_OP_neg:
{
if (fAddressSize == 4)
_Push(-(int32)_Pop());
else
_Push(-(int64)_Pop());
break;
}
case DW_OP_not: case DW_OP_not:
_Push(~_Pop());
break;
case DW_OP_or: case DW_OP_or:
_Push(_Pop() | _Pop());
break;
case DW_OP_plus: case DW_OP_plus:
_Push(_Pop() + _Pop());
break;
case DW_OP_plus_uconst: case DW_OP_plus_uconst:
_Push(_Pop() + fDataReader.ReadUnsignedLEB128(0));
break;
case DW_OP_shl: case DW_OP_shl:
{
target_addr_t top = _Pop();
_Push(_Pop() << top);
break;
}
case DW_OP_shr: case DW_OP_shr:
{
target_addr_t top = _Pop();
_Push(_Pop() >> top);
break;
}
case DW_OP_shra: case DW_OP_shra:
{
target_addr_t top = _Pop();
int64 second = (int64)_Pop();
_Push(second >= 0 ? second >> top : -(-second >> top));
// right shift on negative values is implementation defined
break;
}
case DW_OP_xor: case DW_OP_xor:
case DW_OP_skip: _Push(_Pop() ^ _Pop());
break;
case DW_OP_bra: case DW_OP_bra:
if (_Pop() == 0)
break;
// fall through
case DW_OP_skip:
{
int16 offset = fDataReader.Read<int16>(0);
if (offset >= 0 ? offset > fDataReader.BytesRemaining()
: -offset > fDataReader.Offset()) {
throw EvaluationException();
}
fDataReader.SeekAbsolute(fDataReader.Offset() + offset);
break;
}
case DW_OP_eq: case DW_OP_eq:
_Push(_Pop() == _Pop() ? 1 : 0);
break;
case DW_OP_ge: case DW_OP_ge:
{
int64 top = (int64)_Pop();
_Push((int64)_Pop() >= top ? 1 : 0);
break;
}
case DW_OP_gt: case DW_OP_gt:
{
int64 top = (int64)_Pop();
_Push((int64)_Pop() > top ? 1 : 0);
break;
}
case DW_OP_le: case DW_OP_le:
{
int64 top = (int64)_Pop();
_Push((int64)_Pop() <= top ? 1 : 0);
break;
}
case DW_OP_lt: case DW_OP_lt:
{
int64 top = (int64)_Pop();
_Push((int64)_Pop() < top ? 1 : 0);
break;
}
case DW_OP_ne: case DW_OP_ne:
_Push(_Pop() == _Pop() ? 1 : 0);
break;
case DW_OP_push_object_address:
if (!fObjectAddressValid)
throw EvaluationException();
_Push(fObjectAddress);
break;
case DW_OP_call_frame_cfa:
if (!fFrameAddressValid)
throw EvaluationException();
_Push(fFrameAddress);
break;
case DW_OP_regx: case DW_OP_regx:
case DW_OP_fbreg: _PushRegister(fDataReader.ReadUnsignedLEB128(0), 0);
break;
case DW_OP_bregx: case DW_OP_bregx:
case DW_OP_piece: {
case DW_OP_deref_size: uint32 reg = fDataReader.ReadUnsignedLEB128(0);
case DW_OP_xderef_size: _PushRegister(reg, fDataReader.ReadSignedLEB128(0));
case DW_OP_nop: break;
case DW_OP_push_object_address: }
case DW_OP_form_tls_address:
// TODO:...
break;
case DW_OP_fbreg:
// TODO:...
break;
case DW_OP_call2: case DW_OP_call2:
case DW_OP_call4: case DW_OP_call4:
case DW_OP_call_ref: case DW_OP_call_ref:
case DW_OP_form_tls_address: // TODO:...
case DW_OP_call_frame_cfa: break;
case DW_OP_piece:
case DW_OP_bit_piece: case DW_OP_bit_piece:
// TODO:...
break;
case DW_OP_nop:
break; break;
default: default:
if (opcode >= DW_OP_lit0 && opcode <= DW_OP_lit31) { if (opcode >= DW_OP_lit0 && opcode <= DW_OP_lit31) {
_Push(opcode - DW_OP_lit0); _Push(opcode - DW_OP_lit0);
} else if (opcode >= DW_OP_reg0 && opcode <= DW_OP_reg31) { } else if (opcode >= DW_OP_reg0 && opcode <= DW_OP_reg31) {
// TODO:... _PushRegister(opcode - DW_OP_reg0, 0);
} else if (opcode >= DW_OP_breg0 && opcode <= DW_OP_breg31) { } else if (opcode >= DW_OP_breg0 && opcode <= DW_OP_breg31) {
// TODO:... _PushRegister(opcode - DW_OP_reg0,
fDataReader.ReadSignedLEB128(0));
} else { } else {
printf("DwarfExpressionEvaluator::_Evaluate(): unsupported " printf("DwarfExpressionEvaluator::_Evaluate(): unsupported "
"opcode: %u\n", opcode); "opcode: %u\n", opcode);
return B_BAD_DATA; return B_BAD_DATA;
} }
break;
} }
if (++operationsExecuted >= kMaxOperationCount)
return B_BAD_DATA;
} }
return fDataReader.HasOverflow() ? B_BAD_DATA : B_OK; return fDataReader.HasOverflow() ? B_BAD_DATA : B_OK;
} }
void
DwarfExpressionEvaluator::_DereferenceAddress(uint8 addressSize)
{
uint32 valueType;
switch (addressSize) {
case 1:
valueType = B_UINT8_TYPE;
break;
case 2:
valueType = B_UINT16_TYPE;
break;
case 4:
valueType = B_UINT32_TYPE;
break;
case 8:
if (fAddressSize == 8) {
valueType = B_UINT64_TYPE;
break;
}
// fall through
default:
throw EvaluationException();
}
target_addr_t address = _Pop();
BVariant value;
if (!fTargetInterface->ReadValueFromMemory(address, valueType, value)) {
throw EvaluationException();
}
_Push(value.ToUInt64());
}
void
DwarfExpressionEvaluator::_DereferenceAddressSpaceAddress(uint8 addressSize)
{
uint32 valueType;
switch (addressSize) {
case 1:
valueType = B_UINT8_TYPE;
break;
case 2:
valueType = B_UINT16_TYPE;
break;
case 4:
valueType = B_UINT32_TYPE;
break;
case 8:
if (fAddressSize == 8) {
valueType = B_UINT64_TYPE;
break;
}
// fall through
default:
throw EvaluationException();
}
target_addr_t address = _Pop();
target_addr_t addressSpace = _Pop();
BVariant value;
if (!fTargetInterface->ReadValueFromMemory(addressSpace, address, valueType,
value)) {
throw EvaluationException();
}
_Push(value.ToUInt64());
}
void
DwarfExpressionEvaluator::_PushRegister(uint32 reg, target_addr_t offset)
{
BVariant value;
if (!fTargetInterface->GetRegisterValue(reg, value))
throw EvaluationException();
_Push(value.ToUInt64());
}
@@ -10,11 +10,19 @@
#include "Types.h" #include "Types.h"
class DwarfTargetInterface;
class DwarfExpressionEvaluator { class DwarfExpressionEvaluator {
public: public:
DwarfExpressionEvaluator(uint8 addressSize); DwarfExpressionEvaluator(
DwarfTargetInterface* targetInterface,
uint8 addressSize);
~DwarfExpressionEvaluator(); ~DwarfExpressionEvaluator();
void SetObjectAddress(target_addr_t address);
void SetFrameAddress(target_addr_t address);
status_t Evaluate(const void* expression, size_t size); status_t Evaluate(const void* expression, size_t size);
private: private:
@@ -27,13 +35,22 @@ private:
inline target_addr_t _Pop(); inline target_addr_t _Pop();
status_t _Evaluate(); status_t _Evaluate();
void _DereferenceAddress(uint8 addressSize);
void _DereferenceAddressSpaceAddress(
uint8 addressSize);
void _PushRegister(uint32 reg, target_addr_t offset);
private: private:
DwarfTargetInterface* fTargetInterface;
target_addr_t* fStack; target_addr_t* fStack;
size_t fStackSize; size_t fStackSize;
size_t fStackCapacity; size_t fStackCapacity;
DataReader fDataReader; DataReader fDataReader;
target_addr_t fObjectAddress;
target_addr_t fFrameAddress;
uint8 fAddressSize; uint8 fAddressSize;
bool fObjectAddressValid;
bool fFrameAddressValid;
}; };