diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:51:52 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:51:52 +0000 |
commit | 5f29bb8a675e8f96452b632e7129113f7dec850e (patch) | |
tree | 3d3f2a0d3ad10872a4dcaba8ec8d1d20c87ab147 /source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp | |
parent | 88c643b6fec27eec436c8d138fee6346e92337d6 (diff) |
Notes
Diffstat (limited to 'source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp')
-rw-r--r-- | source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp b/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp new file mode 100644 index 000000000000..79dd010ff311 --- /dev/null +++ b/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp @@ -0,0 +1,137 @@ +//===-- PdbFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PdbFPOProgramToDWARFExpression.h" +#include "CodeViewRegisterMapping.h" + +#include "lldb/Core/StreamBuffer.h" +#include "lldb/Symbol/PostfixExpression.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/DenseMap.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/EnumTables.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::postfix; + +static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) { + // lookup register name to get lldb register number + llvm::codeview::CPUType cpu_type; + switch (arch_type) { + case llvm::Triple::ArchType::aarch64: + cpu_type = llvm::codeview::CPUType::ARM64; + break; + + default: + cpu_type = llvm::codeview::CPUType::X64; + break; + } + + llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names = + llvm::codeview::getRegisterNames(cpu_type); + auto it = llvm::find_if( + register_names, + [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { + return reg_name.compare_lower(register_entry.Name) == 0; + }); + + if (it == register_names.end()) + return LLDB_INVALID_REGNUM; + + auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value); + return npdb::GetLLDBRegisterNumber(arch_type, reg_id); +} + +static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program, + llvm::BumpPtrAllocator &alloc, + llvm::StringRef ®ister_name, + Node *&ast) { + // lvalue of assignment is always first token + // rvalue program goes next + std::tie(register_name, program) = getToken(program); + if (register_name.empty()) + return false; + + ast = Parse(program, alloc); + return ast != nullptr; +} + +static Node *ParseFPOProgram(llvm::StringRef program, + llvm::StringRef register_name, + llvm::Triple::ArchType arch_type, + llvm::BumpPtrAllocator &alloc) { + llvm::DenseMap<llvm::StringRef, Node *> dependent_programs; + + size_t cur = 0; + while (true) { + size_t assign_index = program.find('=', cur); + if (assign_index == llvm::StringRef::npos) { + llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos); + if (!tail.trim().empty()) { + // missing assign operator + return nullptr; + } + break; + } + llvm::StringRef assignment_program = program.slice(cur, assign_index); + + llvm::StringRef lvalue_name; + Node *rvalue_ast = nullptr; + if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name, + rvalue_ast)) { + return nullptr; + } + + lldbassert(rvalue_ast); + + // Emplace valid dependent subtrees to make target assignment independent + // from predecessors. Resolve all other SymbolNodes as registers. + bool success = + ResolveSymbols(rvalue_ast, [&](SymbolNode &symbol) -> Node * { + if (Node *node = dependent_programs.lookup(symbol.GetName())) + return node; + uint32_t reg_num = + ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type); + + if (reg_num == LLDB_INVALID_REGNUM) + return nullptr; + + return MakeNode<RegisterNode>(alloc, reg_num); + }); + if (!success) + return nullptr; + + if (lvalue_name == register_name) { + // found target assignment program - no need to parse further + return rvalue_ast; + } + + dependent_programs[lvalue_name] = rvalue_ast; + cur = assign_index + 1; + } + + return nullptr; +} + +bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( + llvm::StringRef program, llvm::StringRef register_name, + llvm::Triple::ArchType arch_type, Stream &stream) { + llvm::BumpPtrAllocator node_alloc; + Node *target_program = + ParseFPOProgram(program, register_name, arch_type, node_alloc); + if (target_program == nullptr) { + return false; + } + + ToDWARF(*target_program, stream); + return true; +} |