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(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, "$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(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