PdbFPOProgramToDWARFExpression.cpp revision 351290
1351290Sdim//===-- PdbFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===// 2351290Sdim// 3351290Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4351290Sdim// See https://llvm.org/LICENSE.txt for license information. 5351290Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6351290Sdim// 7351290Sdim//===----------------------------------------------------------------------===// 8351290Sdim 9351290Sdim#include "PdbFPOProgramToDWARFExpression.h" 10351290Sdim#include "CodeViewRegisterMapping.h" 11351290Sdim 12351290Sdim#include "lldb/Core/StreamBuffer.h" 13351290Sdim#include "lldb/Symbol/PostfixExpression.h" 14351290Sdim#include "lldb/Utility/LLDBAssert.h" 15351290Sdim#include "lldb/Utility/Stream.h" 16351290Sdim#include "llvm/ADT/DenseMap.h" 17351290Sdim 18351290Sdim#include "llvm/ADT/StringExtras.h" 19351290Sdim#include "llvm/DebugInfo/CodeView/CodeView.h" 20351290Sdim#include "llvm/DebugInfo/CodeView/EnumTables.h" 21351290Sdim 22351290Sdimusing namespace lldb; 23351290Sdimusing namespace lldb_private; 24351290Sdimusing namespace lldb_private::postfix; 25351290Sdim 26351290Sdimstatic uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) { 27351290Sdim // lookup register name to get lldb register number 28351290Sdim llvm::codeview::CPUType cpu_type; 29351290Sdim switch (arch_type) { 30351290Sdim case llvm::Triple::ArchType::aarch64: 31351290Sdim cpu_type = llvm::codeview::CPUType::ARM64; 32351290Sdim break; 33351290Sdim 34351290Sdim default: 35351290Sdim cpu_type = llvm::codeview::CPUType::X64; 36351290Sdim break; 37351290Sdim } 38351290Sdim 39351290Sdim llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names = 40351290Sdim llvm::codeview::getRegisterNames(cpu_type); 41351290Sdim auto it = llvm::find_if( 42351290Sdim register_names, 43351290Sdim [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { 44351290Sdim return reg_name.compare_lower(register_entry.Name) == 0; 45351290Sdim }); 46351290Sdim 47351290Sdim if (it == register_names.end()) 48351290Sdim return LLDB_INVALID_REGNUM; 49351290Sdim 50351290Sdim auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value); 51351290Sdim return npdb::GetLLDBRegisterNumber(arch_type, reg_id); 52351290Sdim} 53351290Sdim 54351290Sdimstatic bool ParseFPOSingleAssignmentProgram(llvm::StringRef program, 55351290Sdim llvm::BumpPtrAllocator &alloc, 56351290Sdim llvm::StringRef ®ister_name, 57351290Sdim Node *&ast) { 58351290Sdim // lvalue of assignment is always first token 59351290Sdim // rvalue program goes next 60351290Sdim std::tie(register_name, program) = getToken(program); 61351290Sdim if (register_name.empty()) 62351290Sdim return false; 63351290Sdim 64351290Sdim ast = Parse(program, alloc); 65351290Sdim return ast != nullptr; 66351290Sdim} 67351290Sdim 68351290Sdimstatic Node *ParseFPOProgram(llvm::StringRef program, 69351290Sdim llvm::StringRef register_name, 70351290Sdim llvm::Triple::ArchType arch_type, 71351290Sdim llvm::BumpPtrAllocator &alloc) { 72351290Sdim llvm::DenseMap<llvm::StringRef, Node *> dependent_programs; 73351290Sdim 74351290Sdim size_t cur = 0; 75351290Sdim while (true) { 76351290Sdim size_t assign_index = program.find('=', cur); 77351290Sdim if (assign_index == llvm::StringRef::npos) { 78351290Sdim llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos); 79351290Sdim if (!tail.trim().empty()) { 80351290Sdim // missing assign operator 81351290Sdim return nullptr; 82351290Sdim } 83351290Sdim break; 84351290Sdim } 85351290Sdim llvm::StringRef assignment_program = program.slice(cur, assign_index); 86351290Sdim 87351290Sdim llvm::StringRef lvalue_name; 88351290Sdim Node *rvalue_ast = nullptr; 89351290Sdim if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name, 90351290Sdim rvalue_ast)) { 91351290Sdim return nullptr; 92351290Sdim } 93351290Sdim 94351290Sdim lldbassert(rvalue_ast); 95351290Sdim 96351290Sdim // Emplace valid dependent subtrees to make target assignment independent 97351290Sdim // from predecessors. Resolve all other SymbolNodes as registers. 98351290Sdim bool success = 99351290Sdim ResolveSymbols(rvalue_ast, [&](SymbolNode &symbol) -> Node * { 100351290Sdim if (Node *node = dependent_programs.lookup(symbol.GetName())) 101351290Sdim return node; 102351290Sdim uint32_t reg_num = 103351290Sdim ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type); 104351290Sdim 105351290Sdim if (reg_num == LLDB_INVALID_REGNUM) 106351290Sdim return nullptr; 107351290Sdim 108351290Sdim return MakeNode<RegisterNode>(alloc, reg_num); 109351290Sdim }); 110351290Sdim if (!success) 111351290Sdim return nullptr; 112351290Sdim 113351290Sdim if (lvalue_name == register_name) { 114351290Sdim // found target assignment program - no need to parse further 115351290Sdim return rvalue_ast; 116351290Sdim } 117351290Sdim 118351290Sdim dependent_programs[lvalue_name] = rvalue_ast; 119351290Sdim cur = assign_index + 1; 120351290Sdim } 121351290Sdim 122351290Sdim return nullptr; 123351290Sdim} 124351290Sdim 125351290Sdimbool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( 126351290Sdim llvm::StringRef program, llvm::StringRef register_name, 127351290Sdim llvm::Triple::ArchType arch_type, Stream &stream) { 128351290Sdim llvm::BumpPtrAllocator node_alloc; 129351290Sdim Node *target_program = 130351290Sdim ParseFPOProgram(program, register_name, arch_type, node_alloc); 131351290Sdim if (target_program == nullptr) { 132351290Sdim return false; 133351290Sdim } 134351290Sdim 135351290Sdim ToDWARF(*target_program, stream); 136351290Sdim return true; 137351290Sdim} 138