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
29using namespace lldb;
30using namespace lldb_private;
31using namespace lldb_private::npdb;
32using namespace llvm::codeview;
33using namespace llvm::pdb;
34
35uint32_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
42static 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
54static 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
77static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
78 TpiStream &tpi) {
79 if (ti.isSimple()) {
80 SimpleTypeKind stk = ti.getSimpleKind();
81 return {GetTypeSizeForSimpleKind(kind: stk), IsSimpleTypeSignedInteger(kind: stk)};
82 }
83
84 CVType cvt = tpi.getType(Index: ti);
85 switch (cvt.kind()) {
86 case LF_MODIFIER: {
87 ModifierRecord mfr;
88 llvm::cantFail(Err: TypeDeserializer::deserializeAs<ModifierRecord>(CVT&: cvt, Record&: mfr));
89 return GetIntegralTypeInfo(ti: mfr.ModifiedType, tpi);
90 }
91 case LF_POINTER: {
92 PointerRecord pr;
93 llvm::cantFail(Err: TypeDeserializer::deserializeAs<PointerRecord>(CVT&: cvt, Record&: pr));
94 return GetIntegralTypeInfo(ti: pr.ReferentType, tpi);
95 }
96 case LF_ENUM: {
97 EnumRecord er;
98 llvm::cantFail(Err: TypeDeserializer::deserializeAs<EnumRecord>(CVT&: cvt, Record&: er));
99 return GetIntegralTypeInfo(ti: er.UnderlyingType, tpi);
100 }
101 default:
102 assert(false && "Type is not integral!");
103 return {0, false};
104 }
105}
106
107template <typename StreamWriter>
108static 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>(args: stream.GetData(), args: 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
132static 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(arch_type: module->GetArchitecture().GetMachine(),
136 register_id: 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(uvalue: base);
144 stream.PutULEB128(uval: 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(uvalue: base + reg_num);
149 }
150
151 if (relative_offset)
152 stream.PutSLEB128(uval: *relative_offset);
153
154 return true;
155}
156
157static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
158 llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
159 lldb::ModuleSP module) {
160 return MakeLocationExpressionInternal(
161 module, writer: [&](Stream &stream, RegisterKind &register_kind) -> bool {
162 return MakeRegisterBasedLocationExpressionInternal(
163 stream, reg, register_kind, relative_offset, module);
164 });
165}
166
167DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
168 llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
169 return MakeRegisterBasedLocationExpressionInternal(reg, relative_offset: std::nullopt, module);
170}
171
172DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
173 llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
174 return MakeRegisterBasedLocationExpressionInternal(reg, relative_offset: offset, module);
175}
176
177static 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, register_name: "$T0", arch_type,
181 stream);
182}
183
184DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
185 llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
186 return MakeLocationExpressionInternal(
187 module, writer: [&](Stream &stream, RegisterKind &register_kind) -> bool {
188 const ArchSpec &architecture = module->GetArchitecture();
189
190 if (!EmitVFrameEvaluationDWARFExpression(program: fpo_program, arch_type: architecture.GetMachine(),
191 stream))
192 return false;
193
194 stream.PutHex8(uvalue: llvm::dwarf::DW_OP_consts);
195 stream.PutSLEB128(uval: offset);
196 stream.PutHex8(uvalue: llvm::dwarf::DW_OP_plus);
197
198 register_kind = eRegisterKindLLDB;
199
200 return true;
201 });
202}
203
204DWARFExpression 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, writer: [&](Stream &stream, RegisterKind &register_kind) -> bool {
211 stream.PutHex8(uvalue: llvm::dwarf::DW_OP_addr);
212
213 SectionList *section_list = module->GetSectionList();
214 assert(section_list);
215
216 auto section_ptr = section_list->FindSectionByID(sect_id: section);
217 if (!section_ptr)
218 return false;
219
220 stream.PutMaxHex64(uvalue: section_ptr->GetFileAddress() + offset,
221 byte_size: stream.GetAddressByteSize(), byte_order: stream.GetByteOrder());
222
223 return true;
224 });
225}
226
227DWARFExpression 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(args&: size, args&: is_signed) = GetIntegralTypeInfo(ti: 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(N: size);
254 buffer->CopyData(src: bytes.data(), src_len: size);
255 DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
256 DWARFExpression result(extractor);
257 return result;
258}
259
260DWARFExpression
261lldb_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, writer: [&](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(uvalue: llvm::dwarf::DW_OP_piece);
274 stream.PutULEB128(uval: 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, reg: (RegisterId)loc.reg_id, register_kind, relative_offset: offset,
283 module))
284 return false;
285 if (!is_simple_type) {
286 stream.PutHex8(uvalue: llvm::dwarf::DW_OP_piece);
287 stream.PutULEB128(uval: 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(uvalue: llvm::dwarf::DW_OP_piece);
296 stream.PutULEB128(uval: total_size - cur_offset);
297 }
298 return true;
299 });
300}
301

source code of lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp