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 [®_name](const llvm::EnumEntry<uint16_t> ®ister_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 ®, 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 ®, 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 ®ister_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