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" 211beeda68SPavel 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 281c4ee160SPavel Labath class NodeAllocator { 291c4ee160SPavel Labath public: 301c4ee160SPavel Labath template <typename T, typename... Args> T *makeNode(Args &&... args) { 31*85ce053dSPavel Labath static_assert(std::is_trivially_destructible<T>::value, 32*85ce053dSPavel Labath "This object will not be destroyed!"); 331c4ee160SPavel Labath void *new_node_mem = m_alloc.Allocate(sizeof(T), alignof(T)); 341c4ee160SPavel Labath return new (new_node_mem) T(std::forward<Args>(args)...); 351c4ee160SPavel Labath } 361c4ee160SPavel Labath 371c4ee160SPavel Labath private: 381c4ee160SPavel Labath llvm::BumpPtrAllocator m_alloc; 391c4ee160SPavel Labath }; 401c4ee160SPavel Labath 41758657e5SAleksandr Urakov class FPOProgramNode { 42758657e5SAleksandr Urakov public: 43758657e5SAleksandr Urakov enum Kind { 441c4ee160SPavel Labath Symbol, 45758657e5SAleksandr Urakov Register, 46758657e5SAleksandr Urakov IntegerLiteral, 47758657e5SAleksandr Urakov BinaryOp, 48758657e5SAleksandr Urakov UnaryOp, 49758657e5SAleksandr Urakov }; 50758657e5SAleksandr Urakov 51758657e5SAleksandr Urakov protected: 52758657e5SAleksandr Urakov FPOProgramNode(Kind kind) : m_token_kind(kind) {} 53758657e5SAleksandr Urakov 54758657e5SAleksandr Urakov public: 55758657e5SAleksandr Urakov Kind GetKind() const { return m_token_kind; } 56758657e5SAleksandr Urakov 57758657e5SAleksandr Urakov private: 58758657e5SAleksandr Urakov Kind m_token_kind; 59758657e5SAleksandr Urakov }; 60758657e5SAleksandr Urakov 611c4ee160SPavel Labath class FPOProgramNodeSymbol: public FPOProgramNode { 62758657e5SAleksandr Urakov public: 631c4ee160SPavel Labath FPOProgramNodeSymbol(llvm::StringRef name) 641c4ee160SPavel Labath : FPOProgramNode(Symbol), m_name(name) {} 65758657e5SAleksandr Urakov 66758657e5SAleksandr Urakov llvm::StringRef GetName() const { return m_name; } 67758657e5SAleksandr Urakov 681beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 691beeda68SPavel Labath return node->GetKind() == Symbol; 701beeda68SPavel Labath } 711beeda68SPavel Labath 72758657e5SAleksandr Urakov private: 73758657e5SAleksandr Urakov llvm::StringRef m_name; 74758657e5SAleksandr Urakov }; 75758657e5SAleksandr Urakov 761c4ee160SPavel Labath class FPOProgramNodeRegisterRef : public FPOProgramNode { 771c4ee160SPavel Labath public: 781c4ee160SPavel Labath FPOProgramNodeRegisterRef(uint32_t lldb_reg_num) 791c4ee160SPavel Labath : FPOProgramNode(Register), m_lldb_reg_num(lldb_reg_num) {} 80758657e5SAleksandr Urakov 811c4ee160SPavel Labath uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; } 82758657e5SAleksandr Urakov 831beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 841beeda68SPavel Labath return node->GetKind() == Register; 851beeda68SPavel Labath } 861beeda68SPavel Labath 871c4ee160SPavel Labath private: 881c4ee160SPavel Labath uint32_t m_lldb_reg_num; 891c4ee160SPavel Labath }; 90758657e5SAleksandr Urakov 91758657e5SAleksandr Urakov class FPOProgramNodeIntegerLiteral : public FPOProgramNode { 92758657e5SAleksandr Urakov public: 93758657e5SAleksandr Urakov FPOProgramNodeIntegerLiteral(uint32_t value) 94758657e5SAleksandr Urakov : FPOProgramNode(IntegerLiteral), m_value(value) {} 95758657e5SAleksandr Urakov 96758657e5SAleksandr Urakov uint32_t GetValue() const { return m_value; } 97758657e5SAleksandr Urakov 981beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 991beeda68SPavel Labath return node->GetKind() == IntegerLiteral; 1001beeda68SPavel Labath } 1011beeda68SPavel Labath 102758657e5SAleksandr Urakov private: 103758657e5SAleksandr Urakov uint32_t m_value; 104758657e5SAleksandr Urakov }; 105758657e5SAleksandr Urakov 106758657e5SAleksandr Urakov class FPOProgramNodeBinaryOp : public FPOProgramNode { 107758657e5SAleksandr Urakov public: 108758657e5SAleksandr Urakov enum OpType { 109758657e5SAleksandr Urakov Plus, 110758657e5SAleksandr Urakov Minus, 111758657e5SAleksandr Urakov Align, 112758657e5SAleksandr Urakov }; 113758657e5SAleksandr Urakov 11494cd0667SPavel Labath FPOProgramNodeBinaryOp(OpType op_type, FPOProgramNode &left, 11594cd0667SPavel Labath FPOProgramNode &right) 11694cd0667SPavel Labath : FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(&left), 11794cd0667SPavel Labath m_right(&right) {} 118758657e5SAleksandr Urakov 119758657e5SAleksandr Urakov OpType GetOpType() const { return m_op_type; } 120758657e5SAleksandr Urakov 121758657e5SAleksandr Urakov const FPOProgramNode *Left() const { return m_left; } 122758657e5SAleksandr Urakov FPOProgramNode *&Left() { return m_left; } 123758657e5SAleksandr Urakov 124758657e5SAleksandr Urakov const FPOProgramNode *Right() const { return m_right; } 125758657e5SAleksandr Urakov FPOProgramNode *&Right() { return m_right; } 126758657e5SAleksandr Urakov 1271beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 1281beeda68SPavel Labath return node->GetKind() == BinaryOp; 1291beeda68SPavel Labath } 1301beeda68SPavel Labath 131758657e5SAleksandr Urakov private: 132758657e5SAleksandr Urakov OpType m_op_type; 133758657e5SAleksandr Urakov FPOProgramNode *m_left; 134758657e5SAleksandr Urakov FPOProgramNode *m_right; 135758657e5SAleksandr Urakov }; 136758657e5SAleksandr Urakov 137758657e5SAleksandr Urakov class FPOProgramNodeUnaryOp : public FPOProgramNode { 138758657e5SAleksandr Urakov public: 139758657e5SAleksandr Urakov enum OpType { 140758657e5SAleksandr Urakov Deref, 141758657e5SAleksandr Urakov }; 142758657e5SAleksandr Urakov 14394cd0667SPavel Labath FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode &operand) 14494cd0667SPavel Labath : FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(&operand) {} 145758657e5SAleksandr Urakov 146758657e5SAleksandr Urakov OpType GetOpType() const { return m_op_type; } 147758657e5SAleksandr Urakov 148758657e5SAleksandr Urakov const FPOProgramNode *Operand() const { return m_operand; } 149758657e5SAleksandr Urakov FPOProgramNode *&Operand() { return m_operand; } 150758657e5SAleksandr Urakov 1511beeda68SPavel Labath static bool classof(const FPOProgramNode *node) { 1521beeda68SPavel Labath return node->GetKind() == UnaryOp; 1531beeda68SPavel Labath } 1541beeda68SPavel Labath 155758657e5SAleksandr Urakov private: 156758657e5SAleksandr Urakov OpType m_op_type; 157758657e5SAleksandr Urakov FPOProgramNode *m_operand; 158758657e5SAleksandr Urakov }; 159758657e5SAleksandr Urakov 160*85ce053dSPavel Labath template <typename ResultT = void> 161758657e5SAleksandr Urakov class FPOProgramASTVisitor { 162*85ce053dSPavel Labath protected: 163*85ce053dSPavel Labath virtual ResultT Visit(FPOProgramNodeBinaryOp &binary, 164*85ce053dSPavel Labath FPOProgramNode *&ref) = 0; 165*85ce053dSPavel Labath virtual ResultT Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&ref) = 0; 166*85ce053dSPavel Labath virtual ResultT Visit(FPOProgramNodeRegisterRef ®, FPOProgramNode *&) = 0; 167*85ce053dSPavel Labath virtual ResultT Visit(FPOProgramNodeIntegerLiteral &integer, 168*85ce053dSPavel Labath FPOProgramNode *&) = 0; 169*85ce053dSPavel Labath virtual ResultT Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) = 0; 170758657e5SAleksandr Urakov 171*85ce053dSPavel Labath ResultT Dispatch(FPOProgramNode *&node) { 172*85ce053dSPavel Labath switch (node->GetKind()) { 173*85ce053dSPavel Labath case FPOProgramNode::Register: 174*85ce053dSPavel Labath return Visit(llvm::cast<FPOProgramNodeRegisterRef>(*node), node); 175*85ce053dSPavel Labath case FPOProgramNode::Symbol: 176*85ce053dSPavel Labath return Visit(llvm::cast<FPOProgramNodeSymbol>(*node), node); 177*85ce053dSPavel Labath 178*85ce053dSPavel Labath case FPOProgramNode::IntegerLiteral: 179*85ce053dSPavel Labath return Visit(llvm::cast<FPOProgramNodeIntegerLiteral>(*node), node); 180*85ce053dSPavel Labath case FPOProgramNode::UnaryOp: 181*85ce053dSPavel Labath return Visit(llvm::cast<FPOProgramNodeUnaryOp>(*node), node); 182*85ce053dSPavel Labath case FPOProgramNode::BinaryOp: 183*85ce053dSPavel Labath return Visit(llvm::cast<FPOProgramNodeBinaryOp>(*node), node); 184*85ce053dSPavel Labath } 185*85ce053dSPavel Labath llvm_unreachable("Fully covered switch!"); 186*85ce053dSPavel Labath } 187*85ce053dSPavel Labath 188758657e5SAleksandr Urakov }; 189758657e5SAleksandr Urakov 190*85ce053dSPavel Labath class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor<> { 191758657e5SAleksandr Urakov public: 192*85ce053dSPavel Labath void Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&) override { 193*85ce053dSPavel Labath Dispatch(binary.Left()); 194*85ce053dSPavel Labath Dispatch(binary.Right()); 195*85ce053dSPavel Labath } 196*85ce053dSPavel Labath 197*85ce053dSPavel Labath void Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&) override { 198*85ce053dSPavel Labath Dispatch(unary.Operand()); 199*85ce053dSPavel Labath } 200*85ce053dSPavel Labath 201*85ce053dSPavel Labath void Visit(FPOProgramNodeRegisterRef &, FPOProgramNode *&) override {} 202*85ce053dSPavel Labath void Visit(FPOProgramNodeIntegerLiteral &, FPOProgramNode *&) override {} 203*85ce053dSPavel Labath void Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) override; 204*85ce053dSPavel Labath 205*85ce053dSPavel Labath static void Merge(const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 206*85ce053dSPavel Labath &dependent_programs, 207*85ce053dSPavel Labath FPOProgramNode *&ast) { 208*85ce053dSPavel Labath FPOProgramASTVisitorMergeDependent(dependent_programs).Dispatch(ast); 209*85ce053dSPavel Labath } 210*85ce053dSPavel Labath 211*85ce053dSPavel Labath private: 212758657e5SAleksandr Urakov FPOProgramASTVisitorMergeDependent( 213758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 214758657e5SAleksandr Urakov &dependent_programs) 215758657e5SAleksandr Urakov : m_dependent_programs(dependent_programs) {} 216758657e5SAleksandr Urakov 217758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs; 218758657e5SAleksandr Urakov }; 219758657e5SAleksandr Urakov 220*85ce053dSPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeSymbol &symbol, 221*85ce053dSPavel Labath FPOProgramNode *&ref) { 222*85ce053dSPavel Labath 223*85ce053dSPavel Labath auto it = m_dependent_programs.find(symbol.GetName()); 224*85ce053dSPavel Labath if (it == m_dependent_programs.end()) 225*85ce053dSPavel Labath return; 226*85ce053dSPavel Labath 227*85ce053dSPavel Labath ref = it->second; 228*85ce053dSPavel Labath Dispatch(ref); 229758657e5SAleksandr Urakov } 230758657e5SAleksandr Urakov 231*85ce053dSPavel Labath class FPOProgramASTVisitorResolveRegisterRefs 232*85ce053dSPavel Labath : public FPOProgramASTVisitor<bool> { 233758657e5SAleksandr Urakov public: 234*85ce053dSPavel Labath static bool Resolve(const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 235*85ce053dSPavel Labath &dependent_programs, 236*85ce053dSPavel Labath llvm::Triple::ArchType arch_type, NodeAllocator &alloc, 237*85ce053dSPavel Labath FPOProgramNode *&ast) { 238*85ce053dSPavel Labath return FPOProgramASTVisitorResolveRegisterRefs(dependent_programs, 239*85ce053dSPavel Labath arch_type, alloc) 240*85ce053dSPavel Labath .Dispatch(ast); 241*85ce053dSPavel Labath } 242*85ce053dSPavel Labath 243*85ce053dSPavel Labath bool Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&) override { 244*85ce053dSPavel Labath return Dispatch(binary.Left()) && Dispatch(binary.Right()); 245*85ce053dSPavel Labath } 246*85ce053dSPavel Labath 247*85ce053dSPavel Labath bool Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&) override { 248*85ce053dSPavel Labath return Dispatch(unary.Operand()); 249*85ce053dSPavel Labath } 250*85ce053dSPavel Labath 251*85ce053dSPavel Labath bool Visit(FPOProgramNodeRegisterRef &, FPOProgramNode *&) override { 252*85ce053dSPavel Labath return true; 253*85ce053dSPavel Labath } 254*85ce053dSPavel Labath 255*85ce053dSPavel Labath bool Visit(FPOProgramNodeIntegerLiteral &, FPOProgramNode *&) override { 256*85ce053dSPavel Labath return true; 257*85ce053dSPavel Labath } 258*85ce053dSPavel Labath 259*85ce053dSPavel Labath bool Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) override; 260*85ce053dSPavel Labath 261*85ce053dSPavel Labath private: 262758657e5SAleksandr Urakov FPOProgramASTVisitorResolveRegisterRefs( 263758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 264758657e5SAleksandr Urakov &dependent_programs, 2651c4ee160SPavel Labath llvm::Triple::ArchType arch_type, NodeAllocator &alloc) 2661c4ee160SPavel Labath : m_dependent_programs(dependent_programs), m_arch_type(arch_type), 2671c4ee160SPavel Labath m_alloc(alloc) {} 268758657e5SAleksandr Urakov 269758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs; 270758657e5SAleksandr Urakov llvm::Triple::ArchType m_arch_type; 2711c4ee160SPavel Labath NodeAllocator &m_alloc; 272758657e5SAleksandr Urakov }; 273758657e5SAleksandr Urakov 2741c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) { 2751c4ee160SPavel Labath // lookup register name to get lldb register number 2761c4ee160SPavel Labath llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names = 2771c4ee160SPavel Labath llvm::codeview::getRegisterNames(); 2781c4ee160SPavel Labath auto it = llvm::find_if( 2791c4ee160SPavel Labath register_names, 2801c4ee160SPavel Labath [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { 2811c4ee160SPavel Labath return reg_name.compare_lower(register_entry.Name) == 0; 2821c4ee160SPavel Labath }); 283758657e5SAleksandr Urakov 2841c4ee160SPavel Labath if (it == register_names.end()) 2851c4ee160SPavel Labath return LLDB_INVALID_REGNUM; 2861c4ee160SPavel Labath 2871c4ee160SPavel Labath auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value); 2881c4ee160SPavel Labath return npdb::GetLLDBRegisterNumber(arch_type, reg_id); 289758657e5SAleksandr Urakov } 2901c4ee160SPavel Labath 291*85ce053dSPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::Visit( 292*85ce053dSPavel Labath FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) { 2931c4ee160SPavel Labath // Look up register reference as lvalue in preceding assignments. 294*85ce053dSPavel Labath auto it = m_dependent_programs.find(symbol.GetName()); 2951c4ee160SPavel Labath if (it != m_dependent_programs.end()) { 2961c4ee160SPavel Labath // Dependent programs are handled elsewhere. 2971c4ee160SPavel Labath return true; 2981c4ee160SPavel Labath } 2991c4ee160SPavel Labath 3001c4ee160SPavel Labath uint32_t reg_num = 301*85ce053dSPavel Labath ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), m_arch_type); 3021c4ee160SPavel Labath 3031c4ee160SPavel Labath if (reg_num == LLDB_INVALID_REGNUM) 3041c4ee160SPavel Labath return false; 3051c4ee160SPavel Labath 306*85ce053dSPavel Labath ref = m_alloc.makeNode<FPOProgramNodeRegisterRef>(reg_num); 3071c4ee160SPavel Labath return true; 308758657e5SAleksandr Urakov } 309758657e5SAleksandr Urakov 310*85ce053dSPavel Labath class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor<> { 311758657e5SAleksandr Urakov public: 312*85ce053dSPavel Labath static void Emit(Stream &stream, FPOProgramNode *&ast) { 313*85ce053dSPavel Labath FPOProgramASTVisitorDWARFCodegen(stream).Dispatch(ast); 314*85ce053dSPavel Labath } 315*85ce053dSPavel Labath 316*85ce053dSPavel Labath void Visit(FPOProgramNodeRegisterRef ®, FPOProgramNode *&); 317*85ce053dSPavel Labath void Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&); 318*85ce053dSPavel Labath void Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&); 319*85ce053dSPavel Labath void Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&) { 320*85ce053dSPavel Labath llvm_unreachable("Symbols should have been resolved by now!"); 321*85ce053dSPavel Labath } 322*85ce053dSPavel Labath void Visit(FPOProgramNodeIntegerLiteral &integer, FPOProgramNode *&); 323*85ce053dSPavel Labath 324*85ce053dSPavel Labath private: 325758657e5SAleksandr Urakov FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {} 326758657e5SAleksandr Urakov 327758657e5SAleksandr Urakov Stream &m_out_stream; 328758657e5SAleksandr Urakov }; 329758657e5SAleksandr Urakov 330*85ce053dSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef ®, 331*85ce053dSPavel Labath FPOProgramNode *&) { 332758657e5SAleksandr Urakov 333*85ce053dSPavel Labath uint32_t reg_num = reg.GetLLDBRegNum(); 334758657e5SAleksandr Urakov lldbassert(reg_num != LLDB_INVALID_REGNUM); 335758657e5SAleksandr Urakov 336758657e5SAleksandr Urakov if (reg_num > 31) { 337758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_bregx); 338758657e5SAleksandr Urakov m_out_stream.PutULEB128(reg_num); 339758657e5SAleksandr Urakov } else 340758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_breg0 + reg_num); 341758657e5SAleksandr Urakov 342758657e5SAleksandr Urakov m_out_stream.PutSLEB128(0); 343758657e5SAleksandr Urakov } 344758657e5SAleksandr Urakov 345758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit( 346*85ce053dSPavel Labath FPOProgramNodeIntegerLiteral &integer, FPOProgramNode *&) { 347*85ce053dSPavel Labath uint32_t value = integer.GetValue(); 348758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_constu); 349758657e5SAleksandr Urakov m_out_stream.PutULEB128(value); 350758657e5SAleksandr Urakov } 351758657e5SAleksandr Urakov 352*85ce053dSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &binary, 353*85ce053dSPavel Labath FPOProgramNode *&) { 354*85ce053dSPavel Labath Dispatch(binary.Left()); 355*85ce053dSPavel Labath Dispatch(binary.Right()); 356758657e5SAleksandr Urakov 357*85ce053dSPavel Labath switch (binary.GetOpType()) { 358758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Plus: 359758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_plus); 360758657e5SAleksandr Urakov // NOTE: can be optimized by using DW_OP_plus_uconst opcpode 361758657e5SAleksandr Urakov // if right child node is constant value 362758657e5SAleksandr Urakov break; 363758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Minus: 364758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_minus); 365758657e5SAleksandr Urakov break; 366758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Align: 367758657e5SAleksandr Urakov // emit align operator a @ b as 368758657e5SAleksandr Urakov // a & ~(b - 1) 369758657e5SAleksandr Urakov // NOTE: implicitly assuming that b is power of 2 370758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_lit1); 371758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_minus); 372758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_not); 373758657e5SAleksandr Urakov 374758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_and); 375758657e5SAleksandr Urakov break; 376758657e5SAleksandr Urakov } 377758657e5SAleksandr Urakov } 378758657e5SAleksandr Urakov 379*85ce053dSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp &unary, 380*85ce053dSPavel Labath FPOProgramNode *&) { 381*85ce053dSPavel Labath Dispatch(unary.Operand()); 382758657e5SAleksandr Urakov 383*85ce053dSPavel Labath switch (unary.GetOpType()) { 384758657e5SAleksandr Urakov case FPOProgramNodeUnaryOp::Deref: 385758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_deref); 386758657e5SAleksandr Urakov break; 387758657e5SAleksandr Urakov } 388758657e5SAleksandr Urakov } 389758657e5SAleksandr Urakov 390758657e5SAleksandr Urakov } // namespace 391758657e5SAleksandr Urakov 392758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program, 393758657e5SAleksandr Urakov NodeAllocator &alloc, 394758657e5SAleksandr Urakov llvm::StringRef ®ister_name, 395758657e5SAleksandr Urakov FPOProgramNode *&ast) { 396758657e5SAleksandr Urakov llvm::SmallVector<llvm::StringRef, 16> tokens; 397758657e5SAleksandr Urakov llvm::SplitString(program, tokens, " "); 398758657e5SAleksandr Urakov 399758657e5SAleksandr Urakov if (tokens.empty()) 400758657e5SAleksandr Urakov return false; 401758657e5SAleksandr Urakov 402758657e5SAleksandr Urakov llvm::SmallVector<FPOProgramNode *, 4> eval_stack; 403758657e5SAleksandr Urakov 404758657e5SAleksandr Urakov llvm::DenseMap<llvm::StringRef, FPOProgramNodeBinaryOp::OpType> ops_binary = { 405758657e5SAleksandr Urakov {"+", FPOProgramNodeBinaryOp::Plus}, 406758657e5SAleksandr Urakov {"-", FPOProgramNodeBinaryOp::Minus}, 407758657e5SAleksandr Urakov {"@", FPOProgramNodeBinaryOp::Align}, 408758657e5SAleksandr Urakov }; 409758657e5SAleksandr Urakov 410758657e5SAleksandr Urakov llvm::DenseMap<llvm::StringRef, FPOProgramNodeUnaryOp::OpType> ops_unary = { 411758657e5SAleksandr Urakov {"^", FPOProgramNodeUnaryOp::Deref}, 412758657e5SAleksandr Urakov }; 413758657e5SAleksandr Urakov 414758657e5SAleksandr Urakov constexpr llvm::StringLiteral ra_search_keyword = ".raSearch"; 415758657e5SAleksandr Urakov 416758657e5SAleksandr Urakov // lvalue of assignment is always first token 417758657e5SAleksandr Urakov // rvalue program goes next 418758657e5SAleksandr Urakov for (size_t i = 1; i < tokens.size(); ++i) { 419758657e5SAleksandr Urakov llvm::StringRef cur = tokens[i]; 420758657e5SAleksandr Urakov 421758657e5SAleksandr Urakov auto ops_binary_it = ops_binary.find(cur); 422758657e5SAleksandr Urakov if (ops_binary_it != ops_binary.end()) { 423758657e5SAleksandr Urakov // token is binary operator 424758657e5SAleksandr Urakov if (eval_stack.size() < 2) { 425758657e5SAleksandr Urakov return false; 426758657e5SAleksandr Urakov } 427758657e5SAleksandr Urakov FPOProgramNode *right = eval_stack.pop_back_val(); 428758657e5SAleksandr Urakov FPOProgramNode *left = eval_stack.pop_back_val(); 429758657e5SAleksandr Urakov FPOProgramNode *node = alloc.makeNode<FPOProgramNodeBinaryOp>( 43094cd0667SPavel Labath ops_binary_it->second, *left, *right); 431758657e5SAleksandr Urakov eval_stack.push_back(node); 432758657e5SAleksandr Urakov continue; 433758657e5SAleksandr Urakov } 434758657e5SAleksandr Urakov 435758657e5SAleksandr Urakov auto ops_unary_it = ops_unary.find(cur); 436758657e5SAleksandr Urakov if (ops_unary_it != ops_unary.end()) { 437758657e5SAleksandr Urakov // token is unary operator 438758657e5SAleksandr Urakov if (eval_stack.empty()) { 439758657e5SAleksandr Urakov return false; 440758657e5SAleksandr Urakov } 441758657e5SAleksandr Urakov FPOProgramNode *operand = eval_stack.pop_back_val(); 442758657e5SAleksandr Urakov FPOProgramNode *node = 44394cd0667SPavel Labath alloc.makeNode<FPOProgramNodeUnaryOp>(ops_unary_it->second, *operand); 444758657e5SAleksandr Urakov eval_stack.push_back(node); 445758657e5SAleksandr Urakov continue; 446758657e5SAleksandr Urakov } 447758657e5SAleksandr Urakov 448758657e5SAleksandr Urakov if (cur.startswith("$")) { 4491c4ee160SPavel Labath eval_stack.push_back(alloc.makeNode<FPOProgramNodeSymbol>(cur)); 450758657e5SAleksandr Urakov continue; 451758657e5SAleksandr Urakov } 452758657e5SAleksandr Urakov 453758657e5SAleksandr Urakov if (cur == ra_search_keyword) { 454758657e5SAleksandr Urakov // TODO: .raSearch is unsupported 455758657e5SAleksandr Urakov return false; 456758657e5SAleksandr Urakov } 457758657e5SAleksandr Urakov 458758657e5SAleksandr Urakov uint32_t value; 459758657e5SAleksandr Urakov if (!cur.getAsInteger(10, value)) { 460758657e5SAleksandr Urakov // token is integer literal 461758657e5SAleksandr Urakov eval_stack.push_back(alloc.makeNode<FPOProgramNodeIntegerLiteral>(value)); 462758657e5SAleksandr Urakov continue; 463758657e5SAleksandr Urakov } 464758657e5SAleksandr Urakov 465758657e5SAleksandr Urakov // unexpected token 466758657e5SAleksandr Urakov return false; 467758657e5SAleksandr Urakov } 468758657e5SAleksandr Urakov 469758657e5SAleksandr Urakov if (eval_stack.size() != 1) { 470758657e5SAleksandr Urakov return false; 471758657e5SAleksandr Urakov } 472758657e5SAleksandr Urakov 473758657e5SAleksandr Urakov register_name = tokens[0]; 474758657e5SAleksandr Urakov ast = eval_stack.pop_back_val(); 475758657e5SAleksandr Urakov 476758657e5SAleksandr Urakov return true; 477758657e5SAleksandr Urakov } 478758657e5SAleksandr Urakov 479758657e5SAleksandr Urakov static FPOProgramNode *ParseFPOProgram(llvm::StringRef program, 480758657e5SAleksandr Urakov llvm::StringRef register_name, 481758657e5SAleksandr Urakov llvm::Triple::ArchType arch_type, 482758657e5SAleksandr Urakov NodeAllocator &alloc) { 483758657e5SAleksandr Urakov llvm::DenseMap<llvm::StringRef, FPOProgramNode *> dependent_programs; 484758657e5SAleksandr Urakov 485758657e5SAleksandr Urakov size_t cur = 0; 486758657e5SAleksandr Urakov while (true) { 487758657e5SAleksandr Urakov size_t assign_index = program.find('=', cur); 488758657e5SAleksandr Urakov if (assign_index == llvm::StringRef::npos) { 489758657e5SAleksandr Urakov llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos); 490758657e5SAleksandr Urakov if (!tail.trim().empty()) { 491758657e5SAleksandr Urakov // missing assign operator 492758657e5SAleksandr Urakov return nullptr; 493758657e5SAleksandr Urakov } 494758657e5SAleksandr Urakov break; 495758657e5SAleksandr Urakov } 496758657e5SAleksandr Urakov llvm::StringRef assignment_program = program.slice(cur, assign_index); 497758657e5SAleksandr Urakov 498758657e5SAleksandr Urakov llvm::StringRef lvalue_name; 499758657e5SAleksandr Urakov FPOProgramNode *rvalue_ast = nullptr; 500758657e5SAleksandr Urakov if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name, 501758657e5SAleksandr Urakov rvalue_ast)) { 502758657e5SAleksandr Urakov return nullptr; 503758657e5SAleksandr Urakov } 504758657e5SAleksandr Urakov 505758657e5SAleksandr Urakov lldbassert(rvalue_ast); 506758657e5SAleksandr Urakov 507758657e5SAleksandr Urakov // check & resolve assignment program 508*85ce053dSPavel Labath if (!FPOProgramASTVisitorResolveRegisterRefs::Resolve( 509*85ce053dSPavel Labath dependent_programs, arch_type, alloc, rvalue_ast)) 510758657e5SAleksandr Urakov return nullptr; 511758657e5SAleksandr Urakov 512758657e5SAleksandr Urakov if (lvalue_name == register_name) { 513758657e5SAleksandr Urakov // found target assignment program - no need to parse further 514758657e5SAleksandr Urakov 515758657e5SAleksandr Urakov // emplace valid dependent subtrees to make target assignment independent 516758657e5SAleksandr Urakov // from predecessors 517*85ce053dSPavel Labath FPOProgramASTVisitorMergeDependent::Merge(dependent_programs, rvalue_ast); 518758657e5SAleksandr Urakov 519758657e5SAleksandr Urakov return rvalue_ast; 520758657e5SAleksandr Urakov } 521758657e5SAleksandr Urakov 522758657e5SAleksandr Urakov dependent_programs[lvalue_name] = rvalue_ast; 523758657e5SAleksandr Urakov cur = assign_index + 1; 524758657e5SAleksandr Urakov } 525758657e5SAleksandr Urakov 526758657e5SAleksandr Urakov return nullptr; 527758657e5SAleksandr Urakov } 528758657e5SAleksandr Urakov 529758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( 530758657e5SAleksandr Urakov llvm::StringRef program, llvm::StringRef register_name, 531758657e5SAleksandr Urakov llvm::Triple::ArchType arch_type, Stream &stream) { 532758657e5SAleksandr Urakov NodeAllocator node_alloc; 533758657e5SAleksandr Urakov FPOProgramNode *target_program = 534758657e5SAleksandr Urakov ParseFPOProgram(program, register_name, arch_type, node_alloc); 535758657e5SAleksandr Urakov if (target_program == nullptr) { 536758657e5SAleksandr Urakov return false; 537758657e5SAleksandr Urakov } 538758657e5SAleksandr Urakov 539*85ce053dSPavel Labath FPOProgramASTVisitorDWARFCodegen::Emit(stream, target_program); 540758657e5SAleksandr Urakov return true; 541758657e5SAleksandr Urakov } 542