xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- DWARFLocationExpression.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "DWARFLocationExpression.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Core/Module.h"
12061da546Spatrick #include "lldb/Core/Section.h"
13061da546Spatrick #include "lldb/Core/StreamBuffer.h"
14061da546Spatrick #include "lldb/Expression/DWARFExpression.h"
15061da546Spatrick #include "lldb/Utility/ArchSpec.h"
16061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
17061da546Spatrick 
18061da546Spatrick #include "llvm/BinaryFormat/Dwarf.h"
19061da546Spatrick #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
20061da546Spatrick #include "llvm/DebugInfo/CodeView/TypeIndex.h"
21061da546Spatrick #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
22061da546Spatrick #include "llvm/Support/Endian.h"
23061da546Spatrick 
24061da546Spatrick #include "PdbUtil.h"
25061da546Spatrick #include "CodeViewRegisterMapping.h"
26061da546Spatrick #include "PdbFPOProgramToDWARFExpression.h"
27*f6aab3d8Srobert #include <optional>
28061da546Spatrick 
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick using namespace lldb_private::npdb;
32061da546Spatrick using namespace llvm::codeview;
33061da546Spatrick using namespace llvm::pdb;
34061da546Spatrick 
GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)35061da546Spatrick uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
36061da546Spatrick   if (register_id == llvm::codeview::RegisterId::VFRAME)
37061da546Spatrick     return LLDB_REGNUM_GENERIC_FP;
38061da546Spatrick 
39061da546Spatrick   return LLDB_INVALID_REGNUM;
40061da546Spatrick }
41061da546Spatrick 
GetRegisterNumber(llvm::Triple::ArchType arch_type,llvm::codeview::RegisterId register_id,RegisterKind & register_kind)42061da546Spatrick static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
43061da546Spatrick                                   llvm::codeview::RegisterId register_id,
44061da546Spatrick                                   RegisterKind &register_kind) {
45061da546Spatrick   register_kind = eRegisterKindLLDB;
46061da546Spatrick   uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
47061da546Spatrick   if (reg_num != LLDB_INVALID_REGNUM)
48061da546Spatrick     return reg_num;
49061da546Spatrick 
50061da546Spatrick   register_kind = eRegisterKindGeneric;
51061da546Spatrick   return GetGenericRegisterNumber(register_id);
52061da546Spatrick }
53061da546Spatrick 
IsSimpleTypeSignedInteger(SimpleTypeKind kind)54061da546Spatrick static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
55061da546Spatrick   switch (kind) {
56061da546Spatrick   case SimpleTypeKind::Int128:
57061da546Spatrick   case SimpleTypeKind::Int64:
58061da546Spatrick   case SimpleTypeKind::Int64Quad:
59061da546Spatrick   case SimpleTypeKind::Int32:
60061da546Spatrick   case SimpleTypeKind::Int32Long:
61061da546Spatrick   case SimpleTypeKind::Int16:
62061da546Spatrick   case SimpleTypeKind::Int16Short:
63061da546Spatrick   case SimpleTypeKind::Float128:
64061da546Spatrick   case SimpleTypeKind::Float80:
65061da546Spatrick   case SimpleTypeKind::Float64:
66061da546Spatrick   case SimpleTypeKind::Float32:
67061da546Spatrick   case SimpleTypeKind::Float16:
68061da546Spatrick   case SimpleTypeKind::NarrowCharacter:
69061da546Spatrick   case SimpleTypeKind::SignedCharacter:
70061da546Spatrick   case SimpleTypeKind::SByte:
71061da546Spatrick     return true;
72061da546Spatrick   default:
73061da546Spatrick     return false;
74061da546Spatrick   }
75061da546Spatrick }
76061da546Spatrick 
GetIntegralTypeInfo(TypeIndex ti,TpiStream & tpi)77061da546Spatrick static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
78061da546Spatrick                                                    TpiStream &tpi) {
79061da546Spatrick   if (ti.isSimple()) {
80061da546Spatrick     SimpleTypeKind stk = ti.getSimpleKind();
81061da546Spatrick     return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
82061da546Spatrick   }
83061da546Spatrick 
84061da546Spatrick   CVType cvt = tpi.getType(ti);
85061da546Spatrick   switch (cvt.kind()) {
86061da546Spatrick   case LF_MODIFIER: {
87061da546Spatrick     ModifierRecord mfr;
88061da546Spatrick     llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
89061da546Spatrick     return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
90061da546Spatrick   }
91061da546Spatrick   case LF_POINTER: {
92061da546Spatrick     PointerRecord pr;
93061da546Spatrick     llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
94061da546Spatrick     return GetIntegralTypeInfo(pr.ReferentType, tpi);
95061da546Spatrick   }
96061da546Spatrick   case LF_ENUM: {
97061da546Spatrick     EnumRecord er;
98061da546Spatrick     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
99061da546Spatrick     return GetIntegralTypeInfo(er.UnderlyingType, tpi);
100061da546Spatrick   }
101061da546Spatrick   default:
102061da546Spatrick     assert(false && "Type is not integral!");
103061da546Spatrick     return {0, false};
104061da546Spatrick   }
105061da546Spatrick }
106061da546Spatrick 
107061da546Spatrick template <typename StreamWriter>
MakeLocationExpressionInternal(lldb::ModuleSP module,StreamWriter && writer)108061da546Spatrick static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
109061da546Spatrick                                                       StreamWriter &&writer) {
110061da546Spatrick   const ArchSpec &architecture = module->GetArchitecture();
111061da546Spatrick   ByteOrder byte_order = architecture.GetByteOrder();
112061da546Spatrick   uint32_t address_size = architecture.GetAddressByteSize();
113061da546Spatrick   uint32_t byte_size = architecture.GetDataByteSize();
114061da546Spatrick   if (byte_order == eByteOrderInvalid || address_size == 0)
115061da546Spatrick     return DWARFExpression();
116061da546Spatrick 
117061da546Spatrick   RegisterKind register_kind = eRegisterKindDWARF;
118061da546Spatrick   StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
119061da546Spatrick 
120061da546Spatrick   if (!writer(stream, register_kind))
121061da546Spatrick     return DWARFExpression();
122061da546Spatrick 
123061da546Spatrick   DataBufferSP buffer =
124061da546Spatrick       std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
125061da546Spatrick   DataExtractor extractor(buffer, byte_order, address_size, byte_size);
126*f6aab3d8Srobert   DWARFExpression result(extractor);
127061da546Spatrick   result.SetRegisterKind(register_kind);
128061da546Spatrick 
129061da546Spatrick   return result;
130061da546Spatrick }
131061da546Spatrick 
MakeRegisterBasedLocationExpressionInternal(Stream & stream,llvm::codeview::RegisterId reg,RegisterKind & register_kind,std::optional<int32_t> relative_offset,lldb::ModuleSP module)132*f6aab3d8Srobert static bool MakeRegisterBasedLocationExpressionInternal(
133*f6aab3d8Srobert     Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
134*f6aab3d8Srobert     std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
135*f6aab3d8Srobert   uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
136*f6aab3d8Srobert                                        reg, register_kind);
137061da546Spatrick   if (reg_num == LLDB_INVALID_REGNUM)
138061da546Spatrick     return false;
139061da546Spatrick 
140061da546Spatrick   if (reg_num > 31) {
141*f6aab3d8Srobert     llvm::dwarf::LocationAtom base =
142*f6aab3d8Srobert         relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
143061da546Spatrick     stream.PutHex8(base);
144061da546Spatrick     stream.PutULEB128(reg_num);
145061da546Spatrick   } else {
146*f6aab3d8Srobert     llvm::dwarf::LocationAtom base =
147*f6aab3d8Srobert         relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
148061da546Spatrick     stream.PutHex8(base + reg_num);
149061da546Spatrick   }
150061da546Spatrick 
151061da546Spatrick   if (relative_offset)
152061da546Spatrick     stream.PutSLEB128(*relative_offset);
153061da546Spatrick 
154061da546Spatrick   return true;
155*f6aab3d8Srobert }
156*f6aab3d8Srobert 
MakeRegisterBasedLocationExpressionInternal(llvm::codeview::RegisterId reg,std::optional<int32_t> relative_offset,lldb::ModuleSP module)157*f6aab3d8Srobert static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
158*f6aab3d8Srobert     llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
159*f6aab3d8Srobert     lldb::ModuleSP module) {
160*f6aab3d8Srobert   return MakeLocationExpressionInternal(
161*f6aab3d8Srobert       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
162*f6aab3d8Srobert         return MakeRegisterBasedLocationExpressionInternal(
163*f6aab3d8Srobert             stream, reg, register_kind, relative_offset, module);
164061da546Spatrick       });
165061da546Spatrick }
166061da546Spatrick 
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,lldb::ModuleSP module)167061da546Spatrick DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
168061da546Spatrick     llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
169*f6aab3d8Srobert   return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
170061da546Spatrick }
171061da546Spatrick 
MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,int32_t offset,lldb::ModuleSP module)172061da546Spatrick DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
173061da546Spatrick     llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
174061da546Spatrick   return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
175061da546Spatrick }
176061da546Spatrick 
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)177061da546Spatrick static bool EmitVFrameEvaluationDWARFExpression(
178061da546Spatrick     llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
179061da546Spatrick   // VFrame value always stored in $TO pseudo-register
180061da546Spatrick   return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
181061da546Spatrick                                               stream);
182061da546Spatrick }
183061da546Spatrick 
MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,int32_t offset,lldb::ModuleSP module)184061da546Spatrick DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
185061da546Spatrick     llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
186061da546Spatrick   return MakeLocationExpressionInternal(
187061da546Spatrick       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
188061da546Spatrick         const ArchSpec &architecture = module->GetArchitecture();
189061da546Spatrick 
190061da546Spatrick         if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
191061da546Spatrick                                                  stream))
192061da546Spatrick           return false;
193061da546Spatrick 
194061da546Spatrick         stream.PutHex8(llvm::dwarf::DW_OP_consts);
195061da546Spatrick         stream.PutSLEB128(offset);
196061da546Spatrick         stream.PutHex8(llvm::dwarf::DW_OP_plus);
197061da546Spatrick 
198061da546Spatrick         register_kind = eRegisterKindLLDB;
199061da546Spatrick 
200061da546Spatrick         return true;
201061da546Spatrick       });
202061da546Spatrick }
203061da546Spatrick 
MakeGlobalLocationExpression(uint16_t section,uint32_t offset,ModuleSP module)204061da546Spatrick DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
205061da546Spatrick     uint16_t section, uint32_t offset, ModuleSP module) {
206061da546Spatrick   assert(section > 0);
207061da546Spatrick   assert(module);
208061da546Spatrick 
209061da546Spatrick   return MakeLocationExpressionInternal(
210061da546Spatrick       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
211061da546Spatrick         stream.PutHex8(llvm::dwarf::DW_OP_addr);
212061da546Spatrick 
213061da546Spatrick         SectionList *section_list = module->GetSectionList();
214061da546Spatrick         assert(section_list);
215061da546Spatrick 
216061da546Spatrick         auto section_ptr = section_list->FindSectionByID(section);
217061da546Spatrick         if (!section_ptr)
218061da546Spatrick           return false;
219061da546Spatrick 
220061da546Spatrick         stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
221061da546Spatrick                            stream.GetAddressByteSize(), stream.GetByteOrder());
222061da546Spatrick 
223061da546Spatrick         return true;
224061da546Spatrick       });
225061da546Spatrick }
226061da546Spatrick 
MakeConstantLocationExpression(TypeIndex underlying_ti,TpiStream & tpi,const llvm::APSInt & constant,ModuleSP module)227061da546Spatrick DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
228061da546Spatrick     TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
229061da546Spatrick     ModuleSP module) {
230061da546Spatrick   const ArchSpec &architecture = module->GetArchitecture();
231061da546Spatrick   uint32_t address_size = architecture.GetAddressByteSize();
232061da546Spatrick 
233061da546Spatrick   size_t size = 0;
234061da546Spatrick   bool is_signed = false;
235061da546Spatrick   std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
236061da546Spatrick 
237061da546Spatrick   union {
238061da546Spatrick     llvm::support::little64_t I;
239061da546Spatrick     llvm::support::ulittle64_t U;
240061da546Spatrick   } Value;
241061da546Spatrick 
242061da546Spatrick   std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
243061da546Spatrick   buffer->SetByteSize(size);
244061da546Spatrick 
245061da546Spatrick   llvm::ArrayRef<uint8_t> bytes;
246061da546Spatrick   if (is_signed) {
247061da546Spatrick     Value.I = constant.getSExtValue();
248061da546Spatrick   } else {
249061da546Spatrick     Value.U = constant.getZExtValue();
250061da546Spatrick   }
251061da546Spatrick 
252*f6aab3d8Srobert   bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
253061da546Spatrick               .take_front(size);
254061da546Spatrick   buffer->CopyData(bytes.data(), size);
255061da546Spatrick   DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
256*f6aab3d8Srobert   DWARFExpression result(extractor);
257061da546Spatrick   return result;
258061da546Spatrick }
259*f6aab3d8Srobert 
260*f6aab3d8Srobert 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)261*f6aab3d8Srobert lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
262*f6aab3d8Srobert     const std::map<uint64_t, MemberValLocation> &offset_to_location,
263*f6aab3d8Srobert     std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
264*f6aab3d8Srobert     lldb::ModuleSP module) {
265*f6aab3d8Srobert   return MakeLocationExpressionInternal(
266*f6aab3d8Srobert       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
267*f6aab3d8Srobert         size_t cur_offset = 0;
268*f6aab3d8Srobert         bool is_simple_type = offset_to_size.empty();
269*f6aab3d8Srobert         // Iterate through offset_to_location because offset_to_size might be
270*f6aab3d8Srobert         // empty if the variable is a simple type.
271*f6aab3d8Srobert         for (const auto &offset_loc : offset_to_location) {
272*f6aab3d8Srobert           if (cur_offset < offset_loc.first) {
273*f6aab3d8Srobert             stream.PutHex8(llvm::dwarf::DW_OP_piece);
274*f6aab3d8Srobert             stream.PutULEB128(offset_loc.first - cur_offset);
275*f6aab3d8Srobert             cur_offset = offset_loc.first;
276*f6aab3d8Srobert           }
277*f6aab3d8Srobert           MemberValLocation loc = offset_loc.second;
278*f6aab3d8Srobert           std::optional<int32_t> offset =
279*f6aab3d8Srobert               loc.is_at_reg ? std::nullopt
280*f6aab3d8Srobert                             : std::optional<int32_t>(loc.reg_offset);
281*f6aab3d8Srobert           if (!MakeRegisterBasedLocationExpressionInternal(
282*f6aab3d8Srobert                   stream, (RegisterId)loc.reg_id, register_kind, offset,
283*f6aab3d8Srobert                   module))
284*f6aab3d8Srobert             return false;
285*f6aab3d8Srobert           if (!is_simple_type) {
286*f6aab3d8Srobert             stream.PutHex8(llvm::dwarf::DW_OP_piece);
287*f6aab3d8Srobert             stream.PutULEB128(offset_to_size[offset_loc.first]);
288*f6aab3d8Srobert             cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
289*f6aab3d8Srobert           }
290*f6aab3d8Srobert         }
291*f6aab3d8Srobert         // For simple type, it specifies the byte size of the value described by
292*f6aab3d8Srobert         // the previous dwarf expr. For udt, it's the remaining byte size at end
293*f6aab3d8Srobert         // of a struct.
294*f6aab3d8Srobert         if (total_size > cur_offset) {
295*f6aab3d8Srobert           stream.PutHex8(llvm::dwarf::DW_OP_piece);
296*f6aab3d8Srobert           stream.PutULEB128(total_size - cur_offset);
297*f6aab3d8Srobert         }
298*f6aab3d8Srobert         return true;
299*f6aab3d8Srobert       });
300*f6aab3d8Srobert }
301