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 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_insensitive(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 Node *ResolveFPOProgram(llvm::StringRef program, 55 llvm::StringRef register_name, 56 llvm::Triple::ArchType arch_type, 57 llvm::BumpPtrAllocator &alloc) { 58 std::vector<std::pair<llvm::StringRef, Node *>> parsed = 59 postfix::ParseFPOProgram(program, alloc); 60 61 for (auto it = parsed.begin(), end = parsed.end(); it != end; ++it) { 62 // Emplace valid dependent subtrees to make target assignment independent 63 // from predecessors. Resolve all other SymbolNodes as registers. 64 bool success = 65 ResolveSymbols(it->second, [&](SymbolNode &symbol) -> Node * { 66 for (const auto &pair : llvm::make_range(parsed.begin(), it)) { 67 if (pair.first == symbol.GetName()) 68 return pair.second; 69 } 70 71 uint32_t reg_num = 72 ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type); 73 74 if (reg_num == LLDB_INVALID_REGNUM) 75 return nullptr; 76 77 return MakeNode<RegisterNode>(alloc, reg_num); 78 }); 79 if (!success) 80 return nullptr; 81 82 if (it->first == register_name) { 83 // found target assignment program - no need to parse further 84 return it->second; 85 } 86 } 87 88 return nullptr; 89 } 90 91 bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( 92 llvm::StringRef program, llvm::StringRef register_name, 93 llvm::Triple::ArchType arch_type, Stream &stream) { 94 llvm::BumpPtrAllocator node_alloc; 95 Node *target_program = 96 ResolveFPOProgram(program, register_name, arch_type, node_alloc); 97 if (target_program == nullptr) { 98 return false; 99 } 100 101 ToDWARF(*target_program, stream); 102 return true; 103 } 104