1 //===-- PdbFPOProgramToDWARFExpression.cpp --------------------------------===// 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 #include "llvm/Support/ScopedPrinter.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 using namespace lldb_private::postfix; 26 27 static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) { 28 // lookup register name to get lldb register number 29 llvm::codeview::CPUType cpu_type; 30 switch (arch_type) { 31 case llvm::Triple::ArchType::aarch64: 32 cpu_type = llvm::codeview::CPUType::ARM64; 33 break; 34 35 default: 36 cpu_type = llvm::codeview::CPUType::X64; 37 break; 38 } 39 40 llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names = 41 llvm::codeview::getRegisterNames(cpu_type); 42 auto it = llvm::find_if( 43 register_names, 44 [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { 45 return reg_name.compare_insensitive(register_entry.Name) == 0; 46 }); 47 48 if (it == register_names.end()) 49 return LLDB_INVALID_REGNUM; 50 51 auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value); 52 return npdb::GetLLDBRegisterNumber(arch_type, reg_id); 53 } 54 55 static Node *ResolveFPOProgram(llvm::StringRef program, 56 llvm::StringRef register_name, 57 llvm::Triple::ArchType arch_type, 58 llvm::BumpPtrAllocator &alloc) { 59 std::vector<std::pair<llvm::StringRef, Node *>> parsed = 60 postfix::ParseFPOProgram(program, alloc); 61 62 for (auto it = parsed.begin(), end = parsed.end(); it != end; ++it) { 63 // Emplace valid dependent subtrees to make target assignment independent 64 // from predecessors. Resolve all other SymbolNodes as registers. 65 bool success = 66 ResolveSymbols(it->second, [&](SymbolNode &symbol) -> Node * { 67 for (const auto &pair : llvm::make_range(parsed.begin(), it)) { 68 if (pair.first == symbol.GetName()) 69 return pair.second; 70 } 71 72 uint32_t reg_num = 73 ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type); 74 75 if (reg_num == LLDB_INVALID_REGNUM) 76 return nullptr; 77 78 return MakeNode<RegisterNode>(alloc, reg_num); 79 }); 80 if (!success) 81 return nullptr; 82 83 if (it->first == register_name) { 84 // found target assignment program - no need to parse further 85 return it->second; 86 } 87 } 88 89 return nullptr; 90 } 91 92 bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( 93 llvm::StringRef program, llvm::StringRef register_name, 94 llvm::Triple::ArchType arch_type, Stream &stream) { 95 llvm::BumpPtrAllocator node_alloc; 96 Node *target_program = 97 ResolveFPOProgram(program, register_name, arch_type, node_alloc); 98 if (target_program == nullptr) { 99 return false; 100 } 101 102 ToDWARF(*target_program, stream); 103 return true; 104 } 105