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" 13758657e5SAleksandr Urakov #include "lldb/Core/dwarf.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" 21*1beeda68SPavel Labath #include "llvm/Support/Casting.h" 22758657e5SAleksandr Urakov 23758657e5SAleksandr Urakov using namespace lldb; 24758657e5SAleksandr Urakov using namespace lldb_private; 25758657e5SAleksandr Urakov 26758657e5SAleksandr Urakov namespace { 27758657e5SAleksandr Urakov 28758657e5SAleksandr Urakov class FPOProgramNode; 29758657e5SAleksandr Urakov class FPOProgramASTVisitor; 30758657e5SAleksandr Urakov 311c4ee160SPavel Labath class NodeAllocator { 321c4ee160SPavel Labath public: 331c4ee160SPavel Labath template <typename T, typename... Args> T *makeNode(Args &&... args) { 341c4ee160SPavel Labath void *new_node_mem = m_alloc.Allocate(sizeof(T), alignof(T)); 351c4ee160SPavel Labath return new (new_node_mem) T(std::forward<Args>(args)...); 361c4ee160SPavel Labath } 371c4ee160SPavel Labath 381c4ee160SPavel Labath private: 391c4ee160SPavel Labath llvm::BumpPtrAllocator m_alloc; 401c4ee160SPavel Labath }; 411c4ee160SPavel Labath 42758657e5SAleksandr Urakov class FPOProgramNode { 43758657e5SAleksandr Urakov public: 44758657e5SAleksandr Urakov enum Kind { 451c4ee160SPavel Labath Symbol, 46758657e5SAleksandr Urakov Register, 47758657e5SAleksandr Urakov IntegerLiteral, 48758657e5SAleksandr Urakov BinaryOp, 49758657e5SAleksandr Urakov UnaryOp, 50758657e5SAleksandr Urakov }; 51758657e5SAleksandr Urakov 52758657e5SAleksandr Urakov protected: 53758657e5SAleksandr Urakov FPOProgramNode(Kind kind) : m_token_kind(kind) {} 54758657e5SAleksandr Urakov 55758657e5SAleksandr Urakov public: 56758657e5SAleksandr Urakov virtual ~FPOProgramNode() = default; 5794cd0667SPavel Labath virtual void Accept(FPOProgramASTVisitor &visitor) = 0; 58758657e5SAleksandr Urakov 59758657e5SAleksandr Urakov Kind GetKind() const { return m_token_kind; } 60758657e5SAleksandr Urakov 61758657e5SAleksandr Urakov private: 62758657e5SAleksandr Urakov Kind m_token_kind; 63758657e5SAleksandr Urakov }; 64758657e5SAleksandr Urakov 651c4ee160SPavel Labath class FPOProgramNodeSymbol: public FPOProgramNode { 66758657e5SAleksandr Urakov public: 671c4ee160SPavel Labath FPOProgramNodeSymbol(llvm::StringRef name) 681c4ee160SPavel Labath : FPOProgramNode(Symbol), m_name(name) {} 69758657e5SAleksandr Urakov 7094cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 71758657e5SAleksandr Urakov 72758657e5SAleksandr Urakov llvm::StringRef GetName() const { return m_name; } 73758657e5SAleksandr Urakov 74*1beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 75*1beeda68SPavel Labath return node->GetKind() == Symbol; 76*1beeda68SPavel Labath } 77*1beeda68SPavel Labath 78758657e5SAleksandr Urakov private: 79758657e5SAleksandr Urakov llvm::StringRef m_name; 80758657e5SAleksandr Urakov }; 81758657e5SAleksandr Urakov 821c4ee160SPavel Labath class FPOProgramNodeRegisterRef : public FPOProgramNode { 831c4ee160SPavel Labath public: 841c4ee160SPavel Labath FPOProgramNodeRegisterRef(uint32_t lldb_reg_num) 851c4ee160SPavel Labath : FPOProgramNode(Register), m_lldb_reg_num(lldb_reg_num) {} 86758657e5SAleksandr Urakov 8794cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 88758657e5SAleksandr Urakov 891c4ee160SPavel Labath uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; } 90758657e5SAleksandr Urakov 91*1beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 92*1beeda68SPavel Labath return node->GetKind() == Register; 93*1beeda68SPavel Labath } 94*1beeda68SPavel Labath 951c4ee160SPavel Labath private: 961c4ee160SPavel Labath uint32_t m_lldb_reg_num; 971c4ee160SPavel Labath }; 98758657e5SAleksandr Urakov 99758657e5SAleksandr Urakov class FPOProgramNodeIntegerLiteral : public FPOProgramNode { 100758657e5SAleksandr Urakov public: 101758657e5SAleksandr Urakov FPOProgramNodeIntegerLiteral(uint32_t value) 102758657e5SAleksandr Urakov : FPOProgramNode(IntegerLiteral), m_value(value) {} 103758657e5SAleksandr Urakov 10494cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 105758657e5SAleksandr Urakov 106758657e5SAleksandr Urakov uint32_t GetValue() const { return m_value; } 107758657e5SAleksandr Urakov 108*1beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 109*1beeda68SPavel Labath return node->GetKind() == IntegerLiteral; 110*1beeda68SPavel Labath } 111*1beeda68SPavel Labath 112758657e5SAleksandr Urakov private: 113758657e5SAleksandr Urakov uint32_t m_value; 114758657e5SAleksandr Urakov }; 115758657e5SAleksandr Urakov 116758657e5SAleksandr Urakov class FPOProgramNodeBinaryOp : public FPOProgramNode { 117758657e5SAleksandr Urakov public: 118758657e5SAleksandr Urakov enum OpType { 119758657e5SAleksandr Urakov Plus, 120758657e5SAleksandr Urakov Minus, 121758657e5SAleksandr Urakov Align, 122758657e5SAleksandr Urakov }; 123758657e5SAleksandr Urakov 12494cd0667SPavel Labath FPOProgramNodeBinaryOp(OpType op_type, FPOProgramNode &left, 12594cd0667SPavel Labath FPOProgramNode &right) 12694cd0667SPavel Labath : FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(&left), 12794cd0667SPavel Labath m_right(&right) {} 128758657e5SAleksandr Urakov 12994cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 130758657e5SAleksandr Urakov 131758657e5SAleksandr Urakov OpType GetOpType() const { return m_op_type; } 132758657e5SAleksandr Urakov 133758657e5SAleksandr Urakov const FPOProgramNode *Left() const { return m_left; } 134758657e5SAleksandr Urakov FPOProgramNode *&Left() { return m_left; } 135758657e5SAleksandr Urakov 136758657e5SAleksandr Urakov const FPOProgramNode *Right() const { return m_right; } 137758657e5SAleksandr Urakov FPOProgramNode *&Right() { return m_right; } 138758657e5SAleksandr Urakov 139*1beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 140*1beeda68SPavel Labath return node->GetKind() == BinaryOp; 141*1beeda68SPavel Labath } 142*1beeda68SPavel Labath 143758657e5SAleksandr Urakov private: 144758657e5SAleksandr Urakov OpType m_op_type; 145758657e5SAleksandr Urakov FPOProgramNode *m_left; 146758657e5SAleksandr Urakov FPOProgramNode *m_right; 147758657e5SAleksandr Urakov }; 148758657e5SAleksandr Urakov 149758657e5SAleksandr Urakov class FPOProgramNodeUnaryOp : public FPOProgramNode { 150758657e5SAleksandr Urakov public: 151758657e5SAleksandr Urakov enum OpType { 152758657e5SAleksandr Urakov Deref, 153758657e5SAleksandr Urakov }; 154758657e5SAleksandr Urakov 15594cd0667SPavel Labath FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode &operand) 15694cd0667SPavel Labath : FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(&operand) {} 157758657e5SAleksandr Urakov 15894cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 159758657e5SAleksandr Urakov 160758657e5SAleksandr Urakov OpType GetOpType() const { return m_op_type; } 161758657e5SAleksandr Urakov 162758657e5SAleksandr Urakov const FPOProgramNode *Operand() const { return m_operand; } 163758657e5SAleksandr Urakov FPOProgramNode *&Operand() { return m_operand; } 164758657e5SAleksandr Urakov 165*1beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 166*1beeda68SPavel Labath return node->GetKind() == UnaryOp; 167*1beeda68SPavel Labath } 168*1beeda68SPavel Labath 169758657e5SAleksandr Urakov private: 170758657e5SAleksandr Urakov OpType m_op_type; 171758657e5SAleksandr Urakov FPOProgramNode *m_operand; 172758657e5SAleksandr Urakov }; 173758657e5SAleksandr Urakov 174758657e5SAleksandr Urakov class FPOProgramASTVisitor { 175758657e5SAleksandr Urakov public: 176758657e5SAleksandr Urakov virtual ~FPOProgramASTVisitor() = default; 177758657e5SAleksandr Urakov 17894cd0667SPavel Labath virtual void Visit(FPOProgramNodeSymbol &node) {} 17994cd0667SPavel Labath virtual void Visit(FPOProgramNodeRegisterRef &node) {} 18094cd0667SPavel Labath virtual void Visit(FPOProgramNodeIntegerLiteral &node) {} 18194cd0667SPavel Labath virtual void Visit(FPOProgramNodeBinaryOp &node) {} 18294cd0667SPavel Labath virtual void Visit(FPOProgramNodeUnaryOp &node) {} 183758657e5SAleksandr Urakov }; 184758657e5SAleksandr Urakov 18594cd0667SPavel Labath void FPOProgramNodeSymbol::Accept(FPOProgramASTVisitor &visitor) { 18694cd0667SPavel Labath visitor.Visit(*this); 1871c4ee160SPavel Labath } 1881c4ee160SPavel Labath 18994cd0667SPavel Labath void FPOProgramNodeRegisterRef::Accept(FPOProgramASTVisitor &visitor) { 19094cd0667SPavel Labath visitor.Visit(*this); 191758657e5SAleksandr Urakov } 192758657e5SAleksandr Urakov 19394cd0667SPavel Labath void FPOProgramNodeIntegerLiteral::Accept(FPOProgramASTVisitor &visitor) { 19494cd0667SPavel Labath visitor.Visit(*this); 195758657e5SAleksandr Urakov } 196758657e5SAleksandr Urakov 19794cd0667SPavel Labath void FPOProgramNodeBinaryOp::Accept(FPOProgramASTVisitor &visitor) { 19894cd0667SPavel Labath visitor.Visit(*this); 199758657e5SAleksandr Urakov } 200758657e5SAleksandr Urakov 20194cd0667SPavel Labath void FPOProgramNodeUnaryOp::Accept(FPOProgramASTVisitor &visitor) { 20294cd0667SPavel Labath visitor.Visit(*this); 203758657e5SAleksandr Urakov } 204758657e5SAleksandr Urakov 205758657e5SAleksandr Urakov class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor { 206758657e5SAleksandr Urakov public: 207758657e5SAleksandr Urakov FPOProgramASTVisitorMergeDependent( 208758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 209758657e5SAleksandr Urakov &dependent_programs) 210758657e5SAleksandr Urakov : m_dependent_programs(dependent_programs) {} 211758657e5SAleksandr Urakov 212758657e5SAleksandr Urakov void Merge(FPOProgramNode *&node_ref); 213758657e5SAleksandr Urakov 214758657e5SAleksandr Urakov private: 21594cd0667SPavel Labath void Visit(FPOProgramNodeBinaryOp &node) override; 21694cd0667SPavel Labath void Visit(FPOProgramNodeUnaryOp &node) override; 217758657e5SAleksandr Urakov 218758657e5SAleksandr Urakov void TryReplace(FPOProgramNode *&node_ref) const; 219758657e5SAleksandr Urakov 220758657e5SAleksandr Urakov private: 221758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs; 222758657e5SAleksandr Urakov }; 223758657e5SAleksandr Urakov 224758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::Merge(FPOProgramNode *&node_ref) { 225758657e5SAleksandr Urakov TryReplace(node_ref); 22694cd0667SPavel Labath node_ref->Accept(*this); 227758657e5SAleksandr Urakov } 228758657e5SAleksandr Urakov 22994cd0667SPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeBinaryOp &node) { 23094cd0667SPavel Labath Merge(node.Left()); 23194cd0667SPavel Labath Merge(node.Right()); 232758657e5SAleksandr Urakov } 23394cd0667SPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeUnaryOp &node) { 23494cd0667SPavel Labath Merge(node.Operand()); 235758657e5SAleksandr Urakov } 236758657e5SAleksandr Urakov 237758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::TryReplace( 238758657e5SAleksandr Urakov FPOProgramNode *&node_ref) const { 239758657e5SAleksandr Urakov 240*1beeda68SPavel Labath while (auto *symbol = llvm::dyn_cast<FPOProgramNodeSymbol>(node_ref)) { 241*1beeda68SPavel Labath auto it = m_dependent_programs.find(symbol->GetName()); 242758657e5SAleksandr Urakov if (it == m_dependent_programs.end()) { 243758657e5SAleksandr Urakov break; 244758657e5SAleksandr Urakov } 245758657e5SAleksandr Urakov 246758657e5SAleksandr Urakov node_ref = it->second; 247758657e5SAleksandr Urakov } 248758657e5SAleksandr Urakov } 249758657e5SAleksandr Urakov 250758657e5SAleksandr Urakov class FPOProgramASTVisitorResolveRegisterRefs : public FPOProgramASTVisitor { 251758657e5SAleksandr Urakov public: 252758657e5SAleksandr Urakov FPOProgramASTVisitorResolveRegisterRefs( 253758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 254758657e5SAleksandr Urakov &dependent_programs, 2551c4ee160SPavel Labath llvm::Triple::ArchType arch_type, NodeAllocator &alloc) 2561c4ee160SPavel Labath : m_dependent_programs(dependent_programs), m_arch_type(arch_type), 2571c4ee160SPavel Labath m_alloc(alloc) {} 258758657e5SAleksandr Urakov 2591c4ee160SPavel Labath bool Resolve(FPOProgramNode *&program); 260758657e5SAleksandr Urakov 261758657e5SAleksandr Urakov private: 26294cd0667SPavel Labath void Visit(FPOProgramNodeBinaryOp &node) override; 26394cd0667SPavel Labath void Visit(FPOProgramNodeUnaryOp &node) override; 264758657e5SAleksandr Urakov 2651c4ee160SPavel Labath bool TryReplace(FPOProgramNode *&node_ref); 2661c4ee160SPavel Labath 267758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs; 268758657e5SAleksandr Urakov llvm::Triple::ArchType m_arch_type; 2691c4ee160SPavel Labath NodeAllocator &m_alloc; 270758657e5SAleksandr Urakov bool m_no_error_flag = true; 271758657e5SAleksandr Urakov }; 272758657e5SAleksandr Urakov 2731c4ee160SPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::Resolve(FPOProgramNode *&program) { 2741c4ee160SPavel Labath if (!TryReplace(program)) 2751c4ee160SPavel Labath return false; 27694cd0667SPavel Labath program->Accept(*this); 277758657e5SAleksandr Urakov return m_no_error_flag; 278758657e5SAleksandr Urakov } 279758657e5SAleksandr Urakov 2801c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) { 2811c4ee160SPavel Labath // lookup register name to get lldb register number 2821c4ee160SPavel Labath llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names = 2831c4ee160SPavel Labath llvm::codeview::getRegisterNames(); 2841c4ee160SPavel Labath auto it = llvm::find_if( 2851c4ee160SPavel Labath register_names, 2861c4ee160SPavel Labath [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { 2871c4ee160SPavel Labath return reg_name.compare_lower(register_entry.Name) == 0; 2881c4ee160SPavel Labath }); 289758657e5SAleksandr Urakov 2901c4ee160SPavel Labath if (it == register_names.end()) 2911c4ee160SPavel Labath return LLDB_INVALID_REGNUM; 2921c4ee160SPavel Labath 2931c4ee160SPavel Labath auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value); 2941c4ee160SPavel Labath return npdb::GetLLDBRegisterNumber(arch_type, reg_id); 295758657e5SAleksandr Urakov } 2961c4ee160SPavel Labath 2971c4ee160SPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::TryReplace( 2981c4ee160SPavel Labath FPOProgramNode *&node_ref) { 299*1beeda68SPavel Labath auto *symbol = llvm::dyn_cast<FPOProgramNodeSymbol>(node_ref); 300*1beeda68SPavel Labath if (!symbol) 3011c4ee160SPavel Labath return true; 3021c4ee160SPavel Labath 3031c4ee160SPavel Labath // Look up register reference as lvalue in preceding assignments. 3041c4ee160SPavel Labath auto it = m_dependent_programs.find(symbol->GetName()); 3051c4ee160SPavel Labath if (it != m_dependent_programs.end()) { 3061c4ee160SPavel Labath // Dependent programs are handled elsewhere. 3071c4ee160SPavel Labath return true; 3081c4ee160SPavel Labath } 3091c4ee160SPavel Labath 3101c4ee160SPavel Labath uint32_t reg_num = 3111c4ee160SPavel Labath ResolveLLDBRegisterNum(symbol->GetName().drop_front(1), m_arch_type); 3121c4ee160SPavel Labath 3131c4ee160SPavel Labath if (reg_num == LLDB_INVALID_REGNUM) 3141c4ee160SPavel Labath return false; 3151c4ee160SPavel Labath 3161c4ee160SPavel Labath node_ref = m_alloc.makeNode<FPOProgramNodeRegisterRef>(reg_num); 3171c4ee160SPavel Labath return true; 318758657e5SAleksandr Urakov } 319758657e5SAleksandr Urakov 320758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit( 32194cd0667SPavel Labath FPOProgramNodeBinaryOp &node) { 32294cd0667SPavel Labath m_no_error_flag = Resolve(node.Left()) && Resolve(node.Right()); 323758657e5SAleksandr Urakov } 324758657e5SAleksandr Urakov 325758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit( 32694cd0667SPavel Labath FPOProgramNodeUnaryOp &node) { 32794cd0667SPavel Labath m_no_error_flag = Resolve(node.Operand()); 328758657e5SAleksandr Urakov } 329758657e5SAleksandr Urakov 330758657e5SAleksandr Urakov class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor { 331758657e5SAleksandr Urakov public: 332758657e5SAleksandr Urakov FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {} 333758657e5SAleksandr Urakov 33494cd0667SPavel Labath void Emit(FPOProgramNode &program); 335758657e5SAleksandr Urakov 336758657e5SAleksandr Urakov private: 33794cd0667SPavel Labath void Visit(FPOProgramNodeRegisterRef &node) override; 33894cd0667SPavel Labath void Visit(FPOProgramNodeIntegerLiteral &node) override; 33994cd0667SPavel Labath void Visit(FPOProgramNodeBinaryOp &node) override; 34094cd0667SPavel Labath void Visit(FPOProgramNodeUnaryOp &node) override; 341758657e5SAleksandr Urakov 342758657e5SAleksandr Urakov private: 343758657e5SAleksandr Urakov Stream &m_out_stream; 344758657e5SAleksandr Urakov }; 345758657e5SAleksandr Urakov 34694cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Emit(FPOProgramNode &program) { 34794cd0667SPavel Labath program.Accept(*this); 348758657e5SAleksandr Urakov } 349758657e5SAleksandr Urakov 35094cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef &node) { 351758657e5SAleksandr Urakov 35294cd0667SPavel Labath uint32_t reg_num = node.GetLLDBRegNum(); 353758657e5SAleksandr Urakov lldbassert(reg_num != LLDB_INVALID_REGNUM); 354758657e5SAleksandr Urakov 355758657e5SAleksandr Urakov if (reg_num > 31) { 356758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_bregx); 357758657e5SAleksandr Urakov m_out_stream.PutULEB128(reg_num); 358758657e5SAleksandr Urakov } else 359758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_breg0 + reg_num); 360758657e5SAleksandr Urakov 361758657e5SAleksandr Urakov m_out_stream.PutSLEB128(0); 362758657e5SAleksandr Urakov } 363758657e5SAleksandr Urakov 364758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit( 36594cd0667SPavel Labath FPOProgramNodeIntegerLiteral &node) { 36694cd0667SPavel Labath uint32_t value = node.GetValue(); 367758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_constu); 368758657e5SAleksandr Urakov m_out_stream.PutULEB128(value); 369758657e5SAleksandr Urakov } 370758657e5SAleksandr Urakov 37194cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &node) { 372758657e5SAleksandr Urakov 37394cd0667SPavel Labath Emit(*node.Left()); 37494cd0667SPavel Labath Emit(*node.Right()); 375758657e5SAleksandr Urakov 37694cd0667SPavel Labath switch (node.GetOpType()) { 377758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Plus: 378758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_plus); 379758657e5SAleksandr Urakov // NOTE: can be optimized by using DW_OP_plus_uconst opcpode 380758657e5SAleksandr Urakov // if right child node is constant value 381758657e5SAleksandr Urakov break; 382758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Minus: 383758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_minus); 384758657e5SAleksandr Urakov break; 385758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Align: 386758657e5SAleksandr Urakov // emit align operator a @ b as 387758657e5SAleksandr Urakov // a & ~(b - 1) 388758657e5SAleksandr Urakov // NOTE: implicitly assuming that b is power of 2 389758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_lit1); 390758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_minus); 391758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_not); 392758657e5SAleksandr Urakov 393758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_and); 394758657e5SAleksandr Urakov break; 395758657e5SAleksandr Urakov } 396758657e5SAleksandr Urakov } 397758657e5SAleksandr Urakov 39894cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp &node) { 39994cd0667SPavel Labath Emit(*node.Operand()); 400758657e5SAleksandr Urakov 40194cd0667SPavel Labath switch (node.GetOpType()) { 402758657e5SAleksandr Urakov case FPOProgramNodeUnaryOp::Deref: 403758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_deref); 404758657e5SAleksandr Urakov break; 405758657e5SAleksandr Urakov } 406758657e5SAleksandr Urakov } 407758657e5SAleksandr Urakov 408758657e5SAleksandr Urakov } // namespace 409758657e5SAleksandr Urakov 410758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program, 411758657e5SAleksandr Urakov NodeAllocator &alloc, 412758657e5SAleksandr Urakov llvm::StringRef ®ister_name, 413758657e5SAleksandr Urakov FPOProgramNode *&ast) { 414758657e5SAleksandr Urakov llvm::SmallVector<llvm::StringRef, 16> tokens; 415758657e5SAleksandr Urakov llvm::SplitString(program, tokens, " "); 416758657e5SAleksandr Urakov 417758657e5SAleksandr Urakov if (tokens.empty()) 418758657e5SAleksandr Urakov return false; 419758657e5SAleksandr Urakov 420758657e5SAleksandr Urakov llvm::SmallVector<FPOProgramNode *, 4> eval_stack; 421758657e5SAleksandr Urakov 422758657e5SAleksandr Urakov llvm::DenseMap<llvm::StringRef, FPOProgramNodeBinaryOp::OpType> ops_binary = { 423758657e5SAleksandr Urakov {"+", FPOProgramNodeBinaryOp::Plus}, 424758657e5SAleksandr Urakov {"-", FPOProgramNodeBinaryOp::Minus}, 425758657e5SAleksandr Urakov {"@", FPOProgramNodeBinaryOp::Align}, 426758657e5SAleksandr Urakov }; 427758657e5SAleksandr Urakov 428758657e5SAleksandr Urakov llvm::DenseMap<llvm::StringRef, FPOProgramNodeUnaryOp::OpType> ops_unary = { 429758657e5SAleksandr Urakov {"^", FPOProgramNodeUnaryOp::Deref}, 430758657e5SAleksandr Urakov }; 431758657e5SAleksandr Urakov 432758657e5SAleksandr Urakov constexpr llvm::StringLiteral ra_search_keyword = ".raSearch"; 433758657e5SAleksandr Urakov 434758657e5SAleksandr Urakov // lvalue of assignment is always first token 435758657e5SAleksandr Urakov // rvalue program goes next 436758657e5SAleksandr Urakov for (size_t i = 1; i < tokens.size(); ++i) { 437758657e5SAleksandr Urakov llvm::StringRef cur = tokens[i]; 438758657e5SAleksandr Urakov 439758657e5SAleksandr Urakov auto ops_binary_it = ops_binary.find(cur); 440758657e5SAleksandr Urakov if (ops_binary_it != ops_binary.end()) { 441758657e5SAleksandr Urakov // token is binary operator 442758657e5SAleksandr Urakov if (eval_stack.size() < 2) { 443758657e5SAleksandr Urakov return false; 444758657e5SAleksandr Urakov } 445758657e5SAleksandr Urakov FPOProgramNode *right = eval_stack.pop_back_val(); 446758657e5SAleksandr Urakov FPOProgramNode *left = eval_stack.pop_back_val(); 447758657e5SAleksandr Urakov FPOProgramNode *node = alloc.makeNode<FPOProgramNodeBinaryOp>( 44894cd0667SPavel Labath ops_binary_it->second, *left, *right); 449758657e5SAleksandr Urakov eval_stack.push_back(node); 450758657e5SAleksandr Urakov continue; 451758657e5SAleksandr Urakov } 452758657e5SAleksandr Urakov 453758657e5SAleksandr Urakov auto ops_unary_it = ops_unary.find(cur); 454758657e5SAleksandr Urakov if (ops_unary_it != ops_unary.end()) { 455758657e5SAleksandr Urakov // token is unary operator 456758657e5SAleksandr Urakov if (eval_stack.empty()) { 457758657e5SAleksandr Urakov return false; 458758657e5SAleksandr Urakov } 459758657e5SAleksandr Urakov FPOProgramNode *operand = eval_stack.pop_back_val(); 460758657e5SAleksandr Urakov FPOProgramNode *node = 46194cd0667SPavel Labath alloc.makeNode<FPOProgramNodeUnaryOp>(ops_unary_it->second, *operand); 462758657e5SAleksandr Urakov eval_stack.push_back(node); 463758657e5SAleksandr Urakov continue; 464758657e5SAleksandr Urakov } 465758657e5SAleksandr Urakov 466758657e5SAleksandr Urakov if (cur.startswith("$")) { 4671c4ee160SPavel Labath eval_stack.push_back(alloc.makeNode<FPOProgramNodeSymbol>(cur)); 468758657e5SAleksandr Urakov continue; 469758657e5SAleksandr Urakov } 470758657e5SAleksandr Urakov 471758657e5SAleksandr Urakov if (cur == ra_search_keyword) { 472758657e5SAleksandr Urakov // TODO: .raSearch is unsupported 473758657e5SAleksandr Urakov return false; 474758657e5SAleksandr Urakov } 475758657e5SAleksandr Urakov 476758657e5SAleksandr Urakov uint32_t value; 477758657e5SAleksandr Urakov if (!cur.getAsInteger(10, value)) { 478758657e5SAleksandr Urakov // token is integer literal 479758657e5SAleksandr Urakov eval_stack.push_back(alloc.makeNode<FPOProgramNodeIntegerLiteral>(value)); 480758657e5SAleksandr Urakov continue; 481758657e5SAleksandr Urakov } 482758657e5SAleksandr Urakov 483758657e5SAleksandr Urakov // unexpected token 484758657e5SAleksandr Urakov return false; 485758657e5SAleksandr Urakov } 486758657e5SAleksandr Urakov 487758657e5SAleksandr Urakov if (eval_stack.size() != 1) { 488758657e5SAleksandr Urakov return false; 489758657e5SAleksandr Urakov } 490758657e5SAleksandr Urakov 491758657e5SAleksandr Urakov register_name = tokens[0]; 492758657e5SAleksandr Urakov ast = eval_stack.pop_back_val(); 493758657e5SAleksandr Urakov 494758657e5SAleksandr Urakov return true; 495758657e5SAleksandr Urakov } 496758657e5SAleksandr Urakov 497758657e5SAleksandr Urakov static FPOProgramNode *ParseFPOProgram(llvm::StringRef program, 498758657e5SAleksandr Urakov llvm::StringRef register_name, 499758657e5SAleksandr Urakov llvm::Triple::ArchType arch_type, 500758657e5SAleksandr Urakov NodeAllocator &alloc) { 501758657e5SAleksandr Urakov llvm::DenseMap<llvm::StringRef, FPOProgramNode *> dependent_programs; 502758657e5SAleksandr Urakov 503758657e5SAleksandr Urakov size_t cur = 0; 504758657e5SAleksandr Urakov while (true) { 505758657e5SAleksandr Urakov size_t assign_index = program.find('=', cur); 506758657e5SAleksandr Urakov if (assign_index == llvm::StringRef::npos) { 507758657e5SAleksandr Urakov llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos); 508758657e5SAleksandr Urakov if (!tail.trim().empty()) { 509758657e5SAleksandr Urakov // missing assign operator 510758657e5SAleksandr Urakov return nullptr; 511758657e5SAleksandr Urakov } 512758657e5SAleksandr Urakov break; 513758657e5SAleksandr Urakov } 514758657e5SAleksandr Urakov llvm::StringRef assignment_program = program.slice(cur, assign_index); 515758657e5SAleksandr Urakov 516758657e5SAleksandr Urakov llvm::StringRef lvalue_name; 517758657e5SAleksandr Urakov FPOProgramNode *rvalue_ast = nullptr; 518758657e5SAleksandr Urakov if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name, 519758657e5SAleksandr Urakov rvalue_ast)) { 520758657e5SAleksandr Urakov return nullptr; 521758657e5SAleksandr Urakov } 522758657e5SAleksandr Urakov 523758657e5SAleksandr Urakov lldbassert(rvalue_ast); 524758657e5SAleksandr Urakov 525758657e5SAleksandr Urakov // check & resolve assignment program 526758657e5SAleksandr Urakov FPOProgramASTVisitorResolveRegisterRefs resolver(dependent_programs, 5271c4ee160SPavel Labath arch_type, alloc); 528758657e5SAleksandr Urakov if (!resolver.Resolve(rvalue_ast)) { 529758657e5SAleksandr Urakov return nullptr; 530758657e5SAleksandr Urakov } 531758657e5SAleksandr Urakov 532758657e5SAleksandr Urakov if (lvalue_name == register_name) { 533758657e5SAleksandr Urakov // found target assignment program - no need to parse further 534758657e5SAleksandr Urakov 535758657e5SAleksandr Urakov // emplace valid dependent subtrees to make target assignment independent 536758657e5SAleksandr Urakov // from predecessors 537758657e5SAleksandr Urakov FPOProgramASTVisitorMergeDependent merger(dependent_programs); 538758657e5SAleksandr Urakov merger.Merge(rvalue_ast); 539758657e5SAleksandr Urakov 540758657e5SAleksandr Urakov return rvalue_ast; 541758657e5SAleksandr Urakov } 542758657e5SAleksandr Urakov 543758657e5SAleksandr Urakov dependent_programs[lvalue_name] = rvalue_ast; 544758657e5SAleksandr Urakov cur = assign_index + 1; 545758657e5SAleksandr Urakov } 546758657e5SAleksandr Urakov 547758657e5SAleksandr Urakov return nullptr; 548758657e5SAleksandr Urakov } 549758657e5SAleksandr Urakov 550758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( 551758657e5SAleksandr Urakov llvm::StringRef program, llvm::StringRef register_name, 552758657e5SAleksandr Urakov llvm::Triple::ArchType arch_type, Stream &stream) { 553758657e5SAleksandr Urakov NodeAllocator node_alloc; 554758657e5SAleksandr Urakov FPOProgramNode *target_program = 555758657e5SAleksandr Urakov ParseFPOProgram(program, register_name, arch_type, node_alloc); 556758657e5SAleksandr Urakov if (target_program == nullptr) { 557758657e5SAleksandr Urakov return false; 558758657e5SAleksandr Urakov } 559758657e5SAleksandr Urakov 560758657e5SAleksandr Urakov FPOProgramASTVisitorDWARFCodegen codegen(stream); 56194cd0667SPavel Labath codegen.Emit(*target_program); 562758657e5SAleksandr Urakov return true; 563758657e5SAleksandr Urakov } 564