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/Symbol/PostfixExpression.h" |
13 | #include "lldb/Utility/LLDBAssert.h" |
14 | #include "lldb/Utility/Stream.h" |
15 | #include "llvm/ADT/DenseMap.h" |
16 | |
17 | #include "llvm/ADT/StringExtras.h" |
18 | #include "llvm/DebugInfo/CodeView/CodeView.h" |
19 | #include "llvm/DebugInfo/CodeView/EnumTables.h" |
20 | #include "llvm/Support/ScopedPrinter.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: cpu_type); |
41 | auto it = llvm::find_if( |
42 | Range&: register_names, |
43 | P: [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { |
44 | return reg_name.compare_insensitive(RHS: 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, register_id: 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(prog: 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(node&: it->second, replacer: [&](SymbolNode &symbol) -> Node * { |
66 | for (const auto &pair : llvm::make_range(x: parsed.begin(), y: it)) { |
67 | if (pair.first == symbol.GetName()) |
68 | return pair.second; |
69 | } |
70 | |
71 | uint32_t reg_num = |
72 | ResolveLLDBRegisterNum(reg_name: symbol.GetName().drop_front(N: 1), arch_type); |
73 | |
74 | if (reg_num == LLDB_INVALID_REGNUM) |
75 | return nullptr; |
76 | |
77 | return MakeNode<RegisterNode>(alloc, args&: 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, alloc&: node_alloc); |
97 | if (target_program == nullptr) { |
98 | return false; |
99 | } |
100 | |
101 | ToDWARF(node&: *target_program, stream); |
102 | return true; |
103 | } |
104 | |