1 //===-- DWARFLocationExpression.cpp ---------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DWARFLocationExpression.h"
10 
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/Section.h"
13 #include "lldb/Expression/DWARFExpression.h"
14 #include "lldb/Utility/ArchSpec.h"
15 #include "lldb/Utility/DataBufferHeap.h"
16 #include "lldb/Utility/StreamBuffer.h"
17 
18 #include "llvm/BinaryFormat/Dwarf.h"
19 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
20 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
21 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
22 #include "llvm/Support/Endian.h"
23 
24 #include "PdbUtil.h"
25 #include "CodeViewRegisterMapping.h"
26 #include "PdbFPOProgramToDWARFExpression.h"
27 #include <optional>
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 using namespace lldb_private::npdb;
32 using namespace llvm::codeview;
33 using namespace llvm::pdb;
34 
GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)35 uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
36   if (register_id == llvm::codeview::RegisterId::VFRAME)
37     return LLDB_REGNUM_GENERIC_FP;
38 
39   return LLDB_INVALID_REGNUM;
40 }
41 
GetRegisterNumber(llvm::Triple::ArchType arch_type,llvm::codeview::RegisterId register_id,RegisterKind & register_kind)42 static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
43                                   llvm::codeview::RegisterId register_id,
44                                   RegisterKind &register_kind) {
45   register_kind = eRegisterKindLLDB;
46   uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
47   if (reg_num != LLDB_INVALID_REGNUM)
48     return reg_num;
49 
50   register_kind = eRegisterKindGeneric;
51   return GetGenericRegisterNumber(register_id);
52 }
53 
IsSimpleTypeSignedInteger(SimpleTypeKind kind)54 static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
55   switch (kind) {
56   case SimpleTypeKind::Int128:
57   case SimpleTypeKind::Int64:
58   case SimpleTypeKind::Int64Quad:
59   case SimpleTypeKind::Int32:
60   case SimpleTypeKind::Int32Long:
61   case SimpleTypeKind::Int16:
62   case SimpleTypeKind::Int16Short:
63   case SimpleTypeKind::Float128:
64   case SimpleTypeKind::Float80:
65   case SimpleTypeKind::Float64:
66   case SimpleTypeKind::Float32:
67   case SimpleTypeKind::Float16:
68   case SimpleTypeKind::NarrowCharacter:
69   case SimpleTypeKind::SignedCharacter:
70   case SimpleTypeKind::SByte:
71     return true;
72   default:
73     return false;
74   }
75 }
76 
GetIntegralTypeInfo(TypeIndex ti,TpiStream & tpi)77 static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
78                                                    TpiStream &tpi) {
79   if (ti.isSimple()) {
80     SimpleTypeKind stk = ti.getSimpleKind();
81     return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
82   }
83 
84   CVType cvt = tpi.getType(ti);
85   switch (cvt.kind()) {
86   case LF_MODIFIER: {
87     ModifierRecord mfr;
88     llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
89     return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
90   }
91   case LF_POINTER: {
92     PointerRecord pr;
93     llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
94     return GetIntegralTypeInfo(pr.ReferentType, tpi);
95   }
96   case LF_ENUM: {
97     EnumRecord er;
98     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
99     return GetIntegralTypeInfo(er.UnderlyingType, tpi);
100   }
101   default:
102     assert(false && "Type is not integral!");
103     return {0, false};
104   }
105 }
106 
107 template <typename StreamWriter>
MakeLocationExpressionInternal(lldb::ModuleSP module,StreamWriter && writer)108 static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
109                                                       StreamWriter &&writer) {
110   const ArchSpec &architecture = module->GetArchitecture();
111   ByteOrder byte_order = architecture.GetByteOrder();
112   uint32_t address_size = architecture.GetAddressByteSize();
113   uint32_t byte_size = architecture.GetDataByteSize();
114   if (byte_order == eByteOrderInvalid || address_size == 0)
115     return DWARFExpression();
116 
117   RegisterKind register_kind = eRegisterKindDWARF;
118   StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
119 
120   if (!writer(stream, register_kind))
121     return DWARFExpression();
122 
123   DataBufferSP buffer =
124       std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
125   DataExtractor extractor(buffer, byte_order, address_size, byte_size);
126   DWARFExpression result(extractor);
127   result.SetRegisterKind(register_kind);
128 
129   return result;
130 }
131 
MakeRegisterBasedLocationExpressionInternal(Stream & stream,llvm::codeview::RegisterId reg,RegisterKind & register_kind,std::optional<int32_t> relative_offset,lldb::ModuleSP module)132 static bool MakeRegisterBasedLocationExpressionInternal(
133     Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
134     std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
135   uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
136                                        reg, register_kind);
137   if (reg_num == LLDB_INVALID_REGNUM)
138     return false;
139 
140   if (reg_num > 31) {
141     llvm::dwarf::LocationAtom base =
142         relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
143     stream.PutHex8(base);
144     stream.PutULEB128(reg_num);
145   } else {
146     llvm::dwarf::LocationAtom base =
147         relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
148     stream.PutHex8(base + reg_num);
149   }
150 
151   if (relative_offset)
152     stream.PutSLEB128(*relative_offset);
153 
154   return true;
155 }
156 
MakeRegisterBasedLocationExpressionInternal(llvm::codeview::RegisterId reg,std::optional<int32_t> relative_offset,lldb::ModuleSP module)157 static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
158     llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
159     lldb::ModuleSP module) {
160   return MakeLocationExpressionInternal(
161       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
162         return MakeRegisterBasedLocationExpressionInternal(
163             stream, reg, register_kind, relative_offset, module);
164       });
165 }
166 
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,lldb::ModuleSP module)167 DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
168     llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
169   return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
170 }
171 
MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,int32_t offset,lldb::ModuleSP module)172 DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
173     llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
174   return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
175 }
176 
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)177 static bool EmitVFrameEvaluationDWARFExpression(
178     llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
179   // VFrame value always stored in $TO pseudo-register
180   return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
181                                               stream);
182 }
183 
MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,int32_t offset,lldb::ModuleSP module)184 DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
185     llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
186   return MakeLocationExpressionInternal(
187       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
188         const ArchSpec &architecture = module->GetArchitecture();
189 
190         if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
191                                                  stream))
192           return false;
193 
194         stream.PutHex8(llvm::dwarf::DW_OP_consts);
195         stream.PutSLEB128(offset);
196         stream.PutHex8(llvm::dwarf::DW_OP_plus);
197 
198         register_kind = eRegisterKindLLDB;
199 
200         return true;
201       });
202 }
203 
MakeGlobalLocationExpression(uint16_t section,uint32_t offset,ModuleSP module)204 DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
205     uint16_t section, uint32_t offset, ModuleSP module) {
206   assert(section > 0);
207   assert(module);
208 
209   return MakeLocationExpressionInternal(
210       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
211         stream.PutHex8(llvm::dwarf::DW_OP_addr);
212 
213         SectionList *section_list = module->GetSectionList();
214         assert(section_list);
215 
216         auto section_ptr = section_list->FindSectionByID(section);
217         if (!section_ptr)
218           return false;
219 
220         stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
221                            stream.GetAddressByteSize(), stream.GetByteOrder());
222 
223         return true;
224       });
225 }
226 
MakeConstantLocationExpression(TypeIndex underlying_ti,TpiStream & tpi,const llvm::APSInt & constant,ModuleSP module)227 DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
228     TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
229     ModuleSP module) {
230   const ArchSpec &architecture = module->GetArchitecture();
231   uint32_t address_size = architecture.GetAddressByteSize();
232 
233   size_t size = 0;
234   bool is_signed = false;
235   std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
236 
237   union {
238     llvm::support::little64_t I;
239     llvm::support::ulittle64_t U;
240   } Value;
241 
242   std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
243   buffer->SetByteSize(size);
244 
245   llvm::ArrayRef<uint8_t> bytes;
246   if (is_signed) {
247     Value.I = constant.getSExtValue();
248   } else {
249     Value.U = constant.getZExtValue();
250   }
251 
252   bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
253               .take_front(size);
254   buffer->CopyData(bytes.data(), size);
255   DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
256   DWARFExpression result(extractor);
257   return result;
258 }
259 
260 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 lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
262     const std::map<uint64_t, MemberValLocation> &offset_to_location,
263     std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
264     lldb::ModuleSP module) {
265   return MakeLocationExpressionInternal(
266       module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
267         size_t cur_offset = 0;
268         bool is_simple_type = offset_to_size.empty();
269         // Iterate through offset_to_location because offset_to_size might be
270         // empty if the variable is a simple type.
271         for (const auto &offset_loc : offset_to_location) {
272           if (cur_offset < offset_loc.first) {
273             stream.PutHex8(llvm::dwarf::DW_OP_piece);
274             stream.PutULEB128(offset_loc.first - cur_offset);
275             cur_offset = offset_loc.first;
276           }
277           MemberValLocation loc = offset_loc.second;
278           std::optional<int32_t> offset =
279               loc.is_at_reg ? std::nullopt
280                             : std::optional<int32_t>(loc.reg_offset);
281           if (!MakeRegisterBasedLocationExpressionInternal(
282                   stream, (RegisterId)loc.reg_id, register_kind, offset,
283                   module))
284             return false;
285           if (!is_simple_type) {
286             stream.PutHex8(llvm::dwarf::DW_OP_piece);
287             stream.PutULEB128(offset_to_size[offset_loc.first]);
288             cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
289           }
290         }
291         // For simple type, it specifies the byte size of the value described by
292         // the previous dwarf expr. For udt, it's the remaining byte size at end
293         // of a struct.
294         if (total_size > cur_offset) {
295           stream.PutHex8(llvm::dwarf::DW_OP_piece);
296           stream.PutULEB128(total_size - cur_offset);
297         }
298         return true;
299       });
300 }
301