Page MenuHomePhabricator

No OneTemporary

File Metadata

Created
Thu, May 28, 10:06 PM
This file is larger than 256 KB, so syntax highlighting was skipped.
Index: lldb/trunk/lit/SymbolFile/PDB/variables-locations.test
===================================================================
--- lldb/trunk/lit/SymbolFile/PDB/variables-locations.test (revision 352844)
+++ lldb/trunk/lit/SymbolFile/PDB/variables-locations.test (revision 352845)
@@ -1,14 +1,20 @@
REQUIRES: system-windows, lld
RUN: %build --compiler=clang-cl --output=%t.exe %S/Inputs/VariablesLocationsTest.cpp
+RUN: env LLDB_USE_NATIVE_PDB_READER=0 %lldb -b -s %S/Inputs/VariablesLocationsTest.script -- %t.exe | FileCheck %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -b -s %S/Inputs/VariablesLocationsTest.script -- %t.exe | FileCheck %s
CHECK: g_var = 2222
CHECK: arg_0 = 1111
CHECK: arg_1 = 0.123
CHECK: loc_0 = 'x'
CHECK: loc_1 = 0.567
CHECK: loc_0 = true
CHECK: loc_1 = 3333
+
+CHECK: arg_0 = 22
+
+CHECK: loc_0 = (a = 1234)
+CHECK: loc_1 = 5678
Index: lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.cpp
===================================================================
--- lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.cpp (revision 352844)
+++ lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.cpp (revision 352845)
@@ -1,15 +1,26 @@
int g_var = 2222;
void __fastcall foo(short arg_0, float arg_1) {
char loc_0 = 'x';
double loc_1 = 0.5678;
}
+__declspec(align(128)) struct S {
+ int a = 1234;
+};
+
+void bar(int arg_0) {
+ S loc_0;
+ int loc_1 = 5678;
+}
+
+
int main(int argc, char *argv[]) {
bool loc_0 = true;
int loc_1 = 3333;
foo(1111, 0.1234);
+ bar(22);
return 0;
}
Index: lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.script
===================================================================
--- lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.script (revision 352844)
+++ lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.script (revision 352845)
@@ -1,16 +1,25 @@
breakpoint set --file VariablesLocationsTest.cpp --line 6
+breakpoint set --file VariablesLocationsTest.cpp --line 15
run
target variable g_var
frame variable arg_0
frame variable arg_1
frame variable loc_0
frame variable loc_1
frame select 1
frame variable loc_0
frame variable loc_1
+
+continue
+
+frame variable arg_0
+
+frame variable loc_0
+frame variable loc_1
+
Index: lldb/trunk/source/Expression/DWARFExpression.cpp
===================================================================
--- lldb/trunk/source/Expression/DWARFExpression.cpp (revision 352844)
+++ lldb/trunk/source/Expression/DWARFExpression.cpp (revision 352845)
@@ -1,3416 +1,3416 @@
//===-- DWARFExpression.cpp -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Expression/DWARFExpression.h"
#include <inttypes.h>
#include <vector>
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Utility/DataEncoder.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/VMRange.h"
#include "lldb/Host/Host.h"
#include "lldb/Utility/Endian.h"
#include "lldb/Symbol/Function.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"
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
using namespace lldb;
using namespace lldb_private;
static lldb::addr_t
ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu,
uint32_t index) {
uint32_t index_size = dwarf_cu->GetAddressByteSize();
dw_offset_t addr_base = dwarf_cu->GetAddrBase();
lldb::offset_t offset = addr_base + index * index_size;
return dwarf_cu->GetSymbolFileDWARF()->get_debug_addr_data().GetMaxU64(
&offset, index_size);
}
//----------------------------------------------------------------------
// DWARFExpression constructor
//----------------------------------------------------------------------
DWARFExpression::DWARFExpression(DWARFUnit *dwarf_cu)
: m_module_wp(), m_data(), m_dwarf_cu(dwarf_cu),
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_dwarf_cu(rhs.m_dwarf_cu), m_reg_kind(rhs.m_reg_kind),
m_loclist_slide(rhs.m_loclist_slide) {}
DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp,
const DataExtractor &data,
DWARFUnit *dwarf_cu,
lldb::offset_t data_offset,
lldb::offset_t data_length)
: m_module_wp(), m_data(data, data_offset, data_length),
m_dwarf_cu(dwarf_cu), m_reg_kind(eRegisterKindDWARF),
m_loclist_slide(LLDB_INVALID_ADDRESS) {
if (module_sp)
m_module_wp = module_sp;
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
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::CopyOpcodeData(const void *data,
lldb::offset_t data_length,
ByteOrder byte_order,
uint8_t addr_byte_size) {
if (data && data_length) {
m_data.SetData(DataBufferSP(new DataBufferHeap(data, data_length)));
m_data.SetByteOrder(byte_order);
m_data.SetAddressByteSize(addr_byte_size);
}
}
void DWARFExpression::CopyOpcodeData(uint64_t const_value,
lldb::offset_t const_value_byte_size,
uint8_t addr_byte_size) {
if (const_value_byte_size) {
m_data.SetData(
DataBufferSP(new DataBufferHeap(&const_value, const_value_byte_size)));
m_data.SetByteOrder(endian::InlHostByteOrder());
m_data.SetAddressByteSize(addr_byte_size);
}
}
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 (op_offset > start_offset)
s->PutChar(' ');
break;
case lldb::eDescriptionLevelFull:
case lldb::eDescriptionLevelVerbose:
if (op_offset > start_offset)
s->EOL();
s->Indent();
if (level == lldb::eDescriptionLevelFull)
break;
// Fall through for verbose and print offset and DW_OP prefix..
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; // 0x03 1 address
case DW_OP_deref:
*s << "DW_OP_deref";
break; // 0x06
case DW_OP_const1u:
s->Printf("DW_OP_const1u(0x%2.2x)", m_data.GetU8(&offset));
break; // 0x08 1 1-byte constant
case DW_OP_const1s:
s->Printf("DW_OP_const1s(0x%2.2x)", m_data.GetU8(&offset));
break; // 0x09 1 1-byte constant
case DW_OP_const2u:
s->Printf("DW_OP_const2u(0x%4.4x)", m_data.GetU16(&offset));
break; // 0x0a 1 2-byte constant
case DW_OP_const2s:
s->Printf("DW_OP_const2s(0x%4.4x)", m_data.GetU16(&offset));
break; // 0x0b 1 2-byte constant
case DW_OP_const4u:
s->Printf("DW_OP_const4u(0x%8.8x)", m_data.GetU32(&offset));
break; // 0x0c 1 4-byte constant
case DW_OP_const4s:
s->Printf("DW_OP_const4s(0x%8.8x)", m_data.GetU32(&offset));
break; // 0x0d 1 4-byte constant
case DW_OP_const8u:
s->Printf("DW_OP_const8u(0x%16.16" PRIx64 ")", m_data.GetU64(&offset));
break; // 0x0e 1 8-byte constant
case DW_OP_const8s:
s->Printf("DW_OP_const8s(0x%16.16" PRIx64 ")", m_data.GetU64(&offset));
break; // 0x0f 1 8-byte constant
case DW_OP_constu:
s->Printf("DW_OP_constu(0x%" PRIx64 ")", m_data.GetULEB128(&offset));
break; // 0x10 1 ULEB128 constant
case DW_OP_consts:
s->Printf("DW_OP_consts(0x%" PRId64 ")", m_data.GetSLEB128(&offset));
break; // 0x11 1 SLEB128 constant
case DW_OP_dup:
s->PutCString("DW_OP_dup");
break; // 0x12
case DW_OP_drop:
s->PutCString("DW_OP_drop");
break; // 0x13
case DW_OP_over:
s->PutCString("DW_OP_over");
break; // 0x14
case DW_OP_pick:
s->Printf("DW_OP_pick(0x%2.2x)", m_data.GetU8(&offset));
break; // 0x15 1 1-byte stack index
case DW_OP_swap:
s->PutCString("DW_OP_swap");
break; // 0x16
case DW_OP_rot:
s->PutCString("DW_OP_rot");
break; // 0x17
case DW_OP_xderef:
s->PutCString("DW_OP_xderef");
break; // 0x18
case DW_OP_abs:
s->PutCString("DW_OP_abs");
break; // 0x19
case DW_OP_and:
s->PutCString("DW_OP_and");
break; // 0x1a
case DW_OP_div:
s->PutCString("DW_OP_div");
break; // 0x1b
case DW_OP_minus:
s->PutCString("DW_OP_minus");
break; // 0x1c
case DW_OP_mod:
s->PutCString("DW_OP_mod");
break; // 0x1d
case DW_OP_mul:
s->PutCString("DW_OP_mul");
break; // 0x1e
case DW_OP_neg:
s->PutCString("DW_OP_neg");
break; // 0x1f
case DW_OP_not:
s->PutCString("DW_OP_not");
break; // 0x20
case DW_OP_or:
s->PutCString("DW_OP_or");
break; // 0x21
case DW_OP_plus:
s->PutCString("DW_OP_plus");
break; // 0x22
case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
s->Printf("DW_OP_plus_uconst(0x%" PRIx64 ")",
m_data.GetULEB128(&offset));
break;
case DW_OP_shl:
s->PutCString("DW_OP_shl");
break; // 0x24
case DW_OP_shr:
s->PutCString("DW_OP_shr");
break; // 0x25
case DW_OP_shra:
s->PutCString("DW_OP_shra");
break; // 0x26
case DW_OP_xor:
s->PutCString("DW_OP_xor");
break; // 0x27
case DW_OP_skip:
s->Printf("DW_OP_skip(0x%4.4x)", m_data.GetU16(&offset));
break; // 0x2f 1 signed 2-byte constant
case DW_OP_bra:
s->Printf("DW_OP_bra(0x%4.4x)", m_data.GetU16(&offset));
break; // 0x28 1 signed 2-byte constant
case DW_OP_eq:
s->PutCString("DW_OP_eq");
break; // 0x29
case DW_OP_ge:
s->PutCString("DW_OP_ge");
break; // 0x2a
case DW_OP_gt:
s->PutCString("DW_OP_gt");
break; // 0x2b
case DW_OP_le:
s->PutCString("DW_OP_le");
break; // 0x2c
case DW_OP_lt:
s->PutCString("DW_OP_lt");
break; // 0x2d
case DW_OP_ne:
s->PutCString("DW_OP_ne");
break; // 0x2e
case DW_OP_lit0: // 0x30
case DW_OP_lit1: // 0x31
case DW_OP_lit2: // 0x32
case DW_OP_lit3: // 0x33
case DW_OP_lit4: // 0x34
case DW_OP_lit5: // 0x35
case DW_OP_lit6: // 0x36
case DW_OP_lit7: // 0x37
case DW_OP_lit8: // 0x38
case DW_OP_lit9: // 0x39
case DW_OP_lit10: // 0x3A
case DW_OP_lit11: // 0x3B
case DW_OP_lit12: // 0x3C
case DW_OP_lit13: // 0x3D
case DW_OP_lit14: // 0x3E
case DW_OP_lit15: // 0x3F
case DW_OP_lit16: // 0x40
case DW_OP_lit17: // 0x41
case DW_OP_lit18: // 0x42
case DW_OP_lit19: // 0x43
case DW_OP_lit20: // 0x44
case DW_OP_lit21: // 0x45
case DW_OP_lit22: // 0x46
case DW_OP_lit23: // 0x47
case DW_OP_lit24: // 0x48
case DW_OP_lit25: // 0x49
case DW_OP_lit26: // 0x4A
case DW_OP_lit27: // 0x4B
case DW_OP_lit28: // 0x4C
case DW_OP_lit29: // 0x4D
case DW_OP_lit30: // 0x4E
case DW_OP_lit31:
s->Printf("DW_OP_lit%i", op - DW_OP_lit0);
break; // 0x4f
case DW_OP_reg0: // 0x50
case DW_OP_reg1: // 0x51
case DW_OP_reg2: // 0x52
case DW_OP_reg3: // 0x53
case DW_OP_reg4: // 0x54
case DW_OP_reg5: // 0x55
case DW_OP_reg6: // 0x56
case DW_OP_reg7: // 0x57
case DW_OP_reg8: // 0x58
case DW_OP_reg9: // 0x59
case DW_OP_reg10: // 0x5A
case DW_OP_reg11: // 0x5B
case DW_OP_reg12: // 0x5C
case DW_OP_reg13: // 0x5D
case DW_OP_reg14: // 0x5E
case DW_OP_reg15: // 0x5F
case DW_OP_reg16: // 0x60
case DW_OP_reg17: // 0x61
case DW_OP_reg18: // 0x62
case DW_OP_reg19: // 0x63
case DW_OP_reg20: // 0x64
case DW_OP_reg21: // 0x65
case DW_OP_reg22: // 0x66
case DW_OP_reg23: // 0x67
case DW_OP_reg24: // 0x68
case DW_OP_reg25: // 0x69
case DW_OP_reg26: // 0x6A
case DW_OP_reg27: // 0x6B
case DW_OP_reg28: // 0x6C
case DW_OP_reg29: // 0x6D
case DW_OP_reg30: // 0x6E
case DW_OP_reg31: // 0x6F
{
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: // 0x90 1 ULEB128 register
{
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: // 0x91 1 SLEB128 offset
s->Printf("DW_OP_fbreg(%" PRIi64 ")", m_data.GetSLEB128(&offset));
break;
case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
{
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: // 0x93 1 ULEB128 size of piece addressed
s->Printf("DW_OP_piece(0x%" PRIx64 ")", m_data.GetULEB128(&offset));
break;
case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
s->Printf("DW_OP_deref_size(0x%2.2x)", m_data.GetU8(&offset));
break;
case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
s->Printf("DW_OP_xderef_size(0x%2.2x)", m_data.GetU8(&offset));
break;
case DW_OP_nop:
s->PutCString("DW_OP_nop");
break; // 0x96
case DW_OP_push_object_address:
s->PutCString("DW_OP_push_object_address");
break; // 0x97 DWARF3
case DW_OP_call2: // 0x98 DWARF3 1 2-byte offset of DIE
s->Printf("DW_OP_call2(0x%4.4x)", m_data.GetU16(&offset));
break;
case DW_OP_call4: // 0x99 DWARF3 1 4-byte offset of DIE
s->Printf("DW_OP_call4(0x%8.8x)", m_data.GetU32(&offset));
break;
case DW_OP_call_ref: // 0x9a DWARF3 1 4- or 8-byte offset of DIE
s->Printf("DW_OP_call_ref(0x%8.8" PRIx64 ")", m_data.GetAddress(&offset));
break;
// case DW_OP_call_frame_cfa: s << "call_frame_cfa"; break;
// // 0x9c DWARF3
// case DW_OP_bit_piece: // 0x9d DWARF3 2
// s->Printf("DW_OP_bit_piece(0x%x, 0x%x)",
// m_data.GetULEB128(&offset), m_data.GetULEB128(&offset));
// break;
// case DW_OP_lo_user: s->PutCString("DW_OP_lo_user"); break;
// // 0xe0
// case DW_OP_hi_user: s->PutCString("DW_OP_hi_user"); break;
// // 0xff
// case DW_OP_APPLE_extern:
// s->Printf("DW_OP_APPLE_extern(%" PRIu64 ")",
// m_data.GetULEB128(&offset));
// break;
// case DW_OP_APPLE_array_ref:
// s->PutCString("DW_OP_APPLE_array_ref");
// break;
case DW_OP_form_tls_address:
s->PutCString("DW_OP_form_tls_address"); // 0x9b
break;
case DW_OP_GNU_addr_index: // 0xfb
s->Printf("DW_OP_GNU_addr_index(0x%" PRIx64 ")",
m_data.GetULEB128(&offset));
break;
case DW_OP_GNU_const_index: // 0xfc
s->Printf("DW_OP_GNU_const_index(0x%" PRIx64 ")",
m_data.GetULEB128(&offset));
break;
case DW_OP_GNU_push_tls_address:
s->PutCString("DW_OP_GNU_push_tls_address"); // 0xe0
break;
case DW_OP_APPLE_uninit:
s->PutCString("DW_OP_APPLE_uninit"); // 0xF0
break;
// case DW_OP_APPLE_assign: // 0xF1 - pops value off and
// assigns it to second item on stack (2nd item must have
// assignable context)
// s->PutCString("DW_OP_APPLE_assign");
// break;
// case DW_OP_APPLE_address_of: // 0xF2 - gets the address of
// the top stack item (top item must be a variable, or have
// value_type that is an address already)
// s->PutCString("DW_OP_APPLE_address_of");
// break;
// case DW_OP_APPLE_value_of: // 0xF3 - pops the value off the
// stack and pushes the value of that object (top item must be a
// variable, or expression local)
// s->PutCString("DW_OP_APPLE_value_of");
// break;
// case DW_OP_APPLE_deref_type: // 0xF4 - gets the address of
// the top stack item (top item must be a variable, or a clang
// type)
// s->PutCString("DW_OP_APPLE_deref_type");
// break;
// case DW_OP_APPLE_expr_local: // 0xF5 - ULEB128 expression
// local index
// s->Printf("DW_OP_APPLE_expr_local(%" PRIu64 ")",
// m_data.GetULEB128(&offset));
// break;
// case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size,
// followed by constant float data
// {
// uint8_t float_length = m_data.GetU8(&offset);
// s->Printf("DW_OP_APPLE_constf(<%u> ", float_length);
// m_data.Dump(s, offset, eFormatHex, float_length, 1,
// UINT32_MAX, DW_INVALID_ADDRESS, 0, 0);
// s->PutChar(')');
// // Consume the float data
// m_data.GetData(&offset, float_length);
// }
// break;
// case DW_OP_APPLE_scalar_cast:
// s->Printf("DW_OP_APPLE_scalar_cast(%s)",
// Scalar::GetValueTypeAsCString
// ((Scalar::Type)m_data.GetU8(&offset)));
// break;
// case DW_OP_APPLE_clang_cast:
// {
// clang::Type *clang_type = (clang::Type
// *)m_data.GetMaxU64(&offset, sizeof(void*));
// s->Printf("DW_OP_APPLE_clang_cast(%p)", clang_type);
// }
// break;
// case DW_OP_APPLE_clear:
// s->PutCString("DW_OP_APPLE_clear");
// break;
// case DW_OP_APPLE_error: // 0xFF - Stops expression
// evaluation and returns an error (no args)
// s->PutCString("DW_OP_APPLE_error");
// 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()) {
// We have a location list
lldb::offset_t offset = 0;
uint32_t count = 0;
addr_t curr_base_addr = location_list_base_addr;
while (m_data.ValidOffset(offset)) {
addr_t begin_addr_offset = LLDB_INVALID_ADDRESS;
addr_t end_addr_offset = LLDB_INVALID_ADDRESS;
if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset,
begin_addr_offset, end_addr_offset))
break;
if (begin_addr_offset == 0 && end_addr_offset == 0)
break;
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 ((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;
// We have a new base address
if (count > 0)
s->PutCString(", ");
*s << "base_addr = " << end_addr_offset;
}
}
count++;
}
} else {
// We have a normal location that contains DW_OP location opcodes
DumpLocation(s, 0, m_data.GetByteSize(), level, abi);
}
}
static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
lldb::RegisterKind reg_kind,
uint32_t reg_num, Status *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 we get this error, then we need to implement a value buffer in
// the dwarf expression evaluation function...
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;
}
// bool
// DWARFExpression::LocationListContainsLoadAddress (Process* process, const
// Address &addr) const
//{
// return LocationListContainsLoadAddress(process,
// addr.GetLoadAddress(process));
//}
//
// bool
// DWARFExpression::LocationListContainsLoadAddress (Process* process, addr_t
// load_addr) const
//{
// if (load_addr == LLDB_INVALID_ADDRESS)
// return false;
//
// if (IsLocationList())
// {
// lldb::offset_t offset = 0;
//
// addr_t loc_list_base_addr = m_loclist_slide.GetLoadAddress(process);
//
// if (loc_list_base_addr == LLDB_INVALID_ADDRESS)
// return false;
//
// while (m_data.ValidOffset(offset))
// {
// // We need to figure out what the value is for the location.
// 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 += loc_list_base_addr;
// hi_pc += loc_list_base_addr;
//
// if (lo_pc <= load_addr && load_addr < hi_pc)
// return true;
//
// offset += m_data.GetU16(&offset);
// }
// }
// }
// 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: // 0x9a 1 address sized offset of DIE (DWARF3)
return data.GetAddressByteSize();
// Opcodes with no arguments
case DW_OP_deref: // 0x06
case DW_OP_dup: // 0x12
case DW_OP_drop: // 0x13
case DW_OP_over: // 0x14
case DW_OP_swap: // 0x16
case DW_OP_rot: // 0x17
case DW_OP_xderef: // 0x18
case DW_OP_abs: // 0x19
case DW_OP_and: // 0x1a
case DW_OP_div: // 0x1b
case DW_OP_minus: // 0x1c
case DW_OP_mod: // 0x1d
case DW_OP_mul: // 0x1e
case DW_OP_neg: // 0x1f
case DW_OP_not: // 0x20
case DW_OP_or: // 0x21
case DW_OP_plus: // 0x22
case DW_OP_shl: // 0x24
case DW_OP_shr: // 0x25
case DW_OP_shra: // 0x26
case DW_OP_xor: // 0x27
case DW_OP_eq: // 0x29
case DW_OP_ge: // 0x2a
case DW_OP_gt: // 0x2b
case DW_OP_le: // 0x2c
case DW_OP_lt: // 0x2d
case DW_OP_ne: // 0x2e
case DW_OP_lit0: // 0x30
case DW_OP_lit1: // 0x31
case DW_OP_lit2: // 0x32
case DW_OP_lit3: // 0x33
case DW_OP_lit4: // 0x34
case DW_OP_lit5: // 0x35
case DW_OP_lit6: // 0x36
case DW_OP_lit7: // 0x37
case DW_OP_lit8: // 0x38
case DW_OP_lit9: // 0x39
case DW_OP_lit10: // 0x3A
case DW_OP_lit11: // 0x3B
case DW_OP_lit12: // 0x3C
case DW_OP_lit13: // 0x3D
case DW_OP_lit14: // 0x3E
case DW_OP_lit15: // 0x3F
case DW_OP_lit16: // 0x40
case DW_OP_lit17: // 0x41
case DW_OP_lit18: // 0x42
case DW_OP_lit19: // 0x43
case DW_OP_lit20: // 0x44
case DW_OP_lit21: // 0x45
case DW_OP_lit22: // 0x46
case DW_OP_lit23: // 0x47
case DW_OP_lit24: // 0x48
case DW_OP_lit25: // 0x49
case DW_OP_lit26: // 0x4A
case DW_OP_lit27: // 0x4B
case DW_OP_lit28: // 0x4C
case DW_OP_lit29: // 0x4D
case DW_OP_lit30: // 0x4E
case DW_OP_lit31: // 0x4f
case DW_OP_reg0: // 0x50
case DW_OP_reg1: // 0x51
case DW_OP_reg2: // 0x52
case DW_OP_reg3: // 0x53
case DW_OP_reg4: // 0x54
case DW_OP_reg5: // 0x55
case DW_OP_reg6: // 0x56
case DW_OP_reg7: // 0x57
case DW_OP_reg8: // 0x58
case DW_OP_reg9: // 0x59
case DW_OP_reg10: // 0x5A
case DW_OP_reg11: // 0x5B
case DW_OP_reg12: // 0x5C
case DW_OP_reg13: // 0x5D
case DW_OP_reg14: // 0x5E
case DW_OP_reg15: // 0x5F
case DW_OP_reg16: // 0x60
case DW_OP_reg17: // 0x61
case DW_OP_reg18: // 0x62
case DW_OP_reg19: // 0x63
case DW_OP_reg20: // 0x64
case DW_OP_reg21: // 0x65
case DW_OP_reg22: // 0x66
case DW_OP_reg23: // 0x67
case DW_OP_reg24: // 0x68
case DW_OP_reg25: // 0x69
case DW_OP_reg26: // 0x6A
case DW_OP_reg27: // 0x6B
case DW_OP_reg28: // 0x6C
case DW_OP_reg29: // 0x6D
case DW_OP_reg30: // 0x6E
case DW_OP_reg31: // 0x6F
case DW_OP_nop: // 0x96
case DW_OP_push_object_address: // 0x97 DWARF3
case DW_OP_form_tls_address: // 0x9b DWARF3
case DW_OP_call_frame_cfa: // 0x9c DWARF3
case DW_OP_stack_value: // 0x9f DWARF4
case DW_OP_GNU_push_tls_address: // 0xe0 GNU extension
return 0;
// Opcodes with a single 1 byte arguments
case DW_OP_const1u: // 0x08 1 1-byte constant
case DW_OP_const1s: // 0x09 1 1-byte constant
case DW_OP_pick: // 0x15 1 1-byte stack index
case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
return 1;
// Opcodes with a single 2 byte arguments
case DW_OP_const2u: // 0x0a 1 2-byte constant
case DW_OP_const2s: // 0x0b 1 2-byte constant
case DW_OP_skip: // 0x2f 1 signed 2-byte constant
case DW_OP_bra: // 0x28 1 signed 2-byte constant
case DW_OP_call2: // 0x98 1 2-byte offset of DIE (DWARF3)
return 2;
// Opcodes with a single 4 byte arguments
case DW_OP_const4u: // 0x0c 1 4-byte constant
case DW_OP_const4s: // 0x0d 1 4-byte constant
case DW_OP_call4: // 0x99 1 4-byte offset of DIE (DWARF3)
return 4;
// Opcodes with a single 8 byte arguments
case DW_OP_const8u: // 0x0e 1 8-byte constant
case DW_OP_const8s: // 0x0f 1 8-byte constant
return 8;
// All opcodes that have a single ULEB (signed or unsigned) argument
case DW_OP_constu: // 0x10 1 ULEB128 constant
case DW_OP_consts: // 0x11 1 SLEB128 constant
case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
case DW_OP_breg0: // 0x70 1 ULEB128 register
case DW_OP_breg1: // 0x71 1 ULEB128 register
case DW_OP_breg2: // 0x72 1 ULEB128 register
case DW_OP_breg3: // 0x73 1 ULEB128 register
case DW_OP_breg4: // 0x74 1 ULEB128 register
case DW_OP_breg5: // 0x75 1 ULEB128 register
case DW_OP_breg6: // 0x76 1 ULEB128 register
case DW_OP_breg7: // 0x77 1 ULEB128 register
case DW_OP_breg8: // 0x78 1 ULEB128 register
case DW_OP_breg9: // 0x79 1 ULEB128 register
case DW_OP_breg10: // 0x7a 1 ULEB128 register
case DW_OP_breg11: // 0x7b 1 ULEB128 register
case DW_OP_breg12: // 0x7c 1 ULEB128 register
case DW_OP_breg13: // 0x7d 1 ULEB128 register
case DW_OP_breg14: // 0x7e 1 ULEB128 register
case DW_OP_breg15: // 0x7f 1 ULEB128 register
case DW_OP_breg16: // 0x80 1 ULEB128 register
case DW_OP_breg17: // 0x81 1 ULEB128 register
case DW_OP_breg18: // 0x82 1 ULEB128 register
case DW_OP_breg19: // 0x83 1 ULEB128 register
case DW_OP_breg20: // 0x84 1 ULEB128 register
case DW_OP_breg21: // 0x85 1 ULEB128 register
case DW_OP_breg22: // 0x86 1 ULEB128 register
case DW_OP_breg23: // 0x87 1 ULEB128 register
case DW_OP_breg24: // 0x88 1 ULEB128 register
case DW_OP_breg25: // 0x89 1 ULEB128 register
case DW_OP_breg26: // 0x8a 1 ULEB128 register
case DW_OP_breg27: // 0x8b 1 ULEB128 register
case DW_OP_breg28: // 0x8c 1 ULEB128 register
case DW_OP_breg29: // 0x8d 1 ULEB128 register
case DW_OP_breg30: // 0x8e 1 ULEB128 register
case DW_OP_breg31: // 0x8f 1 ULEB128 register
case DW_OP_regx: // 0x90 1 ULEB128 register
case DW_OP_fbreg: // 0x91 1 SLEB128 offset
case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed
case DW_OP_GNU_addr_index: // 0xfb 1 ULEB128 index
case DW_OP_GNU_const_index: // 0xfc 1 ULEB128 index
data.Skip_LEB128(&offset);
return offset - data_offset;
// All opcodes that have a 2 ULEB (signed or unsigned) arguments
case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
data.Skip_LEB128(&offset);
data.Skip_LEB128(&offset);
return offset - data_offset;
case DW_OP_implicit_value: // 0x9e ULEB128 size followed by block of that size
// (DWARF4)
{
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 if (op == DW_OP_GNU_addr_index) {
uint64_t index = m_data.GetULEB128(&offset);
if (curr_op_addr_idx == op_addr_idx) {
if (!m_dwarf_cu) {
error = true;
break;
}
return ReadAddressFromDebugAddrSection(m_dwarf_cu, index);
} 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();
// We have to make a copy of the data as we don't know if this data is
// from a read only memory mapped buffer, so we duplicate all of the data
// first, then modify it, and if all goes well, we then replace the data
// for this expression
// So first we copy the data into a heap buffer
std::unique_ptr<DataBufferHeap> head_data_ap(
new DataBufferHeap(m_data.GetDataStart(), m_data.GetByteSize()));
// Make en encoder so we can write the address into the buffer using the
// correct byte order (endianness)
DataEncoder encoder(head_data_ap->GetBytes(), head_data_ap->GetByteSize(),
m_data.GetByteOrder(), addr_byte_size);
// Replace the address in the new buffer
if (encoder.PutMaxU64(offset, addr_byte_size, file_addr) == UINT32_MAX)
return false;
// All went well, so now we can reset the data using a shared pointer to
// the heap data so "m_data" will now correctly manage the heap data.
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::ContainsThreadLocalStorage() const {
// We are assuming for now that any thread local variable will not have a
// location list. This has been true for all thread local variables we have
// seen so far produced by any compiler.
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_form_tls_address || op == DW_OP_GNU_push_tls_address)
return true;
const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op);
if (op_arg_size == LLDB_INVALID_OFFSET)
return false;
else
offset += op_arg_size;
}
return false;
}
bool DWARFExpression::LinkThreadLocalStorage(
lldb::ModuleSP new_module_sp,
std::function<lldb::addr_t(lldb::addr_t file_addr)> const
&link_address_callback) {
// We are assuming for now that any thread local variable will not have a
// location list. This has been true for all thread local variables we have
// seen so far produced by any compiler.
if (IsLocationList())
return false;
const uint32_t addr_byte_size = m_data.GetAddressByteSize();
// We have to make a copy of the data as we don't know if this data is from a
// read only memory mapped buffer, so we duplicate all of the data first,
// then modify it, and if all goes well, we then replace the data for this
// expression
// So first we copy the data into a heap buffer
std::shared_ptr<DataBufferHeap> heap_data_sp(
new DataBufferHeap(m_data.GetDataStart(), m_data.GetByteSize()));
// Make en encoder so we can write the address into the buffer using the
// correct byte order (endianness)
DataEncoder encoder(heap_data_sp->GetBytes(), heap_data_sp->GetByteSize(),
m_data.GetByteOrder(), addr_byte_size);
lldb::offset_t offset = 0;
lldb::offset_t const_offset = 0;
lldb::addr_t const_value = 0;
size_t const_byte_size = 0;
while (m_data.ValidOffset(offset)) {
const uint8_t op = m_data.GetU8(&offset);
bool decoded_data = false;
switch (op) {
case DW_OP_const4u:
// Remember the const offset in case we later have a
// DW_OP_form_tls_address or DW_OP_GNU_push_tls_address
const_offset = offset;
const_value = m_data.GetU32(&offset);
decoded_data = true;
const_byte_size = 4;
break;
case DW_OP_const8u:
// Remember the const offset in case we later have a
// DW_OP_form_tls_address or DW_OP_GNU_push_tls_address
const_offset = offset;
const_value = m_data.GetU64(&offset);
decoded_data = true;
const_byte_size = 8;
break;
case DW_OP_form_tls_address:
case DW_OP_GNU_push_tls_address:
// DW_OP_form_tls_address and DW_OP_GNU_push_tls_address must be preceded
// by a file address on the stack. We assume that DW_OP_const4u or
// DW_OP_const8u is used for these values, and we check that the last
// opcode we got before either of these was DW_OP_const4u or
// DW_OP_const8u. If so, then we can link the value accodingly. For
// Darwin, the value in the DW_OP_const4u or DW_OP_const8u is the file
// address of a structure that contains a function pointer, the pthread
// key and the offset into the data pointed to by the pthread key. So we
// must link this address and also set the module of this expression to
// the new_module_sp so we can resolve the file address correctly
if (const_byte_size > 0) {
lldb::addr_t linked_file_addr = link_address_callback(const_value);
if (linked_file_addr == LLDB_INVALID_ADDRESS)
return false;
// Replace the address in the new buffer
if (encoder.PutMaxU64(const_offset, const_byte_size,
linked_file_addr) == UINT32_MAX)
return false;
}
break;
default:
const_offset = 0;
const_value = 0;
const_byte_size = 0;
break;
}
if (!decoded_data) {
const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op);
if (op_arg_size == LLDB_INVALID_OFFSET)
return false;
else
offset += op_arg_size;
}
}
// If we linked the TLS address correctly, update the module so that when the
// expression is evaluated it can resolve the file address to a load address
// and read the
// TLS data
m_module_wp = new_module_sp;
m_data.SetData(heap_data_sp);
return true;
}
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)) {
// We need to figure out what the value is for the location.
addr_t lo_pc = LLDB_INVALID_ADDRESS;
addr_t hi_pc = LLDB_INVALID_ADDRESS;
if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc,
hi_pc))
break;
if (lo_pc == 0 && hi_pc == 0)
break;
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)) {
// We need to figure out what the value is for the location.
addr_t lo_pc = LLDB_INVALID_ADDRESS;
addr_t hi_pc = LLDB_INVALID_ADDRESS;
if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc,
hi_pc))
break;
if (lo_pc == 0 && hi_pc == 0)
break;
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,
lldb::addr_t loclist_base_load_addr,
const Value *initial_value_ptr,
const Value *object_address_ptr, Value &result,
Status *error_ptr) const {
ExecutionContext exe_ctx(exe_scope);
return Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, initial_value_ptr,
object_address_ptr, result, error_ptr);
}
bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx,
RegisterContext *reg_ctx,
lldb::addr_t loclist_base_load_addr,
const Value *initial_value_ptr,
const Value *object_address_ptr, Value &result,
Status *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)) {
// We need to figure out what the value is for the location.
addr_t lo_pc = LLDB_INVALID_ADDRESS;
addr_t hi_pc = LLDB_INVALID_ADDRESS;
if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset,
lo_pc, hi_pc))
break;
if (lo_pc == 0 && hi_pc == 0)
break;
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, reg_ctx, module_sp, m_data, m_dwarf_cu, offset, length,
m_reg_kind, initial_value_ptr, object_address_ptr, result,
error_ptr);
}
offset += length;
}
}
if (error_ptr)
error_ptr->SetErrorString("variable not available");
return false;
}
// Not a location list, just a single expression.
return DWARFExpression::Evaluate(
exe_ctx, reg_ctx, module_sp, m_data, m_dwarf_cu, 0, m_data.GetByteSize(),
m_reg_kind, initial_value_ptr, object_address_ptr, result, error_ptr);
}
bool DWARFExpression::Evaluate(
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
DWARFUnit *dwarf_cu, const lldb::offset_t opcodes_offset,
const lldb::offset_t opcodes_length, const lldb::RegisterKind reg_kind,
const Value *initial_value_ptr, const Value *object_address_ptr,
Value &result, Status *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;
/// Insertion point for evaluating multi-piece expression.
uint64_t op_piece_offset = 0;
Value pieces; // Used for DW_OP_piece
// Make sure all of the data is available in opcodes.
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 %" PRIu64 " values:",
(uint64_t)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) {
//----------------------------------------------------------------------
// 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.
//----------------------------------------------------------------------
case DW_OP_addr:
stack.push_back(Scalar(opcodes.GetAddress(&offset)));
stack.back().SetValueType(Value::eValueTypeFileAddress);
// Convert the file address to a load address, so subsequent
// DWARF operators can operate on it.
if (frame)
stack.back().ConvertToLoadAddress(module_sp.get(),
frame->CalculateTarget().get());
break;
//----------------------------------------------------------------------
// The DW_OP_addr_sect_offset4 is used for any location expressions in
// shared libraries that have a location like:
// DW_OP_addr(0x1000)
// If this address resides in a shared library, then this virtual address
// won't make sense when it is evaluated in the context of a running
// process where shared libraries have been slid. To account for this, this
// new address type where we can store the section pointer and a 4 byte
// offset.
//----------------------------------------------------------------------
// case DW_OP_addr_sect_offset4:
// {
// result_type = eResultTypeFileAddress;
// lldb::Section *sect = (lldb::Section
// *)opcodes.GetMaxU64(&offset, sizeof(void *));
// lldb::addr_t sect_offset = opcodes.GetU32(&offset);
//
// Address so_addr (sect, sect_offset);
// lldb::addr_t load_addr = so_addr.GetLoadAddress();
// if (load_addr != LLDB_INVALID_ADDRESS)
// {
// // We successfully resolve a file address to a load
// // address.
// stack.push_back(load_addr);
// break;
// }
// else
// {
// // We were able
// if (error_ptr)
// error_ptr->SetErrorStringWithFormat ("Section %s in
// %s is not currently loaded.\n",
// sect->GetName().AsCString(),
// sect->GetModule()->GetFileSpec().GetFilename().AsCString());
// return false;
// }
// }
// break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_deref
// OPERANDS: none
// DESCRIPTION: Pops the top stack entry and treats it as an address.
// The value retrieved from that address is pushed. The size of the data
// retrieved from the dereferenced address is the size of an address on the
// target machine.
//----------------------------------------------------------------------
case DW_OP_deref: {
if (stack.empty()) {
if (error_ptr)
error_ptr->SetErrorString("Expression stack empty for DW_OP_deref.");
return false;
}
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::eValueTypeFileAddress: {
auto file_addr = stack.back().GetScalar().ULongLong(
LLDB_INVALID_ADDRESS);
if (!module_sp) {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"need module to resolve file address for DW_OP_deref");
return false;
}
Address so_addr;
if (!module_sp->ResolveFileAddress(file_addr, so_addr)) {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"failed to resolve file address in module");
return false;
}
addr_t load_Addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr());
if (load_Addr == LLDB_INVALID_ADDRESS) {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"failed to resolve load address");
return false;
}
stack.back().GetScalar() = load_Addr;
stack.back().SetValueType(Value::eValueTypeLoadAddress);
// Fall through to load address code below...
} LLVM_FALLTHROUGH;
case Value::eValueTypeLoadAddress:
if (exe_ctx) {
if (process) {
lldb::addr_t pointer_addr =
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
Status error;
lldb::addr_t pointer_value =
process->ReadPointerFromMemory(pointer_addr, error);
if (pointer_value != LLDB_INVALID_ADDRESS) {
stack.back().GetScalar() = pointer_value;
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_deref_size
// OPERANDS: 1
// 1 - uint8_t that specifies the size of the data to dereference.
// DESCRIPTION: Behaves like the DW_OP_deref operation: it pops the top
// stack entry and treats it as an address. The value retrieved from that
// address is pushed. In the DW_OP_deref_size operation, however, the size
// in bytes of the data retrieved from the dereferenced address is
// specified by the single operand. This operand is a 1-byte unsigned
// integral constant whose value may not be larger than the size of an
// address on the target machine. The data retrieved is zero extended to
// the size of an address on the target machine before being pushed on the
// expression stack.
//----------------------------------------------------------------------
case DW_OP_deref_size: {
if (stack.empty()) {
if (error_ptr)
error_ptr->SetErrorString(
"Expression stack empty for DW_OP_deref_size.");
return false;
}
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 *));
// I can't decide whether the size operand should apply to the bytes in
// their
// lldb-host endianness or the target endianness.. I doubt this'll ever
// come up but I'll opt for assuming big endian regardless.
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;
// the casts are added to work around the case where intptr_t is a 32
// bit quantity;
// presumably we won't hit the 5..7 cases if (void*) is 32-bits in this
// program.
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)];
Status 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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_xderef_size
// OPERANDS: 1
// 1 - uint8_t that specifies the size of the data to dereference.
// DESCRIPTION: Behaves like the DW_OP_xderef operation: the entry at
// the top of the stack is treated as an address. The second stack entry is
// treated as an "address space identifier" for those architectures that
// support multiple address spaces. The top two stack elements are popped,
// a data item is retrieved through an implementation-defined address
// calculation and pushed as the new stack top. In the DW_OP_xderef_size
// operation, however, the size in bytes of the data retrieved from the
// dereferenced address is specified by the single operand. This operand is
// a 1-byte unsigned integral constant whose value may not be larger than
// the size of an address on the target machine. The data retrieved is zero
// extended to the size of an address on the target machine before being
// pushed on the expression stack.
//----------------------------------------------------------------------
case DW_OP_xderef_size:
if (error_ptr)
error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size.");
return false;
//----------------------------------------------------------------------
// OPCODE: DW_OP_xderef
// OPERANDS: none
// DESCRIPTION: Provides an extended dereference mechanism. The entry at
// the top of the stack is treated as an address. The second stack entry is
// treated as an "address space identifier" for those architectures that
// support multiple address spaces. The top two stack elements are popped,
// 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.
//----------------------------------------------------------------------
case DW_OP_xderef:
if (error_ptr)
error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef.");
return false;
//----------------------------------------------------------------------
// All DW_OP_constXXX opcodes have a single operand as noted below:
//
// Opcode Operand 1
// --------------- ----------------------------------------------------
// DW_OP_const1u 1-byte unsigned integer constant DW_OP_const1s
// 1-byte signed integer constant DW_OP_const2u 2-byte unsigned integer
// constant DW_OP_const2s 2-byte signed integer constant DW_OP_const4u
// 4-byte unsigned integer constant DW_OP_const4s 4-byte signed integer
// constant DW_OP_const8u 8-byte unsigned integer constant DW_OP_const8s
// 8-byte signed integer constant DW_OP_constu unsigned LEB128 integer
// constant DW_OP_consts signed LEB128 integer constant
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_dup
// OPERANDS: none
// DESCRIPTION: duplicates the value at the top of the stack
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_drop
// OPERANDS: none
// DESCRIPTION: pops the value at the top of the stack
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_over
// OPERANDS: none
// DESCRIPTION: Duplicates the entry currently second in the stack at
// the top of the stack.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_pick
// OPERANDS: uint8_t index into the current stack
// DESCRIPTION: The stack entry with the specified index (0 through 255,
// inclusive) is pushed on the stack
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_swap
// OPERANDS: none
// DESCRIPTION: swaps the top two stack entries. The entry at the top
// of the stack becomes the second stack entry, and the second entry
// becomes the top of the stack
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_rot
// OPERANDS: none
// DESCRIPTION: Rotates the first three stack entries. The entry at
// the top of the stack becomes the third stack entry, the second entry
// becomes the top of the stack, and the third entry becomes the second
// entry.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_abs
// OPERANDS: none
// DESCRIPTION: pops the top stack entry, interprets it as a signed
// value and pushes its absolute value. If the absolute value can not be
// represented, the result is undefined.
//----------------------------------------------------------------------
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()) {
if (error_ptr)
error_ptr->SetErrorString(
"Failed to take the absolute value of the first stack item.");
return false;
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_and
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, performs a bitwise and
// operation on the two, and pushes the result.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_div
// OPERANDS: none
// DESCRIPTION: 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.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_minus
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, subtracts the former top
// of the stack from the former second entry, and pushes the result.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_mod
// OPERANDS: none
// DESCRIPTION: pops the top two stack values and pushes the result of
// the calculation: former second stack entry modulo the former top of the
// stack.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_mul
// OPERANDS: none
// DESCRIPTION: pops the top two stack entries, multiplies them
// together, and pushes the result.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_neg
// OPERANDS: none
// DESCRIPTION: pops the top stack entry, and pushes its negation.
//----------------------------------------------------------------------
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()) {
if (error_ptr)
error_ptr->SetErrorString("Unary negate failed.");
return false;
}
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_not
// OPERANDS: none
// DESCRIPTION: pops the top stack entry, and pushes its bitwise
// complement
//----------------------------------------------------------------------
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()) {
if (error_ptr)
error_ptr->SetErrorString("Logical NOT failed.");
return false;
}
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_or
// OPERANDS: none
// DESCRIPTION: pops the top two stack entries, performs a bitwise or
// operation on the two, and pushes the result.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_plus
// OPERANDS: none
// DESCRIPTION: pops the top two stack entries, adds them together, and
// pushes the result.
//----------------------------------------------------------------------
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().GetScalar() += tmp.GetScalar();
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_plus_uconst
// OPERANDS: none
// DESCRIPTION: pops the top stack entry, adds it to the unsigned LEB128
// constant operand and pushes the result.
//----------------------------------------------------------------------
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);
// Implicit conversion from a UINT to a Scalar...
stack.back().GetScalar() += uconst_value;
if (!stack.back().GetScalar().IsValid()) {
if (error_ptr)
error_ptr->SetErrorString("DW_OP_plus_uconst failed.");
return false;
}
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_shl
// OPERANDS: none
// DESCRIPTION: pops the top two stack entries, shifts the former
// second entry left by the number of bits specified by the former top of
// the stack, and pushes the result.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_shr
// OPERANDS: none
// DESCRIPTION: pops the top two stack entries, shifts the former second
// entry right logically (filling with zero bits) by the number of bits
// specified by the former top of the stack, and pushes the result.
//----------------------------------------------------------------------
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))) {
if (error_ptr)
error_ptr->SetErrorString("DW_OP_shr failed.");
return false;
}
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_shra
// OPERANDS: none
// DESCRIPTION: pops the top two stack entries, shifts the former second
// entry right arithmetically (divide the magnitude by 2, keep the same
// sign for the result) by the number of bits specified by the former top
// of the stack, and pushes the result.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_xor
// OPERANDS: none
// DESCRIPTION: pops the top two stack entries, performs the bitwise
// exclusive-or operation on the two, and pushes the result.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_skip
// OPERANDS: int16_t
// DESCRIPTION: An unconditional branch. Its single operand is a 2-byte
// signed integer constant. The 2-byte constant is the number of bytes of
// the DWARF expression to skip forward or backward from the current
// operation, beginning after the 2-byte constant.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_bra
// OPERANDS: int16_t
// DESCRIPTION: A conditional branch. Its single operand is a 2-byte
// signed integer constant. This operation pops the top of stack. If the
// value popped is not the constant 0, the 2-byte constant operand is the
// number of bytes of the DWARF expression to skip forward or backward from
// the current operation, beginning after the 2-byte constant.
//----------------------------------------------------------------------
case DW_OP_bra:
if (stack.empty()) {
if (error_ptr)
error_ptr->SetErrorString(
"Expression stack needs at least 1 item for DW_OP_bra.");
return false;
} else {
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_eq
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, compares using the
// equals (==) operator.
// STACK RESULT: push the constant value 1 onto the stack if the result
// of the operation is true or the constant value 0 if the result of the
// operation is false.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_ge
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, compares using the
// greater than or equal to (>=) operator.
// STACK RESULT: push the constant value 1 onto the stack if the result
// of the operation is true or the constant value 0 if the result of the
// operation is false.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_gt
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, compares using the
// greater than (>) operator.
// STACK RESULT: push the constant value 1 onto the stack if the result
// of the operation is true or the constant value 0 if the result of the
// operation is false.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_le
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, compares using the
// less than or equal to (<=) operator.
// STACK RESULT: push the constant value 1 onto the stack if the result
// of the operation is true or the constant value 0 if the result of the
// operation is false.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_lt
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, compares using the
// less than (<) operator.
// STACK RESULT: push the constant value 1 onto the stack if the result
// of the operation is true or the constant value 0 if the result of the
// operation is false.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_ne
// OPERANDS: none
// DESCRIPTION: pops the top two stack values, compares using the
// not equal (!=) operator.
// STACK RESULT: push the constant value 1 onto the stack if the result
// of the operation is true or the constant value 0 if the result of the
// operation is false.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_litn
// OPERANDS: none
// DESCRIPTION: encode the unsigned literal values from 0 through 31.
// STACK RESULT: push the unsigned literal constant value onto the top
// of the stack.
//----------------------------------------------------------------------
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((uint64_t)(op - DW_OP_lit0)));
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_regN
// OPERANDS: none
// DESCRIPTION: Push the value in register n on the top of the stack.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_regx
// OPERANDS:
// ULEB128 literal operand that encodes the register.
// DESCRIPTION: Push the value in register on the top of the stack.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_bregN
// OPERANDS:
// SLEB128 offset from register N
// DESCRIPTION: Value is in memory at the address specified by register
// N plus an offset.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_bregx
// OPERANDS: 2
// ULEB128 literal operand that encodes the register.
// SLEB128 offset from register N
// DESCRIPTION: Value is in memory at the address specified by register
// N plus an offset.
//----------------------------------------------------------------------
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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_nop
// OPERANDS: none
// DESCRIPTION: A place holder. It has no effect on the location stack
// or any of its values.
//----------------------------------------------------------------------
case DW_OP_nop:
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_piece
// OPERANDS: 1
// ULEB128: byte size of the piece
// DESCRIPTION: The operand describes the size in bytes of the piece of
// the object referenced by the DWARF expression whose result is at the top
// of the stack. If the piece is located in a register, but does not occupy
// the entire register, the placement of the piece within that register is
// defined by the ABI.
//
// Many compilers store a single variable in sets of registers, or store a
// variable partially in memory and partially in registers. DW_OP_piece
// provides a way of describing how large a part of a variable a particular
// DWARF expression refers to.
//----------------------------------------------------------------------
case DW_OP_piece: {
const uint64_t piece_byte_size = opcodes.GetULEB128(&offset);
if (piece_byte_size > 0) {
Value curr_piece;
if (stack.empty()) {
// In a multi-piece expression, this means that the current piece is
// not available. Fill with zeros for now by resizing the data and
// appending it
curr_piece.ResizeData(piece_byte_size);
::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
pieces.AppendDataToHostBuffer(curr_piece);
} else {
Status error;
// Extract the current piece into "curr_piece"
Value curr_piece_source_value(stack.back());
stack.pop_back();
const Value::ValueType curr_piece_source_value_type =
curr_piece_source_value.GetValueType();
switch (curr_piece_source_value_type) {
case Value::eValueTypeLoadAddress:
if (process) {
if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size) {
lldb::addr_t load_addr =
curr_piece_source_value.GetScalar().ULongLong(
LLDB_INVALID_ADDRESS);
if (process->ReadMemory(
load_addr, curr_piece.GetBuffer().GetBytes(),
piece_byte_size, error) != piece_byte_size) {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"failed to read memory DW_OP_piece(%" PRIu64
") from 0x%" PRIx64,
piece_byte_size, load_addr);
return false;
}
} else {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"failed to resize the piece memory buffer for "
"DW_OP_piece(%" PRIu64 ")",
piece_byte_size);
return false;
}
}
break;
case Value::eValueTypeFileAddress:
case Value::eValueTypeHostAddress:
if (error_ptr) {
lldb::addr_t addr = curr_piece_source_value.GetScalar().ULongLong(
LLDB_INVALID_ADDRESS);
error_ptr->SetErrorStringWithFormat(
"failed to read memory DW_OP_piece(%" PRIu64
") from %s address 0x%" PRIx64,
piece_byte_size, curr_piece_source_value.GetValueType() ==
Value::eValueTypeFileAddress
? "file"
: "host",
addr);
}
return false;
case Value::eValueTypeScalar: {
uint32_t bit_size = piece_byte_size * 8;
uint32_t bit_offset = 0;
if (!curr_piece_source_value.GetScalar().ExtractBitfield(
bit_size, bit_offset)) {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"unable to extract %" PRIu64 " bytes from a %" PRIu64
" byte scalar value.",
piece_byte_size,
(uint64_t)curr_piece_source_value.GetScalar()
.GetByteSize());
return false;
}
curr_piece = curr_piece_source_value;
} break;
case Value::eValueTypeVector: {
if (curr_piece_source_value.GetVector().length >= piece_byte_size)
curr_piece_source_value.GetVector().length = piece_byte_size;
else {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"unable to extract %" PRIu64 " bytes from a %" PRIu64
" byte vector value.",
piece_byte_size,
(uint64_t)curr_piece_source_value.GetVector().length);
return false;
}
} break;
}
// Check if this is the first piece?
if (op_piece_offset == 0) {
// This is the first piece, we should push it back onto the stack
// so subsequent pieces will be able to access this piece and add
// to it
if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
if (error_ptr)
error_ptr->SetErrorString("failed to append piece data");
return false;
}
} else {
// If this is the second or later piece there should be a value on
// the stack
if (pieces.GetBuffer().GetByteSize() != op_piece_offset) {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"DW_OP_piece for offset %" PRIu64
" but top of stack is of size %" PRIu64,
op_piece_offset, pieces.GetBuffer().GetByteSize());
return false;
}
if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
if (error_ptr)
error_ptr->SetErrorString("failed to append piece data");
return false;
}
}
op_piece_offset += piece_byte_size;
}
}
} break;
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
if (stack.size() < 1) {
if (error_ptr)
error_ptr->SetErrorString(
"Expression stack needs at least 1 item for DW_OP_bit_piece.");
return false;
} else {
const uint64_t piece_bit_size = opcodes.GetULEB128(&offset);
const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset);
switch (stack.back().GetValueType()) {
case Value::eValueTypeScalar: {
if (!stack.back().GetScalar().ExtractBitfield(piece_bit_size,
piece_bit_offset)) {
if (error_ptr)
error_ptr->SetErrorStringWithFormat(
"unable to extract %" PRIu64 " bit value with %" PRIu64
" bit offset from a %" PRIu64 " bit scalar value.",
piece_bit_size, piece_bit_offset,
(uint64_t)(stack.back().GetScalar().GetByteSize() * 8));
return false;
}
} break;
case Value::eValueTypeFileAddress:
case Value::eValueTypeLoadAddress:
case Value::eValueTypeHostAddress:
if (error_ptr) {
error_ptr->SetErrorStringWithFormat(
"unable to extract DW_OP_bit_piece(bit_size = %" PRIu64
", bit_offset = %" PRIu64 ") from an address value.",
piece_bit_size, piece_bit_offset);
}
return false;
case Value::eValueTypeVector:
if (error_ptr) {
error_ptr->SetErrorStringWithFormat(
"unable to extract DW_OP_bit_piece(bit_size = %" PRIu64
", bit_offset = %" PRIu64 ") from a vector value.",
piece_bit_size, piece_bit_offset);
}
return false;
}
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_push_object_address
// OPERANDS: none
// DESCRIPTION: 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
// DIE 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.
//----------------------------------------------------------------------
case DW_OP_push_object_address:
if (object_address_ptr)
stack.push_back(*object_address_ptr);
else {
if (error_ptr)
error_ptr->SetErrorString("DW_OP_push_object_address used without "
"specifying an object address");
return false;
}
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_call2
// OPERANDS:
// uint16_t compile unit relative offset of a DIE
// DESCRIPTION: Performs subroutine calls during evaluation
// of a DWARF expression. The operand is the 2-byte unsigned offset of a
// debugging information entry in the current compilation unit.
//
// Operand interpretation is exactly like that for DW_FORM_ref2.
//
// This operation transfers control of DWARF expression evaluation to the
// DW_AT_location attribute of the referenced DIE. If there is no such
// attribute, then there is no effect. Execution of the DWARF expression of
// a DW_AT_location attribute may add to and/or remove from values on the
// stack. Execution returns to the point following the call when the end of
// the attribute is reached. Values on the stack at the time of the call
// may be used as parameters by the called expression and values left on
// the stack by the called expression may be used as return values by prior
// agreement between the calling and called expressions.
//----------------------------------------------------------------------
case DW_OP_call2:
if (error_ptr)
error_ptr->SetErrorString("Unimplemented opcode DW_OP_call2.");
return false;
//----------------------------------------------------------------------
// OPCODE: DW_OP_call4
// OPERANDS: 1
// uint32_t compile unit relative offset of a DIE
// DESCRIPTION: Performs a subroutine call during evaluation of a DWARF
// expression. For DW_OP_call4, the operand is a 4-byte unsigned offset of
// a debugging information entry in the current compilation unit.
//
// Operand interpretation DW_OP_call4 is exactly like that for
// DW_FORM_ref4.
//
// This operation transfers control of DWARF expression evaluation to the
// DW_AT_location attribute of the referenced DIE. If there is no such
// attribute, then there is no effect. Execution of the DWARF expression of
// a DW_AT_location attribute may add to and/or remove from values on the
// stack. Execution returns to the point following the call when the end of
// the attribute is reached. Values on the stack at the time of the call
// may be used as parameters by the called expression and values left on
// the stack by the called expression may be used as return values by prior
// agreement between the calling and called expressions.
//----------------------------------------------------------------------
case DW_OP_call4:
if (error_ptr)
error_ptr->SetErrorString("Unimplemented opcode DW_OP_call4.");
return false;
//----------------------------------------------------------------------
// OPCODE: DW_OP_stack_value
// OPERANDS: None
// DESCRIPTION: Specifies that the object does not exist in memory but
// rather is a constant value. The value from the top of the stack is the
// value to be used. This is the actual object value and not the location.
//----------------------------------------------------------------------
case DW_OP_stack_value:
stack.back().SetValueType(Value::eValueTypeScalar);
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_call_frame_cfa
// OPERANDS: None
// DESCRIPTION: Specifies a DWARF expression that pushes the value of
// the canonical frame address consistent with the call frame information
// located in .debug_frame (or in the FDEs of the eh_frame section).
//----------------------------------------------------------------------
case DW_OP_call_frame_cfa:
if (frame) {
// Note that we don't have to parse FDEs because this DWARF expression
// is commonly evaluated with a valid stack frame.
StackID id = frame->GetStackID();
addr_t cfa = id.GetCallFrameAddress();
if (cfa != LLDB_INVALID_ADDRESS) {
stack.push_back(Scalar(cfa));
stack.back().SetValueType(Value::eValueTypeLoadAddress);
} 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;
//----------------------------------------------------------------------
// OPCODE: DW_OP_form_tls_address (or the old pre-DWARFv3 vendor extension
// opcode, DW_OP_GNU_push_tls_address)
// OPERANDS: none
// DESCRIPTION: Pops a TLS offset from the stack, converts it to
// an address in the current thread's thread-local storage block, and
// pushes it on the stack.
//----------------------------------------------------------------------
case DW_OP_form_tls_address:
case DW_OP_GNU_push_tls_address: {
if (stack.size() < 1) {
if (error_ptr) {
if (op == DW_OP_form_tls_address)
error_ptr->SetErrorString(
"DW_OP_form_tls_address needs an argument.");
else
error_ptr->SetErrorString(
"DW_OP_GNU_push_tls_address needs an argument.");
}
return false;
}
if (!exe_ctx || !module_sp) {
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;
}
// Lookup the TLS block address for this thread and module.
const addr_t tls_file_addr =
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
const addr_t tls_load_addr =
thread->GetThreadLocalData(module_sp, tls_file_addr);
if (tls_load_addr == LLDB_INVALID_ADDRESS) {
if (error_ptr)
error_ptr->SetErrorString(
"No TLS data currently exists for this thread.");
return false;
}
stack.back().GetScalar() = tls_load_addr;
stack.back().SetValueType(Value::eValueTypeLoadAddress);
} break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_GNU_addr_index
// OPERANDS: 1
// ULEB128: index to the .debug_addr section
// DESCRIPTION: Pushes an address to the stack from the .debug_addr
// section with the base address specified by the DW_AT_addr_base attribute
// and the 0 based index is the ULEB128 encoded index.
//----------------------------------------------------------------------
case DW_OP_GNU_addr_index: {
if (!dwarf_cu) {
if (error_ptr)
error_ptr->SetErrorString("DW_OP_GNU_addr_index found without a "
"compile unit being specified");
return false;
}
uint64_t index = opcodes.GetULEB128(&offset);
uint32_t index_size = dwarf_cu->GetAddressByteSize();
dw_offset_t addr_base = dwarf_cu->GetAddrBase();
lldb::offset_t offset = addr_base + index * index_size;
uint64_t value =
dwarf_cu->GetSymbolFileDWARF()->get_debug_addr_data().GetMaxU64(
&offset, index_size);
stack.push_back(Scalar(value));
stack.back().SetValueType(Value::eValueTypeFileAddress);
} break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_GNU_const_index
// OPERANDS: 1
// ULEB128: index to the .debug_addr section
// DESCRIPTION: Pushes an constant with the size of a machine address to
// the stack from the .debug_addr section with the base address specified
// by the DW_AT_addr_base attribute and the 0 based index is the ULEB128
// encoded index.
//----------------------------------------------------------------------
case DW_OP_GNU_const_index: {
if (!dwarf_cu) {
if (error_ptr)
error_ptr->SetErrorString("DW_OP_GNU_const_index found without a "
"compile unit being specified");
return false;
}
uint64_t index = opcodes.GetULEB128(&offset);
uint32_t index_size = dwarf_cu->GetAddressByteSize();
dw_offset_t addr_base = dwarf_cu->GetAddrBase();
lldb::offset_t offset = addr_base + index * index_size;
const DWARFDataExtractor &debug_addr =
dwarf_cu->GetSymbolFileDWARF()->get_debug_addr_data();
switch (index_size) {
case 4:
stack.push_back(Scalar(debug_addr.GetU32(&offset)));
break;
case 8:
stack.push_back(Scalar(debug_addr.GetU64(&offset)));
break;
default:
assert(false && "Unhandled index size");
return false;
}
} break;
default:
if (log)
log->Printf("Unhandled opcode %s in DWARFExpression.",
DW_OP_value_to_name(op));
break;
}
}
if (stack.empty()) {
// Nothing on the stack, check if we created a piece value from DW_OP_piece
// or DW_OP_bit_piece opcodes
if (pieces.GetBuffer().GetByteSize()) {
result = pieces;
} else {
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 %" PRIu64 " values:",
(uint64_t)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; // Return true on success
}
size_t DWARFExpression::LocationListSize(const DWARFUnit *dwarf_cu,
const DataExtractor &debug_loc_data,
lldb::offset_t offset) {
const lldb::offset_t debug_loc_offset = offset;
while (debug_loc_data.ValidOffset(offset)) {
lldb::addr_t start_addr = LLDB_INVALID_ADDRESS;
lldb::addr_t end_addr = LLDB_INVALID_ADDRESS;
if (!AddressRangeForLocationListEntry(dwarf_cu, debug_loc_data, &offset,
start_addr, end_addr))
break;
if (start_addr == 0 && end_addr == 0)
break;
uint16_t loc_length = debug_loc_data.GetU16(&offset);
offset += loc_length;
}
if (offset > debug_loc_offset)
return offset - debug_loc_offset;
return 0;
}
bool DWARFExpression::AddressRangeForLocationListEntry(
const DWARFUnit *dwarf_cu, const DataExtractor &debug_loc_data,
lldb::offset_t *offset_ptr, lldb::addr_t &low_pc, lldb::addr_t &high_pc) {
if (!debug_loc_data.ValidOffset(*offset_ptr))
return false;
DWARFExpression::LocationListFormat format =
dwarf_cu->GetSymbolFileDWARF()->GetLocationListFormat();
switch (format) {
case NonLocationList:
return false;
case RegularLocationList:
low_pc = debug_loc_data.GetAddress(offset_ptr);
high_pc = debug_loc_data.GetAddress(offset_ptr);
return true;
case SplitDwarfLocationList:
case LocLists:
switch (debug_loc_data.GetU8(offset_ptr)) {
case DW_LLE_end_of_list:
return false;
case DW_LLE_startx_endx: {
uint64_t index = debug_loc_data.GetULEB128(offset_ptr);
low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index);
index = debug_loc_data.GetULEB128(offset_ptr);
high_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index);
return true;
}
case DW_LLE_startx_length: {
uint64_t index = debug_loc_data.GetULEB128(offset_ptr);
low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index);
uint64_t length = (format == LocLists)
? debug_loc_data.GetULEB128(offset_ptr)
: debug_loc_data.GetU32(offset_ptr);
high_pc = low_pc + length;
return true;
}
case DW_LLE_start_length: {
low_pc = debug_loc_data.GetAddress(offset_ptr);
high_pc = low_pc + debug_loc_data.GetULEB128(offset_ptr);
return true;
}
case DW_LLE_start_end: {
low_pc = debug_loc_data.GetAddress(offset_ptr);
high_pc = debug_loc_data.GetAddress(offset_ptr);
return true;
}
default:
// Not supported entry type
lldbassert(false && "Not supported location list type");
return false;
}
}
assert(false && "Not supported location list type");
return false;
}
static bool print_dwarf_exp_op(Stream &s, const DataExtractor &data,
lldb::offset_t *offset_ptr, int address_size,
int dwarf_ref_size) {
uint8_t opcode = data.GetU8(offset_ptr);
DRC_class opcode_class;
uint64_t uint;
int64_t sint;
int size;
opcode_class = DW_OP_value_to_class(opcode) & (~DRC_DWARFv3);
s.Printf("%s ", DW_OP_value_to_name(opcode));
/* Does this take zero parameters? If so we can shortcut this function. */
if (opcode_class == DRC_ZEROOPERANDS)
return true;
if (opcode_class == DRC_TWOOPERANDS && opcode == DW_OP_bregx) {
uint = data.GetULEB128(offset_ptr);
sint = data.GetSLEB128(offset_ptr);
s.Printf("%" PRIu64 " %" PRIi64, uint, sint);
return true;
}
if (opcode_class != DRC_ONEOPERAND) {
s.Printf("UNKNOWN OP %u", opcode);
return false;
}
switch (opcode) {
case DW_OP_addr:
size = address_size;
break;
case DW_OP_const1u:
size = 1;
break;
case DW_OP_const1s:
size = -1;
break;
case DW_OP_const2u:
size = 2;
break;
case DW_OP_const2s:
size = -2;
break;
case DW_OP_const4u:
size = 4;
break;
case DW_OP_const4s:
size = -4;
break;
case DW_OP_const8u:
size = 8;
break;
case DW_OP_const8s:
size = -8;
break;
case DW_OP_constu:
size = 128;
break;
case DW_OP_consts:
size = -128;
break;
case DW_OP_fbreg:
size = -128;
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:
size = -128;
break;
case DW_OP_pick:
case DW_OP_deref_size:
case DW_OP_xderef_size:
size = 1;
break;
case DW_OP_skip:
case DW_OP_bra:
size = -2;
break;
case DW_OP_call2:
size = 2;
break;
case DW_OP_call4:
size = 4;
break;
case DW_OP_call_ref:
size = dwarf_ref_size;
break;
case DW_OP_piece:
case DW_OP_plus_uconst:
case DW_OP_regx:
case DW_OP_GNU_addr_index:
case DW_OP_GNU_const_index:
size = 128;
break;
default:
s.Printf("UNKNOWN ONE-OPERAND OPCODE, #%u", opcode);
- return true;
+ return false;
}
switch (size) {
case -1:
sint = (int8_t)data.GetU8(offset_ptr);
s.Printf("%+" PRIi64, sint);
break;
case -2:
sint = (int16_t)data.GetU16(offset_ptr);
s.Printf("%+" PRIi64, sint);
break;
case -4:
sint = (int32_t)data.GetU32(offset_ptr);
s.Printf("%+" PRIi64, sint);
break;
case -8:
sint = (int64_t)data.GetU64(offset_ptr);
s.Printf("%+" PRIi64, sint);
break;
case -128:
sint = data.GetSLEB128(offset_ptr);
s.Printf("%+" PRIi64, sint);
break;
case 1:
uint = data.GetU8(offset_ptr);
s.Printf("0x%2.2" PRIx64, uint);
break;
case 2:
uint = data.GetU16(offset_ptr);
s.Printf("0x%4.4" PRIx64, uint);
break;
case 4:
uint = data.GetU32(offset_ptr);
s.Printf("0x%8.8" PRIx64, uint);
break;
case 8:
uint = data.GetU64(offset_ptr);
s.Printf("0x%16.16" PRIx64, uint);
break;
case 128:
uint = data.GetULEB128(offset_ptr);
s.Printf("0x%" PRIx64, uint);
break;
}
- return false;
+ return true;
}
bool DWARFExpression::PrintDWARFExpression(Stream &s, const DataExtractor &data,
int address_size, int dwarf_ref_size,
bool location_expression) {
int op_count = 0;
lldb::offset_t offset = 0;
while (data.ValidOffset(offset)) {
if (location_expression && op_count > 0)
return false;
if (op_count > 0)
s.PutCString(", ");
if (!print_dwarf_exp_op(s, data, &offset, address_size, dwarf_ref_size))
return false;
op_count++;
}
return true;
}
void DWARFExpression::PrintDWARFLocationList(
Stream &s, const DWARFUnit *cu, const DataExtractor &debug_loc_data,
lldb::offset_t offset) {
uint64_t start_addr, end_addr;
uint32_t addr_size = DWARFUnit::GetAddressByteSize(cu);
s.SetAddressByteSize(DWARFUnit::GetAddressByteSize(cu));
dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
while (debug_loc_data.ValidOffset(offset)) {
start_addr = debug_loc_data.GetMaxU64(&offset, addr_size);
end_addr = debug_loc_data.GetMaxU64(&offset, addr_size);
if (start_addr == 0 && end_addr == 0)
break;
s.PutCString("\n ");
s.Indent();
if (cu)
s.AddressRange(start_addr + base_addr, end_addr + base_addr,
cu->GetAddressByteSize(), NULL, ": ");
uint32_t loc_length = debug_loc_data.GetU16(&offset);
DataExtractor locationData(debug_loc_data, offset, loc_length);
PrintDWARFExpression(s, locationData, addr_size, 4, false);
offset += loc_length;
}
}
bool DWARFExpression::GetOpAndEndOffsets(StackFrame &frame,
lldb::offset_t &op_offset,
lldb::offset_t &end_offset) {
SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);
if (!sc.function) {
return false;
}
addr_t loclist_base_file_addr =
sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
if (loclist_base_file_addr == LLDB_INVALID_ADDRESS) {
return false;
}
addr_t pc_file_addr = frame.GetFrameCodeAddress().GetFileAddress();
lldb::offset_t opcodes_offset, opcodes_length;
if (!GetLocation(loclist_base_file_addr, pc_file_addr, opcodes_offset,
opcodes_length)) {
return false;
}
if (opcodes_length == 0) {
return false;
}
op_offset = opcodes_offset;
end_offset = opcodes_offset + opcodes_length;
return true;
}
bool DWARFExpression::MatchesOperand(StackFrame &frame,
const Instruction::Operand &operand) {
using namespace OperandMatchers;
lldb::offset_t op_offset;
lldb::offset_t end_offset;
if (!GetOpAndEndOffsets(frame, op_offset, end_offset)) {
return false;
}
if (!m_data.ValidOffset(op_offset) || op_offset >= end_offset) {
return false;
}
RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
if (!reg_ctx_sp) {
return false;
}
DataExtractor opcodes = m_data;
uint8_t opcode = opcodes.GetU8(&op_offset);
if (opcode == DW_OP_fbreg) {
int64_t offset = opcodes.GetSLEB128(&op_offset);
DWARFExpression *fb_expr = frame.GetFrameBaseExpression(nullptr);
if (!fb_expr) {
return false;
}
auto recurse = [&frame, fb_expr](const Instruction::Operand &child) {
return fb_expr->MatchesOperand(frame, child);
};
if (!offset &&
MatchUnaryOp(MatchOpType(Instruction::Operand::Type::Dereference),
recurse)(operand)) {
return true;
}
return MatchUnaryOp(
MatchOpType(Instruction::Operand::Type::Dereference),
MatchBinaryOp(MatchOpType(Instruction::Operand::Type::Sum),
MatchImmOp(offset), recurse))(operand);
}
bool dereference = false;
const RegisterInfo *reg = nullptr;
int64_t offset = 0;
if (opcode >= DW_OP_reg0 && opcode <= DW_OP_reg31) {
reg = reg_ctx_sp->GetRegisterInfo(m_reg_kind, opcode - DW_OP_reg0);
} else if (opcode >= DW_OP_breg0 && opcode <= DW_OP_breg31) {
offset = opcodes.GetSLEB128(&op_offset);
reg = reg_ctx_sp->GetRegisterInfo(m_reg_kind, opcode - DW_OP_breg0);
} else if (opcode == DW_OP_regx) {
uint32_t reg_num = static_cast<uint32_t>(opcodes.GetULEB128(&op_offset));
reg = reg_ctx_sp->GetRegisterInfo(m_reg_kind, reg_num);
} else if (opcode == DW_OP_bregx) {
uint32_t reg_num = static_cast<uint32_t>(opcodes.GetULEB128(&op_offset));
offset = opcodes.GetSLEB128(&op_offset);
reg = reg_ctx_sp->GetRegisterInfo(m_reg_kind, reg_num);
} else {
return false;
}
if (!reg) {
return false;
}
if (dereference) {
if (!offset &&
MatchUnaryOp(MatchOpType(Instruction::Operand::Type::Dereference),
MatchRegOp(*reg))(operand)) {
return true;
}
return MatchUnaryOp(
MatchOpType(Instruction::Operand::Type::Dereference),
MatchBinaryOp(MatchOpType(Instruction::Operand::Type::Sum),
MatchRegOp(*reg),
MatchImmOp(offset)))(operand);
} else {
return MatchRegOp(*reg)(operand);
}
}
Index: lldb/trunk/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp (revision 352844)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp (revision 352845)
@@ -1,584 +1,183 @@
//===-- PDBLocationToDWARFExpression.cpp ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "PDBLocationToDWARFExpression.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamBuffer.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Variable.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
+#include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h"
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::npdb;
using namespace llvm::pdb;
-namespace {
-const uint32_t g_code_view_to_lldb_registers_x86[] = {
- LLDB_INVALID_REGNUM, // NONE
- lldb_al_i386, // AL
- lldb_cl_i386, // CL
- lldb_dl_i386, // DL
- lldb_bl_i386, // BL
- lldb_ah_i386, // AH
- lldb_ch_i386, // CH
- lldb_dh_i386, // DH
- lldb_bh_i386, // BH
- lldb_ax_i386, // AX
- lldb_cx_i386, // CX
- lldb_dx_i386, // DX
- lldb_bx_i386, // BX
- lldb_sp_i386, // SP
- lldb_bp_i386, // BP
- lldb_si_i386, // SI
- lldb_di_i386, // DI
- lldb_eax_i386, // EAX
- lldb_ecx_i386, // ECX
- lldb_edx_i386, // EDX
- lldb_ebx_i386, // EBX
- lldb_esp_i386, // ESP
- lldb_ebp_i386, // EBP
- lldb_esi_i386, // ESI
- lldb_edi_i386, // EDI
- lldb_es_i386, // ES
- lldb_cs_i386, // CS
- lldb_ss_i386, // SS
- lldb_ds_i386, // DS
- lldb_fs_i386, // FS
- lldb_gs_i386, // GS
- LLDB_INVALID_REGNUM, // IP
- LLDB_INVALID_REGNUM, // FLAGS
- lldb_eip_i386, // EIP
- lldb_eflags_i386, // EFLAGS
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, // TEMP
- LLDB_INVALID_REGNUM, // TEMPH
- LLDB_INVALID_REGNUM, // QUOTE
- LLDB_INVALID_REGNUM, // PCDR3
- LLDB_INVALID_REGNUM, // PCDR4
- LLDB_INVALID_REGNUM, // PCDR5
- LLDB_INVALID_REGNUM, // PCDR6
- LLDB_INVALID_REGNUM, // PCDR7
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, // CR0
- LLDB_INVALID_REGNUM, // CR1
- LLDB_INVALID_REGNUM, // CR2
- LLDB_INVALID_REGNUM, // CR3
- LLDB_INVALID_REGNUM, // CR4
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- lldb_dr0_i386, // DR0
- lldb_dr1_i386, // DR1
- lldb_dr2_i386, // DR2
- lldb_dr3_i386, // DR3
- lldb_dr4_i386, // DR4
- lldb_dr5_i386, // DR5
- lldb_dr6_i386, // DR6
- lldb_dr7_i386, // DR7
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, // GDTR
- LLDB_INVALID_REGNUM, // GDTL
- LLDB_INVALID_REGNUM, // IDTR
- LLDB_INVALID_REGNUM, // IDTL
- LLDB_INVALID_REGNUM, // LDTR
- LLDB_INVALID_REGNUM, // TR
- LLDB_INVALID_REGNUM, // PSEUDO1
- LLDB_INVALID_REGNUM, // PSEUDO2
- LLDB_INVALID_REGNUM, // PSEUDO3
- LLDB_INVALID_REGNUM, // PSEUDO4
- LLDB_INVALID_REGNUM, // PSEUDO5
- LLDB_INVALID_REGNUM, // PSEUDO6
- LLDB_INVALID_REGNUM, // PSEUDO7
- LLDB_INVALID_REGNUM, // PSEUDO8
- LLDB_INVALID_REGNUM, // PSEUDO9
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- lldb_st0_i386, // ST0
- lldb_st1_i386, // ST1
- lldb_st2_i386, // ST2
- lldb_st3_i386, // ST3
- lldb_st4_i386, // ST4
- lldb_st5_i386, // ST5
- lldb_st6_i386, // ST6
- lldb_st7_i386, // ST7
- LLDB_INVALID_REGNUM, // CTRL
- LLDB_INVALID_REGNUM, // STAT
- LLDB_INVALID_REGNUM, // TAG
- LLDB_INVALID_REGNUM, // FPIP
- LLDB_INVALID_REGNUM, // FPCS
- LLDB_INVALID_REGNUM, // FPDO
- LLDB_INVALID_REGNUM, // FPDS
- LLDB_INVALID_REGNUM, // ISEM
- LLDB_INVALID_REGNUM, // FPEIP
- LLDB_INVALID_REGNUM, // FPEDO
- lldb_mm0_i386, // MM0
- lldb_mm1_i386, // MM1
- lldb_mm2_i386, // MM2
- lldb_mm3_i386, // MM3
- lldb_mm4_i386, // MM4
- lldb_mm5_i386, // MM5
- lldb_mm6_i386, // MM6
- lldb_mm7_i386, // MM7
- lldb_xmm0_i386, // XMM0
- lldb_xmm1_i386, // XMM1
- lldb_xmm2_i386, // XMM2
- lldb_xmm3_i386, // XMM3
- lldb_xmm4_i386, // XMM4
- lldb_xmm5_i386, // XMM5
- lldb_xmm6_i386, // XMM6
- lldb_xmm7_i386 // XMM7
-};
-
-const uint32_t g_code_view_to_lldb_registers_x86_64[] = {
- LLDB_INVALID_REGNUM, // NONE
- lldb_al_x86_64, // AL
- lldb_cl_x86_64, // CL
- lldb_dl_x86_64, // DL
- lldb_bl_x86_64, // BL
- lldb_ah_x86_64, // AH
- lldb_ch_x86_64, // CH
- lldb_dh_x86_64, // DH
- lldb_bh_x86_64, // BH
- lldb_ax_x86_64, // AX
- lldb_cx_x86_64, // CX
- lldb_dx_x86_64, // DX
- lldb_bx_x86_64, // BX
- lldb_sp_x86_64, // SP
- lldb_bp_x86_64, // BP
- lldb_si_x86_64, // SI
- lldb_di_x86_64, // DI
- lldb_eax_x86_64, // EAX
- lldb_ecx_x86_64, // ECX
- lldb_edx_x86_64, // EDX
- lldb_ebx_x86_64, // EBX
- lldb_esp_x86_64, // ESP
- lldb_ebp_x86_64, // EBP
- lldb_esi_x86_64, // ESI
- lldb_edi_x86_64, // EDI
- lldb_es_x86_64, // ES
- lldb_cs_x86_64, // CS
- lldb_ss_x86_64, // SS
- lldb_ds_x86_64, // DS
- lldb_fs_x86_64, // FS
- lldb_gs_x86_64, // GS
- LLDB_INVALID_REGNUM, // IP
- LLDB_INVALID_REGNUM, // FLAGS
- LLDB_INVALID_REGNUM, // EIP
- LLDB_INVALID_REGNUM, // EFLAGS
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, // TEMP
- LLDB_INVALID_REGNUM, // TEMPH
- LLDB_INVALID_REGNUM, // QUOTE
- LLDB_INVALID_REGNUM, // PCDR3
- LLDB_INVALID_REGNUM, // PCDR4
- LLDB_INVALID_REGNUM, // PCDR5
- LLDB_INVALID_REGNUM, // PCDR6
- LLDB_INVALID_REGNUM, // PCDR7
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, // CR0
- LLDB_INVALID_REGNUM, // CR1
- LLDB_INVALID_REGNUM, // CR2
- LLDB_INVALID_REGNUM, // CR3
- LLDB_INVALID_REGNUM, // CR4
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- lldb_dr0_x86_64, // DR0
- lldb_dr1_x86_64, // DR1
- lldb_dr2_x86_64, // DR2
- lldb_dr3_x86_64, // DR3
- lldb_dr4_x86_64, // DR4
- lldb_dr5_x86_64, // DR5
- lldb_dr6_x86_64, // DR6
- lldb_dr7_x86_64, // DR7
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, // GDTR
- LLDB_INVALID_REGNUM, // GDTL
- LLDB_INVALID_REGNUM, // IDTR
- LLDB_INVALID_REGNUM, // IDTL
- LLDB_INVALID_REGNUM, // LDTR
- LLDB_INVALID_REGNUM, // TR
- LLDB_INVALID_REGNUM, // PSEUDO1
- LLDB_INVALID_REGNUM, // PSEUDO2
- LLDB_INVALID_REGNUM, // PSEUDO3
- LLDB_INVALID_REGNUM, // PSEUDO4
- LLDB_INVALID_REGNUM, // PSEUDO5
- LLDB_INVALID_REGNUM, // PSEUDO6
- LLDB_INVALID_REGNUM, // PSEUDO7
- LLDB_INVALID_REGNUM, // PSEUDO8
- LLDB_INVALID_REGNUM, // PSEUDO9
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- lldb_st0_x86_64, // ST0
- lldb_st1_x86_64, // ST1
- lldb_st2_x86_64, // ST2
- lldb_st3_x86_64, // ST3
- lldb_st4_x86_64, // ST4
- lldb_st5_x86_64, // ST5
- lldb_st6_x86_64, // ST6
- lldb_st7_x86_64, // ST7
- LLDB_INVALID_REGNUM, // CTRL
- LLDB_INVALID_REGNUM, // STAT
- LLDB_INVALID_REGNUM, // TAG
- LLDB_INVALID_REGNUM, // FPIP
- LLDB_INVALID_REGNUM, // FPCS
- LLDB_INVALID_REGNUM, // FPDO
- LLDB_INVALID_REGNUM, // FPDS
- LLDB_INVALID_REGNUM, // ISEM
- LLDB_INVALID_REGNUM, // FPEIP
- LLDB_INVALID_REGNUM, // FPEDO
- lldb_mm0_x86_64, // MM0
- lldb_mm1_x86_64, // MM1
- lldb_mm2_x86_64, // MM2
- lldb_mm3_x86_64, // MM3
- lldb_mm4_x86_64, // MM4
- lldb_mm5_x86_64, // MM5
- lldb_mm6_x86_64, // MM6
- lldb_mm7_x86_64, // MM7
- lldb_xmm0_x86_64, // XMM0
- lldb_xmm1_x86_64, // XMM1
- lldb_xmm2_x86_64, // XMM2
- lldb_xmm3_x86_64, // XMM3
- lldb_xmm4_x86_64, // XMM4
- lldb_xmm5_x86_64, // XMM5
- lldb_xmm6_x86_64, // XMM6
- lldb_xmm7_x86_64, // XMM7
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM,
- lldb_mxcsr_x86_64, // MXCSR
- LLDB_INVALID_REGNUM, // EDXEAX
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, // EMM0L
- LLDB_INVALID_REGNUM, // EMM1L
- LLDB_INVALID_REGNUM, // EMM2L
- LLDB_INVALID_REGNUM, // EMM3L
- LLDB_INVALID_REGNUM, // EMM4L
- LLDB_INVALID_REGNUM, // EMM5L
- LLDB_INVALID_REGNUM, // EMM6L
- LLDB_INVALID_REGNUM, // EMM7L
- LLDB_INVALID_REGNUM, // EMM0H
- LLDB_INVALID_REGNUM, // EMM1H
- LLDB_INVALID_REGNUM, // EMM2H
- LLDB_INVALID_REGNUM, // EMM3H
- LLDB_INVALID_REGNUM, // EMM4H
- LLDB_INVALID_REGNUM, // EMM5H
- LLDB_INVALID_REGNUM, // EMM6H
- LLDB_INVALID_REGNUM, // EMM7H
- LLDB_INVALID_REGNUM, // MM00
- LLDB_INVALID_REGNUM, // MM01
- LLDB_INVALID_REGNUM, // MM10
- LLDB_INVALID_REGNUM, // MM11
- LLDB_INVALID_REGNUM, // MM20
- LLDB_INVALID_REGNUM, // MM21
- LLDB_INVALID_REGNUM, // MM30
- LLDB_INVALID_REGNUM, // MM31
- LLDB_INVALID_REGNUM, // MM40
- LLDB_INVALID_REGNUM, // MM41
- LLDB_INVALID_REGNUM, // MM50
- LLDB_INVALID_REGNUM, // MM51
- LLDB_INVALID_REGNUM, // MM60
- LLDB_INVALID_REGNUM, // MM61
- LLDB_INVALID_REGNUM, // MM70
- LLDB_INVALID_REGNUM, // MM71
- lldb_xmm8_x86_64, // XMM8
- lldb_xmm9_x86_64, // XMM9
- lldb_xmm10_x86_64, // XMM10
- lldb_xmm11_x86_64, // XMM11
- lldb_xmm12_x86_64, // XMM12
- lldb_xmm13_x86_64, // XMM13
- lldb_xmm14_x86_64, // XMM14
- lldb_xmm15_x86_64, // XMM15
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM,
- lldb_sil_x86_64, // SIL
- lldb_dil_x86_64, // DIL
- lldb_bpl_x86_64, // BPL
- lldb_spl_x86_64, // SPL
- lldb_rax_x86_64, // RAX
- lldb_rbx_x86_64, // RBX
- lldb_rcx_x86_64, // RCX
- lldb_rdx_x86_64, // RDX
- lldb_rsi_x86_64, // RSI
- lldb_rdi_x86_64, // RDI
- lldb_rbp_x86_64, // RBP
- lldb_rsp_x86_64, // RSP
- lldb_r8_x86_64, // R8
- lldb_r9_x86_64, // R9
- lldb_r10_x86_64, // R10
- lldb_r11_x86_64, // R11
- lldb_r12_x86_64, // R12
- lldb_r13_x86_64, // R13
- lldb_r14_x86_64, // R14
- lldb_r15_x86_64, // R15
- lldb_r8l_x86_64, // R8B
- lldb_r9l_x86_64, // R9B
- lldb_r10l_x86_64, // R10B
- lldb_r11l_x86_64, // R11B
- lldb_r12l_x86_64, // R12B
- lldb_r13l_x86_64, // R13B
- lldb_r14l_x86_64, // R14B
- lldb_r15l_x86_64, // R15B
- lldb_r8w_x86_64, // R8W
- lldb_r9w_x86_64, // R9W
- lldb_r10w_x86_64, // R10W
- lldb_r11w_x86_64, // R11W
- lldb_r12w_x86_64, // R12W
- lldb_r13w_x86_64, // R13W
- lldb_r14w_x86_64, // R14W
- lldb_r15w_x86_64, // R15W
- lldb_r8d_x86_64, // R8D
- lldb_r9d_x86_64, // R9D
- lldb_r10d_x86_64, // R10D
- lldb_r11d_x86_64, // R11D
- lldb_r12d_x86_64, // R12D
- lldb_r13d_x86_64, // R13D
- lldb_r14d_x86_64, // R14D
- lldb_r15d_x86_64, // R15D
- lldb_ymm0_x86_64, // AMD64_YMM0
- lldb_ymm1_x86_64, // AMD64_YMM1
- lldb_ymm2_x86_64, // AMD64_YMM2
- lldb_ymm3_x86_64, // AMD64_YMM3
- lldb_ymm4_x86_64, // AMD64_YMM4
- lldb_ymm5_x86_64, // AMD64_YMM5
- lldb_ymm6_x86_64, // AMD64_YMM6
- lldb_ymm7_x86_64, // AMD64_YMM7
- lldb_ymm8_x86_64, // AMD64_YMM8
- lldb_ymm9_x86_64, // AMD64_YMM9
- lldb_ymm10_x86_64, // AMD64_YMM10
- lldb_ymm11_x86_64, // AMD64_YMM11
- lldb_ymm12_x86_64, // AMD64_YMM12
- lldb_ymm13_x86_64, // AMD64_YMM13
- lldb_ymm14_x86_64, // AMD64_YMM14
- lldb_ymm15_x86_64, // AMD64_YMM15
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- lldb_bnd0_x86_64, // BND0
- lldb_bnd1_x86_64, // BND1
- lldb_bnd2_x86_64 // BND2
-};
-
-uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
- llvm::codeview::RegisterId register_id) {
- switch (arch_type) {
- case llvm::Triple::x86:
- if (static_cast<uint16_t>(register_id) <
- sizeof(g_code_view_to_lldb_registers_x86) /
- sizeof(g_code_view_to_lldb_registers_x86[0]))
- return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>(
- register_id)];
-
- switch (register_id) {
- case llvm::codeview::RegisterId::MXCSR:
- return lldb_mxcsr_i386;
- case llvm::codeview::RegisterId::BND0:
- return lldb_bnd0_i386;
- case llvm::codeview::RegisterId::BND1:
- return lldb_bnd1_i386;
- case llvm::codeview::RegisterId::BND2:
- return lldb_bnd2_i386;
- default:
- return LLDB_INVALID_REGNUM;
- }
- case llvm::Triple::x86_64:
- if (static_cast<uint16_t>(register_id) <
- sizeof(g_code_view_to_lldb_registers_x86_64) /
- sizeof(g_code_view_to_lldb_registers_x86_64[0]))
- return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>(
- register_id)];
+static std::unique_ptr<IPDBFrameData>
+GetCorrespondingFrameData(const IPDBSession &session,
+ const Variable::RangeList &ranges) {
+ auto enumFrameData = session.getFrameData();
+ if (!enumFrameData)
+ return nullptr;
+
+ std::unique_ptr<IPDBFrameData> found;
+ while (auto fd = enumFrameData->getNext()) {
+ Range<lldb::addr_t, lldb::addr_t> fdRange(fd->getVirtualAddress(),
+ fd->getLengthBlock());
+
+ for (size_t i = 0; i < ranges.GetSize(); i++) {
+ auto range = ranges.GetEntryAtIndex(i);
+ if (!range)
+ continue;
- return LLDB_INVALID_REGNUM;
- default:
- return LLDB_INVALID_REGNUM;
- }
-}
+ if (!range->DoesIntersect(fdRange))
+ continue;
-uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
- if (register_id == llvm::codeview::RegisterId::VFRAME)
- return LLDB_REGNUM_GENERIC_FP;
+ found = std::move(fd);
- return LLDB_INVALID_REGNUM;
-}
+ break;
+ }
+ }
-uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
- llvm::codeview::RegisterId register_id,
- RegisterKind &register_kind) {
- register_kind = eRegisterKindLLDB;
- uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
- if (reg_num != LLDB_INVALID_REGNUM)
- return reg_num;
+ return found;
+}
- register_kind = eRegisterKindGeneric;
- return GetGenericRegisterNumber(register_id);
+static bool EmitVFrameEvaluationDWARFExpression(
+ llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
+ // VFrame value always stored in $TO pseudo-register
+ return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
+ stream);
}
-} // namespace
-DWARFExpression ConvertPDBLocationToDWARFExpression(ModuleSP module,
- const PDBSymbolData &symbol,
- bool &is_constant) {
+DWARFExpression ConvertPDBLocationToDWARFExpression(
+ ModuleSP module, const PDBSymbolData &symbol,
+ const Variable::RangeList &ranges, bool &is_constant) {
is_constant = true;
if (!module)
return DWARFExpression(nullptr);
const ArchSpec &architecture = module->GetArchitecture();
llvm::Triple::ArchType arch_type = architecture.GetMachine();
ByteOrder byte_order = architecture.GetByteOrder();
uint32_t address_size = architecture.GetAddressByteSize();
uint32_t byte_size = architecture.GetDataByteSize();
if (byte_order == eByteOrderInvalid || address_size == 0)
return DWARFExpression(nullptr);
RegisterKind register_kind = eRegisterKindDWARF;
StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
switch (symbol.getLocationType()) {
case PDB_LocType::Static:
case PDB_LocType::TLS: {
stream.PutHex8(DW_OP_addr);
SectionList *section_list = module->GetSectionList();
if (!section_list)
return DWARFExpression(nullptr);
uint32_t section_idx = symbol.getAddressSection() - 1;
if (section_idx >= section_list->GetSize())
return DWARFExpression(nullptr);
auto section = section_list->GetSectionAtIndex(section_idx);
if (!section)
return DWARFExpression(nullptr);
uint32_t offset = symbol.getAddressOffset();
stream.PutMaxHex64(section->GetFileAddress() + offset, address_size,
byte_order);
is_constant = false;
break;
}
case PDB_LocType::RegRel: {
- uint32_t reg_num =
- GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind);
- if (reg_num == LLDB_INVALID_REGNUM)
- return DWARFExpression(nullptr);
+ uint32_t reg_num;
+ auto reg_id = symbol.getRegisterId();
+ if (reg_id == llvm::codeview::RegisterId::VFRAME) {
+ if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) {
+ if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type,
+ stream)) {
+ int32_t offset = symbol.getOffset();
+ stream.PutHex8(DW_OP_consts);
+ stream.PutSLEB128(offset);
+ stream.PutHex8(DW_OP_plus);
+
+ register_kind = eRegisterKindLLDB;
+
+ is_constant = false;
+ break;
+ }
+ }
+
+ register_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_FP;
+ } else {
+ register_kind = eRegisterKindLLDB;
+ reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return DWARFExpression(nullptr);
+ }
if (reg_num > 31) {
stream.PutHex8(DW_OP_bregx);
stream.PutULEB128(reg_num);
} else
stream.PutHex8(DW_OP_breg0 + reg_num);
int32_t offset = symbol.getOffset();
stream.PutSLEB128(offset);
is_constant = false;
break;
}
case PDB_LocType::Enregistered: {
- uint32_t reg_num =
- GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind);
+ register_kind = eRegisterKindLLDB;
+ uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId());
if (reg_num == LLDB_INVALID_REGNUM)
return DWARFExpression(nullptr);
if (reg_num > 31) {
stream.PutHex8(DW_OP_regx);
stream.PutULEB128(reg_num);
} else
stream.PutHex8(DW_OP_reg0 + reg_num);
is_constant = false;
break;
}
case PDB_LocType::Constant: {
Variant value = symbol.getValue();
stream.PutRawBytes(&value.Value, sizeof(value.Value),
endian::InlHostByteOrder());
break;
}
default:
return DWARFExpression(nullptr);
}
DataBufferSP buffer =
std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
DataExtractor extractor(buffer, byte_order, address_size, byte_size);
DWARFExpression result(module, extractor, nullptr, 0, buffer->GetByteSize());
result.SetRegisterKind(register_kind);
return result;
}
Index: lldb/trunk/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h (revision 352844)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h (revision 352845)
@@ -1,44 +1,49 @@
//===-- PDBLocationToDWARFExpression.h --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_
#define lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_
#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Variable.h"
namespace lldb_private {
class DWARFExpression;
}
namespace llvm {
namespace pdb {
class PDBSymbolData;
}
} // namespace llvm
//------------------------------------------------------------------------------
/// Converts a location information from a PDB symbol to a DWARF expression
///
/// @param[in] module
/// The module \a symbol belongs to.
///
/// @param[in] symbol
/// The symbol with a location information to convert.
///
+/// @param[in] ranges
+/// Ranges where this variable is valid.
+///
/// @param[out] is_constant
/// Set to \b true if the result expression is a constant value data,
/// and \b false if it is a DWARF bytecode.
///
/// @return
/// The DWARF expression corresponding to the location data of \a symbol.
//------------------------------------------------------------------------------
lldb_private::DWARFExpression
ConvertPDBLocationToDWARFExpression(lldb::ModuleSP module,
const llvm::pdb::PDBSymbolData &symbol,
+ const lldb_private::Variable::RangeList &ranges,
bool &is_constant);
#endif
Index: lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp (revision 352844)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp (revision 352845)
@@ -1,1993 +1,2006 @@
//===-- SymbolFilePDB.cpp ---------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "SymbolFilePDB.h"
#include "PDBASTParser.h"
#include "PDBLocationToDWARFExpression.h"
#include "clang/Lex/Lexer.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Utility/RegularExpression.h"
#include "llvm/DebugInfo/PDB/GenericError.h"
#include "llvm/DebugInfo/PDB/IPDBDataStream.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h"
#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
#include "llvm/DebugInfo/PDB/IPDBTable.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
#include "Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h"
#include <regex>
using namespace lldb;
using namespace lldb_private;
using namespace llvm::pdb;
namespace {
lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
switch (lang) {
case PDB_Lang::Cpp:
return lldb::LanguageType::eLanguageTypeC_plus_plus;
case PDB_Lang::C:
return lldb::LanguageType::eLanguageTypeC;
default:
return lldb::LanguageType::eLanguageTypeUnknown;
}
}
bool ShouldAddLine(uint32_t requested_line, uint32_t actual_line,
uint32_t addr_length) {
return ((requested_line == 0 || actual_line == requested_line) &&
addr_length > 0);
}
} // namespace
static bool ShouldUseNativeReader() {
#if defined(_WIN32)
llvm::StringRef use_native = ::getenv("LLDB_USE_NATIVE_PDB_READER");
return use_native.equals_lower("on") || use_native.equals_lower("yes") ||
use_native.equals_lower("1") || use_native.equals_lower("true");
#else
return true;
#endif
}
void SymbolFilePDB::Initialize() {
if (ShouldUseNativeReader()) {
npdb::SymbolFileNativePDB::Initialize();
} else {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance,
DebuggerInitialize);
}
}
void SymbolFilePDB::Terminate() {
if (ShouldUseNativeReader()) {
npdb::SymbolFileNativePDB::Terminate();
} else {
PluginManager::UnregisterPlugin(CreateInstance);
}
}
void SymbolFilePDB::DebuggerInitialize(lldb_private::Debugger &debugger) {}
lldb_private::ConstString SymbolFilePDB::GetPluginNameStatic() {
static ConstString g_name("pdb");
return g_name;
}
const char *SymbolFilePDB::GetPluginDescriptionStatic() {
return "Microsoft PDB debug symbol file reader.";
}
lldb_private::SymbolFile *
SymbolFilePDB::CreateInstance(lldb_private::ObjectFile *obj_file) {
return new SymbolFilePDB(obj_file);
}
SymbolFilePDB::SymbolFilePDB(lldb_private::ObjectFile *object_file)
: SymbolFile(object_file), m_session_up(), m_global_scope_up(),
m_cached_compile_unit_count(0), m_tu_decl_ctx_up() {}
SymbolFilePDB::~SymbolFilePDB() {}
uint32_t SymbolFilePDB::CalculateAbilities() {
uint32_t abilities = 0;
if (!m_obj_file)
return 0;
if (!m_session_up) {
// Lazily load and match the PDB file, but only do this once.
std::string exePath = m_obj_file->GetFileSpec().GetPath();
auto error = loadDataForEXE(PDB_ReaderType::DIA, llvm::StringRef(exePath),
m_session_up);
if (error) {
llvm::consumeError(std::move(error));
auto module_sp = m_obj_file->GetModule();
if (!module_sp)
return 0;
// See if any symbol file is specified through `--symfile` option.
FileSpec symfile = module_sp->GetSymbolFileFileSpec();
if (!symfile)
return 0;
error = loadDataForPDB(PDB_ReaderType::DIA,
llvm::StringRef(symfile.GetPath()), m_session_up);
if (error) {
llvm::consumeError(std::move(error));
return 0;
}
}
}
if (!m_session_up)
return 0;
auto enum_tables_up = m_session_up->getEnumTables();
if (!enum_tables_up)
return 0;
while (auto table_up = enum_tables_up->getNext()) {
if (table_up->getItemCount() == 0)
continue;
auto type = table_up->getTableType();
switch (type) {
case PDB_TableType::Symbols:
// This table represents a store of symbols with types listed in
// PDBSym_Type
abilities |= (CompileUnits | Functions | Blocks | GlobalVariables |
LocalVariables | VariableTypes);
break;
case PDB_TableType::LineNumbers:
abilities |= LineTables;
break;
default:
break;
}
}
return abilities;
}
void SymbolFilePDB::InitializeObject() {
lldb::addr_t obj_load_address = m_obj_file->GetFileOffset();
lldbassert(obj_load_address && obj_load_address != LLDB_INVALID_ADDRESS);
m_session_up->setLoadAddress(obj_load_address);
if (!m_global_scope_up)
m_global_scope_up = m_session_up->getGlobalScope();
lldbassert(m_global_scope_up.get());
TypeSystem *type_system =
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
ClangASTContext *clang_type_system =
llvm::dyn_cast_or_null<ClangASTContext>(type_system);
lldbassert(clang_type_system);
m_tu_decl_ctx_up = llvm::make_unique<CompilerDeclContext>(
type_system, clang_type_system->GetTranslationUnitDecl());
}
uint32_t SymbolFilePDB::GetNumCompileUnits() {
if (m_cached_compile_unit_count == 0) {
auto compilands = m_global_scope_up->findAllChildren<PDBSymbolCompiland>();
if (!compilands)
return 0;
// The linker could link *.dll (compiland language = LINK), or import
// *.dll. For example, a compiland with name `Import:KERNEL32.dll` could be
// found as a child of the global scope (PDB executable). Usually, such
// compilands contain `thunk` symbols in which we are not interested for
// now. However we still count them in the compiland list. If we perform
// any compiland related activity, like finding symbols through
// llvm::pdb::IPDBSession methods, such compilands will all be searched
// automatically no matter whether we include them or not.
m_cached_compile_unit_count = compilands->getChildCount();
// The linker can inject an additional "dummy" compilation unit into the
// PDB. Ignore this special compile unit for our purposes, if it is there.
// It is always the last one.
auto last_compiland_up =
compilands->getChildAtIndex(m_cached_compile_unit_count - 1);
lldbassert(last_compiland_up.get());
std::string name = last_compiland_up->getName();
if (name == "* Linker *")
--m_cached_compile_unit_count;
}
return m_cached_compile_unit_count;
}
void SymbolFilePDB::GetCompileUnitIndex(
const llvm::pdb::PDBSymbolCompiland &pdb_compiland, uint32_t &index) {
auto results_up = m_global_scope_up->findAllChildren<PDBSymbolCompiland>();
if (!results_up)
return;
auto uid = pdb_compiland.getSymIndexId();
for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) {
auto compiland_up = results_up->getChildAtIndex(cu_idx);
if (!compiland_up)
continue;
if (compiland_up->getSymIndexId() == uid) {
index = cu_idx;
return;
}
}
index = UINT32_MAX;
return;
}
std::unique_ptr<llvm::pdb::PDBSymbolCompiland>
SymbolFilePDB::GetPDBCompilandByUID(uint32_t uid) {
return m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(uid);
}
lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) {
if (index >= GetNumCompileUnits())
return CompUnitSP();
// Assuming we always retrieve same compilands listed in same order through
// `PDBSymbolExe::findAllChildren` method, otherwise using `index` to get a
// compile unit makes no sense.
auto results = m_global_scope_up->findAllChildren<PDBSymbolCompiland>();
if (!results)
return CompUnitSP();
auto compiland_up = results->getChildAtIndex(index);
if (!compiland_up)
return CompUnitSP();
return ParseCompileUnitForUID(compiland_up->getSymIndexId(), index);
}
lldb::LanguageType SymbolFilePDB::ParseLanguage(CompileUnit &comp_unit) {
auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
if (!compiland_up)
return lldb::eLanguageTypeUnknown;
auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>();
if (!details)
return lldb::eLanguageTypeUnknown;
return TranslateLanguage(details->getLanguage());
}
lldb_private::Function *
SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc(const PDBSymbolFunc &pdb_func,
CompileUnit &comp_unit) {
if (FunctionSP result = comp_unit.FindFunctionByUID(pdb_func.getSymIndexId()))
return result.get();
auto file_vm_addr = pdb_func.getVirtualAddress();
if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
return nullptr;
auto func_length = pdb_func.getLength();
AddressRange func_range =
AddressRange(file_vm_addr, func_length,
GetObjectFile()->GetModule()->GetSectionList());
if (!func_range.GetBaseAddress().IsValid())
return nullptr;
lldb_private::Type *func_type = ResolveTypeUID(pdb_func.getSymIndexId());
if (!func_type)
return nullptr;
user_id_t func_type_uid = pdb_func.getSignatureId();
Mangled mangled = GetMangledForPDBFunc(pdb_func);
FunctionSP func_sp =
std::make_shared<Function>(&comp_unit, pdb_func.getSymIndexId(),
func_type_uid, mangled, func_type, func_range);
comp_unit.AddFunction(func_sp);
TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
if (!type_system)
return nullptr;
ClangASTContext *clang_type_system =
llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang_type_system)
return nullptr;
clang_type_system->GetPDBParser()->GetDeclForSymbol(pdb_func);
return func_sp.get();
}
size_t SymbolFilePDB::ParseFunctions(CompileUnit &comp_unit) {
size_t func_added = 0;
auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
if (!compiland_up)
return 0;
auto results_up = compiland_up->findAllChildren<PDBSymbolFunc>();
if (!results_up)
return 0;
while (auto pdb_func_up = results_up->getNext()) {
auto func_sp = comp_unit.FindFunctionByUID(pdb_func_up->getSymIndexId());
if (!func_sp) {
if (ParseCompileUnitFunctionForPDBFunc(*pdb_func_up, comp_unit))
++func_added;
}
}
return func_added;
}
bool SymbolFilePDB::ParseLineTable(CompileUnit &comp_unit) {
if (comp_unit.GetLineTable())
return true;
return ParseCompileUnitLineTable(comp_unit, 0);
}
bool SymbolFilePDB::ParseDebugMacros(CompileUnit &comp_unit) {
// PDB doesn't contain information about macros
return false;
}
bool SymbolFilePDB::ParseSupportFiles(
CompileUnit &comp_unit, lldb_private::FileSpecList &support_files) {
// In theory this is unnecessary work for us, because all of this information
// is easily (and quickly) accessible from DebugInfoPDB, so caching it a
// second time seems like a waste. Unfortunately, there's no good way around
// this short of a moderate refactor since SymbolVendor depends on being able
// to cache this list.
auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
if (!compiland_up)
return false;
auto files = m_session_up->getSourceFilesForCompiland(*compiland_up);
if (!files || files->getChildCount() == 0)
return false;
while (auto file = files->getNext()) {
FileSpec spec(file->getFileName(), FileSpec::Style::windows);
support_files.AppendIfUnique(spec);
}
// LLDB uses the DWARF-like file numeration (one based),
// the zeroth file is the compile unit itself
support_files.Insert(0, comp_unit);
return true;
}
bool SymbolFilePDB::ParseImportedModules(
const lldb_private::SymbolContext &sc,
std::vector<lldb_private::ConstString> &imported_modules) {
// PDB does not yet support module debug info
return false;
}
static size_t ParseFunctionBlocksForPDBSymbol(
uint64_t func_file_vm_addr, const llvm::pdb::PDBSymbol *pdb_symbol,
lldb_private::Block *parent_block, bool is_top_parent) {
assert(pdb_symbol && parent_block);
size_t num_added = 0;
switch (pdb_symbol->getSymTag()) {
case PDB_SymType::Block:
case PDB_SymType::Function: {
Block *block = nullptr;
auto &raw_sym = pdb_symbol->getRawSymbol();
if (auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(pdb_symbol)) {
if (pdb_func->hasNoInlineAttribute())
break;
if (is_top_parent)
block = parent_block;
else
break;
} else if (llvm::dyn_cast<PDBSymbolBlock>(pdb_symbol)) {
auto uid = pdb_symbol->getSymIndexId();
if (parent_block->FindBlockByID(uid))
break;
if (raw_sym.getVirtualAddress() < func_file_vm_addr)
break;
auto block_sp = std::make_shared<Block>(pdb_symbol->getSymIndexId());
parent_block->AddChild(block_sp);
block = block_sp.get();
} else
llvm_unreachable("Unexpected PDB symbol!");
block->AddRange(Block::Range(
raw_sym.getVirtualAddress() - func_file_vm_addr, raw_sym.getLength()));
block->FinalizeRanges();
++num_added;
auto results_up = pdb_symbol->findAllChildren();
if (!results_up)
break;
while (auto symbol_up = results_up->getNext()) {
num_added += ParseFunctionBlocksForPDBSymbol(
func_file_vm_addr, symbol_up.get(), block, false);
}
} break;
default:
break;
}
return num_added;
}
size_t SymbolFilePDB::ParseBlocksRecursive(Function &func) {
size_t num_added = 0;
auto uid = func.GetID();
auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid);
if (!pdb_func_up)
return 0;
Block &parent_block = func.GetBlock(false);
num_added = ParseFunctionBlocksForPDBSymbol(
pdb_func_up->getVirtualAddress(), pdb_func_up.get(), &parent_block, true);
return num_added;
}
size_t SymbolFilePDB::ParseTypes(CompileUnit &comp_unit) {
size_t num_added = 0;
auto compiland = GetPDBCompilandByUID(comp_unit.GetID());
if (!compiland)
return 0;
auto ParseTypesByTagFn = [&num_added, this](const PDBSymbol &raw_sym) {
std::unique_ptr<IPDBEnumSymbols> results;
PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef,
PDB_SymType::UDT};
for (auto tag : tags_to_search) {
results = raw_sym.findAllChildren(tag);
if (!results || results->getChildCount() == 0)
continue;
while (auto symbol = results->getNext()) {
switch (symbol->getSymTag()) {
case PDB_SymType::Enum:
case PDB_SymType::UDT:
case PDB_SymType::Typedef:
break;
default:
continue;
}
// This should cause the type to get cached and stored in the `m_types`
// lookup.
if (auto type = ResolveTypeUID(symbol->getSymIndexId())) {
// Resolve the type completely to avoid a completion
// (and so a list change, which causes an iterators invalidation)
// during a TypeList dumping
type->GetFullCompilerType();
++num_added;
}
}
}
};
ParseTypesByTagFn(*compiland);
// Also parse global types particularly coming from this compiland.
// Unfortunately, PDB has no compiland information for each global type. We
// have to parse them all. But ensure we only do this once.
static bool parse_all_global_types = false;
if (!parse_all_global_types) {
ParseTypesByTagFn(*m_global_scope_up);
parse_all_global_types = true;
}
return num_added;
}
size_t
SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) {
if (!sc.comp_unit)
return 0;
size_t num_added = 0;
if (sc.function) {
auto pdb_func = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(
sc.function->GetID());
if (!pdb_func)
return 0;
num_added += ParseVariables(sc, *pdb_func);
sc.function->GetBlock(false).SetDidParseVariables(true, true);
} else if (sc.comp_unit) {
auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID());
if (!compiland)
return 0;
if (sc.comp_unit->GetVariableList(false))
return 0;
auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
if (results && results->getChildCount()) {
while (auto result = results->getNext()) {
auto cu_id = GetCompilandId(*result);
// FIXME: We are not able to determine variable's compile unit.
if (cu_id == 0)
continue;
if (cu_id == sc.comp_unit->GetID())
num_added += ParseVariables(sc, *result);
}
}
// FIXME: A `file static` or `global constant` variable appears both in
// compiland's children and global scope's children with unexpectedly
// different symbol's Id making it ambiguous.
// FIXME: 'local constant', for example, const char var[] = "abc", declared
// in a function scope, can't be found in PDB.
// Parse variables in this compiland.
num_added += ParseVariables(sc, *compiland);
}
return num_added;
}
lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
auto find_result = m_types.find(type_uid);
if (find_result != m_types.end())
return find_result->second.get();
TypeSystem *type_system =
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
ClangASTContext *clang_type_system =
llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang_type_system)
return nullptr;
PDBASTParser *pdb = clang_type_system->GetPDBParser();
if (!pdb)
return nullptr;
auto pdb_type = m_session_up->getSymbolById(type_uid);
if (pdb_type == nullptr)
return nullptr;
lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type);
if (result) {
m_types.insert(std::make_pair(type_uid, result));
auto type_list = GetTypeList();
if (type_list)
type_list->Insert(result);
}
return result.get();
}
llvm::Optional<SymbolFile::ArrayInfo> SymbolFilePDB::GetDynamicArrayInfoForUID(
lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
return llvm::None;
}
bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) {
std::lock_guard<std::recursive_mutex> guard(
GetObjectFile()->GetModule()->GetMutex());
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return false;
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return false;
return pdb->CompleteTypeFromPDB(compiler_type);
}
lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) {
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return CompilerDecl();
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return CompilerDecl();
auto symbol = m_session_up->getSymbolById(uid);
if (!symbol)
return CompilerDecl();
auto decl = pdb->GetDeclForSymbol(*symbol);
if (!decl)
return CompilerDecl();
return CompilerDecl(clang_ast_ctx, decl);
}
lldb_private::CompilerDeclContext
SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) {
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return CompilerDeclContext();
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return CompilerDeclContext();
auto symbol = m_session_up->getSymbolById(uid);
if (!symbol)
return CompilerDeclContext();
auto decl_context = pdb->GetDeclContextForSymbol(*symbol);
if (!decl_context)
return GetDeclContextContainingUID(uid);
return CompilerDeclContext(clang_ast_ctx, decl_context);
}
lldb_private::CompilerDeclContext
SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return CompilerDeclContext();
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return CompilerDeclContext();
auto symbol = m_session_up->getSymbolById(uid);
if (!symbol)
return CompilerDeclContext();
auto decl_context = pdb->GetDeclContextContainingSymbol(*symbol);
assert(decl_context);
return CompilerDeclContext(clang_ast_ctx, decl_context);
}
void SymbolFilePDB::ParseDeclsForContext(
lldb_private::CompilerDeclContext decl_ctx) {
ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
if (!clang_ast_ctx)
return;
PDBASTParser *pdb = clang_ast_ctx->GetPDBParser();
if (!pdb)
return;
pdb->ParseDeclsForDeclContext(
static_cast<clang::DeclContext *>(decl_ctx.GetOpaqueDeclContext()));
}
uint32_t
SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr,
SymbolContextItem resolve_scope,
lldb_private::SymbolContext &sc) {
uint32_t resolved_flags = 0;
if (resolve_scope & eSymbolContextCompUnit ||
resolve_scope & eSymbolContextVariable ||
resolve_scope & eSymbolContextFunction ||
resolve_scope & eSymbolContextBlock ||
resolve_scope & eSymbolContextLineEntry) {
auto cu_sp = GetCompileUnitContainsAddress(so_addr);
if (!cu_sp) {
if (resolved_flags | eSymbolContextVariable) {
// TODO: Resolve variables
}
return 0;
}
sc.comp_unit = cu_sp.get();
resolved_flags |= eSymbolContextCompUnit;
lldbassert(sc.module_sp == cu_sp->GetModule());
}
if (resolve_scope & eSymbolContextFunction ||
resolve_scope & eSymbolContextBlock) {
addr_t file_vm_addr = so_addr.GetFileAddress();
auto symbol_up =
m_session_up->findSymbolByAddress(file_vm_addr, PDB_SymType::Function);
if (symbol_up) {
auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get());
assert(pdb_func);
auto func_uid = pdb_func->getSymIndexId();
sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get();
if (sc.function == nullptr)
sc.function =
ParseCompileUnitFunctionForPDBFunc(*pdb_func, *sc.comp_unit);
if (sc.function) {
resolved_flags |= eSymbolContextFunction;
if (resolve_scope & eSymbolContextBlock) {
auto block_symbol = m_session_up->findSymbolByAddress(
file_vm_addr, PDB_SymType::Block);
auto block_id = block_symbol ? block_symbol->getSymIndexId()
: sc.function->GetID();
sc.block = sc.function->GetBlock(true).FindBlockByID(block_id);
if (sc.block)
resolved_flags |= eSymbolContextBlock;
}
}
}
}
if (resolve_scope & eSymbolContextLineEntry) {
if (auto *line_table = sc.comp_unit->GetLineTable()) {
Address addr(so_addr);
if (line_table->FindLineEntryByAddress(addr, sc.line_entry))
resolved_flags |= eSymbolContextLineEntry;
}
}
return resolved_flags;
}
uint32_t SymbolFilePDB::ResolveSymbolContext(
const lldb_private::FileSpec &file_spec, uint32_t line, bool check_inlines,
SymbolContextItem resolve_scope, lldb_private::SymbolContextList &sc_list) {
const size_t old_size = sc_list.GetSize();
if (resolve_scope & lldb::eSymbolContextCompUnit) {
// Locate all compilation units with line numbers referencing the specified
// file. For example, if `file_spec` is <vector>, then this should return
// all source files and header files that reference <vector>, either
// directly or indirectly.
auto compilands = m_session_up->findCompilandsForSourceFile(
file_spec.GetPath(), PDB_NameSearchFlags::NS_CaseInsensitive);
if (!compilands)
return 0;
// For each one, either find its previously parsed data or parse it afresh
// and add it to the symbol context list.
while (auto compiland = compilands->getNext()) {
// If we're not checking inlines, then don't add line information for
// this file unless the FileSpec matches. For inline functions, we don't
// have to match the FileSpec since they could be defined in headers
// other than file specified in FileSpec.
if (!check_inlines) {
std::string source_file = compiland->getSourceFileFullPath();
if (source_file.empty())
continue;
FileSpec this_spec(source_file, FileSpec::Style::windows);
bool need_full_match = !file_spec.GetDirectory().IsEmpty();
if (FileSpec::Compare(file_spec, this_spec, need_full_match) != 0)
continue;
}
SymbolContext sc;
auto cu = ParseCompileUnitForUID(compiland->getSymIndexId());
if (!cu)
continue;
sc.comp_unit = cu.get();
sc.module_sp = cu->GetModule();
// If we were asked to resolve line entries, add all entries to the line
// table that match the requested line (or all lines if `line` == 0).
if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock |
eSymbolContextLineEntry)) {
bool has_line_table = ParseCompileUnitLineTable(*sc.comp_unit, line);
if ((resolve_scope & eSymbolContextLineEntry) && !has_line_table) {
// The query asks for line entries, but we can't get them for the
// compile unit. This is not normal for `line` = 0. So just assert
// it.
assert(line && "Couldn't get all line entries!\n");
// Current compiland does not have the requested line. Search next.
continue;
}
if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) {
if (!has_line_table)
continue;
auto *line_table = sc.comp_unit->GetLineTable();
lldbassert(line_table);
uint32_t num_line_entries = line_table->GetSize();
// Skip the terminal line entry.
--num_line_entries;
// If `line `!= 0, see if we can resolve function for each line entry
// in the line table.
for (uint32_t line_idx = 0; line && line_idx < num_line_entries;
++line_idx) {
if (!line_table->GetLineEntryAtIndex(line_idx, sc.line_entry))
continue;
auto file_vm_addr =
sc.line_entry.range.GetBaseAddress().GetFileAddress();
if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
continue;
auto symbol_up = m_session_up->findSymbolByAddress(
file_vm_addr, PDB_SymType::Function);
if (symbol_up) {
auto func_uid = symbol_up->getSymIndexId();
sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get();
if (sc.function == nullptr) {
auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get());
assert(pdb_func);
sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func,
*sc.comp_unit);
}
if (sc.function && (resolve_scope & eSymbolContextBlock)) {
Block &block = sc.function->GetBlock(true);
sc.block = block.FindBlockByID(sc.function->GetID());
}
}
sc_list.Append(sc);
}
} else if (has_line_table) {
// We can parse line table for the compile unit. But no query to
// resolve function or block. We append `sc` to the list anyway.
sc_list.Append(sc);
}
} else {
// No query for line entry, function or block. But we have a valid
// compile unit, append `sc` to the list.
sc_list.Append(sc);
}
}
}
return sc_list.GetSize() - old_size;
}
std::string SymbolFilePDB::GetMangledForPDBData(const PDBSymbolData &pdb_data) {
// Cache public names at first
if (m_public_names.empty())
if (auto result_up =
m_global_scope_up->findAllChildren(PDB_SymType::PublicSymbol))
while (auto symbol_up = result_up->getNext())
if (auto addr = symbol_up->getRawSymbol().getVirtualAddress())
m_public_names[addr] = symbol_up->getRawSymbol().getName();
// Look up the name in the cache
return m_public_names.lookup(pdb_data.getVirtualAddress());
}
VariableSP SymbolFilePDB::ParseVariableForPDBData(
const lldb_private::SymbolContext &sc,
const llvm::pdb::PDBSymbolData &pdb_data) {
VariableSP var_sp;
uint32_t var_uid = pdb_data.getSymIndexId();
auto result = m_variables.find(var_uid);
if (result != m_variables.end())
return result->second;
ValueType scope = eValueTypeInvalid;
bool is_static_member = false;
bool is_external = false;
bool is_artificial = false;
switch (pdb_data.getDataKind()) {
case PDB_DataKind::Global:
scope = eValueTypeVariableGlobal;
is_external = true;
break;
case PDB_DataKind::Local:
scope = eValueTypeVariableLocal;
break;
case PDB_DataKind::FileStatic:
scope = eValueTypeVariableStatic;
break;
case PDB_DataKind::StaticMember:
is_static_member = true;
scope = eValueTypeVariableStatic;
break;
case PDB_DataKind::Member:
scope = eValueTypeVariableStatic;
break;
case PDB_DataKind::Param:
scope = eValueTypeVariableArgument;
break;
case PDB_DataKind::Constant:
scope = eValueTypeConstResult;
break;
default:
break;
}
switch (pdb_data.getLocationType()) {
case PDB_LocType::TLS:
scope = eValueTypeVariableThreadLocal;
break;
case PDB_LocType::RegRel: {
// It is a `this` pointer.
if (pdb_data.getDataKind() == PDB_DataKind::ObjectPtr) {
scope = eValueTypeVariableArgument;
is_artificial = true;
}
} break;
default:
break;
}
Declaration decl;
if (!is_artificial && !pdb_data.isCompilerGenerated()) {
if (auto lines = pdb_data.getLineNumbers()) {
if (auto first_line = lines->getNext()) {
uint32_t src_file_id = first_line->getSourceFileId();
auto src_file = m_session_up->getSourceFileById(src_file_id);
if (src_file) {
FileSpec spec(src_file->getFileName());
decl.SetFile(spec);
decl.SetColumn(first_line->getColumnNumber());
decl.SetLine(first_line->getLineNumber());
}
}
}
}
Variable::RangeList ranges;
SymbolContextScope *context_scope = sc.comp_unit;
- if (scope == eValueTypeVariableLocal) {
+ if (scope == eValueTypeVariableLocal || scope == eValueTypeVariableArgument) {
if (sc.function) {
- context_scope = sc.function->GetBlock(true).FindBlockByID(
- pdb_data.getLexicalParentId());
- if (context_scope == nullptr)
- context_scope = sc.function;
+ Block &function_block = sc.function->GetBlock(true);
+ Block *block =
+ function_block.FindBlockByID(pdb_data.getLexicalParentId());
+ if (!block)
+ block = &function_block;
+
+ context_scope = block;
+
+ for (size_t i = 0, num_ranges = block->GetNumRanges(); i < num_ranges;
+ ++i) {
+ AddressRange range;
+ if (!block->GetRangeAtIndex(i, range))
+ continue;
+
+ ranges.Append(range.GetBaseAddress().GetFileAddress(),
+ range.GetByteSize());
+ }
}
}
SymbolFileTypeSP type_sp =
std::make_shared<SymbolFileType>(*this, pdb_data.getTypeId());
auto var_name = pdb_data.getName();
auto mangled = GetMangledForPDBData(pdb_data);
auto mangled_cstr = mangled.empty() ? nullptr : mangled.c_str();
bool is_constant;
DWARFExpression location = ConvertPDBLocationToDWARFExpression(
- GetObjectFile()->GetModule(), pdb_data, is_constant);
+ GetObjectFile()->GetModule(), pdb_data, ranges, is_constant);
var_sp = std::make_shared<Variable>(
var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope,
ranges, &decl, location, is_external, is_artificial, is_static_member);
var_sp->SetLocationIsConstantValueData(is_constant);
m_variables.insert(std::make_pair(var_uid, var_sp));
return var_sp;
}
size_t
SymbolFilePDB::ParseVariables(const lldb_private::SymbolContext &sc,
const llvm::pdb::PDBSymbol &pdb_symbol,
lldb_private::VariableList *variable_list) {
size_t num_added = 0;
if (auto pdb_data = llvm::dyn_cast<PDBSymbolData>(&pdb_symbol)) {
VariableListSP local_variable_list_sp;
auto result = m_variables.find(pdb_data->getSymIndexId());
if (result != m_variables.end()) {
if (variable_list)
variable_list->AddVariableIfUnique(result->second);
} else {
// Prepare right VariableList for this variable.
if (auto lexical_parent = pdb_data->getLexicalParent()) {
switch (lexical_parent->getSymTag()) {
case PDB_SymType::Exe:
assert(sc.comp_unit);
LLVM_FALLTHROUGH;
case PDB_SymType::Compiland: {
if (sc.comp_unit) {
local_variable_list_sp = sc.comp_unit->GetVariableList(false);
if (!local_variable_list_sp) {
local_variable_list_sp = std::make_shared<VariableList>();
sc.comp_unit->SetVariableList(local_variable_list_sp);
}
}
} break;
case PDB_SymType::Block:
case PDB_SymType::Function: {
if (sc.function) {
Block *block = sc.function->GetBlock(true).FindBlockByID(
lexical_parent->getSymIndexId());
if (block) {
local_variable_list_sp = block->GetBlockVariableList(false);
if (!local_variable_list_sp) {
local_variable_list_sp = std::make_shared<VariableList>();
block->SetVariableList(local_variable_list_sp);
}
}
}
} break;
default:
break;
}
}
if (local_variable_list_sp) {
if (auto var_sp = ParseVariableForPDBData(sc, *pdb_data)) {
local_variable_list_sp->AddVariableIfUnique(var_sp);
if (variable_list)
variable_list->AddVariableIfUnique(var_sp);
++num_added;
PDBASTParser *ast = GetPDBAstParser();
if (ast)
ast->GetDeclForSymbol(*pdb_data);
}
}
}
}
if (auto results = pdb_symbol.findAllChildren()) {
while (auto result = results->getNext())
num_added += ParseVariables(sc, *result, variable_list);
}
return num_added;
}
uint32_t SymbolFilePDB::FindGlobalVariables(
const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
uint32_t max_matches, lldb_private::VariableList &variables) {
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
if (name.IsEmpty())
return 0;
auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
if (!results)
return 0;
uint32_t matches = 0;
size_t old_size = variables.GetSize();
while (auto result = results->getNext()) {
auto pdb_data = llvm::dyn_cast<PDBSymbolData>(result.get());
if (max_matches > 0 && matches >= max_matches)
break;
SymbolContext sc;
sc.module_sp = m_obj_file->GetModule();
lldbassert(sc.module_sp.get());
if (!name.GetStringRef().equals(
MSVCUndecoratedNameParser::DropScope(pdb_data->getName())))
continue;
sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get();
// FIXME: We are not able to determine the compile unit.
if (sc.comp_unit == nullptr)
continue;
if (parent_decl_ctx && GetDeclContextContainingUID(
result->getSymIndexId()) != *parent_decl_ctx)
continue;
ParseVariables(sc, *pdb_data, &variables);
matches = variables.GetSize() - old_size;
}
return matches;
}
uint32_t
SymbolFilePDB::FindGlobalVariables(const lldb_private::RegularExpression &regex,
uint32_t max_matches,
lldb_private::VariableList &variables) {
if (!regex.IsValid())
return 0;
auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
if (!results)
return 0;
uint32_t matches = 0;
size_t old_size = variables.GetSize();
while (auto pdb_data = results->getNext()) {
if (max_matches > 0 && matches >= max_matches)
break;
auto var_name = pdb_data->getName();
if (var_name.empty())
continue;
if (!regex.Execute(var_name))
continue;
SymbolContext sc;
sc.module_sp = m_obj_file->GetModule();
lldbassert(sc.module_sp.get());
sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get();
// FIXME: We are not able to determine the compile unit.
if (sc.comp_unit == nullptr)
continue;
ParseVariables(sc, *pdb_data, &variables);
matches = variables.GetSize() - old_size;
}
return matches;
}
bool SymbolFilePDB::ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func,
bool include_inlines,
lldb_private::SymbolContextList &sc_list) {
lldb_private::SymbolContext sc;
sc.comp_unit = ParseCompileUnitForUID(pdb_func.getCompilandId()).get();
if (!sc.comp_unit)
return false;
sc.module_sp = sc.comp_unit->GetModule();
sc.function = ParseCompileUnitFunctionForPDBFunc(pdb_func, *sc.comp_unit);
if (!sc.function)
return false;
sc_list.Append(sc);
return true;
}
bool SymbolFilePDB::ResolveFunction(uint32_t uid, bool include_inlines,
lldb_private::SymbolContextList &sc_list) {
auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid);
if (!pdb_func_up && !(include_inlines && pdb_func_up->hasInlineAttribute()))
return false;
return ResolveFunction(*pdb_func_up, include_inlines, sc_list);
}
void SymbolFilePDB::CacheFunctionNames() {
if (!m_func_full_names.IsEmpty())
return;
std::map<uint64_t, uint32_t> addr_ids;
if (auto results_up = m_global_scope_up->findAllChildren<PDBSymbolFunc>()) {
while (auto pdb_func_up = results_up->getNext()) {
if (pdb_func_up->isCompilerGenerated())
continue;
auto name = pdb_func_up->getName();
auto demangled_name = pdb_func_up->getUndecoratedName();
if (name.empty() && demangled_name.empty())
continue;
auto uid = pdb_func_up->getSymIndexId();
if (!demangled_name.empty() && pdb_func_up->getVirtualAddress())
addr_ids.insert(std::make_pair(pdb_func_up->getVirtualAddress(), uid));
if (auto parent = pdb_func_up->getClassParent()) {
// PDB have symbols for class/struct methods or static methods in Enum
// Class. We won't bother to check if the parent is UDT or Enum here.
m_func_method_names.Append(ConstString(name), uid);
// To search a method name, like NS::Class:MemberFunc, LLDB searches
// its base name, i.e. MemberFunc by default. Since PDBSymbolFunc does
// not have inforamtion of this, we extract base names and cache them
// by our own effort.
llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name);
if (!basename.empty())
m_func_base_names.Append(ConstString(basename), uid);
else {
m_func_base_names.Append(ConstString(name), uid);
}
if (!demangled_name.empty())
m_func_full_names.Append(ConstString(demangled_name), uid);
} else {
// Handle not-method symbols.
// The function name might contain namespace, or its lexical scope.
llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(name);
if (!basename.empty())
m_func_base_names.Append(ConstString(basename), uid);
else
m_func_base_names.Append(ConstString(name), uid);
if (name == "main") {
m_func_full_names.Append(ConstString(name), uid);
if (!demangled_name.empty() && name != demangled_name) {
m_func_full_names.Append(ConstString(demangled_name), uid);
m_func_base_names.Append(ConstString(demangled_name), uid);
}
} else if (!demangled_name.empty()) {
m_func_full_names.Append(ConstString(demangled_name), uid);
} else {
m_func_full_names.Append(ConstString(name), uid);
}
}
}
}
if (auto results_up =
m_global_scope_up->findAllChildren<PDBSymbolPublicSymbol>()) {
while (auto pub_sym_up = results_up->getNext()) {
if (!pub_sym_up->isFunction())
continue;
auto name = pub_sym_up->getName();
if (name.empty())
continue;
if (CPlusPlusLanguage::IsCPPMangledName(name.c_str())) {
auto vm_addr = pub_sym_up->getVirtualAddress();
// PDB public symbol has mangled name for its associated function.
if (vm_addr && addr_ids.find(vm_addr) != addr_ids.end()) {
// Cache mangled name.
m_func_full_names.Append(ConstString(name), addr_ids[vm_addr]);
}
}
}
}
// Sort them before value searching is working properly
m_func_full_names.Sort();
m_func_full_names.SizeToFit();
m_func_method_names.Sort();
m_func_method_names.SizeToFit();
m_func_base_names.Sort();
m_func_base_names.SizeToFit();
}
uint32_t SymbolFilePDB::FindFunctions(
const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
FunctionNameType name_type_mask, bool include_inlines, bool append,
lldb_private::SymbolContextList &sc_list) {
if (!append)
sc_list.Clear();
lldbassert((name_type_mask & eFunctionNameTypeAuto) == 0);
if (name_type_mask == eFunctionNameTypeNone)
return 0;
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
if (name.IsEmpty())
return 0;
auto old_size = sc_list.GetSize();
if (name_type_mask & eFunctionNameTypeFull ||
name_type_mask & eFunctionNameTypeBase ||
name_type_mask & eFunctionNameTypeMethod) {
CacheFunctionNames();
std::set<uint32_t> resolved_ids;
auto ResolveFn = [this, &name, parent_decl_ctx, include_inlines, &sc_list,
&resolved_ids](UniqueCStringMap<uint32_t> &Names) {
std::vector<uint32_t> ids;
if (!Names.GetValues(name, ids))
return;
for (uint32_t id : ids) {
if (resolved_ids.find(id) != resolved_ids.end())
continue;
if (parent_decl_ctx &&
GetDeclContextContainingUID(id) != *parent_decl_ctx)
continue;
if (ResolveFunction(id, include_inlines, sc_list))
resolved_ids.insert(id);
}
};
if (name_type_mask & eFunctionNameTypeFull) {
ResolveFn(m_func_full_names);
ResolveFn(m_func_base_names);
ResolveFn(m_func_method_names);
}
if (name_type_mask & eFunctionNameTypeBase) {
ResolveFn(m_func_base_names);
}
if (name_type_mask & eFunctionNameTypeMethod) {
ResolveFn(m_func_method_names);
}
}
return sc_list.GetSize() - old_size;
}
uint32_t
SymbolFilePDB::FindFunctions(const lldb_private::RegularExpression &regex,
bool include_inlines, bool append,
lldb_private::SymbolContextList &sc_list) {
if (!append)
sc_list.Clear();
if (!regex.IsValid())
return 0;
auto old_size = sc_list.GetSize();
CacheFunctionNames();
std::set<uint32_t> resolved_ids;
auto ResolveFn = [&regex, include_inlines, &sc_list, &resolved_ids,
this](UniqueCStringMap<uint32_t> &Names) {
std::vector<uint32_t> ids;
if (Names.GetValues(regex, ids)) {
for (auto id : ids) {
if (resolved_ids.find(id) == resolved_ids.end())
if (ResolveFunction(id, include_inlines, sc_list))
resolved_ids.insert(id);
}
}
};
ResolveFn(m_func_full_names);
ResolveFn(m_func_base_names);
return sc_list.GetSize() - old_size;
}
void SymbolFilePDB::GetMangledNamesForFunction(
const std::string &scope_qualified_name,
std::vector<lldb_private::ConstString> &mangled_names) {}
void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
std::set<lldb::addr_t> sym_addresses;
for (size_t i = 0; i < symtab.GetNumSymbols(); i++)
sym_addresses.insert(symtab.SymbolAtIndex(i)->GetFileAddress());
auto results = m_global_scope_up->findAllChildren<PDBSymbolPublicSymbol>();
if (!results)
return;
auto section_list = m_obj_file->GetSectionList();
if (!section_list)
return;
while (auto pub_symbol = results->getNext()) {
auto section_idx = pub_symbol->getAddressSection() - 1;
if (section_idx >= section_list->GetSize())
continue;
auto section = section_list->GetSectionAtIndex(section_idx);
if (!section)
continue;
auto offset = pub_symbol->getAddressOffset();
auto file_addr = section->GetFileAddress() + offset;
if (sym_addresses.find(file_addr) != sym_addresses.end())
continue;
sym_addresses.insert(file_addr);
auto size = pub_symbol->getLength();
symtab.AddSymbol(
Symbol(pub_symbol->getSymIndexId(), // symID
pub_symbol->getName().c_str(), // name
true, // name_is_mangled
pub_symbol->isCode() ? eSymbolTypeCode : eSymbolTypeData, // type
true, // external
false, // is_debug
false, // is_trampoline
false, // is_artificial
section, // section_sp
offset, // value
size, // size
size != 0, // size_is_valid
false, // contains_linker_annotations
0 // flags
));
}
symtab.CalculateSymbolSizes();
symtab.Finalize();
}
uint32_t SymbolFilePDB::FindTypes(
const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append,
uint32_t max_matches,
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
lldb_private::TypeMap &types) {
if (!append)
types.Clear();
if (!name)
return 0;
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
searched_symbol_files.clear();
searched_symbol_files.insert(this);
// There is an assumption 'name' is not a regex
FindTypesByName(name.GetStringRef(), parent_decl_ctx, max_matches, types);
return types.GetSize();
}
void SymbolFilePDB::DumpClangAST(Stream &s) {
auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
auto clang = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang)
return;
clang->Dump(s);
}
void SymbolFilePDB::FindTypesByRegex(
const lldb_private::RegularExpression &regex, uint32_t max_matches,
lldb_private::TypeMap &types) {
// When searching by regex, we need to go out of our way to limit the search
// space as much as possible since this searches EVERYTHING in the PDB,
// manually doing regex comparisons. PDB library isn't optimized for regex
// searches or searches across multiple symbol types at the same time, so the
// best we can do is to search enums, then typedefs, then classes one by one,
// and do a regex comparison against each of them.
PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef,
PDB_SymType::UDT};
std::unique_ptr<IPDBEnumSymbols> results;
uint32_t matches = 0;
for (auto tag : tags_to_search) {
results = m_global_scope_up->findAllChildren(tag);
if (!results)
continue;
while (auto result = results->getNext()) {
if (max_matches > 0 && matches >= max_matches)
break;
std::string type_name;
if (auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(result.get()))
type_name = enum_type->getName();
else if (auto typedef_type =
llvm::dyn_cast<PDBSymbolTypeTypedef>(result.get()))
type_name = typedef_type->getName();
else if (auto class_type = llvm::dyn_cast<PDBSymbolTypeUDT>(result.get()))
type_name = class_type->getName();
else {
// We're looking only for types that have names. Skip symbols, as well
// as unnamed types such as arrays, pointers, etc.
continue;
}
if (!regex.Execute(type_name))
continue;
// This should cause the type to get cached and stored in the `m_types`
// lookup.
if (!ResolveTypeUID(result->getSymIndexId()))
continue;
auto iter = m_types.find(result->getSymIndexId());
if (iter == m_types.end())
continue;
types.Insert(iter->second);
++matches;
}
}
}
void SymbolFilePDB::FindTypesByName(
llvm::StringRef name,
const lldb_private::CompilerDeclContext *parent_decl_ctx,
uint32_t max_matches, lldb_private::TypeMap &types) {
std::unique_ptr<IPDBEnumSymbols> results;
if (name.empty())
return;
results = m_global_scope_up->findAllChildren(PDB_SymType::None);
if (!results)
return;
uint32_t matches = 0;
while (auto result = results->getNext()) {
if (max_matches > 0 && matches >= max_matches)
break;
if (MSVCUndecoratedNameParser::DropScope(
result->getRawSymbol().getName()) != name)
continue;
switch (result->getSymTag()) {
case PDB_SymType::Enum:
case PDB_SymType::UDT:
case PDB_SymType::Typedef:
break;
default:
// We're looking only for types that have names. Skip symbols, as well
// as unnamed types such as arrays, pointers, etc.
continue;
}
// This should cause the type to get cached and stored in the `m_types`
// lookup.
if (!ResolveTypeUID(result->getSymIndexId()))
continue;
if (parent_decl_ctx && GetDeclContextContainingUID(
result->getSymIndexId()) != *parent_decl_ctx)
continue;
auto iter = m_types.find(result->getSymIndexId());
if (iter == m_types.end())
continue;
types.Insert(iter->second);
++matches;
}
}
size_t SymbolFilePDB::FindTypes(
const std::vector<lldb_private::CompilerContext> &contexts, bool append,
lldb_private::TypeMap &types) {
return 0;
}
lldb_private::TypeList *SymbolFilePDB::GetTypeList() {
return m_obj_file->GetModule()->GetTypeList();
}
void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol,
uint32_t type_mask,
TypeCollection &type_collection) {
bool can_parse = false;
switch (pdb_symbol.getSymTag()) {
case PDB_SymType::ArrayType:
can_parse = ((type_mask & eTypeClassArray) != 0);
break;
case PDB_SymType::BuiltinType:
can_parse = ((type_mask & eTypeClassBuiltin) != 0);
break;
case PDB_SymType::Enum:
can_parse = ((type_mask & eTypeClassEnumeration) != 0);
break;
case PDB_SymType::Function:
case PDB_SymType::FunctionSig:
can_parse = ((type_mask & eTypeClassFunction) != 0);
break;
case PDB_SymType::PointerType:
can_parse = ((type_mask & (eTypeClassPointer | eTypeClassBlockPointer |
eTypeClassMemberPointer)) != 0);
break;
case PDB_SymType::Typedef:
can_parse = ((type_mask & eTypeClassTypedef) != 0);
break;
case PDB_SymType::UDT: {
auto *udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&pdb_symbol);
assert(udt);
can_parse = (udt->getUdtKind() != PDB_UdtType::Interface &&
((type_mask & (eTypeClassClass | eTypeClassStruct |
eTypeClassUnion)) != 0));
} break;
default:
break;
}
if (can_parse) {
if (auto *type = ResolveTypeUID(pdb_symbol.getSymIndexId())) {
auto result =
std::find(type_collection.begin(), type_collection.end(), type);
if (result == type_collection.end())
type_collection.push_back(type);
}
}
auto results_up = pdb_symbol.findAllChildren();
while (auto symbol_up = results_up->getNext())
GetTypesForPDBSymbol(*symbol_up, type_mask, type_collection);
}
size_t SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,
TypeClass type_mask,
lldb_private::TypeList &type_list) {
TypeCollection type_collection;
uint32_t old_size = type_list.GetSize();
CompileUnit *cu =
sc_scope ? sc_scope->CalculateSymbolContextCompileUnit() : nullptr;
if (cu) {
auto compiland_up = GetPDBCompilandByUID(cu->GetID());
if (!compiland_up)
return 0;
GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection);
} else {
for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) {
auto cu_sp = ParseCompileUnitAtIndex(cu_idx);
if (cu_sp) {
if (auto compiland_up = GetPDBCompilandByUID(cu_sp->GetID()))
GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection);
}
}
}
for (auto type : type_collection) {
type->GetForwardCompilerType();
type_list.Insert(type->shared_from_this());
}
return type_list.GetSize() - old_size;
}
lldb_private::TypeSystem *
SymbolFilePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {
auto type_system =
m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
if (type_system)
type_system->SetSymbolFile(this);
return type_system;
}
PDBASTParser *SymbolFilePDB::GetPDBAstParser() {
auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
auto clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang_type_system)
return nullptr;
return clang_type_system->GetPDBParser();
}
lldb_private::CompilerDeclContext SymbolFilePDB::FindNamespace(
const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx) {
auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
auto clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang_type_system)
return CompilerDeclContext();
PDBASTParser *pdb = clang_type_system->GetPDBParser();
if (!pdb)
return CompilerDeclContext();
clang::DeclContext *decl_context = nullptr;
if (parent_decl_ctx)
decl_context = static_cast<clang::DeclContext *>(
parent_decl_ctx->GetOpaqueDeclContext());
auto namespace_decl =
pdb->FindNamespaceDecl(decl_context, name.GetStringRef());
if (!namespace_decl)
return CompilerDeclContext();
return CompilerDeclContext(type_system,
static_cast<clang::DeclContext *>(namespace_decl));
}
lldb_private::ConstString SymbolFilePDB::GetPluginName() {
static ConstString g_name("pdb");
return g_name;
}
uint32_t SymbolFilePDB::GetPluginVersion() { return 1; }
IPDBSession &SymbolFilePDB::GetPDBSession() { return *m_session_up; }
const IPDBSession &SymbolFilePDB::GetPDBSession() const {
return *m_session_up;
}
lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForUID(uint32_t id,
uint32_t index) {
auto found_cu = m_comp_units.find(id);
if (found_cu != m_comp_units.end())
return found_cu->second;
auto compiland_up = GetPDBCompilandByUID(id);
if (!compiland_up)
return CompUnitSP();
lldb::LanguageType lang;
auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>();
if (!details)
lang = lldb::eLanguageTypeC_plus_plus;
else
lang = TranslateLanguage(details->getLanguage());
if (lang == lldb::LanguageType::eLanguageTypeUnknown)
return CompUnitSP();
std::string path = compiland_up->getSourceFileFullPath();
if (path.empty())
return CompUnitSP();
// Don't support optimized code for now, DebugInfoPDB does not return this
// information.
LazyBool optimized = eLazyBoolNo;
auto cu_sp = std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr,
path.c_str(), id, lang, optimized);
if (!cu_sp)
return CompUnitSP();
m_comp_units.insert(std::make_pair(id, cu_sp));
if (index == UINT32_MAX)
GetCompileUnitIndex(*compiland_up, index);
lldbassert(index != UINT32_MAX);
m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(index,
cu_sp);
return cu_sp;
}
bool SymbolFilePDB::ParseCompileUnitLineTable(CompileUnit &comp_unit,
uint32_t match_line) {
auto compiland_up = GetPDBCompilandByUID(comp_unit.GetID());
if (!compiland_up)
return false;
// LineEntry needs the *index* of the file into the list of support files
// returned by ParseCompileUnitSupportFiles. But the underlying SDK gives us
// a globally unique idenfitifier in the namespace of the PDB. So, we have
// to do a mapping so that we can hand out indices.
llvm::DenseMap<uint32_t, uint32_t> index_map;
BuildSupportFileIdToSupportFileIndexMap(*compiland_up, index_map);
auto line_table = llvm::make_unique<LineTable>(&comp_unit);
// Find contributions to `compiland` from all source and header files.
std::string path = comp_unit.GetPath();
auto files = m_session_up->getSourceFilesForCompiland(*compiland_up);
if (!files)
return false;
// For each source and header file, create a LineSequence for contributions
// to the compiland from that file, and add the sequence.
while (auto file = files->getNext()) {
std::unique_ptr<LineSequence> sequence(
line_table->CreateLineSequenceContainer());
auto lines = m_session_up->findLineNumbers(*compiland_up, *file);
if (!lines)
continue;
int entry_count = lines->getChildCount();
uint64_t prev_addr;
uint32_t prev_length;
uint32_t prev_line;
uint32_t prev_source_idx;
for (int i = 0; i < entry_count; ++i) {
auto line = lines->getChildAtIndex(i);
uint64_t lno = line->getLineNumber();
uint64_t addr = line->getVirtualAddress();
uint32_t length = line->getLength();
uint32_t source_id = line->getSourceFileId();
uint32_t col = line->getColumnNumber();
uint32_t source_idx = index_map[source_id];
// There was a gap between the current entry and the previous entry if
// the addresses don't perfectly line up.
bool is_gap = (i > 0) && (prev_addr + prev_length < addr);
// Before inserting the current entry, insert a terminal entry at the end
// of the previous entry's address range if the current entry resulted in
// a gap from the previous entry.
if (is_gap && ShouldAddLine(match_line, prev_line, prev_length)) {
line_table->AppendLineEntryToSequence(
sequence.get(), prev_addr + prev_length, prev_line, 0,
prev_source_idx, false, false, false, false, true);
line_table->InsertSequence(sequence.release());
sequence.reset(line_table->CreateLineSequenceContainer());
}
if (ShouldAddLine(match_line, lno, length)) {
bool is_statement = line->isStatement();
bool is_prologue = false;
bool is_epilogue = false;
auto func =
m_session_up->findSymbolByAddress(addr, PDB_SymType::Function);
if (func) {
auto prologue = func->findOneChild<PDBSymbolFuncDebugStart>();
if (prologue)
is_prologue = (addr == prologue->getVirtualAddress());
auto epilogue = func->findOneChild<PDBSymbolFuncDebugEnd>();
if (epilogue)
is_epilogue = (addr == epilogue->getVirtualAddress());
}
line_table->AppendLineEntryToSequence(sequence.get(), addr, lno, col,
source_idx, is_statement, false,
is_prologue, is_epilogue, false);
}
prev_addr = addr;
prev_length = length;
prev_line = lno;
prev_source_idx = source_idx;
}
if (entry_count > 0 && ShouldAddLine(match_line, prev_line, prev_length)) {
// The end is always a terminal entry, so insert it regardless.
line_table->AppendLineEntryToSequence(
sequence.get(), prev_addr + prev_length, prev_line, 0,
prev_source_idx, false, false, false, false, true);
}
line_table->InsertSequence(sequence.release());
}
if (line_table->GetSize()) {
comp_unit.SetLineTable(line_table.release());
return true;
}
return false;
}
void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap(
const PDBSymbolCompiland &compiland,
llvm::DenseMap<uint32_t, uint32_t> &index_map) const {
// This is a hack, but we need to convert the source id into an index into
// the support files array. We don't want to do path comparisons to avoid
// basename / full path issues that may or may not even be a problem, so we
// use the globally unique source file identifiers. Ideally we could use the
// global identifiers everywhere, but LineEntry currently assumes indices.
auto source_files = m_session_up->getSourceFilesForCompiland(compiland);
if (!source_files)
return;
// LLDB uses the DWARF-like file numeration (one based)
int index = 1;
while (auto file = source_files->getNext()) {
uint32_t source_id = file->getUniqueId();
index_map[source_id] = index++;
}
}
lldb::CompUnitSP SymbolFilePDB::GetCompileUnitContainsAddress(
const lldb_private::Address &so_addr) {
lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
return nullptr;
// If it is a PDB function's vm addr, this is the first sure bet.
if (auto lines =
m_session_up->findLineNumbersByAddress(file_vm_addr, /*Length=*/1)) {
if (auto first_line = lines->getNext())
return ParseCompileUnitForUID(first_line->getCompilandId());
}
// Otherwise we resort to section contributions.
if (auto sec_contribs = m_session_up->getSectionContribs()) {
while (auto section = sec_contribs->getNext()) {
auto va = section->getVirtualAddress();
if (file_vm_addr >= va && file_vm_addr < va + section->getLength())
return ParseCompileUnitForUID(section->getCompilandId());
}
}
return nullptr;
}
Mangled
SymbolFilePDB::GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func) {
Mangled mangled;
auto func_name = pdb_func.getName();
auto func_undecorated_name = pdb_func.getUndecoratedName();
std::string func_decorated_name;
// Seek from public symbols for non-static function's decorated name if any.
// For static functions, they don't have undecorated names and aren't exposed
// in Public Symbols either.
if (!func_undecorated_name.empty()) {
auto result_up = m_global_scope_up->findChildren(
PDB_SymType::PublicSymbol, func_undecorated_name,
PDB_NameSearchFlags::NS_UndecoratedName);
if (result_up) {
while (auto symbol_up = result_up->getNext()) {
// For a public symbol, it is unique.
lldbassert(result_up->getChildCount() == 1);
if (auto *pdb_public_sym =
llvm::dyn_cast_or_null<PDBSymbolPublicSymbol>(
symbol_up.get())) {
if (pdb_public_sym->isFunction()) {
func_decorated_name = pdb_public_sym->getName();
break;
}
}
}
}
}
if (!func_decorated_name.empty()) {
mangled.SetMangledName(ConstString(func_decorated_name));
// For MSVC, format of C funciton's decorated name depends on calling
// conventon. Unfortunately none of the format is recognized by current
// LLDB. For example, `_purecall` is a __cdecl C function. From PDB,
// `__purecall` is retrieved as both its decorated and undecorated name
// (using PDBSymbolFunc::getUndecoratedName method). However `__purecall`
// string is not treated as mangled in LLDB (neither `?` nor `_Z` prefix).
// Mangled::GetDemangledName method will fail internally and caches an
// empty string as its undecorated name. So we will face a contradition
// here for the same symbol:
// non-empty undecorated name from PDB
// empty undecorated name from LLDB
if (!func_undecorated_name.empty() &&
mangled.GetDemangledName(mangled.GuessLanguage()).IsEmpty())
mangled.SetDemangledName(ConstString(func_undecorated_name));
// LLDB uses several flags to control how a C++ decorated name is
// undecorated for MSVC. See `safeUndecorateName` in Class Mangled. So the
// yielded name could be different from what we retrieve from
// PDB source unless we also apply same flags in getting undecorated
// name through PDBSymbolFunc::getUndecoratedNameEx method.
if (!func_undecorated_name.empty() &&
mangled.GetDemangledName(mangled.GuessLanguage()) !=
ConstString(func_undecorated_name))
mangled.SetDemangledName(ConstString(func_undecorated_name));
} else if (!func_undecorated_name.empty()) {
mangled.SetDemangledName(ConstString(func_undecorated_name));
} else if (!func_name.empty())
mangled.SetValue(ConstString(func_name), false);
return mangled;
}
bool SymbolFilePDB::DeclContextMatchesThisSymbolFile(
const lldb_private::CompilerDeclContext *decl_ctx) {
if (decl_ctx == nullptr || !decl_ctx->IsValid())
return true;
TypeSystem *decl_ctx_type_system = decl_ctx->GetTypeSystem();
if (!decl_ctx_type_system)
return false;
TypeSystem *type_system = GetTypeSystemForLanguage(
decl_ctx_type_system->GetMinimumLanguage(nullptr));
if (decl_ctx_type_system == type_system)
return true; // The type systems match, return true
return false;
}
uint32_t SymbolFilePDB::GetCompilandId(const llvm::pdb::PDBSymbolData &data) {
static const auto pred_upper = [](uint32_t lhs, SecContribInfo rhs) {
return lhs < rhs.Offset;
};
// Cache section contributions
if (m_sec_contribs.empty()) {
if (auto SecContribs = m_session_up->getSectionContribs()) {
while (auto SectionContrib = SecContribs->getNext()) {
auto comp_id = SectionContrib->getCompilandId();
if (!comp_id)
continue;
auto sec = SectionContrib->getAddressSection();
auto &sec_cs = m_sec_contribs[sec];
auto offset = SectionContrib->getAddressOffset();
auto it =
std::upper_bound(sec_cs.begin(), sec_cs.end(), offset, pred_upper);
auto size = SectionContrib->getLength();
sec_cs.insert(it, {offset, size, comp_id});
}
}
}
// Check by line number
if (auto Lines = data.getLineNumbers()) {
if (auto FirstLine = Lines->getNext())
return FirstLine->getCompilandId();
}
// Retrieve section + offset
uint32_t DataSection = data.getAddressSection();
uint32_t DataOffset = data.getAddressOffset();
if (DataSection == 0) {
if (auto RVA = data.getRelativeVirtualAddress())
m_session_up->addressForRVA(RVA, DataSection, DataOffset);
}
if (DataSection) {
// Search by section contributions
auto &sec_cs = m_sec_contribs[DataSection];
auto it =
std::upper_bound(sec_cs.begin(), sec_cs.end(), DataOffset, pred_upper);
if (it != sec_cs.begin()) {
--it;
if (DataOffset < it->Offset + it->Size)
return it->CompilandId;
}
} else {
// Search in lexical tree
auto LexParentId = data.getLexicalParentId();
while (auto LexParent = m_session_up->getSymbolById(LexParentId)) {
if (LexParent->getSymTag() == PDB_SymType::Exe)
break;
if (LexParent->getSymTag() == PDB_SymType::Compiland)
return LexParentId;
LexParentId = LexParent->getRawSymbol().getLexicalParentId();
}
}
return 0;
}
Index: lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt (revision 352844)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/CMakeLists.txt (revision 352845)
@@ -1,16 +1,16 @@
add_lldb_library(lldbPluginSymbolFilePDB PLUGIN
PDBASTParser.cpp
PDBLocationToDWARFExpression.cpp
SymbolFilePDB.cpp
LINK_LIBS
clangAST
clangLex
lldbCore
lldbSymbol
- lldbUtility
+ lldbUtility
lldbPluginSymbolFileNativePDB
LINK_COMPONENTS
DebugInfoPDB
Support
)
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h (revision 352844)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h (revision 352845)
@@ -1,41 +1,44 @@
//===-- DWARFLocationExpression.h -------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
#include "lldb/lldb-forward.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
namespace llvm {
class APSInt;
namespace codeview {
class TypeIndex;
}
namespace pdb {
class TpiStream;
}
} // namespace llvm
namespace lldb_private {
namespace npdb {
DWARFExpression
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,
lldb::ModuleSP module);
DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,
int32_t offset,
lldb::ModuleSP module);
+DWARFExpression MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,
+ int32_t offset,
+ lldb::ModuleSP module);
DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset,
lldb::ModuleSP module);
DWARFExpression MakeConstantLocationExpression(
llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi,
const llvm::APSInt &constant, lldb::ModuleSP module);
} // namespace npdb
} // namespace lldb_private
#endif
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp (revision 0)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp (revision 352845)
@@ -0,0 +1,458 @@
+//===-- CodeViewRegisterMapping.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeViewRegisterMapping.h"
+
+#include "lldb/lldb-defines.h"
+
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+using namespace lldb_private;
+
+static const uint32_t g_code_view_to_lldb_registers_x86[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ lldb_al_i386, // AL
+ lldb_cl_i386, // CL
+ lldb_dl_i386, // DL
+ lldb_bl_i386, // BL
+ lldb_ah_i386, // AH
+ lldb_ch_i386, // CH
+ lldb_dh_i386, // DH
+ lldb_bh_i386, // BH
+ lldb_ax_i386, // AX
+ lldb_cx_i386, // CX
+ lldb_dx_i386, // DX
+ lldb_bx_i386, // BX
+ lldb_sp_i386, // SP
+ lldb_bp_i386, // BP
+ lldb_si_i386, // SI
+ lldb_di_i386, // DI
+ lldb_eax_i386, // EAX
+ lldb_ecx_i386, // ECX
+ lldb_edx_i386, // EDX
+ lldb_ebx_i386, // EBX
+ lldb_esp_i386, // ESP
+ lldb_ebp_i386, // EBP
+ lldb_esi_i386, // ESI
+ lldb_edi_i386, // EDI
+ lldb_es_i386, // ES
+ lldb_cs_i386, // CS
+ lldb_ss_i386, // SS
+ lldb_ds_i386, // DS
+ lldb_fs_i386, // FS
+ lldb_gs_i386, // GS
+ LLDB_INVALID_REGNUM, // IP
+ LLDB_INVALID_REGNUM, // FLAGS
+ lldb_eip_i386, // EIP
+ lldb_eflags_i386, // EFLAGS
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // TEMP
+ LLDB_INVALID_REGNUM, // TEMPH
+ LLDB_INVALID_REGNUM, // QUOTE
+ LLDB_INVALID_REGNUM, // PCDR3
+ LLDB_INVALID_REGNUM, // PCDR4
+ LLDB_INVALID_REGNUM, // PCDR5
+ LLDB_INVALID_REGNUM, // PCDR6
+ LLDB_INVALID_REGNUM, // PCDR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // CR0
+ LLDB_INVALID_REGNUM, // CR1
+ LLDB_INVALID_REGNUM, // CR2
+ LLDB_INVALID_REGNUM, // CR3
+ LLDB_INVALID_REGNUM, // CR4
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_dr0_i386, // DR0
+ lldb_dr1_i386, // DR1
+ lldb_dr2_i386, // DR2
+ lldb_dr3_i386, // DR3
+ lldb_dr4_i386, // DR4
+ lldb_dr5_i386, // DR5
+ lldb_dr6_i386, // DR6
+ lldb_dr7_i386, // DR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // GDTR
+ LLDB_INVALID_REGNUM, // GDTL
+ LLDB_INVALID_REGNUM, // IDTR
+ LLDB_INVALID_REGNUM, // IDTL
+ LLDB_INVALID_REGNUM, // LDTR
+ LLDB_INVALID_REGNUM, // TR
+ LLDB_INVALID_REGNUM, // PSEUDO1
+ LLDB_INVALID_REGNUM, // PSEUDO2
+ LLDB_INVALID_REGNUM, // PSEUDO3
+ LLDB_INVALID_REGNUM, // PSEUDO4
+ LLDB_INVALID_REGNUM, // PSEUDO5
+ LLDB_INVALID_REGNUM, // PSEUDO6
+ LLDB_INVALID_REGNUM, // PSEUDO7
+ LLDB_INVALID_REGNUM, // PSEUDO8
+ LLDB_INVALID_REGNUM, // PSEUDO9
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_st0_i386, // ST0
+ lldb_st1_i386, // ST1
+ lldb_st2_i386, // ST2
+ lldb_st3_i386, // ST3
+ lldb_st4_i386, // ST4
+ lldb_st5_i386, // ST5
+ lldb_st6_i386, // ST6
+ lldb_st7_i386, // ST7
+ LLDB_INVALID_REGNUM, // CTRL
+ LLDB_INVALID_REGNUM, // STAT
+ LLDB_INVALID_REGNUM, // TAG
+ LLDB_INVALID_REGNUM, // FPIP
+ LLDB_INVALID_REGNUM, // FPCS
+ LLDB_INVALID_REGNUM, // FPDO
+ LLDB_INVALID_REGNUM, // FPDS
+ LLDB_INVALID_REGNUM, // ISEM
+ LLDB_INVALID_REGNUM, // FPEIP
+ LLDB_INVALID_REGNUM, // FPEDO
+ lldb_mm0_i386, // MM0
+ lldb_mm1_i386, // MM1
+ lldb_mm2_i386, // MM2
+ lldb_mm3_i386, // MM3
+ lldb_mm4_i386, // MM4
+ lldb_mm5_i386, // MM5
+ lldb_mm6_i386, // MM6
+ lldb_mm7_i386, // MM7
+ lldb_xmm0_i386, // XMM0
+ lldb_xmm1_i386, // XMM1
+ lldb_xmm2_i386, // XMM2
+ lldb_xmm3_i386, // XMM3
+ lldb_xmm4_i386, // XMM4
+ lldb_xmm5_i386, // XMM5
+ lldb_xmm6_i386, // XMM6
+ lldb_xmm7_i386 // XMM7
+};
+
+static const uint32_t g_code_view_to_lldb_registers_x86_64[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ lldb_al_x86_64, // AL
+ lldb_cl_x86_64, // CL
+ lldb_dl_x86_64, // DL
+ lldb_bl_x86_64, // BL
+ lldb_ah_x86_64, // AH
+ lldb_ch_x86_64, // CH
+ lldb_dh_x86_64, // DH
+ lldb_bh_x86_64, // BH
+ lldb_ax_x86_64, // AX
+ lldb_cx_x86_64, // CX
+ lldb_dx_x86_64, // DX
+ lldb_bx_x86_64, // BX
+ lldb_sp_x86_64, // SP
+ lldb_bp_x86_64, // BP
+ lldb_si_x86_64, // SI
+ lldb_di_x86_64, // DI
+ lldb_eax_x86_64, // EAX
+ lldb_ecx_x86_64, // ECX
+ lldb_edx_x86_64, // EDX
+ lldb_ebx_x86_64, // EBX
+ lldb_esp_x86_64, // ESP
+ lldb_ebp_x86_64, // EBP
+ lldb_esi_x86_64, // ESI
+ lldb_edi_x86_64, // EDI
+ lldb_es_x86_64, // ES
+ lldb_cs_x86_64, // CS
+ lldb_ss_x86_64, // SS
+ lldb_ds_x86_64, // DS
+ lldb_fs_x86_64, // FS
+ lldb_gs_x86_64, // GS
+ LLDB_INVALID_REGNUM, // IP
+ LLDB_INVALID_REGNUM, // FLAGS
+ LLDB_INVALID_REGNUM, // EIP
+ LLDB_INVALID_REGNUM, // EFLAGS
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // TEMP
+ LLDB_INVALID_REGNUM, // TEMPH
+ LLDB_INVALID_REGNUM, // QUOTE
+ LLDB_INVALID_REGNUM, // PCDR3
+ LLDB_INVALID_REGNUM, // PCDR4
+ LLDB_INVALID_REGNUM, // PCDR5
+ LLDB_INVALID_REGNUM, // PCDR6
+ LLDB_INVALID_REGNUM, // PCDR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // CR0
+ LLDB_INVALID_REGNUM, // CR1
+ LLDB_INVALID_REGNUM, // CR2
+ LLDB_INVALID_REGNUM, // CR3
+ LLDB_INVALID_REGNUM, // CR4
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_dr0_x86_64, // DR0
+ lldb_dr1_x86_64, // DR1
+ lldb_dr2_x86_64, // DR2
+ lldb_dr3_x86_64, // DR3
+ lldb_dr4_x86_64, // DR4
+ lldb_dr5_x86_64, // DR5
+ lldb_dr6_x86_64, // DR6
+ lldb_dr7_x86_64, // DR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // GDTR
+ LLDB_INVALID_REGNUM, // GDTL
+ LLDB_INVALID_REGNUM, // IDTR
+ LLDB_INVALID_REGNUM, // IDTL
+ LLDB_INVALID_REGNUM, // LDTR
+ LLDB_INVALID_REGNUM, // TR
+ LLDB_INVALID_REGNUM, // PSEUDO1
+ LLDB_INVALID_REGNUM, // PSEUDO2
+ LLDB_INVALID_REGNUM, // PSEUDO3
+ LLDB_INVALID_REGNUM, // PSEUDO4
+ LLDB_INVALID_REGNUM, // PSEUDO5
+ LLDB_INVALID_REGNUM, // PSEUDO6
+ LLDB_INVALID_REGNUM, // PSEUDO7
+ LLDB_INVALID_REGNUM, // PSEUDO8
+ LLDB_INVALID_REGNUM, // PSEUDO9
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_st0_x86_64, // ST0
+ lldb_st1_x86_64, // ST1
+ lldb_st2_x86_64, // ST2
+ lldb_st3_x86_64, // ST3
+ lldb_st4_x86_64, // ST4
+ lldb_st5_x86_64, // ST5
+ lldb_st6_x86_64, // ST6
+ lldb_st7_x86_64, // ST7
+ LLDB_INVALID_REGNUM, // CTRL
+ LLDB_INVALID_REGNUM, // STAT
+ LLDB_INVALID_REGNUM, // TAG
+ LLDB_INVALID_REGNUM, // FPIP
+ LLDB_INVALID_REGNUM, // FPCS
+ LLDB_INVALID_REGNUM, // FPDO
+ LLDB_INVALID_REGNUM, // FPDS
+ LLDB_INVALID_REGNUM, // ISEM
+ LLDB_INVALID_REGNUM, // FPEIP
+ LLDB_INVALID_REGNUM, // FPEDO
+ lldb_mm0_x86_64, // MM0
+ lldb_mm1_x86_64, // MM1
+ lldb_mm2_x86_64, // MM2
+ lldb_mm3_x86_64, // MM3
+ lldb_mm4_x86_64, // MM4
+ lldb_mm5_x86_64, // MM5
+ lldb_mm6_x86_64, // MM6
+ lldb_mm7_x86_64, // MM7
+ lldb_xmm0_x86_64, // XMM0
+ lldb_xmm1_x86_64, // XMM1
+ lldb_xmm2_x86_64, // XMM2
+ lldb_xmm3_x86_64, // XMM3
+ lldb_xmm4_x86_64, // XMM4
+ lldb_xmm5_x86_64, // XMM5
+ lldb_xmm6_x86_64, // XMM6
+ lldb_xmm7_x86_64, // XMM7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ lldb_mxcsr_x86_64, // MXCSR
+ LLDB_INVALID_REGNUM, // EDXEAX
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // EMM0L
+ LLDB_INVALID_REGNUM, // EMM1L
+ LLDB_INVALID_REGNUM, // EMM2L
+ LLDB_INVALID_REGNUM, // EMM3L
+ LLDB_INVALID_REGNUM, // EMM4L
+ LLDB_INVALID_REGNUM, // EMM5L
+ LLDB_INVALID_REGNUM, // EMM6L
+ LLDB_INVALID_REGNUM, // EMM7L
+ LLDB_INVALID_REGNUM, // EMM0H
+ LLDB_INVALID_REGNUM, // EMM1H
+ LLDB_INVALID_REGNUM, // EMM2H
+ LLDB_INVALID_REGNUM, // EMM3H
+ LLDB_INVALID_REGNUM, // EMM4H
+ LLDB_INVALID_REGNUM, // EMM5H
+ LLDB_INVALID_REGNUM, // EMM6H
+ LLDB_INVALID_REGNUM, // EMM7H
+ LLDB_INVALID_REGNUM, // MM00
+ LLDB_INVALID_REGNUM, // MM01
+ LLDB_INVALID_REGNUM, // MM10
+ LLDB_INVALID_REGNUM, // MM11
+ LLDB_INVALID_REGNUM, // MM20
+ LLDB_INVALID_REGNUM, // MM21
+ LLDB_INVALID_REGNUM, // MM30
+ LLDB_INVALID_REGNUM, // MM31
+ LLDB_INVALID_REGNUM, // MM40
+ LLDB_INVALID_REGNUM, // MM41
+ LLDB_INVALID_REGNUM, // MM50
+ LLDB_INVALID_REGNUM, // MM51
+ LLDB_INVALID_REGNUM, // MM60
+ LLDB_INVALID_REGNUM, // MM61
+ LLDB_INVALID_REGNUM, // MM70
+ LLDB_INVALID_REGNUM, // MM71
+ lldb_xmm8_x86_64, // XMM8
+ lldb_xmm9_x86_64, // XMM9
+ lldb_xmm10_x86_64, // XMM10
+ lldb_xmm11_x86_64, // XMM11
+ lldb_xmm12_x86_64, // XMM12
+ lldb_xmm13_x86_64, // XMM13
+ lldb_xmm14_x86_64, // XMM14
+ lldb_xmm15_x86_64, // XMM15
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ lldb_sil_x86_64, // SIL
+ lldb_dil_x86_64, // DIL
+ lldb_bpl_x86_64, // BPL
+ lldb_spl_x86_64, // SPL
+ lldb_rax_x86_64, // RAX
+ lldb_rbx_x86_64, // RBX
+ lldb_rcx_x86_64, // RCX
+ lldb_rdx_x86_64, // RDX
+ lldb_rsi_x86_64, // RSI
+ lldb_rdi_x86_64, // RDI
+ lldb_rbp_x86_64, // RBP
+ lldb_rsp_x86_64, // RSP
+ lldb_r8_x86_64, // R8
+ lldb_r9_x86_64, // R9
+ lldb_r10_x86_64, // R10
+ lldb_r11_x86_64, // R11
+ lldb_r12_x86_64, // R12
+ lldb_r13_x86_64, // R13
+ lldb_r14_x86_64, // R14
+ lldb_r15_x86_64, // R15
+ lldb_r8l_x86_64, // R8B
+ lldb_r9l_x86_64, // R9B
+ lldb_r10l_x86_64, // R10B
+ lldb_r11l_x86_64, // R11B
+ lldb_r12l_x86_64, // R12B
+ lldb_r13l_x86_64, // R13B
+ lldb_r14l_x86_64, // R14B
+ lldb_r15l_x86_64, // R15B
+ lldb_r8w_x86_64, // R8W
+ lldb_r9w_x86_64, // R9W
+ lldb_r10w_x86_64, // R10W
+ lldb_r11w_x86_64, // R11W
+ lldb_r12w_x86_64, // R12W
+ lldb_r13w_x86_64, // R13W
+ lldb_r14w_x86_64, // R14W
+ lldb_r15w_x86_64, // R15W
+ lldb_r8d_x86_64, // R8D
+ lldb_r9d_x86_64, // R9D
+ lldb_r10d_x86_64, // R10D
+ lldb_r11d_x86_64, // R11D
+ lldb_r12d_x86_64, // R12D
+ lldb_r13d_x86_64, // R13D
+ lldb_r14d_x86_64, // R14D
+ lldb_r15d_x86_64, // R15D
+ lldb_ymm0_x86_64, // AMD64_YMM0
+ lldb_ymm1_x86_64, // AMD64_YMM1
+ lldb_ymm2_x86_64, // AMD64_YMM2
+ lldb_ymm3_x86_64, // AMD64_YMM3
+ lldb_ymm4_x86_64, // AMD64_YMM4
+ lldb_ymm5_x86_64, // AMD64_YMM5
+ lldb_ymm6_x86_64, // AMD64_YMM6
+ lldb_ymm7_x86_64, // AMD64_YMM7
+ lldb_ymm8_x86_64, // AMD64_YMM8
+ lldb_ymm9_x86_64, // AMD64_YMM9
+ lldb_ymm10_x86_64, // AMD64_YMM10
+ lldb_ymm11_x86_64, // AMD64_YMM11
+ lldb_ymm12_x86_64, // AMD64_YMM12
+ lldb_ymm13_x86_64, // AMD64_YMM13
+ lldb_ymm14_x86_64, // AMD64_YMM14
+ lldb_ymm15_x86_64, // AMD64_YMM15
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_bnd0_x86_64, // BND0
+ lldb_bnd1_x86_64, // BND1
+ lldb_bnd2_x86_64 // BND2
+};
+
+uint32_t lldb_private::npdb::GetLLDBRegisterNumber(
+ llvm::Triple::ArchType arch_type, llvm::codeview::RegisterId register_id) {
+ switch (arch_type) {
+ case llvm::Triple::x86:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_x86) /
+ sizeof(g_code_view_to_lldb_registers_x86[0]))
+ return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>(
+ register_id)];
+
+ switch (register_id) {
+ case llvm::codeview::RegisterId::MXCSR:
+ return lldb_mxcsr_i386;
+ case llvm::codeview::RegisterId::BND0:
+ return lldb_bnd0_i386;
+ case llvm::codeview::RegisterId::BND1:
+ return lldb_bnd1_i386;
+ case llvm::codeview::RegisterId::BND2:
+ return lldb_bnd2_i386;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ case llvm::Triple::x86_64:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_x86_64) /
+ sizeof(g_code_view_to_lldb_registers_x86_64[0]))
+ return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>(
+ register_id)];
+
+ return LLDB_INVALID_REGNUM;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+}
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h (revision 0)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h (revision 352845)
@@ -0,0 +1,25 @@
+//===-- CodeViewRegisterMapping.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Plugins_SymbolFile_PDB_CodeViewRegisterMapping_h_
+#define lldb_Plugins_SymbolFile_PDB_CodeViewRegisterMapping_h_
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+
+namespace lldb_private {
+namespace npdb {
+
+uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
+ llvm::codeview::RegisterId register_id);
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt (revision 352844)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt (revision 352845)
@@ -1,21 +1,23 @@
add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN
+ CodeViewRegisterMapping.cpp
CompileUnitIndex.cpp
DWARFLocationExpression.cpp
PdbAstBuilder.cpp
+ PdbFPOProgramToDWARFExpression.cpp
PdbIndex.cpp
PdbSymUid.cpp
PdbUtil.cpp
SymbolFileNativePDB.cpp
UdtRecordCompleter.cpp
LINK_LIBS
clangAST
clangLex
lldbCore
lldbSymbol
- lldbUtility
+ lldbUtility
LINK_COMPONENTS
DebugInfoCodeView
DebugInfoPDB
Support
)
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h (revision 352844)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.h (revision 352845)
@@ -1,161 +1,162 @@
//===-- PdbIndex.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H
#define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBINDEX_H
#include "lldb/lldb-types.h"
#include "llvm/ADT/IntervalMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h"
#include "CompileUnitIndex.h"
#include "PdbSymUid.h"
#include <map>
#include <memory>
namespace llvm {
namespace pdb {
class DbiStream;
class TpiStream;
class TpiStream;
class InfoStream;
class PublicsStream;
class GlobalsStream;
class SymbolStream;
} // namespace pdb
} // namespace llvm
namespace lldb_private {
namespace npdb {
struct SegmentOffset;
/// PdbIndex - Lazy access to the important parts of a PDB file.
///
/// This is a layer on top of LLVM's native PDB support libraries which cache
/// certain data when it is accessed the first time. The entire PDB file is
/// mapped into memory, and the underlying support libraries vend out memory
/// that is always backed by the file, so it is safe to hold StringRefs and
/// ArrayRefs into the backing memory as long as the PdbIndex instance is
/// alive.
class PdbIndex {
/// The underlying PDB file.
std::unique_ptr<llvm::pdb::PDBFile> m_file;
/// The DBI stream. This contains general high level information about the
/// features present in the PDB file, compile units (such as the information
/// necessary to locate full symbol information for each compile unit),
/// section contributions, and other data which is not specifically symbol or
/// type records.
llvm::pdb::DbiStream *m_dbi = nullptr;