1758657e5SAleksandr Urakov //===-- PDBFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===//
2758657e5SAleksandr Urakov //
3ee21a66aSAleksandr Urakov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ee21a66aSAleksandr Urakov // See https://llvm.org/LICENSE.txt for license information.
5ee21a66aSAleksandr Urakov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6758657e5SAleksandr Urakov //
7758657e5SAleksandr Urakov //===----------------------------------------------------------------------===//
8758657e5SAleksandr Urakov 
9758657e5SAleksandr Urakov #include "PdbFPOProgramToDWARFExpression.h"
10758657e5SAleksandr Urakov #include "CodeViewRegisterMapping.h"
11758657e5SAleksandr Urakov 
12758657e5SAleksandr Urakov #include "lldb/Core/StreamBuffer.h"
134eda12aeSPavel Labath #include "lldb/Symbol/PostfixExpression.h"
14758657e5SAleksandr Urakov #include "lldb/Utility/LLDBAssert.h"
15758657e5SAleksandr Urakov #include "lldb/Utility/Stream.h"
16758657e5SAleksandr Urakov #include "llvm/ADT/DenseMap.h"
17758657e5SAleksandr Urakov 
18758657e5SAleksandr Urakov #include "llvm/ADT/StringExtras.h"
19758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/CodeView.h"
20758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/EnumTables.h"
21758657e5SAleksandr Urakov 
22758657e5SAleksandr Urakov using namespace lldb;
23758657e5SAleksandr Urakov using namespace lldb_private;
244eda12aeSPavel Labath using namespace lldb_private::postfix;
25758657e5SAleksandr Urakov 
261c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
271c4ee160SPavel Labath   // lookup register name to get lldb register number
281c4ee160SPavel Labath   llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
291c4ee160SPavel Labath       llvm::codeview::getRegisterNames();
301c4ee160SPavel Labath   auto it = llvm::find_if(
311c4ee160SPavel Labath       register_names,
321c4ee160SPavel Labath       [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
331c4ee160SPavel Labath         return reg_name.compare_lower(register_entry.Name) == 0;
341c4ee160SPavel Labath       });
35758657e5SAleksandr Urakov 
361c4ee160SPavel Labath   if (it == register_names.end())
371c4ee160SPavel Labath     return LLDB_INVALID_REGNUM;
381c4ee160SPavel Labath 
391c4ee160SPavel Labath   auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
401c4ee160SPavel Labath   return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
41758657e5SAleksandr Urakov }
421c4ee160SPavel Labath 
43758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program,
4488813103SPavel Labath                                             llvm::BumpPtrAllocator &alloc,
45758657e5SAleksandr Urakov                                             llvm::StringRef &register_name,
464eda12aeSPavel Labath                                             Node *&ast) {
47758657e5SAleksandr Urakov   // lvalue of assignment is always first token
48758657e5SAleksandr Urakov   // rvalue program goes next
4988813103SPavel Labath   std::tie(register_name, program) = getToken(program);
5088813103SPavel Labath   if (register_name.empty())
51758657e5SAleksandr Urakov     return false;
52758657e5SAleksandr Urakov 
5388813103SPavel Labath   ast = Parse(program, alloc);
5488813103SPavel Labath   return ast != nullptr;
55758657e5SAleksandr Urakov }
56758657e5SAleksandr Urakov 
574eda12aeSPavel Labath static Node *ParseFPOProgram(llvm::StringRef program,
58758657e5SAleksandr Urakov                              llvm::StringRef register_name,
59758657e5SAleksandr Urakov                              llvm::Triple::ArchType arch_type,
6088813103SPavel Labath                              llvm::BumpPtrAllocator &alloc) {
614eda12aeSPavel Labath   llvm::DenseMap<llvm::StringRef, Node *> dependent_programs;
62758657e5SAleksandr Urakov 
63758657e5SAleksandr Urakov   size_t cur = 0;
64758657e5SAleksandr Urakov   while (true) {
65758657e5SAleksandr Urakov     size_t assign_index = program.find('=', cur);
66758657e5SAleksandr Urakov     if (assign_index == llvm::StringRef::npos) {
67758657e5SAleksandr Urakov       llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos);
68758657e5SAleksandr Urakov       if (!tail.trim().empty()) {
69758657e5SAleksandr Urakov         // missing assign operator
70758657e5SAleksandr Urakov         return nullptr;
71758657e5SAleksandr Urakov       }
72758657e5SAleksandr Urakov       break;
73758657e5SAleksandr Urakov     }
74758657e5SAleksandr Urakov     llvm::StringRef assignment_program = program.slice(cur, assign_index);
75758657e5SAleksandr Urakov 
76758657e5SAleksandr Urakov     llvm::StringRef lvalue_name;
774eda12aeSPavel Labath     Node *rvalue_ast = nullptr;
78758657e5SAleksandr Urakov     if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name,
79758657e5SAleksandr Urakov                                          rvalue_ast)) {
80758657e5SAleksandr Urakov       return nullptr;
81758657e5SAleksandr Urakov     }
82758657e5SAleksandr Urakov 
83758657e5SAleksandr Urakov     lldbassert(rvalue_ast);
84758657e5SAleksandr Urakov 
85*0eadd988SPavel Labath     // Emplace valid dependent subtrees to make target assignment independent
86*0eadd988SPavel Labath     // from predecessors. Resolve all other SymbolNodes as registers.
87*0eadd988SPavel Labath     bool success =
88*0eadd988SPavel Labath         ResolveSymbols(rvalue_ast, [&](SymbolNode &symbol) -> Node * {
89*0eadd988SPavel Labath           if (Node *node = dependent_programs.lookup(symbol.GetName()))
90*0eadd988SPavel Labath             return node;
91*0eadd988SPavel Labath           uint32_t reg_num =
92*0eadd988SPavel Labath               ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type);
93*0eadd988SPavel Labath 
94*0eadd988SPavel Labath           if (reg_num == LLDB_INVALID_REGNUM)
95*0eadd988SPavel Labath             return nullptr;
96*0eadd988SPavel Labath 
97*0eadd988SPavel Labath           return MakeNode<RegisterNode>(alloc, reg_num);
98*0eadd988SPavel Labath         });
99*0eadd988SPavel Labath     if (!success)
100758657e5SAleksandr Urakov       return nullptr;
101758657e5SAleksandr Urakov 
102758657e5SAleksandr Urakov     if (lvalue_name == register_name) {
103758657e5SAleksandr Urakov       // found target assignment program - no need to parse further
104758657e5SAleksandr Urakov       return rvalue_ast;
105758657e5SAleksandr Urakov     }
106758657e5SAleksandr Urakov 
107758657e5SAleksandr Urakov     dependent_programs[lvalue_name] = rvalue_ast;
108758657e5SAleksandr Urakov     cur = assign_index + 1;
109758657e5SAleksandr Urakov   }
110758657e5SAleksandr Urakov 
111758657e5SAleksandr Urakov   return nullptr;
112758657e5SAleksandr Urakov }
113758657e5SAleksandr Urakov 
114758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
115758657e5SAleksandr Urakov     llvm::StringRef program, llvm::StringRef register_name,
116758657e5SAleksandr Urakov     llvm::Triple::ArchType arch_type, Stream &stream) {
11788813103SPavel Labath   llvm::BumpPtrAllocator node_alloc;
1184eda12aeSPavel Labath   Node *target_program =
119758657e5SAleksandr Urakov       ParseFPOProgram(program, register_name, arch_type, node_alloc);
120758657e5SAleksandr Urakov   if (target_program == nullptr) {
121758657e5SAleksandr Urakov     return false;
122758657e5SAleksandr Urakov   }
123758657e5SAleksandr Urakov 
124*0eadd988SPavel Labath   ToDWARF(*target_program, stream);
125758657e5SAleksandr Urakov   return true;
126758657e5SAleksandr Urakov }
127