DWARFExpression.cpp [plain text]
#include "lldb/Expression/DWARFExpression.h"
#include <inttypes.h>
#include <vector>
#include "lldb/Core/DataEncoder.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/VMRange.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
#include "lldb/Expression/ClangExpressionVariable.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/lldb-private-log.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/StackID.h"
#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
const char *
DW_OP_value_to_name (uint32_t val)
{
static char invalid[100];
switch (val) {
case 0x03: return "DW_OP_addr";
case 0x06: return "DW_OP_deref";
case 0x08: return "DW_OP_const1u";
case 0x09: return "DW_OP_const1s";
case 0x0a: return "DW_OP_const2u";
case 0x0b: return "DW_OP_const2s";
case 0x0c: return "DW_OP_const4u";
case 0x0d: return "DW_OP_const4s";
case 0x0e: return "DW_OP_const8u";
case 0x0f: return "DW_OP_const8s";
case 0x10: return "DW_OP_constu";
case 0x11: return "DW_OP_consts";
case 0x12: return "DW_OP_dup";
case 0x13: return "DW_OP_drop";
case 0x14: return "DW_OP_over";
case 0x15: return "DW_OP_pick";
case 0x16: return "DW_OP_swap";
case 0x17: return "DW_OP_rot";
case 0x18: return "DW_OP_xderef";
case 0x19: return "DW_OP_abs";
case 0x1a: return "DW_OP_and";
case 0x1b: return "DW_OP_div";
case 0x1c: return "DW_OP_minus";
case 0x1d: return "DW_OP_mod";
case 0x1e: return "DW_OP_mul";
case 0x1f: return "DW_OP_neg";
case 0x20: return "DW_OP_not";
case 0x21: return "DW_OP_or";
case 0x22: return "DW_OP_plus";
case 0x23: return "DW_OP_plus_uconst";
case 0x24: return "DW_OP_shl";
case 0x25: return "DW_OP_shr";
case 0x26: return "DW_OP_shra";
case 0x27: return "DW_OP_xor";
case 0x2f: return "DW_OP_skip";
case 0x28: return "DW_OP_bra";
case 0x29: return "DW_OP_eq";
case 0x2a: return "DW_OP_ge";
case 0x2b: return "DW_OP_gt";
case 0x2c: return "DW_OP_le";
case 0x2d: return "DW_OP_lt";
case 0x2e: return "DW_OP_ne";
case 0x30: return "DW_OP_lit0";
case 0x31: return "DW_OP_lit1";
case 0x32: return "DW_OP_lit2";
case 0x33: return "DW_OP_lit3";
case 0x34: return "DW_OP_lit4";
case 0x35: return "DW_OP_lit5";
case 0x36: return "DW_OP_lit6";
case 0x37: return "DW_OP_lit7";
case 0x38: return "DW_OP_lit8";
case 0x39: return "DW_OP_lit9";
case 0x3a: return "DW_OP_lit10";
case 0x3b: return "DW_OP_lit11";
case 0x3c: return "DW_OP_lit12";
case 0x3d: return "DW_OP_lit13";
case 0x3e: return "DW_OP_lit14";
case 0x3f: return "DW_OP_lit15";
case 0x40: return "DW_OP_lit16";
case 0x41: return "DW_OP_lit17";
case 0x42: return "DW_OP_lit18";
case 0x43: return "DW_OP_lit19";
case 0x44: return "DW_OP_lit20";
case 0x45: return "DW_OP_lit21";
case 0x46: return "DW_OP_lit22";
case 0x47: return "DW_OP_lit23";
case 0x48: return "DW_OP_lit24";
case 0x49: return "DW_OP_lit25";
case 0x4a: return "DW_OP_lit26";
case 0x4b: return "DW_OP_lit27";
case 0x4c: return "DW_OP_lit28";
case 0x4d: return "DW_OP_lit29";
case 0x4e: return "DW_OP_lit30";
case 0x4f: return "DW_OP_lit31";
case 0x50: return "DW_OP_reg0";
case 0x51: return "DW_OP_reg1";
case 0x52: return "DW_OP_reg2";
case 0x53: return "DW_OP_reg3";
case 0x54: return "DW_OP_reg4";
case 0x55: return "DW_OP_reg5";
case 0x56: return "DW_OP_reg6";
case 0x57: return "DW_OP_reg7";
case 0x58: return "DW_OP_reg8";
case 0x59: return "DW_OP_reg9";
case 0x5a: return "DW_OP_reg10";
case 0x5b: return "DW_OP_reg11";
case 0x5c: return "DW_OP_reg12";
case 0x5d: return "DW_OP_reg13";
case 0x5e: return "DW_OP_reg14";
case 0x5f: return "DW_OP_reg15";
case 0x60: return "DW_OP_reg16";
case 0x61: return "DW_OP_reg17";
case 0x62: return "DW_OP_reg18";
case 0x63: return "DW_OP_reg19";
case 0x64: return "DW_OP_reg20";
case 0x65: return "DW_OP_reg21";
case 0x66: return "DW_OP_reg22";
case 0x67: return "DW_OP_reg23";
case 0x68: return "DW_OP_reg24";
case 0x69: return "DW_OP_reg25";
case 0x6a: return "DW_OP_reg26";
case 0x6b: return "DW_OP_reg27";
case 0x6c: return "DW_OP_reg28";
case 0x6d: return "DW_OP_reg29";
case 0x6e: return "DW_OP_reg30";
case 0x6f: return "DW_OP_reg31";
case 0x70: return "DW_OP_breg0";
case 0x71: return "DW_OP_breg1";
case 0x72: return "DW_OP_breg2";
case 0x73: return "DW_OP_breg3";
case 0x74: return "DW_OP_breg4";
case 0x75: return "DW_OP_breg5";
case 0x76: return "DW_OP_breg6";
case 0x77: return "DW_OP_breg7";
case 0x78: return "DW_OP_breg8";
case 0x79: return "DW_OP_breg9";
case 0x7a: return "DW_OP_breg10";
case 0x7b: return "DW_OP_breg11";
case 0x7c: return "DW_OP_breg12";
case 0x7d: return "DW_OP_breg13";
case 0x7e: return "DW_OP_breg14";
case 0x7f: return "DW_OP_breg15";
case 0x80: return "DW_OP_breg16";
case 0x81: return "DW_OP_breg17";
case 0x82: return "DW_OP_breg18";
case 0x83: return "DW_OP_breg19";
case 0x84: return "DW_OP_breg20";
case 0x85: return "DW_OP_breg21";
case 0x86: return "DW_OP_breg22";
case 0x87: return "DW_OP_breg23";
case 0x88: return "DW_OP_breg24";
case 0x89: return "DW_OP_breg25";
case 0x8a: return "DW_OP_breg26";
case 0x8b: return "DW_OP_breg27";
case 0x8c: return "DW_OP_breg28";
case 0x8d: return "DW_OP_breg29";
case 0x8e: return "DW_OP_breg30";
case 0x8f: return "DW_OP_breg31";
case 0x90: return "DW_OP_regx";
case 0x91: return "DW_OP_fbreg";
case 0x92: return "DW_OP_bregx";
case 0x93: return "DW_OP_piece";
case 0x94: return "DW_OP_deref_size";
case 0x95: return "DW_OP_xderef_size";
case 0x96: return "DW_OP_nop";
case 0x97: return "DW_OP_push_object_address";
case 0x98: return "DW_OP_call2";
case 0x99: return "DW_OP_call4";
case 0x9a: return "DW_OP_call_ref";
case DW_OP_APPLE_uninit: return "DW_OP_APPLE_uninit";
default:
snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
return invalid;
}
}
DWARFExpression::DWARFExpression() :
m_module_wp(),
m_data(),
m_reg_kind (eRegisterKindDWARF),
m_loclist_slide (LLDB_INVALID_ADDRESS)
{
}
DWARFExpression::DWARFExpression(const DWARFExpression& rhs) :
m_module_wp(rhs.m_module_wp),
m_data(rhs.m_data),
m_reg_kind (rhs.m_reg_kind),
m_loclist_slide(rhs.m_loclist_slide)
{
}
DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) :
m_module_wp(),
m_data(data, data_offset, data_length),
m_reg_kind (eRegisterKindDWARF),
m_loclist_slide(LLDB_INVALID_ADDRESS)
{
if (module_sp)
m_module_wp = module_sp;
}
DWARFExpression::~DWARFExpression()
{
}
bool
DWARFExpression::IsValid() const
{
return m_data.GetByteSize() > 0;
}
void
DWARFExpression::SetOpcodeData (const DataExtractor& data)
{
m_data = data;
}
void
DWARFExpression::CopyOpcodeData (lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length)
{
const uint8_t *bytes = data.PeekData(data_offset, data_length);
if (bytes)
{
m_module_wp = module_sp;
m_data.SetData(DataBufferSP(new DataBufferHeap(bytes, data_length)));
m_data.SetByteOrder(data.GetByteOrder());
m_data.SetAddressByteSize(data.GetAddressByteSize());
}
}
void
DWARFExpression::SetOpcodeData (lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length)
{
m_module_wp = module_sp;
m_data.SetData(data, data_offset, data_length);
}
void
DWARFExpression::DumpLocation (Stream *s, lldb::offset_t offset, lldb::offset_t length, lldb::DescriptionLevel level, ABI *abi) const
{
if (!m_data.ValidOffsetForDataOfSize(offset, length))
return;
const lldb::offset_t start_offset = offset;
const lldb::offset_t end_offset = offset + length;
while (m_data.ValidOffset(offset) && offset < end_offset)
{
const lldb::offset_t op_offset = offset;
const uint8_t op = m_data.GetU8(&offset);
switch (level)
{
default:
break;
case lldb::eDescriptionLevelBrief:
if (offset > start_offset)
s->PutChar(' ');
break;
case lldb::eDescriptionLevelFull:
case lldb::eDescriptionLevelVerbose:
if (offset > start_offset)
s->EOL();
s->Indent();
if (level == lldb::eDescriptionLevelFull)
break;
s->Printf("0x%8.8" PRIx64 ": %s", op_offset, op >= DW_OP_APPLE_uninit ? "DW_OP_APPLE_" : "DW_OP_");
break;
}
switch (op)
{
case DW_OP_addr: *s << "DW_OP_addr(" << m_data.GetAddress(&offset) << ") "; break; case DW_OP_deref: *s << "DW_OP_deref"; break; case DW_OP_const1u: s->Printf("DW_OP_const1u(0x%2.2x) ", m_data.GetU8(&offset)); break; case DW_OP_const1s: s->Printf("DW_OP_const1s(0x%2.2x) ", m_data.GetU8(&offset)); break; case DW_OP_const2u: s->Printf("DW_OP_const2u(0x%4.4x) ", m_data.GetU16(&offset)); break; case DW_OP_const2s: s->Printf("DW_OP_const2s(0x%4.4x) ", m_data.GetU16(&offset)); break; case DW_OP_const4u: s->Printf("DW_OP_const4u(0x%8.8x) ", m_data.GetU32(&offset)); break; case DW_OP_const4s: s->Printf("DW_OP_const4s(0x%8.8x) ", m_data.GetU32(&offset)); break; case DW_OP_const8u: s->Printf("DW_OP_const8u(0x%16.16" PRIx64 ") ", m_data.GetU64(&offset)); break; case DW_OP_const8s: s->Printf("DW_OP_const8s(0x%16.16" PRIx64 ") ", m_data.GetU64(&offset)); break; case DW_OP_constu: s->Printf("DW_OP_constu(0x%" PRIx64 ") ", m_data.GetULEB128(&offset)); break; case DW_OP_consts: s->Printf("DW_OP_consts(0x%" PRId64 ") ", m_data.GetSLEB128(&offset)); break; case DW_OP_dup: s->PutCString("DW_OP_dup"); break; case DW_OP_drop: s->PutCString("DW_OP_drop"); break; case DW_OP_over: s->PutCString("DW_OP_over"); break; case DW_OP_pick: s->Printf("DW_OP_pick(0x%2.2x) ", m_data.GetU8(&offset)); break; case DW_OP_swap: s->PutCString("DW_OP_swap"); break; case DW_OP_rot: s->PutCString("DW_OP_rot"); break; case DW_OP_xderef: s->PutCString("DW_OP_xderef"); break; case DW_OP_abs: s->PutCString("DW_OP_abs"); break; case DW_OP_and: s->PutCString("DW_OP_and"); break; case DW_OP_div: s->PutCString("DW_OP_div"); break; case DW_OP_minus: s->PutCString("DW_OP_minus"); break; case DW_OP_mod: s->PutCString("DW_OP_mod"); break; case DW_OP_mul: s->PutCString("DW_OP_mul"); break; case DW_OP_neg: s->PutCString("DW_OP_neg"); break; case DW_OP_not: s->PutCString("DW_OP_not"); break; case DW_OP_or: s->PutCString("DW_OP_or"); break; case DW_OP_plus: s->PutCString("DW_OP_plus"); break; case DW_OP_plus_uconst: s->Printf("DW_OP_plus_uconst(0x%" PRIx64 ") ", m_data.GetULEB128(&offset));
break;
case DW_OP_shl: s->PutCString("DW_OP_shl"); break; case DW_OP_shr: s->PutCString("DW_OP_shr"); break; case DW_OP_shra: s->PutCString("DW_OP_shra"); break; case DW_OP_xor: s->PutCString("DW_OP_xor"); break; case DW_OP_skip: s->Printf("DW_OP_skip(0x%4.4x)", m_data.GetU16(&offset)); break; case DW_OP_bra: s->Printf("DW_OP_bra(0x%4.4x)", m_data.GetU16(&offset)); break; case DW_OP_eq: s->PutCString("DW_OP_eq"); break; case DW_OP_ge: s->PutCString("DW_OP_ge"); break; case DW_OP_gt: s->PutCString("DW_OP_gt"); break; case DW_OP_le: s->PutCString("DW_OP_le"); break; case DW_OP_lt: s->PutCString("DW_OP_lt"); break; case DW_OP_ne: s->PutCString("DW_OP_ne"); break;
case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: s->Printf("DW_OP_lit%i", op - DW_OP_lit0); break;
case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: {
uint32_t reg_num = op - DW_OP_reg0;
if (abi)
{
RegisterInfo reg_info;
if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
{
if (reg_info.name)
{
s->PutCString (reg_info.name);
break;
}
else if (reg_info.alt_name)
{
s->PutCString (reg_info.alt_name);
break;
}
}
}
s->Printf("DW_OP_reg%u", reg_num); break;
}
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
{
uint32_t reg_num = op - DW_OP_breg0;
int64_t reg_offset = m_data.GetSLEB128(&offset);
if (abi)
{
RegisterInfo reg_info;
if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
{
if (reg_info.name)
{
s->Printf("[%s%+" PRIi64 "]", reg_info.name, reg_offset);
break;
}
else if (reg_info.alt_name)
{
s->Printf("[%s%+" PRIi64 "]", reg_info.alt_name, reg_offset);
break;
}
}
}
s->Printf("DW_OP_breg%i(0x%" PRIx64 ")", reg_num, reg_offset);
}
break;
case DW_OP_regx: {
uint32_t reg_num = m_data.GetULEB128(&offset);
if (abi)
{
RegisterInfo reg_info;
if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
{
if (reg_info.name)
{
s->PutCString (reg_info.name);
break;
}
else if (reg_info.alt_name)
{
s->PutCString (reg_info.alt_name);
break;
}
}
}
s->Printf("DW_OP_regx(%" PRIu32 ")", reg_num); break;
}
break;
case DW_OP_fbreg: s->Printf("DW_OP_fbreg(%" PRIi64 ")",m_data.GetSLEB128(&offset));
break;
case DW_OP_bregx: {
uint32_t reg_num = m_data.GetULEB128(&offset);
int64_t reg_offset = m_data.GetSLEB128(&offset);
if (abi)
{
RegisterInfo reg_info;
if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
{
if (reg_info.name)
{
s->Printf("[%s%+" PRIi64 "]", reg_info.name, reg_offset);
break;
}
else if (reg_info.alt_name)
{
s->Printf("[%s%+" PRIi64 "]", reg_info.alt_name, reg_offset);
break;
}
}
}
s->Printf("DW_OP_bregx(reg=%" PRIu32 ",offset=%" PRIi64 ")", reg_num, reg_offset);
}
break;
case DW_OP_piece: s->Printf("DW_OP_piece(0x%" PRIx64 ")", m_data.GetULEB128(&offset));
break;
case DW_OP_deref_size: s->Printf("DW_OP_deref_size(0x%2.2x)", m_data.GetU8(&offset));
break;
case DW_OP_xderef_size: s->Printf("DW_OP_xderef_size(0x%2.2x)", m_data.GetU8(&offset));
break;
case DW_OP_nop: s->PutCString("DW_OP_nop"); break; case DW_OP_push_object_address: s->PutCString("DW_OP_push_object_address"); break; case DW_OP_call2: s->Printf("DW_OP_call2(0x%4.4x)", m_data.GetU16(&offset));
break;
case DW_OP_call4: s->Printf("DW_OP_call4(0x%8.8x)", m_data.GetU32(&offset));
break;
case DW_OP_call_ref: s->Printf("DW_OP_call_ref(0x%8.8" PRIx64 ")", m_data.GetAddress(&offset));
break;
case DW_OP_GNU_push_tls_address:
s->PutCString("DW_OP_GNU_push_tls_address"); break;
case DW_OP_APPLE_uninit:
s->PutCString("DW_OP_APPLE_uninit"); break;
}
}
}
void
DWARFExpression::SetLocationListSlide (addr_t slide)
{
m_loclist_slide = slide;
}
int
DWARFExpression::GetRegisterKind ()
{
return m_reg_kind;
}
void
DWARFExpression::SetRegisterKind (RegisterKind reg_kind)
{
m_reg_kind = reg_kind;
}
bool
DWARFExpression::IsLocationList() const
{
return m_loclist_slide != LLDB_INVALID_ADDRESS;
}
void
DWARFExpression::GetDescription (Stream *s, lldb::DescriptionLevel level, addr_t location_list_base_addr, ABI *abi) const
{
if (IsLocationList())
{
lldb::offset_t offset = 0;
uint32_t count = 0;
addr_t curr_base_addr = location_list_base_addr;
while (m_data.ValidOffset(offset))
{
lldb::addr_t begin_addr_offset = m_data.GetAddress(&offset);
lldb::addr_t end_addr_offset = m_data.GetAddress(&offset);
if (begin_addr_offset < end_addr_offset)
{
if (count > 0)
s->PutCString(", ");
VMRange addr_range(curr_base_addr + begin_addr_offset, curr_base_addr + end_addr_offset);
addr_range.Dump(s, 0, 8);
s->PutChar('{');
lldb::offset_t location_length = m_data.GetU16(&offset);
DumpLocation (s, offset, location_length, level, abi);
s->PutChar('}');
offset += location_length;
}
else if (begin_addr_offset == 0 && end_addr_offset == 0)
{
break;
}
else
{
if ((m_data.GetAddressByteSize() == 4 && (begin_addr_offset == UINT32_MAX)) ||
(m_data.GetAddressByteSize() == 8 && (begin_addr_offset == UINT64_MAX)))
{
curr_base_addr = end_addr_offset + location_list_base_addr;
if (count > 0)
s->PutCString(", ");
*s << "base_addr = " << end_addr_offset;
}
}
count++;
}
}
else
{
DumpLocation (s, 0, m_data.GetByteSize(), level, abi);
}
}
static bool
ReadRegisterValueAsScalar
(
RegisterContext *reg_ctx,
uint32_t reg_kind,
uint32_t reg_num,
Error *error_ptr,
Value &value
)
{
if (reg_ctx == NULL)
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("No register context in frame.\n");
}
else
{
uint32_t native_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
if (native_reg == LLDB_INVALID_REGNUM)
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("Unable to convert register kind=%u reg_num=%u to a native register number.\n", reg_kind, reg_num);
}
else
{
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(native_reg);
RegisterValue reg_value;
if (reg_ctx->ReadRegister (reg_info, reg_value))
{
if (reg_value.GetScalarValue(value.GetScalar()))
{
value.SetValueType (Value::eValueTypeScalar);
value.SetContext (Value::eContextTypeRegisterInfo,
const_cast<RegisterInfo *>(reg_info));
if (error_ptr)
error_ptr->Clear();
return true;
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("register %s can't be converted to a scalar value",
reg_info->name);
}
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("register %s is not available", reg_info->name);
}
}
}
return false;
}
static offset_t
GetOpcodeDataSize (const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op)
{
lldb::offset_t offset = data_offset;
switch (op)
{
case DW_OP_addr:
case DW_OP_call_ref: return data.GetAddressByteSize();
case DW_OP_deref: case DW_OP_dup: case DW_OP_drop: case DW_OP_over: case DW_OP_swap: case DW_OP_rot: case DW_OP_xderef: case DW_OP_abs: case DW_OP_and: case DW_OP_div: case DW_OP_minus: case DW_OP_mod: case DW_OP_mul: case DW_OP_neg: case DW_OP_not: case DW_OP_or: case DW_OP_plus: case DW_OP_shl: case DW_OP_shr: case DW_OP_shra: case DW_OP_xor: case DW_OP_eq: case DW_OP_ge: case DW_OP_gt: case DW_OP_le: case DW_OP_lt: case DW_OP_ne: case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: case DW_OP_nop: case DW_OP_push_object_address: case DW_OP_form_tls_address: case DW_OP_call_frame_cfa: case DW_OP_stack_value: case DW_OP_GNU_push_tls_address: return 0;
case DW_OP_const1u: case DW_OP_const1s: case DW_OP_pick: case DW_OP_deref_size: case DW_OP_xderef_size: return 1;
case DW_OP_const2u: case DW_OP_const2s: case DW_OP_skip: case DW_OP_bra: case DW_OP_call2: return 2;
case DW_OP_const4u: case DW_OP_const4s: case DW_OP_call4: return 4;
case DW_OP_const8u: case DW_OP_const8s: return 8;
case DW_OP_constu: case DW_OP_consts: case DW_OP_plus_uconst: case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: case DW_OP_regx: case DW_OP_fbreg: case DW_OP_piece: data.Skip_LEB128(&offset);
return offset - data_offset;
case DW_OP_bregx: case DW_OP_bit_piece: data.Skip_LEB128(&offset);
data.Skip_LEB128(&offset);
return offset - data_offset;
case DW_OP_implicit_value: {
uint64_t block_len = data.Skip_LEB128(&offset);
offset += block_len;
return offset - data_offset;
}
default:
break;
}
return LLDB_INVALID_OFFSET;
}
lldb::addr_t
DWARFExpression::GetLocation_DW_OP_addr (uint32_t op_addr_idx, bool &error) const
{
error = false;
if (IsLocationList())
return LLDB_INVALID_ADDRESS;
lldb::offset_t offset = 0;
uint32_t curr_op_addr_idx = 0;
while (m_data.ValidOffset(offset))
{
const uint8_t op = m_data.GetU8(&offset);
if (op == DW_OP_addr)
{
const lldb::addr_t op_file_addr = m_data.GetAddress(&offset);
if (curr_op_addr_idx == op_addr_idx)
return op_file_addr;
else
++curr_op_addr_idx;
}
else
{
const offset_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
if (op_arg_size == LLDB_INVALID_OFFSET)
{
error = true;
break;
}
offset += op_arg_size;
}
}
return LLDB_INVALID_ADDRESS;
}
bool
DWARFExpression::Update_DW_OP_addr (lldb::addr_t file_addr)
{
if (IsLocationList())
return false;
lldb::offset_t offset = 0;
while (m_data.ValidOffset(offset))
{
const uint8_t op = m_data.GetU8(&offset);
if (op == DW_OP_addr)
{
const uint32_t addr_byte_size = m_data.GetAddressByteSize();
std::unique_ptr<DataBufferHeap> head_data_ap (new DataBufferHeap (m_data.GetDataStart(),
m_data.GetByteSize()));
DataEncoder encoder (head_data_ap->GetBytes(),
head_data_ap->GetByteSize(),
m_data.GetByteOrder(),
addr_byte_size);
if (encoder.PutMaxU64 (offset, addr_byte_size, file_addr) == UINT32_MAX)
return false;
m_data.SetData (DataBufferSP (head_data_ap.release()));
return true;
}
else
{
const offset_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
if (op_arg_size == LLDB_INVALID_OFFSET)
break;
offset += op_arg_size;
}
}
return false;
}
bool
DWARFExpression::LocationListContainsAddress (lldb::addr_t loclist_base_addr, lldb::addr_t addr) const
{
if (addr == LLDB_INVALID_ADDRESS)
return false;
if (IsLocationList())
{
lldb::offset_t offset = 0;
if (loclist_base_addr == LLDB_INVALID_ADDRESS)
return false;
while (m_data.ValidOffset(offset))
{
addr_t lo_pc = m_data.GetAddress(&offset);
addr_t hi_pc = m_data.GetAddress(&offset);
if (lo_pc == 0 && hi_pc == 0)
break;
else
{
lo_pc += loclist_base_addr - m_loclist_slide;
hi_pc += loclist_base_addr - m_loclist_slide;
if (lo_pc <= addr && addr < hi_pc)
return true;
offset += m_data.GetU16(&offset);
}
}
}
return false;
}
bool
DWARFExpression::GetLocation (addr_t base_addr, addr_t pc, lldb::offset_t &offset, lldb::offset_t &length)
{
offset = 0;
if (!IsLocationList())
{
length = m_data.GetByteSize();
return true;
}
if (base_addr != LLDB_INVALID_ADDRESS && pc != LLDB_INVALID_ADDRESS)
{
addr_t curr_base_addr = base_addr;
while (m_data.ValidOffset(offset))
{
addr_t lo_pc = m_data.GetAddress(&offset);
addr_t hi_pc = m_data.GetAddress(&offset);
if (lo_pc == 0 && hi_pc == 0)
{
break;
}
else
{
lo_pc += curr_base_addr - m_loclist_slide;
hi_pc += curr_base_addr - m_loclist_slide;
length = m_data.GetU16(&offset);
if (length > 0 && lo_pc <= pc && pc < hi_pc)
return true;
offset += length;
}
}
}
offset = LLDB_INVALID_OFFSET;
length = 0;
return false;
}
bool
DWARFExpression::DumpLocationForAddress (Stream *s,
lldb::DescriptionLevel level,
addr_t base_addr,
addr_t address,
ABI *abi)
{
lldb::offset_t offset = 0;
lldb::offset_t length = 0;
if (GetLocation (base_addr, address, offset, length))
{
if (length > 0)
{
DumpLocation(s, offset, length, level, abi);
return true;
}
}
return false;
}
bool
DWARFExpression::Evaluate
(
ExecutionContextScope *exe_scope,
ClangExpressionVariableList *expr_locals,
ClangExpressionDeclMap *decl_map,
lldb::addr_t loclist_base_load_addr,
const Value* initial_value_ptr,
Value& result,
Error *error_ptr
) const
{
ExecutionContext exe_ctx (exe_scope);
return Evaluate(&exe_ctx, expr_locals, decl_map, NULL, loclist_base_load_addr, initial_value_ptr, result, error_ptr);
}
bool
DWARFExpression::Evaluate
(
ExecutionContext *exe_ctx,
ClangExpressionVariableList *expr_locals,
ClangExpressionDeclMap *decl_map,
RegisterContext *reg_ctx,
lldb::addr_t loclist_base_load_addr,
const Value* initial_value_ptr,
Value& result,
Error *error_ptr
) const
{
ModuleSP module_sp = m_module_wp.lock();
if (IsLocationList())
{
lldb::offset_t offset = 0;
addr_t pc;
StackFrame *frame = NULL;
if (reg_ctx)
pc = reg_ctx->GetPC();
else
{
frame = exe_ctx->GetFramePtr();
if (!frame)
return false;
RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
if (!reg_ctx_sp)
return false;
pc = reg_ctx_sp->GetPC();
}
if (loclist_base_load_addr != LLDB_INVALID_ADDRESS)
{
if (pc == LLDB_INVALID_ADDRESS)
{
if (error_ptr)
error_ptr->SetErrorString("Invalid PC in frame.");
return false;
}
addr_t curr_loclist_base_load_addr = loclist_base_load_addr;
while (m_data.ValidOffset(offset))
{
addr_t lo_pc = m_data.GetAddress(&offset);
addr_t hi_pc = m_data.GetAddress(&offset);
if (lo_pc == 0 && hi_pc == 0)
{
break;
}
else
{
lo_pc += curr_loclist_base_load_addr - m_loclist_slide;
hi_pc += curr_loclist_base_load_addr - m_loclist_slide;
uint16_t length = m_data.GetU16(&offset);
if (length > 0 && lo_pc <= pc && pc < hi_pc)
{
return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, module_sp, m_data, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr);
}
offset += length;
}
}
}
if (error_ptr)
error_ptr->SetErrorString ("variable not available");
return false;
}
return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, module_sp, m_data, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr);
}
bool
DWARFExpression::Evaluate
(
ExecutionContext *exe_ctx,
ClangExpressionVariableList *expr_locals,
ClangExpressionDeclMap *decl_map,
RegisterContext *reg_ctx,
lldb::ModuleSP opcode_ctx,
const DataExtractor& opcodes,
const lldb::offset_t opcodes_offset,
const lldb::offset_t opcodes_length,
const uint32_t reg_kind,
const Value* initial_value_ptr,
Value& result,
Error *error_ptr
)
{
if (opcodes_length == 0)
{
if (error_ptr)
error_ptr->SetErrorString ("no location, value may have been optimized out");
return false;
}
std::vector<Value> stack;
Process *process = NULL;
StackFrame *frame = NULL;
if (exe_ctx)
{
process = exe_ctx->GetProcessPtr();
frame = exe_ctx->GetFramePtr();
}
if (reg_ctx == NULL && frame)
reg_ctx = frame->GetRegisterContext().get();
if (initial_value_ptr)
stack.push_back(*initial_value_ptr);
lldb::offset_t offset = opcodes_offset;
const lldb::offset_t end_offset = opcodes_offset + opcodes_length;
Value tmp;
uint32_t reg_num;
if (!opcodes.ValidOffsetForDataOfSize(opcodes_offset, opcodes_length))
{
if (error_ptr)
error_ptr->SetErrorString ("invalid offset and/or length for opcodes buffer.");
return false;
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
while (opcodes.ValidOffset(offset) && offset < end_offset)
{
const lldb::offset_t op_offset = offset;
const uint8_t op = opcodes.GetU8(&offset);
if (log && log->GetVerbose())
{
size_t count = stack.size();
log->Printf("Stack before operation has %zu values:", count);
for (size_t i=0; i<count; ++i)
{
StreamString new_value;
new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
stack[i].Dump(&new_value);
log->Printf(" %s", new_value.GetData());
}
log->Printf("0x%8.8" PRIx64 ": %s", op_offset, DW_OP_value_to_name(op));
}
switch (op)
{
case DW_OP_addr:
stack.push_back(Scalar(opcodes.GetAddress(&offset)));
stack.back().SetValueType (Value::eValueTypeFileAddress);
break;
case DW_OP_deref:
{
Value::ValueType value_type = stack.back().GetValueType();
switch (value_type)
{
case Value::eValueTypeHostAddress:
{
void *src = (void *)stack.back().GetScalar().ULongLong();
intptr_t ptr;
::memcpy (&ptr, src, sizeof(void *));
stack.back().GetScalar() = ptr;
stack.back().ClearContext();
}
break;
case Value::eValueTypeLoadAddress:
if (exe_ctx)
{
if (process)
{
lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
uint8_t addr_bytes[sizeof(lldb::addr_t)];
uint32_t addr_size = process->GetAddressByteSize();
Error error;
if (process->ReadMemory(pointer_addr, &addr_bytes, addr_size, error) == addr_size)
{
DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), addr_size);
lldb::offset_t addr_data_offset = 0;
stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset);
stack.back().ClearContext();
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("Failed to dereference pointer from 0x%" PRIx64 " for DW_OP_deref: %s\n",
pointer_addr,
error.AsCString());
return false;
}
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("NULL process for DW_OP_deref.\n");
return false;
}
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_deref.\n");
return false;
}
break;
default:
break;
}
}
break;
case DW_OP_deref_size:
{
uint8_t size = opcodes.GetU8(&offset);
Value::ValueType value_type = stack.back().GetValueType();
switch (value_type)
{
case Value::eValueTypeHostAddress:
{
void *src = (void *)stack.back().GetScalar().ULongLong();
intptr_t ptr;
::memcpy (&ptr, src, sizeof(void *));
switch (size)
{
case 1: ptr = ptr & 0xff; break;
case 2: ptr = ptr & 0xffff; break;
case 3: ptr = ptr & 0xffffff; break;
case 4: ptr = ptr & 0xffffffff; break;
case 5: ptr = (intptr_t) ptr & 0xffffffffffULL; break;
case 6: ptr = (intptr_t) ptr & 0xffffffffffffULL; break;
case 7: ptr = (intptr_t) ptr & 0xffffffffffffffULL; break;
default: break;
}
stack.back().GetScalar() = ptr;
stack.back().ClearContext();
}
break;
case Value::eValueTypeLoadAddress:
if (exe_ctx)
{
if (process)
{
lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
uint8_t addr_bytes[sizeof(lldb::addr_t)];
Error error;
if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) == size)
{
DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), size);
lldb::offset_t addr_data_offset = 0;
switch (size)
{
case 1: stack.back().GetScalar() = addr_data.GetU8(&addr_data_offset); break;
case 2: stack.back().GetScalar() = addr_data.GetU16(&addr_data_offset); break;
case 4: stack.back().GetScalar() = addr_data.GetU32(&addr_data_offset); break;
case 8: stack.back().GetScalar() = addr_data.GetU64(&addr_data_offset); break;
default: stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset);
}
stack.back().ClearContext();
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("Failed to dereference pointer from 0x%" PRIx64 " for DW_OP_deref: %s\n",
pointer_addr,
error.AsCString());
return false;
}
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("NULL process for DW_OP_deref.\n");
return false;
}
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_deref.\n");
return false;
}
break;
default:
break;
}
}
break;
case DW_OP_xderef_size:
if (error_ptr)
error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size.");
return false;
case DW_OP_xderef:
if (error_ptr)
error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef.");
return false;
case DW_OP_const1u : stack.push_back(Scalar(( uint8_t)opcodes.GetU8 (&offset))); break;
case DW_OP_const1s : stack.push_back(Scalar(( int8_t)opcodes.GetU8 (&offset))); break;
case DW_OP_const2u : stack.push_back(Scalar((uint16_t)opcodes.GetU16 (&offset))); break;
case DW_OP_const2s : stack.push_back(Scalar(( int16_t)opcodes.GetU16 (&offset))); break;
case DW_OP_const4u : stack.push_back(Scalar((uint32_t)opcodes.GetU32 (&offset))); break;
case DW_OP_const4s : stack.push_back(Scalar(( int32_t)opcodes.GetU32 (&offset))); break;
case DW_OP_const8u : stack.push_back(Scalar((uint64_t)opcodes.GetU64 (&offset))); break;
case DW_OP_const8s : stack.push_back(Scalar(( int64_t)opcodes.GetU64 (&offset))); break;
case DW_OP_constu : stack.push_back(Scalar(opcodes.GetULEB128 (&offset))); break;
case DW_OP_consts : stack.push_back(Scalar(opcodes.GetSLEB128 (&offset))); break;
case DW_OP_dup:
if (stack.empty())
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack empty for DW_OP_dup.");
return false;
}
else
stack.push_back(stack.back());
break;
case DW_OP_drop:
if (stack.empty())
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack empty for DW_OP_drop.");
return false;
}
else
stack.pop_back();
break;
case DW_OP_over:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_over.");
return false;
}
else
stack.push_back(stack[stack.size() - 2]);
break;
case DW_OP_pick:
{
uint8_t pick_idx = opcodes.GetU8(&offset);
if (pick_idx < stack.size())
stack.push_back(stack[pick_idx]);
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("Index %u out of range for DW_OP_pick.\n", pick_idx);
return false;
}
}
break;
case DW_OP_swap:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_swap.");
return false;
}
else
{
tmp = stack.back();
stack.back() = stack[stack.size() - 2];
stack[stack.size() - 2] = tmp;
}
break;
case DW_OP_rot:
if (stack.size() < 3)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 3 items for DW_OP_rot.");
return false;
}
else
{
size_t last_idx = stack.size() - 1;
Value old_top = stack[last_idx];
stack[last_idx] = stack[last_idx - 1];
stack[last_idx - 1] = stack[last_idx - 2];
stack[last_idx - 2] = old_top;
}
break;
case DW_OP_abs:
if (stack.empty())
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_abs.");
return false;
}
else if (stack.back().ResolveValue(exe_ctx).AbsoluteValue() == false)
{
if (error_ptr)
error_ptr->SetErrorString("Failed to take the absolute value of the first stack item.");
return false;
}
break;
case DW_OP_and:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_and.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) & tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_div:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_div.");
return false;
}
else
{
tmp = stack.back();
if (tmp.ResolveValue(exe_ctx).IsZero())
{
if (error_ptr)
error_ptr->SetErrorString("Divide by zero.");
return false;
}
else
{
stack.pop_back();
stack.back() = stack.back().ResolveValue(exe_ctx) / tmp.ResolveValue(exe_ctx);
if (!stack.back().ResolveValue(exe_ctx).IsValid())
{
if (error_ptr)
error_ptr->SetErrorString("Divide failed.");
return false;
}
}
}
break;
case DW_OP_minus:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_minus.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) - tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_mod:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mod.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) % tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_mul:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mul.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) * tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_neg:
if (stack.empty())
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_neg.");
return false;
}
else
{
if (stack.back().ResolveValue(exe_ctx).UnaryNegate() == false)
{
if (error_ptr)
error_ptr->SetErrorString("Unary negate failed.");
return false;
}
}
break;
case DW_OP_not:
if (stack.empty())
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_not.");
return false;
}
else
{
if (stack.back().ResolveValue(exe_ctx).OnesComplement() == false)
{
if (error_ptr)
error_ptr->SetErrorString("Logical NOT failed.");
return false;
}
}
break;
case DW_OP_or:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_or.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) | tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_plus:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_plus.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) + tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_plus_uconst:
if (stack.empty())
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_plus_uconst.");
return false;
}
else
{
const uint64_t uconst_value = opcodes.GetULEB128(&offset);
stack.back().ResolveValue(exe_ctx) += uconst_value;
if (!stack.back().ResolveValue(exe_ctx).IsValid())
{
if (error_ptr)
error_ptr->SetErrorString("DW_OP_plus_uconst failed.");
return false;
}
}
break;
case DW_OP_shl:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shl.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) <<= tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_shr:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shr.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
if (stack.back().ResolveValue(exe_ctx).ShiftRightLogical(tmp.ResolveValue(exe_ctx)) == false)
{
if (error_ptr)
error_ptr->SetErrorString("DW_OP_shr failed.");
return false;
}
}
break;
case DW_OP_shra:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shra.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) >>= tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_xor:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_xor.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) ^ tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_skip:
{
int16_t skip_offset = (int16_t)opcodes.GetU16(&offset);
lldb::offset_t new_offset = offset + skip_offset;
if (new_offset >= opcodes_offset && new_offset < end_offset)
offset = new_offset;
else
{
if (error_ptr)
error_ptr->SetErrorString("Invalid opcode offset in DW_OP_skip.");
return false;
}
}
break;
case DW_OP_bra:
{
tmp = stack.back();
stack.pop_back();
int16_t bra_offset = (int16_t)opcodes.GetU16(&offset);
Scalar zero(0);
if (tmp.ResolveValue(exe_ctx) != zero)
{
lldb::offset_t new_offset = offset + bra_offset;
if (new_offset >= opcodes_offset && new_offset < end_offset)
offset = new_offset;
else
{
if (error_ptr)
error_ptr->SetErrorString("Invalid opcode offset in DW_OP_bra.");
return false;
}
}
}
break;
case DW_OP_eq:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_eq.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) == tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_ge:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ge.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) >= tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_gt:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_gt.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) > tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_le:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_le.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) <= tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_lt:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_lt.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) < tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_ne:
if (stack.size() < 2)
{
if (error_ptr)
error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ne.");
return false;
}
else
{
tmp = stack.back();
stack.pop_back();
stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) != tmp.ResolveValue(exe_ctx);
}
break;
case DW_OP_lit0:
case DW_OP_lit1:
case DW_OP_lit2:
case DW_OP_lit3:
case DW_OP_lit4:
case DW_OP_lit5:
case DW_OP_lit6:
case DW_OP_lit7:
case DW_OP_lit8:
case DW_OP_lit9:
case DW_OP_lit10:
case DW_OP_lit11:
case DW_OP_lit12:
case DW_OP_lit13:
case DW_OP_lit14:
case DW_OP_lit15:
case DW_OP_lit16:
case DW_OP_lit17:
case DW_OP_lit18:
case DW_OP_lit19:
case DW_OP_lit20:
case DW_OP_lit21:
case DW_OP_lit22:
case DW_OP_lit23:
case DW_OP_lit24:
case DW_OP_lit25:
case DW_OP_lit26:
case DW_OP_lit27:
case DW_OP_lit28:
case DW_OP_lit29:
case DW_OP_lit30:
case DW_OP_lit31:
stack.push_back(Scalar(op - DW_OP_lit0));
break;
case DW_OP_reg0:
case DW_OP_reg1:
case DW_OP_reg2:
case DW_OP_reg3:
case DW_OP_reg4:
case DW_OP_reg5:
case DW_OP_reg6:
case DW_OP_reg7:
case DW_OP_reg8:
case DW_OP_reg9:
case DW_OP_reg10:
case DW_OP_reg11:
case DW_OP_reg12:
case DW_OP_reg13:
case DW_OP_reg14:
case DW_OP_reg15:
case DW_OP_reg16:
case DW_OP_reg17:
case DW_OP_reg18:
case DW_OP_reg19:
case DW_OP_reg20:
case DW_OP_reg21:
case DW_OP_reg22:
case DW_OP_reg23:
case DW_OP_reg24:
case DW_OP_reg25:
case DW_OP_reg26:
case DW_OP_reg27:
case DW_OP_reg28:
case DW_OP_reg29:
case DW_OP_reg30:
case DW_OP_reg31:
{
reg_num = op - DW_OP_reg0;
if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
stack.push_back(tmp);
else
return false;
}
break;
case DW_OP_regx:
{
reg_num = opcodes.GetULEB128(&offset);
if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
stack.push_back(tmp);
else
return false;
}
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
{
reg_num = op - DW_OP_breg0;
if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
{
int64_t breg_offset = opcodes.GetSLEB128(&offset);
tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
tmp.ClearContext();
stack.push_back(tmp);
stack.back().SetValueType (Value::eValueTypeLoadAddress);
}
else
return false;
}
break;
case DW_OP_bregx:
{
reg_num = opcodes.GetULEB128(&offset);
if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
{
int64_t breg_offset = opcodes.GetSLEB128(&offset);
tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
tmp.ClearContext();
stack.push_back(tmp);
stack.back().SetValueType (Value::eValueTypeLoadAddress);
}
else
return false;
}
break;
case DW_OP_fbreg:
if (exe_ctx)
{
if (frame)
{
Scalar value;
if (frame->GetFrameBaseValue(value, error_ptr))
{
int64_t fbreg_offset = opcodes.GetSLEB128(&offset);
value += fbreg_offset;
stack.push_back(value);
stack.back().SetValueType (Value::eValueTypeLoadAddress);
}
else
return false;
}
else
{
if (error_ptr)
error_ptr->SetErrorString ("Invalid stack frame in context for DW_OP_fbreg opcode.");
return false;
}
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_fbreg.\n");
return false;
}
break;
case DW_OP_nop:
break;
case DW_OP_piece:
if (error_ptr)
error_ptr->SetErrorString ("Unimplemented opcode DW_OP_piece.");
return false;
case DW_OP_push_object_address:
if (error_ptr)
error_ptr->SetErrorString ("Unimplemented opcode DW_OP_push_object_address.");
return false;
case DW_OP_call2:
if (error_ptr)
error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call2.");
return false;
case DW_OP_call4:
if (error_ptr)
error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call4.");
return false;
case DW_OP_stack_value:
stack.back().SetValueType(Value::eValueTypeScalar);
break;
case DW_OP_call_frame_cfa:
if (frame)
{
StackID id = frame->GetStackID();
addr_t cfa = id.GetCallFrameAddress();
if (cfa != LLDB_INVALID_ADDRESS)
{
stack.push_back(Scalar(cfa));
stack.back().SetValueType (Value::eValueTypeHostAddress);
}
else
if (error_ptr)
error_ptr->SetErrorString ("Stack frame does not include a canonical frame address for DW_OP_call_frame_cfa opcode.");
}
else
{
if (error_ptr)
error_ptr->SetErrorString ("Invalid stack frame in context for DW_OP_call_frame_cfa opcode.");
return false;
}
break;
case DW_OP_GNU_push_tls_address:
{
if (stack.size() < 1)
{
if (error_ptr)
error_ptr->SetErrorString("DW_OP_GNU_push_tls_address needs an argument.");
return false;
}
if (!exe_ctx || !opcode_ctx)
{
if (error_ptr)
error_ptr->SetErrorString("No context to evaluate TLS within.");
return false;
}
Thread *thread = exe_ctx->GetThreadPtr();
if (!thread)
{
if (error_ptr)
error_ptr->SetErrorString("No thread to evaluate TLS within.");
return false;
}
addr_t tls_addr = thread->GetThreadLocalData (opcode_ctx);
if (tls_addr == LLDB_INVALID_ADDRESS)
{
if (error_ptr)
error_ptr->SetErrorString ("No TLS data currently exists for this thread.");
return false;
}
Scalar tmp = stack.back().ResolveValue(exe_ctx);
stack.back() = tmp + tls_addr;
stack.back().SetValueType (Value::eValueTypeLoadAddress);
}
break;
default:
if (log)
log->Printf("Unhandled opcode %s in DWARFExpression.", DW_OP_value_to_name(op));
break;
}
}
if (stack.empty())
{
if (error_ptr)
error_ptr->SetErrorString ("Stack empty after evaluation.");
return false;
}
else if (log && log->GetVerbose())
{
size_t count = stack.size();
log->Printf("Stack after operation has %zu values:", count);
for (size_t i=0; i<count; ++i)
{
StreamString new_value;
new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
stack[i].Dump(&new_value);
log->Printf(" %s", new_value.GetData());
}
}
result = stack.back();
return true; }