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/Core/StreamBuffer.h"
14 #include "lldb/Expression/DWARFExpression.h"
15 #include "lldb/Utility/ArchSpec.h"
16 #include "lldb/Utility/DataBufferHeap.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
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace lldb_private::npdb;
31 using namespace llvm::codeview;
32 using namespace llvm::pdb;
33
GetGenericRegisterNumber(llvm::codeview::RegisterId register_id)34 uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
35 if (register_id == llvm::codeview::RegisterId::VFRAME)
36 return LLDB_REGNUM_GENERIC_FP;
37
38 return LLDB_INVALID_REGNUM;
39 }
40
GetRegisterNumber(llvm::Triple::ArchType arch_type,llvm::codeview::RegisterId register_id,RegisterKind & register_kind)41 static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
42 llvm::codeview::RegisterId register_id,
43 RegisterKind ®ister_kind) {
44 register_kind = eRegisterKindLLDB;
45 uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
46 if (reg_num != LLDB_INVALID_REGNUM)
47 return reg_num;
48
49 register_kind = eRegisterKindGeneric;
50 return GetGenericRegisterNumber(register_id);
51 }
52
IsSimpleTypeSignedInteger(SimpleTypeKind kind)53 static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
54 switch (kind) {
55 case SimpleTypeKind::Int128:
56 case SimpleTypeKind::Int64:
57 case SimpleTypeKind::Int64Quad:
58 case SimpleTypeKind::Int32:
59 case SimpleTypeKind::Int32Long:
60 case SimpleTypeKind::Int16:
61 case SimpleTypeKind::Int16Short:
62 case SimpleTypeKind::Float128:
63 case SimpleTypeKind::Float80:
64 case SimpleTypeKind::Float64:
65 case SimpleTypeKind::Float32:
66 case SimpleTypeKind::Float16:
67 case SimpleTypeKind::NarrowCharacter:
68 case SimpleTypeKind::SignedCharacter:
69 case SimpleTypeKind::SByte:
70 return true;
71 default:
72 return false;
73 }
74 }
75
GetIntegralTypeInfo(TypeIndex ti,TpiStream & tpi)76 static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
77 TpiStream &tpi) {
78 if (ti.isSimple()) {
79 SimpleTypeKind stk = ti.getSimpleKind();
80 return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
81 }
82
83 CVType cvt = tpi.getType(ti);
84 switch (cvt.kind()) {
85 case LF_MODIFIER: {
86 ModifierRecord mfr;
87 llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
88 return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
89 }
90 case LF_POINTER: {
91 PointerRecord pr;
92 llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
93 return GetIntegralTypeInfo(pr.ReferentType, tpi);
94 }
95 case LF_ENUM: {
96 EnumRecord er;
97 llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
98 return GetIntegralTypeInfo(er.UnderlyingType, tpi);
99 }
100 default:
101 assert(false && "Type is not integral!");
102 return {0, false};
103 }
104 }
105
106 template <typename StreamWriter>
MakeLocationExpressionInternal(lldb::ModuleSP module,StreamWriter && writer)107 static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
108 StreamWriter &&writer) {
109 const ArchSpec &architecture = module->GetArchitecture();
110 ByteOrder byte_order = architecture.GetByteOrder();
111 uint32_t address_size = architecture.GetAddressByteSize();
112 uint32_t byte_size = architecture.GetDataByteSize();
113 if (byte_order == eByteOrderInvalid || address_size == 0)
114 return DWARFExpression();
115
116 RegisterKind register_kind = eRegisterKindDWARF;
117 StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
118
119 if (!writer(stream, register_kind))
120 return DWARFExpression();
121
122 DataBufferSP buffer =
123 std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
124 DataExtractor extractor(buffer, byte_order, address_size, byte_size);
125 DWARFExpression result(module, extractor, nullptr);
126 result.SetRegisterKind(register_kind);
127
128 return result;
129 }
130
MakeRegisterBasedLocationExpressionInternal(llvm::codeview::RegisterId reg,llvm::Optional<int32_t> relative_offset,lldb::ModuleSP module)131 static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
132 llvm::codeview::RegisterId reg, llvm::Optional<int32_t> relative_offset,
133 lldb::ModuleSP module) {
134 return MakeLocationExpressionInternal(
135 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
136 uint32_t reg_num = GetRegisterNumber(
137 module->GetArchitecture().GetMachine(), reg, register_kind);
138 if (reg_num == LLDB_INVALID_REGNUM)
139 return false;
140
141 if (reg_num > 31) {
142 llvm::dwarf::LocationAtom base = relative_offset
143 ? llvm::dwarf::DW_OP_bregx
144 : llvm::dwarf::DW_OP_regx;
145 stream.PutHex8(base);
146 stream.PutULEB128(reg_num);
147 } else {
148 llvm::dwarf::LocationAtom base = relative_offset
149 ? llvm::dwarf::DW_OP_breg0
150 : llvm::dwarf::DW_OP_reg0;
151 stream.PutHex8(base + reg_num);
152 }
153
154 if (relative_offset)
155 stream.PutSLEB128(*relative_offset);
156
157 return true;
158 });
159 }
160
MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,lldb::ModuleSP module)161 DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
162 llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
163 return MakeRegisterBasedLocationExpressionInternal(reg, llvm::None, module);
164 }
165
MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,int32_t offset,lldb::ModuleSP module)166 DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
167 llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
168 return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
169 }
170
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)171 static bool EmitVFrameEvaluationDWARFExpression(
172 llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
173 // VFrame value always stored in $TO pseudo-register
174 return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
175 stream);
176 }
177
MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,int32_t offset,lldb::ModuleSP module)178 DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
179 llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
180 return MakeLocationExpressionInternal(
181 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
182 const ArchSpec &architecture = module->GetArchitecture();
183
184 if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
185 stream))
186 return false;
187
188 stream.PutHex8(llvm::dwarf::DW_OP_consts);
189 stream.PutSLEB128(offset);
190 stream.PutHex8(llvm::dwarf::DW_OP_plus);
191
192 register_kind = eRegisterKindLLDB;
193
194 return true;
195 });
196 }
197
MakeGlobalLocationExpression(uint16_t section,uint32_t offset,ModuleSP module)198 DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
199 uint16_t section, uint32_t offset, ModuleSP module) {
200 assert(section > 0);
201 assert(module);
202
203 return MakeLocationExpressionInternal(
204 module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
205 stream.PutHex8(llvm::dwarf::DW_OP_addr);
206
207 SectionList *section_list = module->GetSectionList();
208 assert(section_list);
209
210 auto section_ptr = section_list->FindSectionByID(section);
211 if (!section_ptr)
212 return false;
213
214 stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
215 stream.GetAddressByteSize(), stream.GetByteOrder());
216
217 return true;
218 });
219 }
220
MakeConstantLocationExpression(TypeIndex underlying_ti,TpiStream & tpi,const llvm::APSInt & constant,ModuleSP module)221 DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
222 TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
223 ModuleSP module) {
224 const ArchSpec &architecture = module->GetArchitecture();
225 uint32_t address_size = architecture.GetAddressByteSize();
226
227 size_t size = 0;
228 bool is_signed = false;
229 std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
230
231 union {
232 llvm::support::little64_t I;
233 llvm::support::ulittle64_t U;
234 } Value;
235
236 std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
237 buffer->SetByteSize(size);
238
239 llvm::ArrayRef<uint8_t> bytes;
240 if (is_signed) {
241 Value.I = constant.getSExtValue();
242 } else {
243 Value.U = constant.getZExtValue();
244 }
245
246 bytes = llvm::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
247 .take_front(size);
248 buffer->CopyData(bytes.data(), size);
249 DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
250 DWARFExpression result(nullptr, extractor, nullptr);
251 return result;
252 }
253