xref: /llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp (revision 88813103cd7822fad9b111bb33c751a545b55d33)
1758657e5SAleksandr Urakov //===-- PDBFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===//
2758657e5SAleksandr Urakov //
3ee21a66aSAleksandr Urakov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ee21a66aSAleksandr Urakov // See https://llvm.org/LICENSE.txt for license information.
5ee21a66aSAleksandr Urakov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6758657e5SAleksandr Urakov //
7758657e5SAleksandr Urakov //===----------------------------------------------------------------------===//
8758657e5SAleksandr Urakov 
9758657e5SAleksandr Urakov #include "PdbFPOProgramToDWARFExpression.h"
10758657e5SAleksandr Urakov #include "CodeViewRegisterMapping.h"
11758657e5SAleksandr Urakov 
12758657e5SAleksandr Urakov #include "lldb/Core/StreamBuffer.h"
13758657e5SAleksandr Urakov #include "lldb/Core/dwarf.h"
144eda12aeSPavel Labath #include "lldb/Symbol/PostfixExpression.h"
15758657e5SAleksandr Urakov #include "lldb/Utility/LLDBAssert.h"
16758657e5SAleksandr Urakov #include "lldb/Utility/Stream.h"
17758657e5SAleksandr Urakov #include "llvm/ADT/DenseMap.h"
18758657e5SAleksandr Urakov 
19758657e5SAleksandr Urakov #include "llvm/ADT/StringExtras.h"
20758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/CodeView.h"
21758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/EnumTables.h"
22758657e5SAleksandr Urakov 
23758657e5SAleksandr Urakov using namespace lldb;
24758657e5SAleksandr Urakov using namespace lldb_private;
254eda12aeSPavel Labath using namespace lldb_private::postfix;
26758657e5SAleksandr Urakov 
27758657e5SAleksandr Urakov namespace {
28758657e5SAleksandr Urakov 
294eda12aeSPavel Labath class FPOProgramASTVisitorMergeDependent : public Visitor<> {
30758657e5SAleksandr Urakov public:
314eda12aeSPavel Labath   void Visit(BinaryOpNode &binary, Node *&) override {
3285ce053dSPavel Labath     Dispatch(binary.Left());
3385ce053dSPavel Labath     Dispatch(binary.Right());
3485ce053dSPavel Labath   }
3585ce053dSPavel Labath 
364eda12aeSPavel Labath   void Visit(UnaryOpNode &unary, Node *&) override {
3785ce053dSPavel Labath     Dispatch(unary.Operand());
3885ce053dSPavel Labath   }
3985ce053dSPavel Labath 
404eda12aeSPavel Labath   void Visit(RegisterNode &, Node *&) override {}
414eda12aeSPavel Labath   void Visit(IntegerNode &, Node *&) override {}
424eda12aeSPavel Labath   void Visit(SymbolNode &symbol, Node *&ref) override;
4385ce053dSPavel Labath 
444eda12aeSPavel Labath   static void
454eda12aeSPavel Labath   Merge(const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs,
464eda12aeSPavel Labath         Node *&ast) {
4785ce053dSPavel Labath     FPOProgramASTVisitorMergeDependent(dependent_programs).Dispatch(ast);
4885ce053dSPavel Labath   }
4985ce053dSPavel Labath 
5085ce053dSPavel Labath private:
51758657e5SAleksandr Urakov   FPOProgramASTVisitorMergeDependent(
524eda12aeSPavel Labath       const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs)
53758657e5SAleksandr Urakov       : m_dependent_programs(dependent_programs) {}
54758657e5SAleksandr Urakov 
554eda12aeSPavel Labath   const llvm::DenseMap<llvm::StringRef, Node *> &m_dependent_programs;
56758657e5SAleksandr Urakov };
57758657e5SAleksandr Urakov 
584eda12aeSPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(SymbolNode &symbol, Node *&ref) {
5985ce053dSPavel Labath   auto it = m_dependent_programs.find(symbol.GetName());
6085ce053dSPavel Labath   if (it == m_dependent_programs.end())
6185ce053dSPavel Labath     return;
6285ce053dSPavel Labath 
6385ce053dSPavel Labath   ref = it->second;
6485ce053dSPavel Labath   Dispatch(ref);
65758657e5SAleksandr Urakov }
66758657e5SAleksandr Urakov 
674eda12aeSPavel Labath class FPOProgramASTVisitorResolveRegisterRefs : public Visitor<bool> {
68758657e5SAleksandr Urakov public:
694eda12aeSPavel Labath   static bool
704eda12aeSPavel Labath   Resolve(const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs,
71*88813103SPavel Labath           llvm::Triple::ArchType arch_type, llvm::BumpPtrAllocator &alloc,
72*88813103SPavel Labath           Node *&ast) {
7385ce053dSPavel Labath     return FPOProgramASTVisitorResolveRegisterRefs(dependent_programs,
7485ce053dSPavel Labath                                                    arch_type, alloc)
7585ce053dSPavel Labath         .Dispatch(ast);
7685ce053dSPavel Labath   }
7785ce053dSPavel Labath 
784eda12aeSPavel Labath   bool Visit(BinaryOpNode &binary, Node *&) override {
7985ce053dSPavel Labath     return Dispatch(binary.Left()) && Dispatch(binary.Right());
8085ce053dSPavel Labath   }
8185ce053dSPavel Labath 
824eda12aeSPavel Labath   bool Visit(UnaryOpNode &unary, Node *&) override {
8385ce053dSPavel Labath     return Dispatch(unary.Operand());
8485ce053dSPavel Labath   }
8585ce053dSPavel Labath 
864eda12aeSPavel Labath   bool Visit(RegisterNode &, Node *&) override { return true; }
8785ce053dSPavel Labath 
884eda12aeSPavel Labath   bool Visit(IntegerNode &, Node *&) override { return true; }
8985ce053dSPavel Labath 
904eda12aeSPavel Labath   bool Visit(SymbolNode &symbol, Node *&ref) override;
9185ce053dSPavel Labath 
9285ce053dSPavel Labath private:
93758657e5SAleksandr Urakov   FPOProgramASTVisitorResolveRegisterRefs(
944eda12aeSPavel Labath       const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs,
95*88813103SPavel Labath       llvm::Triple::ArchType arch_type, llvm::BumpPtrAllocator &alloc)
961c4ee160SPavel Labath       : m_dependent_programs(dependent_programs), m_arch_type(arch_type),
971c4ee160SPavel Labath         m_alloc(alloc) {}
98758657e5SAleksandr Urakov 
994eda12aeSPavel Labath   const llvm::DenseMap<llvm::StringRef, Node *> &m_dependent_programs;
100758657e5SAleksandr Urakov   llvm::Triple::ArchType m_arch_type;
101*88813103SPavel Labath   llvm::BumpPtrAllocator &m_alloc;
102758657e5SAleksandr Urakov };
103758657e5SAleksandr Urakov 
1041c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
1051c4ee160SPavel Labath   // lookup register name to get lldb register number
1061c4ee160SPavel Labath   llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
1071c4ee160SPavel Labath       llvm::codeview::getRegisterNames();
1081c4ee160SPavel Labath   auto it = llvm::find_if(
1091c4ee160SPavel Labath       register_names,
1101c4ee160SPavel Labath       [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
1111c4ee160SPavel Labath         return reg_name.compare_lower(register_entry.Name) == 0;
1121c4ee160SPavel Labath       });
113758657e5SAleksandr Urakov 
1141c4ee160SPavel Labath   if (it == register_names.end())
1151c4ee160SPavel Labath     return LLDB_INVALID_REGNUM;
1161c4ee160SPavel Labath 
1171c4ee160SPavel Labath   auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
1181c4ee160SPavel Labath   return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
119758657e5SAleksandr Urakov }
1201c4ee160SPavel Labath 
1214eda12aeSPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::Visit(SymbolNode &symbol,
1224eda12aeSPavel Labath                                                     Node *&ref) {
1231c4ee160SPavel Labath   // Look up register reference as lvalue in preceding assignments.
12485ce053dSPavel Labath   auto it = m_dependent_programs.find(symbol.GetName());
1251c4ee160SPavel Labath   if (it != m_dependent_programs.end()) {
1261c4ee160SPavel Labath     // Dependent programs are handled elsewhere.
1271c4ee160SPavel Labath     return true;
1281c4ee160SPavel Labath   }
1291c4ee160SPavel Labath 
1301c4ee160SPavel Labath   uint32_t reg_num =
13185ce053dSPavel Labath       ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), m_arch_type);
1321c4ee160SPavel Labath 
1331c4ee160SPavel Labath   if (reg_num == LLDB_INVALID_REGNUM)
1341c4ee160SPavel Labath     return false;
1351c4ee160SPavel Labath 
136*88813103SPavel Labath   ref = MakeNode<RegisterNode>(m_alloc, reg_num);
1371c4ee160SPavel Labath   return true;
138758657e5SAleksandr Urakov }
139758657e5SAleksandr Urakov 
1404eda12aeSPavel Labath class FPOProgramASTVisitorDWARFCodegen : public Visitor<> {
141758657e5SAleksandr Urakov public:
1424eda12aeSPavel Labath   static void Emit(Stream &stream, Node *&ast) {
14385ce053dSPavel Labath     FPOProgramASTVisitorDWARFCodegen(stream).Dispatch(ast);
14485ce053dSPavel Labath   }
14585ce053dSPavel Labath 
1464eda12aeSPavel Labath   void Visit(RegisterNode &reg, Node *&);
1474eda12aeSPavel Labath   void Visit(BinaryOpNode &binary, Node *&);
1484eda12aeSPavel Labath   void Visit(UnaryOpNode &unary, Node *&);
1494eda12aeSPavel Labath   void Visit(SymbolNode &symbol, Node *&) {
15085ce053dSPavel Labath     llvm_unreachable("Symbols should have been resolved by now!");
15185ce053dSPavel Labath   }
1524eda12aeSPavel Labath   void Visit(IntegerNode &integer, Node *&);
15385ce053dSPavel Labath 
15485ce053dSPavel Labath private:
155758657e5SAleksandr Urakov   FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {}
156758657e5SAleksandr Urakov 
157758657e5SAleksandr Urakov   Stream &m_out_stream;
158758657e5SAleksandr Urakov };
159758657e5SAleksandr Urakov 
1604eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(RegisterNode &reg, Node *&) {
1614eda12aeSPavel Labath   uint32_t reg_num = reg.GetRegNum();
162758657e5SAleksandr Urakov   lldbassert(reg_num != LLDB_INVALID_REGNUM);
163758657e5SAleksandr Urakov 
164758657e5SAleksandr Urakov   if (reg_num > 31) {
165758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_bregx);
166758657e5SAleksandr Urakov     m_out_stream.PutULEB128(reg_num);
167758657e5SAleksandr Urakov   } else
168758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
169758657e5SAleksandr Urakov 
170758657e5SAleksandr Urakov   m_out_stream.PutSLEB128(0);
171758657e5SAleksandr Urakov }
172758657e5SAleksandr Urakov 
1734eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(IntegerNode &integer, Node *&) {
17485ce053dSPavel Labath   uint32_t value = integer.GetValue();
175758657e5SAleksandr Urakov   m_out_stream.PutHex8(DW_OP_constu);
176758657e5SAleksandr Urakov   m_out_stream.PutULEB128(value);
177758657e5SAleksandr Urakov }
178758657e5SAleksandr Urakov 
1794eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(BinaryOpNode &binary, Node *&) {
18085ce053dSPavel Labath   Dispatch(binary.Left());
18185ce053dSPavel Labath   Dispatch(binary.Right());
182758657e5SAleksandr Urakov 
18385ce053dSPavel Labath   switch (binary.GetOpType()) {
1844eda12aeSPavel Labath   case BinaryOpNode::Plus:
185758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_plus);
186758657e5SAleksandr Urakov     // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
187758657e5SAleksandr Urakov     //       if right child node is constant value
188758657e5SAleksandr Urakov     break;
1894eda12aeSPavel Labath   case BinaryOpNode::Minus:
190758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
191758657e5SAleksandr Urakov     break;
1924eda12aeSPavel Labath   case BinaryOpNode::Align:
193758657e5SAleksandr Urakov     // emit align operator a @ b as
194758657e5SAleksandr Urakov     // a & ~(b - 1)
195758657e5SAleksandr Urakov     // NOTE: implicitly assuming that b is power of 2
196758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_lit1);
197758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
198758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_not);
199758657e5SAleksandr Urakov 
200758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_and);
201758657e5SAleksandr Urakov     break;
202758657e5SAleksandr Urakov   }
203758657e5SAleksandr Urakov }
204758657e5SAleksandr Urakov 
2054eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(UnaryOpNode &unary, Node *&) {
20685ce053dSPavel Labath   Dispatch(unary.Operand());
207758657e5SAleksandr Urakov 
20885ce053dSPavel Labath   switch (unary.GetOpType()) {
2094eda12aeSPavel Labath   case UnaryOpNode::Deref:
210758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_deref);
211758657e5SAleksandr Urakov     break;
212758657e5SAleksandr Urakov   }
213758657e5SAleksandr Urakov }
214758657e5SAleksandr Urakov 
215758657e5SAleksandr Urakov } // namespace
216758657e5SAleksandr Urakov 
217758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program,
218*88813103SPavel Labath                                             llvm::BumpPtrAllocator &alloc,
219758657e5SAleksandr Urakov                                             llvm::StringRef &register_name,
2204eda12aeSPavel Labath                                             Node *&ast) {
221758657e5SAleksandr Urakov   // lvalue of assignment is always first token
222758657e5SAleksandr Urakov   // rvalue program goes next
223*88813103SPavel Labath   std::tie(register_name, program) = getToken(program);
224*88813103SPavel Labath   if (register_name.empty())
225758657e5SAleksandr Urakov     return false;
226758657e5SAleksandr Urakov 
227*88813103SPavel Labath   ast = Parse(program, alloc);
228*88813103SPavel Labath   return ast != nullptr;
229758657e5SAleksandr Urakov }
230758657e5SAleksandr Urakov 
2314eda12aeSPavel Labath static Node *ParseFPOProgram(llvm::StringRef program,
232758657e5SAleksandr Urakov                              llvm::StringRef register_name,
233758657e5SAleksandr Urakov                              llvm::Triple::ArchType arch_type,
234*88813103SPavel Labath                              llvm::BumpPtrAllocator &alloc) {
2354eda12aeSPavel Labath   llvm::DenseMap<llvm::StringRef, Node *> dependent_programs;
236758657e5SAleksandr Urakov 
237758657e5SAleksandr Urakov   size_t cur = 0;
238758657e5SAleksandr Urakov   while (true) {
239758657e5SAleksandr Urakov     size_t assign_index = program.find('=', cur);
240758657e5SAleksandr Urakov     if (assign_index == llvm::StringRef::npos) {
241758657e5SAleksandr Urakov       llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos);
242758657e5SAleksandr Urakov       if (!tail.trim().empty()) {
243758657e5SAleksandr Urakov         // missing assign operator
244758657e5SAleksandr Urakov         return nullptr;
245758657e5SAleksandr Urakov       }
246758657e5SAleksandr Urakov       break;
247758657e5SAleksandr Urakov     }
248758657e5SAleksandr Urakov     llvm::StringRef assignment_program = program.slice(cur, assign_index);
249758657e5SAleksandr Urakov 
250758657e5SAleksandr Urakov     llvm::StringRef lvalue_name;
2514eda12aeSPavel Labath     Node *rvalue_ast = nullptr;
252758657e5SAleksandr Urakov     if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name,
253758657e5SAleksandr Urakov                                          rvalue_ast)) {
254758657e5SAleksandr Urakov       return nullptr;
255758657e5SAleksandr Urakov     }
256758657e5SAleksandr Urakov 
257758657e5SAleksandr Urakov     lldbassert(rvalue_ast);
258758657e5SAleksandr Urakov 
259758657e5SAleksandr Urakov     // check & resolve assignment program
26085ce053dSPavel Labath     if (!FPOProgramASTVisitorResolveRegisterRefs::Resolve(
26185ce053dSPavel Labath             dependent_programs, arch_type, alloc, rvalue_ast))
262758657e5SAleksandr Urakov       return nullptr;
263758657e5SAleksandr Urakov 
264758657e5SAleksandr Urakov     if (lvalue_name == register_name) {
265758657e5SAleksandr Urakov       // found target assignment program - no need to parse further
266758657e5SAleksandr Urakov 
267758657e5SAleksandr Urakov       // emplace valid dependent subtrees to make target assignment independent
268758657e5SAleksandr Urakov       // from predecessors
26985ce053dSPavel Labath       FPOProgramASTVisitorMergeDependent::Merge(dependent_programs, rvalue_ast);
270758657e5SAleksandr Urakov 
271758657e5SAleksandr Urakov       return rvalue_ast;
272758657e5SAleksandr Urakov     }
273758657e5SAleksandr Urakov 
274758657e5SAleksandr Urakov     dependent_programs[lvalue_name] = rvalue_ast;
275758657e5SAleksandr Urakov     cur = assign_index + 1;
276758657e5SAleksandr Urakov   }
277758657e5SAleksandr Urakov 
278758657e5SAleksandr Urakov   return nullptr;
279758657e5SAleksandr Urakov }
280758657e5SAleksandr Urakov 
281758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
282758657e5SAleksandr Urakov     llvm::StringRef program, llvm::StringRef register_name,
283758657e5SAleksandr Urakov     llvm::Triple::ArchType arch_type, Stream &stream) {
284*88813103SPavel Labath   llvm::BumpPtrAllocator node_alloc;
2854eda12aeSPavel Labath   Node *target_program =
286758657e5SAleksandr Urakov       ParseFPOProgram(program, register_name, arch_type, node_alloc);
287758657e5SAleksandr Urakov   if (target_program == nullptr) {
288758657e5SAleksandr Urakov     return false;
289758657e5SAleksandr Urakov   }
290758657e5SAleksandr Urakov 
29185ce053dSPavel Labath   FPOProgramASTVisitorDWARFCodegen::Emit(stream, target_program);
292758657e5SAleksandr Urakov   return true;
293758657e5SAleksandr Urakov }
294