1 //===-- PDBLocationToDWARFExpression.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 "PDBLocationToDWARFExpression.h"
10
11 #include "lldb/Core/Section.h"
12 #include "lldb/Core/StreamBuffer.h"
13 #include "lldb/Core/dwarf.h"
14 #include "lldb/Expression/DWARFExpression.h"
15 #include "lldb/Symbol/Variable.h"
16 #include "lldb/Utility/DataBufferHeap.h"
17
18 #include "llvm/DebugInfo/CodeView/CodeView.h"
19 #include "llvm/DebugInfo/PDB/IPDBSession.h"
20 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
21
22 #include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
23 #include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h"
24
25 using namespace lldb;
26 using namespace lldb_private;
27 using namespace lldb_private::npdb;
28 using namespace lldb_private::dwarf;
29 using namespace llvm::pdb;
30
31 static std::unique_ptr<IPDBFrameData>
GetCorrespondingFrameData(const IPDBSession & session,const Variable::RangeList & ranges)32 GetCorrespondingFrameData(const IPDBSession &session,
33 const Variable::RangeList &ranges) {
34 auto enumFrameData = session.getFrameData();
35 if (!enumFrameData)
36 return nullptr;
37
38 std::unique_ptr<IPDBFrameData> found;
39 while (auto fd = enumFrameData->getNext()) {
40 Range<lldb::addr_t, lldb::addr_t> fdRange(fd->getVirtualAddress(),
41 fd->getLengthBlock());
42
43 for (size_t i = 0; i < ranges.GetSize(); i++) {
44 auto range = ranges.GetEntryAtIndex(i);
45 if (!range)
46 continue;
47
48 if (!range->DoesIntersect(fdRange))
49 continue;
50
51 found = std::move(fd);
52
53 break;
54 }
55 }
56
57 return found;
58 }
59
EmitVFrameEvaluationDWARFExpression(llvm::StringRef program,llvm::Triple::ArchType arch_type,Stream & stream)60 static bool EmitVFrameEvaluationDWARFExpression(
61 llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
62 // VFrame value always stored in $TO pseudo-register
63 return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
64 stream);
65 }
66
ConvertPDBLocationToDWARFExpression(ModuleSP module,const PDBSymbolData & symbol,const Variable::RangeList & ranges,bool & is_constant)67 DWARFExpression ConvertPDBLocationToDWARFExpression(
68 ModuleSP module, const PDBSymbolData &symbol,
69 const Variable::RangeList &ranges, bool &is_constant) {
70 is_constant = true;
71
72 if (!module)
73 return DWARFExpression();
74
75 const ArchSpec &architecture = module->GetArchitecture();
76 llvm::Triple::ArchType arch_type = architecture.GetMachine();
77 ByteOrder byte_order = architecture.GetByteOrder();
78 uint32_t address_size = architecture.GetAddressByteSize();
79 uint32_t byte_size = architecture.GetDataByteSize();
80 if (byte_order == eByteOrderInvalid || address_size == 0)
81 return DWARFExpression();
82
83 RegisterKind register_kind = eRegisterKindDWARF;
84 StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
85 switch (symbol.getLocationType()) {
86 case PDB_LocType::Static:
87 case PDB_LocType::TLS: {
88 stream.PutHex8(DW_OP_addr);
89
90 SectionList *section_list = module->GetSectionList();
91 if (!section_list)
92 return DWARFExpression();
93
94 uint32_t section_id = symbol.getAddressSection();
95
96 auto section = section_list->FindSectionByID(section_id);
97 if (!section)
98 return DWARFExpression();
99
100 uint32_t offset = symbol.getAddressOffset();
101 stream.PutMaxHex64(section->GetFileAddress() + offset, address_size,
102 byte_order);
103
104 is_constant = false;
105
106 break;
107 }
108 case PDB_LocType::RegRel: {
109 uint32_t reg_num;
110 auto reg_id = symbol.getRegisterId();
111 if (reg_id == llvm::codeview::RegisterId::VFRAME) {
112 if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) {
113 if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type,
114 stream)) {
115 int32_t offset = symbol.getOffset();
116 stream.PutHex8(DW_OP_consts);
117 stream.PutSLEB128(offset);
118 stream.PutHex8(DW_OP_plus);
119
120 register_kind = eRegisterKindLLDB;
121
122 is_constant = false;
123 break;
124 }
125 }
126
127 register_kind = eRegisterKindGeneric;
128 reg_num = LLDB_REGNUM_GENERIC_FP;
129 } else {
130 register_kind = eRegisterKindLLDB;
131 reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
132 if (reg_num == LLDB_INVALID_REGNUM)
133 return DWARFExpression();
134 }
135
136 if (reg_num > 31) {
137 stream.PutHex8(DW_OP_bregx);
138 stream.PutULEB128(reg_num);
139 } else
140 stream.PutHex8(DW_OP_breg0 + reg_num);
141
142 int32_t offset = symbol.getOffset();
143 stream.PutSLEB128(offset);
144
145 is_constant = false;
146
147 break;
148 }
149 case PDB_LocType::Enregistered: {
150 register_kind = eRegisterKindLLDB;
151 uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId());
152 if (reg_num == LLDB_INVALID_REGNUM)
153 return DWARFExpression();
154
155 if (reg_num > 31) {
156 stream.PutHex8(DW_OP_regx);
157 stream.PutULEB128(reg_num);
158 } else
159 stream.PutHex8(DW_OP_reg0 + reg_num);
160
161 is_constant = false;
162
163 break;
164 }
165 case PDB_LocType::Constant: {
166 Variant value = symbol.getValue();
167 stream.PutRawBytes(&value.Value, sizeof(value.Value),
168 endian::InlHostByteOrder());
169 break;
170 }
171 default:
172 return DWARFExpression();
173 }
174
175 DataBufferSP buffer =
176 std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
177 DataExtractor extractor(buffer, byte_order, address_size, byte_size);
178 DWARFExpression result(extractor);
179 result.SetRegisterKind(register_kind);
180
181 return result;
182 }
183