1cfca06d7SDimitry Andric //===-- DWARFLocationExpression.cpp ---------------------------------------===//
294994d37SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
694994d37SDimitry Andric //
794994d37SDimitry Andric //===----------------------------------------------------------------------===//
894994d37SDimitry Andric
994994d37SDimitry Andric #include "DWARFLocationExpression.h"
1094994d37SDimitry Andric
1194994d37SDimitry Andric #include "lldb/Core/Module.h"
1294994d37SDimitry Andric #include "lldb/Core/Section.h"
1394994d37SDimitry Andric #include "lldb/Expression/DWARFExpression.h"
1494994d37SDimitry Andric #include "lldb/Utility/ArchSpec.h"
1594994d37SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
16b1c73532SDimitry Andric #include "lldb/Utility/StreamBuffer.h"
1794994d37SDimitry Andric
1894994d37SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
1994994d37SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
2094994d37SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndex.h"
2194994d37SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
2294994d37SDimitry Andric #include "llvm/Support/Endian.h"
2394994d37SDimitry Andric
2494994d37SDimitry Andric #include "PdbUtil.h"
255f29bb8aSDimitry Andric #include "CodeViewRegisterMapping.h"
265f29bb8aSDimitry Andric #include "PdbFPOProgramToDWARFExpression.h"
27e3b55780SDimitry Andric #include <optional>
2894994d37SDimitry Andric
2994994d37SDimitry Andric using namespace lldb;
3094994d37SDimitry Andric using namespace lldb_private;
3194994d37SDimitry Andric using namespace lldb_private::npdb;
3294994d37SDimitry Andric using namespace llvm::codeview;
3394994d37SDimitry Andric using namespace llvm::pdb;
3494994d37SDimitry Andric
GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)3594994d37SDimitry Andric uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
3694994d37SDimitry Andric if (register_id == llvm::codeview::RegisterId::VFRAME)
3794994d37SDimitry Andric return LLDB_REGNUM_GENERIC_FP;
3894994d37SDimitry Andric
3994994d37SDimitry Andric return LLDB_INVALID_REGNUM;
4094994d37SDimitry Andric }
4194994d37SDimitry Andric
GetRegisterNumber(llvm::Triple::ArchType arch_type,llvm::codeview::RegisterId register_id,RegisterKind & register_kind)4294994d37SDimitry Andric static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
4394994d37SDimitry Andric llvm::codeview::RegisterId register_id,
4494994d37SDimitry Andric RegisterKind ®ister_kind) {
4594994d37SDimitry Andric register_kind = eRegisterKindLLDB;
4694994d37SDimitry Andric uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
4794994d37SDimitry Andric if (reg_num != LLDB_INVALID_REGNUM)
4894994d37SDimitry Andric return reg_num;
4994994d37SDimitry Andric
5094994d37SDimitry Andric register_kind = eRegisterKindGeneric;
5194994d37SDimitry Andric return GetGenericRegisterNumber(register_id);
5294994d37SDimitry Andric }
5394994d37SDimitry Andric
IsSimpleTypeSignedInteger(SimpleTypeKind kind)5494994d37SDimitry Andric static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
5594994d37SDimitry Andric switch (kind) {
5694994d37SDimitry Andric case SimpleTypeKind::Int128:
5794994d37SDimitry Andric case SimpleTypeKind::Int64:
5894994d37SDimitry Andric case SimpleTypeKind::Int64Quad:
5994994d37SDimitry Andric case SimpleTypeKind::Int32:
6094994d37SDimitry Andric case SimpleTypeKind::Int32Long:
6194994d37SDimitry Andric case SimpleTypeKind::Int16:
6294994d37SDimitry Andric case SimpleTypeKind::Int16Short:
6394994d37SDimitry Andric case SimpleTypeKind::Float128:
6494994d37SDimitry Andric case SimpleTypeKind::Float80:
6594994d37SDimitry Andric case SimpleTypeKind::Float64:
6694994d37SDimitry Andric case SimpleTypeKind::Float32:
6794994d37SDimitry Andric case SimpleTypeKind::Float16:
6894994d37SDimitry Andric case SimpleTypeKind::NarrowCharacter:
6994994d37SDimitry Andric case SimpleTypeKind::SignedCharacter:
7094994d37SDimitry Andric case SimpleTypeKind::SByte:
7194994d37SDimitry Andric return true;
7294994d37SDimitry Andric default:
7394994d37SDimitry Andric return false;
7494994d37SDimitry Andric }
7594994d37SDimitry Andric }
7694994d37SDimitry Andric
GetIntegralTypeInfo(TypeIndex ti,TpiStream & tpi)7794994d37SDimitry Andric static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
7894994d37SDimitry Andric TpiStream &tpi) {
7994994d37SDimitry Andric if (ti.isSimple()) {
8094994d37SDimitry Andric SimpleTypeKind stk = ti.getSimpleKind();
8194994d37SDimitry Andric return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
8294994d37SDimitry Andric }
8394994d37SDimitry Andric
8494994d37SDimitry Andric CVType cvt = tpi.getType(ti);
8594994d37SDimitry Andric switch (cvt.kind()) {
8694994d37SDimitry Andric case LF_MODIFIER: {
8794994d37SDimitry Andric ModifierRecord mfr;
8894994d37SDimitry Andric llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
8994994d37SDimitry Andric return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
9094994d37SDimitry Andric }
9194994d37SDimitry Andric case LF_POINTER: {
9294994d37SDimitry Andric PointerRecord pr;
9394994d37SDimitry Andric llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
9494994d37SDimitry Andric return GetIntegralTypeInfo(pr.ReferentType, tpi);
9594994d37SDimitry Andric }
9694994d37SDimitry Andric case LF_ENUM: {
9794994d37SDimitry Andric EnumRecord er;
9894994d37SDimitry Andric llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
9994994d37SDimitry Andric return GetIntegralTypeInfo(er.UnderlyingType, tpi);
10094994d37SDimitry Andric }
10194994d37SDimitry Andric default:
10294994d37SDimitry Andric assert(false && "Type is not integral!");
10394994d37SDimitry Andric return {0, false};
10494994d37SDimitry Andric }
10594994d37SDimitry Andric }
10694994d37SDimitry Andric
10794994d37SDimitry Andric template <typename StreamWriter>
MakeLocationExpressionInternal(lldb::ModuleSP module,StreamWriter && writer)10894994d37SDimitry Andric static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
10994994d37SDimitry Andric StreamWriter &&writer) {
11094994d37SDimitry Andric const ArchSpec &architecture = module->GetArchitecture();
11194994d37SDimitry Andric ByteOrder byte_order = architecture.GetByteOrder();
11294994d37SDimitry Andric uint32_t address_size = architecture.GetAddressByteSize();
11394994d37SDimitry Andric uint32_t byte_size = architecture.GetDataByteSize();
11494994d37SDimitry Andric if (byte_order == eByteOrderInvalid || address_size == 0)
1155f29bb8aSDimitry Andric return DWARFExpression();
11694994d37SDimitry Andric
11794994d37SDimitry Andric RegisterKind register_kind = eRegisterKindDWARF;
11894994d37SDimitry Andric StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
11994994d37SDimitry Andric
12094994d37SDimitry Andric if (!writer(stream, register_kind))
1215f29bb8aSDimitry Andric return DWARFExpression();
12294994d37SDimitry Andric
12394994d37SDimitry Andric DataBufferSP buffer =
12494994d37SDimitry Andric std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
12594994d37SDimitry Andric DataExtractor extractor(buffer, byte_order, address_size, byte_size);
1261f917f69SDimitry Andric DWARFExpression result(extractor);
12794994d37SDimitry Andric result.SetRegisterKind(register_kind);
12894994d37SDimitry Andric
12994994d37SDimitry Andric return result;
13094994d37SDimitry Andric }
13194994d37SDimitry Andric
MakeRegisterBasedLocationExpressionInternal(Stream & stream,llvm::codeview::RegisterId reg,RegisterKind & register_kind,std::optional<int32_t> relative_offset,lldb::ModuleSP module)132e3b55780SDimitry Andric static bool MakeRegisterBasedLocationExpressionInternal(
133e3b55780SDimitry Andric Stream &stream, llvm::codeview::RegisterId reg, RegisterKind ®ister_kind,
134e3b55780SDimitry Andric std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
135e3b55780SDimitry Andric uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
136e3b55780SDimitry Andric reg, register_kind);
13794994d37SDimitry Andric if (reg_num == LLDB_INVALID_REGNUM)
13894994d37SDimitry Andric return false;
13994994d37SDimitry Andric
14094994d37SDimitry Andric if (reg_num > 31) {
141e3b55780SDimitry Andric llvm::dwarf::LocationAtom base =
142e3b55780SDimitry Andric relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
14394994d37SDimitry Andric stream.PutHex8(base);
14494994d37SDimitry Andric stream.PutULEB128(reg_num);
14594994d37SDimitry Andric } else {
146e3b55780SDimitry Andric llvm::dwarf::LocationAtom base =
147e3b55780SDimitry Andric relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
14894994d37SDimitry Andric stream.PutHex8(base + reg_num);
14994994d37SDimitry Andric }
15094994d37SDimitry Andric
15194994d37SDimitry Andric if (relative_offset)
15294994d37SDimitry Andric stream.PutSLEB128(*relative_offset);
15394994d37SDimitry Andric
15494994d37SDimitry Andric return true;
155e3b55780SDimitry Andric }
156e3b55780SDimitry Andric
MakeRegisterBasedLocationExpressionInternal(llvm::codeview::RegisterId reg,std::optional<int32_t> relative_offset,lldb::ModuleSP module)157e3b55780SDimitry Andric static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
158e3b55780SDimitry Andric llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
159e3b55780SDimitry Andric lldb::ModuleSP module) {
160e3b55780SDimitry Andric return MakeLocationExpressionInternal(
161e3b55780SDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
162e3b55780SDimitry Andric return MakeRegisterBasedLocationExpressionInternal(
163e3b55780SDimitry Andric stream, reg, register_kind, relative_offset, module);
16494994d37SDimitry Andric });
16594994d37SDimitry Andric }
16694994d37SDimitry Andric
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,lldb::ModuleSP module)16794994d37SDimitry Andric DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
16894994d37SDimitry Andric llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
169e3b55780SDimitry Andric return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
17094994d37SDimitry Andric }
17194994d37SDimitry Andric
MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,int32_t offset,lldb::ModuleSP module)17294994d37SDimitry Andric DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
17394994d37SDimitry Andric llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
17494994d37SDimitry Andric return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
17594994d37SDimitry Andric }
17694994d37SDimitry Andric
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)1775f29bb8aSDimitry Andric static bool EmitVFrameEvaluationDWARFExpression(
1785f29bb8aSDimitry Andric llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
1795f29bb8aSDimitry Andric // VFrame value always stored in $TO pseudo-register
1805f29bb8aSDimitry Andric return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
1815f29bb8aSDimitry Andric stream);
1825f29bb8aSDimitry Andric }
1835f29bb8aSDimitry Andric
MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,int32_t offset,lldb::ModuleSP module)1845f29bb8aSDimitry Andric DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
1855f29bb8aSDimitry Andric llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
1865f29bb8aSDimitry Andric return MakeLocationExpressionInternal(
1875f29bb8aSDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
1885f29bb8aSDimitry Andric const ArchSpec &architecture = module->GetArchitecture();
1895f29bb8aSDimitry Andric
1905f29bb8aSDimitry Andric if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
1915f29bb8aSDimitry Andric stream))
1925f29bb8aSDimitry Andric return false;
1935f29bb8aSDimitry Andric
1945f29bb8aSDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_consts);
1955f29bb8aSDimitry Andric stream.PutSLEB128(offset);
1965f29bb8aSDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_plus);
1975f29bb8aSDimitry Andric
1985f29bb8aSDimitry Andric register_kind = eRegisterKindLLDB;
1995f29bb8aSDimitry Andric
2005f29bb8aSDimitry Andric return true;
2015f29bb8aSDimitry Andric });
2025f29bb8aSDimitry Andric }
2035f29bb8aSDimitry Andric
MakeGlobalLocationExpression(uint16_t section,uint32_t offset,ModuleSP module)20494994d37SDimitry Andric DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
20594994d37SDimitry Andric uint16_t section, uint32_t offset, ModuleSP module) {
20694994d37SDimitry Andric assert(section > 0);
20794994d37SDimitry Andric assert(module);
20894994d37SDimitry Andric
20994994d37SDimitry Andric return MakeLocationExpressionInternal(
21094994d37SDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
21194994d37SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_addr);
21294994d37SDimitry Andric
21394994d37SDimitry Andric SectionList *section_list = module->GetSectionList();
21494994d37SDimitry Andric assert(section_list);
21594994d37SDimitry Andric
2165f29bb8aSDimitry Andric auto section_ptr = section_list->FindSectionByID(section);
21794994d37SDimitry Andric if (!section_ptr)
21894994d37SDimitry Andric return false;
21994994d37SDimitry Andric
22094994d37SDimitry Andric stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
22194994d37SDimitry Andric stream.GetAddressByteSize(), stream.GetByteOrder());
22294994d37SDimitry Andric
22394994d37SDimitry Andric return true;
22494994d37SDimitry Andric });
22594994d37SDimitry Andric }
22694994d37SDimitry Andric
MakeConstantLocationExpression(TypeIndex underlying_ti,TpiStream & tpi,const llvm::APSInt & constant,ModuleSP module)22794994d37SDimitry Andric DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
22894994d37SDimitry Andric TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
22994994d37SDimitry Andric ModuleSP module) {
23094994d37SDimitry Andric const ArchSpec &architecture = module->GetArchitecture();
23194994d37SDimitry Andric uint32_t address_size = architecture.GetAddressByteSize();
23294994d37SDimitry Andric
23394994d37SDimitry Andric size_t size = 0;
23494994d37SDimitry Andric bool is_signed = false;
23594994d37SDimitry Andric std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
23694994d37SDimitry Andric
23794994d37SDimitry Andric union {
23894994d37SDimitry Andric llvm::support::little64_t I;
23994994d37SDimitry Andric llvm::support::ulittle64_t U;
24094994d37SDimitry Andric } Value;
24194994d37SDimitry Andric
24294994d37SDimitry Andric std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
24394994d37SDimitry Andric buffer->SetByteSize(size);
24494994d37SDimitry Andric
24594994d37SDimitry Andric llvm::ArrayRef<uint8_t> bytes;
24694994d37SDimitry Andric if (is_signed) {
24794994d37SDimitry Andric Value.I = constant.getSExtValue();
24894994d37SDimitry Andric } else {
24994994d37SDimitry Andric Value.U = constant.getZExtValue();
25094994d37SDimitry Andric }
25194994d37SDimitry Andric
252e3b55780SDimitry Andric bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
25394994d37SDimitry Andric .take_front(size);
25494994d37SDimitry Andric buffer->CopyData(bytes.data(), size);
25594994d37SDimitry Andric DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
2561f917f69SDimitry Andric DWARFExpression result(extractor);
25794994d37SDimitry Andric return result;
25894994d37SDimitry Andric }
259145449b1SDimitry Andric
260e3b55780SDimitry Andric DWARFExpression
MakeEnregisteredLocationExpressionForComposite(const std::map<uint64_t,MemberValLocation> & offset_to_location,std::map<uint64_t,size_t> & offset_to_size,size_t total_size,lldb::ModuleSP module)261e3b55780SDimitry Andric lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
262e3b55780SDimitry Andric const std::map<uint64_t, MemberValLocation> &offset_to_location,
263e3b55780SDimitry Andric std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
264145449b1SDimitry Andric lldb::ModuleSP module) {
265145449b1SDimitry Andric return MakeLocationExpressionInternal(
266145449b1SDimitry Andric module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
267e3b55780SDimitry Andric size_t cur_offset = 0;
268e3b55780SDimitry Andric bool is_simple_type = offset_to_size.empty();
269e3b55780SDimitry Andric // Iterate through offset_to_location because offset_to_size might be
270e3b55780SDimitry Andric // empty if the variable is a simple type.
271e3b55780SDimitry Andric for (const auto &offset_loc : offset_to_location) {
272e3b55780SDimitry Andric if (cur_offset < offset_loc.first) {
273145449b1SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_piece);
274e3b55780SDimitry Andric stream.PutULEB128(offset_loc.first - cur_offset);
275e3b55780SDimitry Andric cur_offset = offset_loc.first;
276e3b55780SDimitry Andric }
277e3b55780SDimitry Andric MemberValLocation loc = offset_loc.second;
278e3b55780SDimitry Andric std::optional<int32_t> offset =
279e3b55780SDimitry Andric loc.is_at_reg ? std::nullopt
280e3b55780SDimitry Andric : std::optional<int32_t>(loc.reg_offset);
281e3b55780SDimitry Andric if (!MakeRegisterBasedLocationExpressionInternal(
282e3b55780SDimitry Andric stream, (RegisterId)loc.reg_id, register_kind, offset,
283e3b55780SDimitry Andric module))
284e3b55780SDimitry Andric return false;
285e3b55780SDimitry Andric if (!is_simple_type) {
286e3b55780SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_piece);
287e3b55780SDimitry Andric stream.PutULEB128(offset_to_size[offset_loc.first]);
288e3b55780SDimitry Andric cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
289e3b55780SDimitry Andric }
290e3b55780SDimitry Andric }
291e3b55780SDimitry Andric // For simple type, it specifies the byte size of the value described by
292e3b55780SDimitry Andric // the previous dwarf expr. For udt, it's the remaining byte size at end
293e3b55780SDimitry Andric // of a struct.
294e3b55780SDimitry Andric if (total_size > cur_offset) {
295e3b55780SDimitry Andric stream.PutHex8(llvm::dwarf::DW_OP_piece);
296e3b55780SDimitry Andric stream.PutULEB128(total_size - cur_offset);
297145449b1SDimitry Andric }
298145449b1SDimitry Andric return true;
299145449b1SDimitry Andric });
300145449b1SDimitry Andric }
301