You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
8.5 KiB
253 lines
8.5 KiB
//===-- DWARFLocationExpression.cpp ---------------------------------------===//
|
|
//
|
|
// 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 "DWARFLocationExpression.h"
|
|
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Core/StreamBuffer.h"
|
|
#include "lldb/Expression/DWARFExpression.h"
|
|
#include "lldb/Utility/ArchSpec.h"
|
|
#include "lldb/Utility/DataBufferHeap.h"
|
|
|
|
#include "llvm/BinaryFormat/Dwarf.h"
|
|
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
|
#include "llvm/Support/Endian.h"
|
|
|
|
#include "PdbUtil.h"
|
|
#include "CodeViewRegisterMapping.h"
|
|
#include "PdbFPOProgramToDWARFExpression.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::npdb;
|
|
using namespace llvm::codeview;
|
|
using namespace llvm::pdb;
|
|
|
|
uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
|
|
if (register_id == llvm::codeview::RegisterId::VFRAME)
|
|
return LLDB_REGNUM_GENERIC_FP;
|
|
|
|
return LLDB_INVALID_REGNUM;
|
|
}
|
|
|
|
static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
|
|
llvm::codeview::RegisterId register_id,
|
|
RegisterKind ®ister_kind) {
|
|
register_kind = eRegisterKindLLDB;
|
|
uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
|
|
if (reg_num != LLDB_INVALID_REGNUM)
|
|
return reg_num;
|
|
|
|
register_kind = eRegisterKindGeneric;
|
|
return GetGenericRegisterNumber(register_id);
|
|
}
|
|
|
|
static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
|
|
switch (kind) {
|
|
case SimpleTypeKind::Int128:
|
|
case SimpleTypeKind::Int64:
|
|
case SimpleTypeKind::Int64Quad:
|
|
case SimpleTypeKind::Int32:
|
|
case SimpleTypeKind::Int32Long:
|
|
case SimpleTypeKind::Int16:
|
|
case SimpleTypeKind::Int16Short:
|
|
case SimpleTypeKind::Float128:
|
|
case SimpleTypeKind::Float80:
|
|
case SimpleTypeKind::Float64:
|
|
case SimpleTypeKind::Float32:
|
|
case SimpleTypeKind::Float16:
|
|
case SimpleTypeKind::NarrowCharacter:
|
|
case SimpleTypeKind::SignedCharacter:
|
|
case SimpleTypeKind::SByte:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
|
|
TpiStream &tpi) {
|
|
if (ti.isSimple()) {
|
|
SimpleTypeKind stk = ti.getSimpleKind();
|
|
return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
|
|
}
|
|
|
|
CVType cvt = tpi.getType(ti);
|
|
switch (cvt.kind()) {
|
|
case LF_MODIFIER: {
|
|
ModifierRecord mfr;
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
|
|
return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
|
|
}
|
|
case LF_POINTER: {
|
|
PointerRecord pr;
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
|
|
return GetIntegralTypeInfo(pr.ReferentType, tpi);
|
|
}
|
|
case LF_ENUM: {
|
|
EnumRecord er;
|
|
llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
|
|
return GetIntegralTypeInfo(er.UnderlyingType, tpi);
|
|
}
|
|
default:
|
|
assert(false && "Type is not integral!");
|
|
return {0, false};
|
|
}
|
|
}
|
|
|
|
template <typename StreamWriter>
|
|
static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
|
|
StreamWriter &&writer) {
|
|
const ArchSpec &architecture = module->GetArchitecture();
|
|
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();
|
|
|
|
RegisterKind register_kind = eRegisterKindDWARF;
|
|
StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
|
|
|
|
if (!writer(stream, register_kind))
|
|
return DWARFExpression();
|
|
|
|
DataBufferSP buffer =
|
|
std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
|
|
DataExtractor extractor(buffer, byte_order, address_size, byte_size);
|
|
DWARFExpression result(module, extractor, nullptr);
|
|
result.SetRegisterKind(register_kind);
|
|
|
|
return result;
|
|
}
|
|
|
|
static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
|
|
llvm::codeview::RegisterId reg, llvm::Optional<int32_t> relative_offset,
|
|
lldb::ModuleSP module) {
|
|
return MakeLocationExpressionInternal(
|
|
module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
|
|
uint32_t reg_num = GetRegisterNumber(
|
|
module->GetArchitecture().GetMachine(), reg, register_kind);
|
|
if (reg_num == LLDB_INVALID_REGNUM)
|
|
return false;
|
|
|
|
if (reg_num > 31) {
|
|
llvm::dwarf::LocationAtom base = relative_offset
|
|
? llvm::dwarf::DW_OP_bregx
|
|
: llvm::dwarf::DW_OP_regx;
|
|
stream.PutHex8(base);
|
|
stream.PutULEB128(reg_num);
|
|
} else {
|
|
llvm::dwarf::LocationAtom base = relative_offset
|
|
? llvm::dwarf::DW_OP_breg0
|
|
: llvm::dwarf::DW_OP_reg0;
|
|
stream.PutHex8(base + reg_num);
|
|
}
|
|
|
|
if (relative_offset)
|
|
stream.PutSLEB128(*relative_offset);
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
|
|
llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
|
|
return MakeRegisterBasedLocationExpressionInternal(reg, llvm::None, module);
|
|
}
|
|
|
|
DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
|
|
llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
|
|
return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
|
|
llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
|
|
return MakeLocationExpressionInternal(
|
|
module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
|
|
const ArchSpec &architecture = module->GetArchitecture();
|
|
|
|
if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
|
|
stream))
|
|
return false;
|
|
|
|
stream.PutHex8(llvm::dwarf::DW_OP_consts);
|
|
stream.PutSLEB128(offset);
|
|
stream.PutHex8(llvm::dwarf::DW_OP_plus);
|
|
|
|
register_kind = eRegisterKindLLDB;
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
|
|
uint16_t section, uint32_t offset, ModuleSP module) {
|
|
assert(section > 0);
|
|
assert(module);
|
|
|
|
return MakeLocationExpressionInternal(
|
|
module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
|
|
stream.PutHex8(llvm::dwarf::DW_OP_addr);
|
|
|
|
SectionList *section_list = module->GetSectionList();
|
|
assert(section_list);
|
|
|
|
auto section_ptr = section_list->FindSectionByID(section);
|
|
if (!section_ptr)
|
|
return false;
|
|
|
|
stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
|
|
stream.GetAddressByteSize(), stream.GetByteOrder());
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
|
|
TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
|
|
ModuleSP module) {
|
|
const ArchSpec &architecture = module->GetArchitecture();
|
|
uint32_t address_size = architecture.GetAddressByteSize();
|
|
|
|
size_t size = 0;
|
|
bool is_signed = false;
|
|
std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
|
|
|
|
union {
|
|
llvm::support::little64_t I;
|
|
llvm::support::ulittle64_t U;
|
|
} Value;
|
|
|
|
std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
|
|
buffer->SetByteSize(size);
|
|
|
|
llvm::ArrayRef<uint8_t> bytes;
|
|
if (is_signed) {
|
|
Value.I = constant.getSExtValue();
|
|
} else {
|
|
Value.U = constant.getZExtValue();
|
|
}
|
|
|
|
bytes = llvm::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
|
|
.take_front(size);
|
|
buffer->CopyData(bytes.data(), size);
|
|
DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
|
|
DWARFExpression result(nullptr, extractor, nullptr);
|
|
return result;
|
|
}
|