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/dwarf.h" |
13 | #include "lldb/Expression/DWARFExpression.h" |
14 | #include "lldb/Symbol/Variable.h" |
15 | #include "lldb/Utility/DataBufferHeap.h" |
16 | #include "lldb/Utility/StreamBuffer.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> |
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(rhs: fdRange)) |
49 | continue; |
50 | |
51 | found = std::move(fd); |
52 | |
53 | break; |
54 | } |
55 | } |
56 | |
57 | return found; |
58 | } |
59 | |
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, register_name: "$T0" , arch_type, |
64 | stream); |
65 | } |
66 | |
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(uvalue: 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(sect_id: section_id); |
97 | if (!section) |
98 | return DWARFExpression(); |
99 | |
100 | uint32_t offset = symbol.getAddressOffset(); |
101 | stream.PutMaxHex64(uvalue: section->GetFileAddress() + offset, byte_size: 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(session: symbol.getSession(), ranges)) { |
113 | if (EmitVFrameEvaluationDWARFExpression(program: fd->getProgram(), arch_type, |
114 | stream)) { |
115 | int32_t offset = symbol.getOffset(); |
116 | stream.PutHex8(uvalue: DW_OP_consts); |
117 | stream.PutSLEB128(uval: offset); |
118 | stream.PutHex8(uvalue: 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, register_id: reg_id); |
132 | if (reg_num == LLDB_INVALID_REGNUM) |
133 | return DWARFExpression(); |
134 | } |
135 | |
136 | if (reg_num > 31) { |
137 | stream.PutHex8(uvalue: DW_OP_bregx); |
138 | stream.PutULEB128(uval: reg_num); |
139 | } else |
140 | stream.PutHex8(uvalue: DW_OP_breg0 + reg_num); |
141 | |
142 | int32_t offset = symbol.getOffset(); |
143 | stream.PutSLEB128(uval: 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, register_id: symbol.getRegisterId()); |
152 | if (reg_num == LLDB_INVALID_REGNUM) |
153 | return DWARFExpression(); |
154 | |
155 | if (reg_num > 31) { |
156 | stream.PutHex8(uvalue: DW_OP_regx); |
157 | stream.PutULEB128(uval: reg_num); |
158 | } else |
159 | stream.PutHex8(uvalue: 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(s: &value.Value, src_len: sizeof(value.Value), |
168 | src_byte_order: endian::InlHostByteOrder()); |
169 | break; |
170 | } |
171 | default: |
172 | return DWARFExpression(); |
173 | } |
174 | |
175 | DataBufferSP buffer = |
176 | std::make_shared<DataBufferHeap>(args: stream.GetData(), args: stream.GetSize()); |
177 | DataExtractor (buffer, byte_order, address_size, byte_size); |
178 | DWARFExpression result(extractor); |
179 | result.SetRegisterKind(register_kind); |
180 | |
181 | return result; |
182 | } |
183 | |