1 //===-- DWARFLocationExpression.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DWARFLocationExpression.h"
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"
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"
25 #include "CodeViewRegisterMapping.h"
26 #include "PdbFPOProgramToDWARFExpression.h"
30 using namespace lldb_private
;
31 using namespace lldb_private::npdb
;
32 using namespace llvm::codeview
;
33 using namespace llvm::pdb
;
35 uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id
) {
36 if (register_id
== llvm::codeview::RegisterId::VFRAME
)
37 return LLDB_REGNUM_GENERIC_FP
;
39 return LLDB_INVALID_REGNUM
;
42 static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type
,
43 llvm::codeview::RegisterId register_id
,
44 RegisterKind
®ister_kind
) {
45 register_kind
= eRegisterKindLLDB
;
46 uint32_t reg_num
= GetLLDBRegisterNumber(arch_type
, register_id
);
47 if (reg_num
!= LLDB_INVALID_REGNUM
)
50 register_kind
= eRegisterKindGeneric
;
51 return GetGenericRegisterNumber(register_id
);
54 static bool IsSimpleTypeSignedInteger(SimpleTypeKind 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
:
77 static std::pair
<size_t, bool> GetIntegralTypeInfo(TypeIndex ti
,
80 SimpleTypeKind stk
= ti
.getSimpleKind();
81 return {GetTypeSizeForSimpleKind(stk
), IsSimpleTypeSignedInteger(stk
)};
84 CVType cvt
= tpi
.getType(ti
);
88 llvm::cantFail(TypeDeserializer::deserializeAs
<ModifierRecord
>(cvt
, mfr
));
89 return GetIntegralTypeInfo(mfr
.ModifiedType
, tpi
);
93 llvm::cantFail(TypeDeserializer::deserializeAs
<PointerRecord
>(cvt
, pr
));
94 return GetIntegralTypeInfo(pr
.ReferentType
, tpi
);
98 llvm::cantFail(TypeDeserializer::deserializeAs
<EnumRecord
>(cvt
, er
));
99 return GetIntegralTypeInfo(er
.UnderlyingType
, tpi
);
102 assert(false && "Type is not integral!");
107 template <typename StreamWriter
>
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();
117 RegisterKind register_kind
= eRegisterKindDWARF
;
118 StreamBuffer
<32> stream(Stream::eBinary
, address_size
, byte_order
);
120 if (!writer(stream
, register_kind
))
121 return DWARFExpression();
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
);
132 static bool MakeRegisterBasedLocationExpressionInternal(
133 Stream
&stream
, llvm::codeview::RegisterId reg
, RegisterKind
®ister_kind
,
134 std::optional
<int32_t> relative_offset
, lldb::ModuleSP module
) {
135 uint32_t reg_num
= GetRegisterNumber(module
->GetArchitecture().GetMachine(),
137 if (reg_num
== LLDB_INVALID_REGNUM
)
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
);
146 llvm::dwarf::LocationAtom base
=
147 relative_offset
? llvm::dwarf::DW_OP_breg0
: llvm::dwarf::DW_OP_reg0
;
148 stream
.PutHex8(base
+ reg_num
);
152 stream
.PutSLEB128(*relative_offset
);
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
®ister_kind
) -> bool {
162 return MakeRegisterBasedLocationExpressionInternal(
163 stream
, reg
, register_kind
, relative_offset
, module
);
167 DWARFExpression
lldb_private::npdb::MakeEnregisteredLocationExpression(
168 llvm::codeview::RegisterId reg
, lldb::ModuleSP module
) {
169 return MakeRegisterBasedLocationExpressionInternal(reg
, std::nullopt
, module
);
172 DWARFExpression
lldb_private::npdb::MakeRegRelLocationExpression(
173 llvm::codeview::RegisterId reg
, int32_t offset
, lldb::ModuleSP module
) {
174 return MakeRegisterBasedLocationExpressionInternal(reg
, offset
, module
);
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
,
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
®ister_kind
) -> bool {
188 const ArchSpec
&architecture
= module
->GetArchitecture();
190 if (!EmitVFrameEvaluationDWARFExpression(fpo_program
, architecture
.GetMachine(),
194 stream
.PutHex8(llvm::dwarf::DW_OP_consts
);
195 stream
.PutSLEB128(offset
);
196 stream
.PutHex8(llvm::dwarf::DW_OP_plus
);
198 register_kind
= eRegisterKindLLDB
;
204 DWARFExpression
lldb_private::npdb::MakeGlobalLocationExpression(
205 uint16_t section
, uint32_t offset
, ModuleSP module
) {
209 return MakeLocationExpressionInternal(
210 module
, [&](Stream
&stream
, RegisterKind
®ister_kind
) -> bool {
211 stream
.PutHex8(llvm::dwarf::DW_OP_addr
);
213 SectionList
*section_list
= module
->GetSectionList();
214 assert(section_list
);
216 auto section_ptr
= section_list
->FindSectionByID(section
);
220 stream
.PutMaxHex64(section_ptr
->GetFileAddress() + offset
,
221 stream
.GetAddressByteSize(), stream
.GetByteOrder());
227 DWARFExpression
lldb_private::npdb::MakeConstantLocationExpression(
228 TypeIndex underlying_ti
, TpiStream
&tpi
, const llvm::APSInt
&constant
,
230 const ArchSpec
&architecture
= module
->GetArchitecture();
231 uint32_t address_size
= architecture
.GetAddressByteSize();
234 bool is_signed
= false;
235 std::tie(size
, is_signed
) = GetIntegralTypeInfo(underlying_ti
, tpi
);
238 llvm::support::little64_t I
;
239 llvm::support::ulittle64_t U
;
242 std::shared_ptr
<DataBufferHeap
> buffer
= std::make_shared
<DataBufferHeap
>();
243 buffer
->SetByteSize(size
);
245 llvm::ArrayRef
<uint8_t> bytes
;
247 Value
.I
= constant
.getSExtValue();
249 Value
.U
= constant
.getZExtValue();
252 bytes
= llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value
), 8)
254 buffer
->CopyData(bytes
.data(), size
);
255 DataExtractor
extractor(buffer
, lldb::eByteOrderLittle
, address_size
);
256 DWARFExpression
result(extractor
);
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
®ister_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
;
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
,
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
];
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
294 if (total_size
> cur_offset
) {
295 stream
.PutHex8(llvm::dwarf::DW_OP_piece
);
296 stream
.PutULEB128(total_size
- cur_offset
);