1 //===-- PdbFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===// 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 "PdbFPOProgramToDWARFExpression.h" 10 #include "CodeViewRegisterMapping.h" 11 12 #include "lldb/Core/StreamBuffer.h" 13 #include "lldb/Symbol/PostfixExpression.h" 14 #include "lldb/Utility/LLDBAssert.h" 15 #include "lldb/Utility/Stream.h" 16 #include "llvm/ADT/DenseMap.h" 17 18 #include "llvm/ADT/StringExtras.h" 19 #include "llvm/DebugInfo/CodeView/CodeView.h" 20 #include "llvm/DebugInfo/CodeView/EnumTables.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 using namespace lldb_private::postfix; 25 26 static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) { 27 // lookup register name to get lldb register number 28 llvm::codeview::CPUType cpu_type; 29 switch (arch_type) { 30 case llvm::Triple::ArchType::aarch64: 31 cpu_type = llvm::codeview::CPUType::ARM64; 32 break; 33 34 default: 35 cpu_type = llvm::codeview::CPUType::X64; 36 break; 37 } 38 39 llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names = 40 llvm::codeview::getRegisterNames(cpu_type); 41 auto it = llvm::find_if( 42 register_names, 43 [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { 44 return reg_name.compare_lower(register_entry.Name) == 0; 45 }); 46 47 if (it == register_names.end()) 48 return LLDB_INVALID_REGNUM; 49 50 auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value); 51 return npdb::GetLLDBRegisterNumber(arch_type, reg_id); 52 } 53 54 static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program, 55 llvm::BumpPtrAllocator &alloc, 56 llvm::StringRef ®ister_name, 57 Node *&ast) { 58 // lvalue of assignment is always first token 59 // rvalue program goes next 60 std::tie(register_name, program) = getToken(program); 61 if (register_name.empty()) 62 return false; 63 64 ast = Parse(program, alloc); 65 return ast != nullptr; 66 } 67 68 static Node *ParseFPOProgram(llvm::StringRef program, 69 llvm::StringRef register_name, 70 llvm::Triple::ArchType arch_type, 71 llvm::BumpPtrAllocator &alloc) { 72 llvm::DenseMap<llvm::StringRef, Node *> dependent_programs; 73 74 size_t cur = 0; 75 while (true) { 76 size_t assign_index = program.find('=', cur); 77 if (assign_index == llvm::StringRef::npos) { 78 llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos); 79 if (!tail.trim().empty()) { 80 // missing assign operator 81 return nullptr; 82 } 83 break; 84 } 85 llvm::StringRef assignment_program = program.slice(cur, assign_index); 86 87 llvm::StringRef lvalue_name; 88 Node *rvalue_ast = nullptr; 89 if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name, 90 rvalue_ast)) { 91 return nullptr; 92 } 93 94 lldbassert(rvalue_ast); 95 96 // Emplace valid dependent subtrees to make target assignment independent 97 // from predecessors. Resolve all other SymbolNodes as registers. 98 bool success = 99 ResolveSymbols(rvalue_ast, [&](SymbolNode &symbol) -> Node * { 100 if (Node *node = dependent_programs.lookup(symbol.GetName())) 101 return node; 102 uint32_t reg_num = 103 ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type); 104 105 if (reg_num == LLDB_INVALID_REGNUM) 106 return nullptr; 107 108 return MakeNode<RegisterNode>(alloc, reg_num); 109 }); 110 if (!success) 111 return nullptr; 112 113 if (lvalue_name == register_name) { 114 // found target assignment program - no need to parse further 115 return rvalue_ast; 116 } 117 118 dependent_programs[lvalue_name] = rvalue_ast; 119 cur = assign_index + 1; 120 } 121 122 return nullptr; 123 } 124 125 bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( 126 llvm::StringRef program, llvm::StringRef register_name, 127 llvm::Triple::ArchType arch_type, Stream &stream) { 128 llvm::BumpPtrAllocator node_alloc; 129 Node *target_program = 130 ParseFPOProgram(program, register_name, arch_type, node_alloc); 131 if (target_program == nullptr) { 132 return false; 133 } 134 135 ToDWARF(*target_program, stream); 136 return true; 137 } 138