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