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