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