180814287SRaphael Isemann //===-- DWARFLocationExpression.cpp ---------------------------------------===//
2a93458b0SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a93458b0SZachary Turner //
7a93458b0SZachary Turner //===----------------------------------------------------------------------===//
8a93458b0SZachary Turner 
9a93458b0SZachary Turner #include "DWARFLocationExpression.h"
10a93458b0SZachary Turner 
11a93458b0SZachary Turner #include "lldb/Core/Module.h"
12a93458b0SZachary Turner #include "lldb/Core/Section.h"
13a93458b0SZachary Turner #include "lldb/Core/StreamBuffer.h"
14a93458b0SZachary Turner #include "lldb/Expression/DWARFExpression.h"
15a93458b0SZachary Turner #include "lldb/Utility/ArchSpec.h"
16a93458b0SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
17d3d2b9b8SZachary Turner 
18a93458b0SZachary Turner #include "llvm/BinaryFormat/Dwarf.h"
19a93458b0SZachary Turner #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
20a93458b0SZachary Turner #include "llvm/DebugInfo/CodeView/TypeIndex.h"
21a93458b0SZachary Turner #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
22a93458b0SZachary Turner #include "llvm/Support/Endian.h"
23a93458b0SZachary Turner 
24a93458b0SZachary Turner #include "PdbUtil.h"
25758657e5SAleksandr Urakov #include "CodeViewRegisterMapping.h"
26758657e5SAleksandr Urakov #include "PdbFPOProgramToDWARFExpression.h"
27a93458b0SZachary Turner 
28a93458b0SZachary Turner using namespace lldb;
29a93458b0SZachary Turner using namespace lldb_private;
30a93458b0SZachary Turner using namespace lldb_private::npdb;
31a93458b0SZachary Turner using namespace llvm::codeview;
32a93458b0SZachary Turner using namespace llvm::pdb;
33a93458b0SZachary Turner 
GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)34d3d2b9b8SZachary Turner uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
35d3d2b9b8SZachary Turner   if (register_id == llvm::codeview::RegisterId::VFRAME)
36d3d2b9b8SZachary Turner     return LLDB_REGNUM_GENERIC_FP;
37d3d2b9b8SZachary Turner 
38d3d2b9b8SZachary Turner   return LLDB_INVALID_REGNUM;
39d3d2b9b8SZachary Turner }
40d3d2b9b8SZachary Turner 
GetRegisterNumber(llvm::Triple::ArchType arch_type,llvm::codeview::RegisterId register_id,RegisterKind & register_kind)41d3d2b9b8SZachary Turner static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
42d3d2b9b8SZachary Turner                                   llvm::codeview::RegisterId register_id,
43d3d2b9b8SZachary Turner                                   RegisterKind &register_kind) {
44d3d2b9b8SZachary Turner   register_kind = eRegisterKindLLDB;
45d3d2b9b8SZachary Turner   uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
46d3d2b9b8SZachary Turner   if (reg_num != LLDB_INVALID_REGNUM)
47d3d2b9b8SZachary Turner     return reg_num;
48d3d2b9b8SZachary Turner 
49d3d2b9b8SZachary Turner   register_kind = eRegisterKindGeneric;
50d3d2b9b8SZachary Turner   return GetGenericRegisterNumber(register_id);
51d3d2b9b8SZachary Turner }
52d3d2b9b8SZachary Turner 
IsSimpleTypeSignedInteger(SimpleTypeKind kind)53a93458b0SZachary Turner static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
54a93458b0SZachary Turner   switch (kind) {
55a93458b0SZachary Turner   case SimpleTypeKind::Int128:
56a93458b0SZachary Turner   case SimpleTypeKind::Int64:
57a93458b0SZachary Turner   case SimpleTypeKind::Int64Quad:
58a93458b0SZachary Turner   case SimpleTypeKind::Int32:
59a93458b0SZachary Turner   case SimpleTypeKind::Int32Long:
60a93458b0SZachary Turner   case SimpleTypeKind::Int16:
61a93458b0SZachary Turner   case SimpleTypeKind::Int16Short:
62a93458b0SZachary Turner   case SimpleTypeKind::Float128:
63a93458b0SZachary Turner   case SimpleTypeKind::Float80:
64a93458b0SZachary Turner   case SimpleTypeKind::Float64:
65a93458b0SZachary Turner   case SimpleTypeKind::Float32:
66a93458b0SZachary Turner   case SimpleTypeKind::Float16:
67a93458b0SZachary Turner   case SimpleTypeKind::NarrowCharacter:
68a93458b0SZachary Turner   case SimpleTypeKind::SignedCharacter:
69a93458b0SZachary Turner   case SimpleTypeKind::SByte:
70a93458b0SZachary Turner     return true;
71a93458b0SZachary Turner   default:
72a93458b0SZachary Turner     return false;
73a93458b0SZachary Turner   }
74a93458b0SZachary Turner }
75a93458b0SZachary Turner 
GetIntegralTypeInfo(TypeIndex ti,TpiStream & tpi)76a93458b0SZachary Turner static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
77a93458b0SZachary Turner                                                    TpiStream &tpi) {
78a93458b0SZachary Turner   if (ti.isSimple()) {
79a93458b0SZachary Turner     SimpleTypeKind stk = ti.getSimpleKind();
80a93458b0SZachary Turner     return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
81a93458b0SZachary Turner   }
82a93458b0SZachary Turner 
83a93458b0SZachary Turner   CVType cvt = tpi.getType(ti);
84a93458b0SZachary Turner   switch (cvt.kind()) {
85a93458b0SZachary Turner   case LF_MODIFIER: {
86a93458b0SZachary Turner     ModifierRecord mfr;
87a93458b0SZachary Turner     llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
88a93458b0SZachary Turner     return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
89a93458b0SZachary Turner   }
90a93458b0SZachary Turner   case LF_POINTER: {
91a93458b0SZachary Turner     PointerRecord pr;
92a93458b0SZachary Turner     llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
93a93458b0SZachary Turner     return GetIntegralTypeInfo(pr.ReferentType, tpi);
94a93458b0SZachary Turner   }
95a93458b0SZachary Turner   case LF_ENUM: {
96a93458b0SZachary Turner     EnumRecord er;
97a93458b0SZachary Turner     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
98a93458b0SZachary Turner     return GetIntegralTypeInfo(er.UnderlyingType, tpi);
99a93458b0SZachary Turner   }
100a93458b0SZachary Turner   default:
101a93458b0SZachary Turner     assert(false && "Type is not integral!");
102a93458b0SZachary Turner     return {0, false};
103a93458b0SZachary Turner   }
104a93458b0SZachary Turner }
105a93458b0SZachary Turner 
106a93458b0SZachary Turner template <typename StreamWriter>
MakeLocationExpressionInternal(lldb::ModuleSP module,StreamWriter && writer)107a93458b0SZachary Turner static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
108a93458b0SZachary Turner                                                       StreamWriter &&writer) {
109a93458b0SZachary Turner   const ArchSpec &architecture = module->GetArchitecture();
110a93458b0SZachary Turner   ByteOrder byte_order = architecture.GetByteOrder();
111a93458b0SZachary Turner   uint32_t address_size = architecture.GetAddressByteSize();
112a93458b0SZachary Turner   uint32_t byte_size = architecture.GetDataByteSize();
113a93458b0SZachary Turner   if (byte_order == eByteOrderInvalid || address_size == 0)
11404a087acSJonas Devlieghere     return DWARFExpression();
115a93458b0SZachary Turner 
116a93458b0SZachary Turner   RegisterKind register_kind = eRegisterKindDWARF;
117a93458b0SZachary Turner   StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
118a93458b0SZachary Turner 
119a93458b0SZachary Turner   if (!writer(stream, register_kind))
12004a087acSJonas Devlieghere     return DWARFExpression();
121a93458b0SZachary Turner 
122a93458b0SZachary Turner   DataBufferSP buffer =
123a93458b0SZachary Turner       std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
124a93458b0SZachary Turner   DataExtractor extractor(buffer, byte_order, address_size, byte_size);
125*b74a01a8SZequan Wu   DWARFExpression result(extractor);
126a93458b0SZachary Turner   result.SetRegisterKind(register_kind);
127a93458b0SZachary Turner 
128a93458b0SZachary Turner   return result;
129a93458b0SZachary Turner }
130a93458b0SZachary Turner 
MakeRegisterBasedLocationExpressionInternal(llvm::codeview::RegisterId reg,llvm::Optional<int32_t> relative_offset,lldb::ModuleSP module)131d3d2b9b8SZachary Turner static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
132d3d2b9b8SZachary Turner     llvm::codeview::RegisterId reg, llvm::Optional<int32_t> relative_offset,
133d3d2b9b8SZachary Turner     lldb::ModuleSP module) {
134d3d2b9b8SZachary Turner   return MakeLocationExpressionInternal(
135d3d2b9b8SZachary Turner       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
136d3d2b9b8SZachary Turner         uint32_t reg_num = GetRegisterNumber(
137d3d2b9b8SZachary Turner             module->GetArchitecture().GetMachine(), reg, register_kind);
138d3d2b9b8SZachary Turner         if (reg_num == LLDB_INVALID_REGNUM)
139d3d2b9b8SZachary Turner           return false;
140d3d2b9b8SZachary Turner 
141d3d2b9b8SZachary Turner         if (reg_num > 31) {
142d3d2b9b8SZachary Turner           llvm::dwarf::LocationAtom base = relative_offset
143d3d2b9b8SZachary Turner                                                ? llvm::dwarf::DW_OP_bregx
144d3d2b9b8SZachary Turner                                                : llvm::dwarf::DW_OP_regx;
145d3d2b9b8SZachary Turner           stream.PutHex8(base);
146d3d2b9b8SZachary Turner           stream.PutULEB128(reg_num);
147d3d2b9b8SZachary Turner         } else {
148d3d2b9b8SZachary Turner           llvm::dwarf::LocationAtom base = relative_offset
149d3d2b9b8SZachary Turner                                                ? llvm::dwarf::DW_OP_breg0
150d3d2b9b8SZachary Turner                                                : llvm::dwarf::DW_OP_reg0;
151d3d2b9b8SZachary Turner           stream.PutHex8(base + reg_num);
152d3d2b9b8SZachary Turner         }
153d3d2b9b8SZachary Turner 
154d3d2b9b8SZachary Turner         if (relative_offset)
155d3d2b9b8SZachary Turner           stream.PutSLEB128(*relative_offset);
156d3d2b9b8SZachary Turner 
157d3d2b9b8SZachary Turner         return true;
158d3d2b9b8SZachary Turner       });
159d3d2b9b8SZachary Turner }
160d3d2b9b8SZachary Turner 
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,lldb::ModuleSP module)161d3d2b9b8SZachary Turner DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
162d3d2b9b8SZachary Turner     llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
163d3d2b9b8SZachary Turner   return MakeRegisterBasedLocationExpressionInternal(reg, llvm::None, module);
164d3d2b9b8SZachary Turner }
165d3d2b9b8SZachary Turner 
MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,int32_t offset,lldb::ModuleSP module)166d3d2b9b8SZachary Turner DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
167d3d2b9b8SZachary Turner     llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
168d3d2b9b8SZachary Turner   return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
169d3d2b9b8SZachary Turner }
170d3d2b9b8SZachary Turner 
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)171758657e5SAleksandr Urakov static bool EmitVFrameEvaluationDWARFExpression(
172758657e5SAleksandr Urakov     llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
173758657e5SAleksandr Urakov   // VFrame value always stored in $TO pseudo-register
174758657e5SAleksandr Urakov   return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
175758657e5SAleksandr Urakov                                               stream);
176758657e5SAleksandr Urakov }
177758657e5SAleksandr Urakov 
MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,int32_t offset,lldb::ModuleSP module)178758657e5SAleksandr Urakov DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
179758657e5SAleksandr Urakov     llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
180758657e5SAleksandr Urakov   return MakeLocationExpressionInternal(
181758657e5SAleksandr Urakov       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
182758657e5SAleksandr Urakov         const ArchSpec &architecture = module->GetArchitecture();
183758657e5SAleksandr Urakov 
184758657e5SAleksandr Urakov         if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
185758657e5SAleksandr Urakov                                                  stream))
186758657e5SAleksandr Urakov           return false;
187758657e5SAleksandr Urakov 
188758657e5SAleksandr Urakov         stream.PutHex8(llvm::dwarf::DW_OP_consts);
189758657e5SAleksandr Urakov         stream.PutSLEB128(offset);
190758657e5SAleksandr Urakov         stream.PutHex8(llvm::dwarf::DW_OP_plus);
191758657e5SAleksandr Urakov 
192758657e5SAleksandr Urakov         register_kind = eRegisterKindLLDB;
193758657e5SAleksandr Urakov 
194758657e5SAleksandr Urakov         return true;
195758657e5SAleksandr Urakov       });
196758657e5SAleksandr Urakov }
197758657e5SAleksandr Urakov 
MakeGlobalLocationExpression(uint16_t section,uint32_t offset,ModuleSP module)198a93458b0SZachary Turner DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
199a93458b0SZachary Turner     uint16_t section, uint32_t offset, ModuleSP module) {
200a93458b0SZachary Turner   assert(section > 0);
201a93458b0SZachary Turner   assert(module);
202a93458b0SZachary Turner 
203a93458b0SZachary Turner   return MakeLocationExpressionInternal(
204a93458b0SZachary Turner       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
205a93458b0SZachary Turner         stream.PutHex8(llvm::dwarf::DW_OP_addr);
206a93458b0SZachary Turner 
207a93458b0SZachary Turner         SectionList *section_list = module->GetSectionList();
208a93458b0SZachary Turner         assert(section_list);
209a93458b0SZachary Turner 
2107db8b5c4SPavel Labath         auto section_ptr = section_list->FindSectionByID(section);
211a93458b0SZachary Turner         if (!section_ptr)
212a93458b0SZachary Turner           return false;
213a93458b0SZachary Turner 
214a93458b0SZachary Turner         stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
215a93458b0SZachary Turner                            stream.GetAddressByteSize(), stream.GetByteOrder());
216a93458b0SZachary Turner 
217a93458b0SZachary Turner         return true;
218a93458b0SZachary Turner       });
219a93458b0SZachary Turner }
220a93458b0SZachary Turner 
MakeConstantLocationExpression(TypeIndex underlying_ti,TpiStream & tpi,const llvm::APSInt & constant,ModuleSP module)221a93458b0SZachary Turner DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
222a93458b0SZachary Turner     TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
223a93458b0SZachary Turner     ModuleSP module) {
224a93458b0SZachary Turner   const ArchSpec &architecture = module->GetArchitecture();
225a93458b0SZachary Turner   uint32_t address_size = architecture.GetAddressByteSize();
226a93458b0SZachary Turner 
227a93458b0SZachary Turner   size_t size = 0;
228a93458b0SZachary Turner   bool is_signed = false;
229a93458b0SZachary Turner   std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
230a93458b0SZachary Turner 
231a93458b0SZachary Turner   union {
232a93458b0SZachary Turner     llvm::support::little64_t I;
233a93458b0SZachary Turner     llvm::support::ulittle64_t U;
234a93458b0SZachary Turner   } Value;
235a93458b0SZachary Turner 
236a93458b0SZachary Turner   std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
237a93458b0SZachary Turner   buffer->SetByteSize(size);
238a93458b0SZachary Turner 
239a93458b0SZachary Turner   llvm::ArrayRef<uint8_t> bytes;
240a93458b0SZachary Turner   if (is_signed) {
241a93458b0SZachary Turner     Value.I = constant.getSExtValue();
242a93458b0SZachary Turner   } else {
243a93458b0SZachary Turner     Value.U = constant.getZExtValue();
244a93458b0SZachary Turner   }
245a93458b0SZachary Turner 
246a93458b0SZachary Turner   bytes = llvm::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
247a93458b0SZachary Turner               .take_front(size);
248a93458b0SZachary Turner   buffer->CopyData(bytes.data(), size);
249a93458b0SZachary Turner   DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
250*b74a01a8SZequan Wu   DWARFExpression result(extractor);
251a93458b0SZachary Turner   return result;
252a93458b0SZachary Turner }
2535e9c9b32SZequan Wu 
MakeEnregisteredLocationExpressionForClass(std::map<uint64_t,std::pair<RegisterId,uint32_t>> & members_info,lldb::ModuleSP module)2545e9c9b32SZequan Wu DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpressionForClass(
2552fa27346SZequan Wu     std::map<uint64_t, std::pair<RegisterId, uint32_t>> &members_info,
2565e9c9b32SZequan Wu     lldb::ModuleSP module) {
2575e9c9b32SZequan Wu   return MakeLocationExpressionInternal(
2585e9c9b32SZequan Wu       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
2592fa27346SZequan Wu         for (auto pair : members_info) {
2602fa27346SZequan Wu           std::pair<RegisterId, uint32_t> member_info = pair.second;
2615e9c9b32SZequan Wu           if (member_info.first != llvm::codeview::RegisterId::NONE) {
2625e9c9b32SZequan Wu             uint32_t reg_num =
2635e9c9b32SZequan Wu                 GetRegisterNumber(module->GetArchitecture().GetMachine(),
2645e9c9b32SZequan Wu                                   member_info.first, register_kind);
2655e9c9b32SZequan Wu             if (reg_num == LLDB_INVALID_REGNUM)
2665e9c9b32SZequan Wu               return false;
2675e9c9b32SZequan Wu             if (reg_num > 31) {
2685e9c9b32SZequan Wu               stream.PutHex8(llvm::dwarf::DW_OP_regx);
2695e9c9b32SZequan Wu               stream.PutULEB128(reg_num);
2705e9c9b32SZequan Wu             } else {
2715e9c9b32SZequan Wu               stream.PutHex8(llvm::dwarf::DW_OP_reg0 + reg_num);
2725e9c9b32SZequan Wu             }
2735e9c9b32SZequan Wu           }
2745e9c9b32SZequan Wu           stream.PutHex8(llvm::dwarf::DW_OP_piece);
2755e9c9b32SZequan Wu           stream.PutULEB128(member_info.second);
2765e9c9b32SZequan Wu         }
2775e9c9b32SZequan Wu         return true;
2785e9c9b32SZequan Wu       });
2795e9c9b32SZequan Wu }
280