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" 21758657e5SAleksandr Urakov 22758657e5SAleksandr Urakov using namespace lldb; 23758657e5SAleksandr Urakov using namespace lldb_private; 24758657e5SAleksandr Urakov 25758657e5SAleksandr Urakov namespace { 26758657e5SAleksandr Urakov 27758657e5SAleksandr Urakov class FPOProgramNode; 28758657e5SAleksandr Urakov class FPOProgramASTVisitor; 29758657e5SAleksandr Urakov 301c4ee160SPavel Labath class NodeAllocator { 311c4ee160SPavel Labath public: 321c4ee160SPavel Labath template <typename T, typename... Args> T *makeNode(Args &&... args) { 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 virtual ~FPOProgramNode() = default; 56*94cd0667SPavel Labath virtual void Accept(FPOProgramASTVisitor &visitor) = 0; 57758657e5SAleksandr Urakov 58758657e5SAleksandr Urakov Kind GetKind() const { return m_token_kind; } 59758657e5SAleksandr Urakov 60758657e5SAleksandr Urakov private: 61758657e5SAleksandr Urakov Kind m_token_kind; 62758657e5SAleksandr Urakov }; 63758657e5SAleksandr Urakov 641c4ee160SPavel Labath class FPOProgramNodeSymbol: public FPOProgramNode { 65758657e5SAleksandr Urakov public: 661c4ee160SPavel Labath FPOProgramNodeSymbol(llvm::StringRef name) 671c4ee160SPavel Labath : FPOProgramNode(Symbol), m_name(name) {} 68758657e5SAleksandr Urakov 69*94cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 70758657e5SAleksandr Urakov 71758657e5SAleksandr Urakov llvm::StringRef GetName() const { return m_name; } 72758657e5SAleksandr Urakov 73758657e5SAleksandr Urakov private: 74758657e5SAleksandr Urakov llvm::StringRef m_name; 75758657e5SAleksandr Urakov }; 76758657e5SAleksandr Urakov 771c4ee160SPavel Labath class FPOProgramNodeRegisterRef : public FPOProgramNode { 781c4ee160SPavel Labath public: 791c4ee160SPavel Labath FPOProgramNodeRegisterRef(uint32_t lldb_reg_num) 801c4ee160SPavel Labath : FPOProgramNode(Register), m_lldb_reg_num(lldb_reg_num) {} 81758657e5SAleksandr Urakov 82*94cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 83758657e5SAleksandr Urakov 841c4ee160SPavel Labath uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; } 85758657e5SAleksandr Urakov 861c4ee160SPavel Labath private: 871c4ee160SPavel Labath uint32_t m_lldb_reg_num; 881c4ee160SPavel Labath }; 89758657e5SAleksandr Urakov 90758657e5SAleksandr Urakov class FPOProgramNodeIntegerLiteral : public FPOProgramNode { 91758657e5SAleksandr Urakov public: 92758657e5SAleksandr Urakov FPOProgramNodeIntegerLiteral(uint32_t value) 93758657e5SAleksandr Urakov : FPOProgramNode(IntegerLiteral), m_value(value) {} 94758657e5SAleksandr Urakov 95*94cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 96758657e5SAleksandr Urakov 97758657e5SAleksandr Urakov uint32_t GetValue() const { return m_value; } 98758657e5SAleksandr Urakov 99758657e5SAleksandr Urakov private: 100758657e5SAleksandr Urakov uint32_t m_value; 101758657e5SAleksandr Urakov }; 102758657e5SAleksandr Urakov 103758657e5SAleksandr Urakov class FPOProgramNodeBinaryOp : public FPOProgramNode { 104758657e5SAleksandr Urakov public: 105758657e5SAleksandr Urakov enum OpType { 106758657e5SAleksandr Urakov Plus, 107758657e5SAleksandr Urakov Minus, 108758657e5SAleksandr Urakov Align, 109758657e5SAleksandr Urakov }; 110758657e5SAleksandr Urakov 111*94cd0667SPavel Labath FPOProgramNodeBinaryOp(OpType op_type, FPOProgramNode &left, 112*94cd0667SPavel Labath FPOProgramNode &right) 113*94cd0667SPavel Labath : FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(&left), 114*94cd0667SPavel Labath m_right(&right) {} 115758657e5SAleksandr Urakov 116*94cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 117758657e5SAleksandr Urakov 118758657e5SAleksandr Urakov OpType GetOpType() const { return m_op_type; } 119758657e5SAleksandr Urakov 120758657e5SAleksandr Urakov const FPOProgramNode *Left() const { return m_left; } 121758657e5SAleksandr Urakov FPOProgramNode *&Left() { return m_left; } 122758657e5SAleksandr Urakov 123758657e5SAleksandr Urakov const FPOProgramNode *Right() const { return m_right; } 124758657e5SAleksandr Urakov FPOProgramNode *&Right() { return m_right; } 125758657e5SAleksandr Urakov 126758657e5SAleksandr Urakov private: 127758657e5SAleksandr Urakov OpType m_op_type; 128758657e5SAleksandr Urakov FPOProgramNode *m_left; 129758657e5SAleksandr Urakov FPOProgramNode *m_right; 130758657e5SAleksandr Urakov }; 131758657e5SAleksandr Urakov 132758657e5SAleksandr Urakov class FPOProgramNodeUnaryOp : public FPOProgramNode { 133758657e5SAleksandr Urakov public: 134758657e5SAleksandr Urakov enum OpType { 135758657e5SAleksandr Urakov Deref, 136758657e5SAleksandr Urakov }; 137758657e5SAleksandr Urakov 138*94cd0667SPavel Labath FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode &operand) 139*94cd0667SPavel Labath : FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(&operand) {} 140758657e5SAleksandr Urakov 141*94cd0667SPavel Labath void Accept(FPOProgramASTVisitor &visitor) override; 142758657e5SAleksandr Urakov 143758657e5SAleksandr Urakov OpType GetOpType() const { return m_op_type; } 144758657e5SAleksandr Urakov 145758657e5SAleksandr Urakov const FPOProgramNode *Operand() const { return m_operand; } 146758657e5SAleksandr Urakov FPOProgramNode *&Operand() { return m_operand; } 147758657e5SAleksandr Urakov 148758657e5SAleksandr Urakov private: 149758657e5SAleksandr Urakov OpType m_op_type; 150758657e5SAleksandr Urakov FPOProgramNode *m_operand; 151758657e5SAleksandr Urakov }; 152758657e5SAleksandr Urakov 153758657e5SAleksandr Urakov class FPOProgramASTVisitor { 154758657e5SAleksandr Urakov public: 155758657e5SAleksandr Urakov virtual ~FPOProgramASTVisitor() = default; 156758657e5SAleksandr Urakov 157*94cd0667SPavel Labath virtual void Visit(FPOProgramNodeSymbol &node) {} 158*94cd0667SPavel Labath virtual void Visit(FPOProgramNodeRegisterRef &node) {} 159*94cd0667SPavel Labath virtual void Visit(FPOProgramNodeIntegerLiteral &node) {} 160*94cd0667SPavel Labath virtual void Visit(FPOProgramNodeBinaryOp &node) {} 161*94cd0667SPavel Labath virtual void Visit(FPOProgramNodeUnaryOp &node) {} 162758657e5SAleksandr Urakov }; 163758657e5SAleksandr Urakov 164*94cd0667SPavel Labath void FPOProgramNodeSymbol::Accept(FPOProgramASTVisitor &visitor) { 165*94cd0667SPavel Labath visitor.Visit(*this); 1661c4ee160SPavel Labath } 1671c4ee160SPavel Labath 168*94cd0667SPavel Labath void FPOProgramNodeRegisterRef::Accept(FPOProgramASTVisitor &visitor) { 169*94cd0667SPavel Labath visitor.Visit(*this); 170758657e5SAleksandr Urakov } 171758657e5SAleksandr Urakov 172*94cd0667SPavel Labath void FPOProgramNodeIntegerLiteral::Accept(FPOProgramASTVisitor &visitor) { 173*94cd0667SPavel Labath visitor.Visit(*this); 174758657e5SAleksandr Urakov } 175758657e5SAleksandr Urakov 176*94cd0667SPavel Labath void FPOProgramNodeBinaryOp::Accept(FPOProgramASTVisitor &visitor) { 177*94cd0667SPavel Labath visitor.Visit(*this); 178758657e5SAleksandr Urakov } 179758657e5SAleksandr Urakov 180*94cd0667SPavel Labath void FPOProgramNodeUnaryOp::Accept(FPOProgramASTVisitor &visitor) { 181*94cd0667SPavel Labath visitor.Visit(*this); 182758657e5SAleksandr Urakov } 183758657e5SAleksandr Urakov 184758657e5SAleksandr Urakov class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor { 185758657e5SAleksandr Urakov public: 186758657e5SAleksandr Urakov FPOProgramASTVisitorMergeDependent( 187758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 188758657e5SAleksandr Urakov &dependent_programs) 189758657e5SAleksandr Urakov : m_dependent_programs(dependent_programs) {} 190758657e5SAleksandr Urakov 191758657e5SAleksandr Urakov void Merge(FPOProgramNode *&node_ref); 192758657e5SAleksandr Urakov 193758657e5SAleksandr Urakov private: 194*94cd0667SPavel Labath void Visit(FPOProgramNodeBinaryOp &node) override; 195*94cd0667SPavel Labath void Visit(FPOProgramNodeUnaryOp &node) override; 196758657e5SAleksandr Urakov 197758657e5SAleksandr Urakov void TryReplace(FPOProgramNode *&node_ref) const; 198758657e5SAleksandr Urakov 199758657e5SAleksandr Urakov private: 200758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs; 201758657e5SAleksandr Urakov }; 202758657e5SAleksandr Urakov 203758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::Merge(FPOProgramNode *&node_ref) { 204758657e5SAleksandr Urakov TryReplace(node_ref); 205*94cd0667SPavel Labath node_ref->Accept(*this); 206758657e5SAleksandr Urakov } 207758657e5SAleksandr Urakov 208*94cd0667SPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeBinaryOp &node) { 209*94cd0667SPavel Labath Merge(node.Left()); 210*94cd0667SPavel Labath Merge(node.Right()); 211758657e5SAleksandr Urakov } 212*94cd0667SPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeUnaryOp &node) { 213*94cd0667SPavel Labath Merge(node.Operand()); 214758657e5SAleksandr Urakov } 215758657e5SAleksandr Urakov 216758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::TryReplace( 217758657e5SAleksandr Urakov FPOProgramNode *&node_ref) const { 218758657e5SAleksandr Urakov 2191c4ee160SPavel Labath while (node_ref->GetKind() == FPOProgramNode::Symbol) { 2201c4ee160SPavel Labath auto *node_symbol_ref = static_cast<FPOProgramNodeSymbol *>(node_ref); 221758657e5SAleksandr Urakov 2221c4ee160SPavel Labath auto it = m_dependent_programs.find(node_symbol_ref->GetName()); 223758657e5SAleksandr Urakov if (it == m_dependent_programs.end()) { 224758657e5SAleksandr Urakov break; 225758657e5SAleksandr Urakov } 226758657e5SAleksandr Urakov 227758657e5SAleksandr Urakov node_ref = it->second; 228758657e5SAleksandr Urakov } 229758657e5SAleksandr Urakov } 230758657e5SAleksandr Urakov 231758657e5SAleksandr Urakov class FPOProgramASTVisitorResolveRegisterRefs : public FPOProgramASTVisitor { 232758657e5SAleksandr Urakov public: 233758657e5SAleksandr Urakov FPOProgramASTVisitorResolveRegisterRefs( 234758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> 235758657e5SAleksandr Urakov &dependent_programs, 2361c4ee160SPavel Labath llvm::Triple::ArchType arch_type, NodeAllocator &alloc) 2371c4ee160SPavel Labath : m_dependent_programs(dependent_programs), m_arch_type(arch_type), 2381c4ee160SPavel Labath m_alloc(alloc) {} 239758657e5SAleksandr Urakov 2401c4ee160SPavel Labath bool Resolve(FPOProgramNode *&program); 241758657e5SAleksandr Urakov 242758657e5SAleksandr Urakov private: 243*94cd0667SPavel Labath void Visit(FPOProgramNodeBinaryOp &node) override; 244*94cd0667SPavel Labath void Visit(FPOProgramNodeUnaryOp &node) override; 245758657e5SAleksandr Urakov 2461c4ee160SPavel Labath bool TryReplace(FPOProgramNode *&node_ref); 2471c4ee160SPavel Labath 248758657e5SAleksandr Urakov const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs; 249758657e5SAleksandr Urakov llvm::Triple::ArchType m_arch_type; 2501c4ee160SPavel Labath NodeAllocator &m_alloc; 251758657e5SAleksandr Urakov bool m_no_error_flag = true; 252758657e5SAleksandr Urakov }; 253758657e5SAleksandr Urakov 2541c4ee160SPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::Resolve(FPOProgramNode *&program) { 2551c4ee160SPavel Labath if (!TryReplace(program)) 2561c4ee160SPavel Labath return false; 257*94cd0667SPavel Labath program->Accept(*this); 258758657e5SAleksandr Urakov return m_no_error_flag; 259758657e5SAleksandr Urakov } 260758657e5SAleksandr Urakov 2611c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) { 2621c4ee160SPavel Labath // lookup register name to get lldb register number 2631c4ee160SPavel Labath llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names = 2641c4ee160SPavel Labath llvm::codeview::getRegisterNames(); 2651c4ee160SPavel Labath auto it = llvm::find_if( 2661c4ee160SPavel Labath register_names, 2671c4ee160SPavel Labath [®_name](const llvm::EnumEntry<uint16_t> ®ister_entry) { 2681c4ee160SPavel Labath return reg_name.compare_lower(register_entry.Name) == 0; 2691c4ee160SPavel Labath }); 270758657e5SAleksandr Urakov 2711c4ee160SPavel Labath if (it == register_names.end()) 2721c4ee160SPavel Labath return LLDB_INVALID_REGNUM; 2731c4ee160SPavel Labath 2741c4ee160SPavel Labath auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value); 2751c4ee160SPavel Labath return npdb::GetLLDBRegisterNumber(arch_type, reg_id); 276758657e5SAleksandr Urakov } 2771c4ee160SPavel Labath 2781c4ee160SPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::TryReplace( 2791c4ee160SPavel Labath FPOProgramNode *&node_ref) { 2801c4ee160SPavel Labath if (node_ref->GetKind() != FPOProgramNode::Symbol) 2811c4ee160SPavel Labath return true; 2821c4ee160SPavel Labath 2831c4ee160SPavel Labath auto *symbol = static_cast<FPOProgramNodeSymbol *>(node_ref); 2841c4ee160SPavel Labath 2851c4ee160SPavel Labath // Look up register reference as lvalue in preceding assignments. 2861c4ee160SPavel Labath auto it = m_dependent_programs.find(symbol->GetName()); 2871c4ee160SPavel Labath if (it != m_dependent_programs.end()) { 2881c4ee160SPavel Labath // Dependent programs are handled elsewhere. 2891c4ee160SPavel Labath return true; 2901c4ee160SPavel Labath } 2911c4ee160SPavel Labath 2921c4ee160SPavel Labath uint32_t reg_num = 2931c4ee160SPavel Labath ResolveLLDBRegisterNum(symbol->GetName().drop_front(1), m_arch_type); 2941c4ee160SPavel Labath 2951c4ee160SPavel Labath if (reg_num == LLDB_INVALID_REGNUM) 2961c4ee160SPavel Labath return false; 2971c4ee160SPavel Labath 2981c4ee160SPavel Labath node_ref = m_alloc.makeNode<FPOProgramNodeRegisterRef>(reg_num); 2991c4ee160SPavel Labath return true; 300758657e5SAleksandr Urakov } 301758657e5SAleksandr Urakov 302758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit( 303*94cd0667SPavel Labath FPOProgramNodeBinaryOp &node) { 304*94cd0667SPavel Labath m_no_error_flag = Resolve(node.Left()) && Resolve(node.Right()); 305758657e5SAleksandr Urakov } 306758657e5SAleksandr Urakov 307758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit( 308*94cd0667SPavel Labath FPOProgramNodeUnaryOp &node) { 309*94cd0667SPavel Labath m_no_error_flag = Resolve(node.Operand()); 310758657e5SAleksandr Urakov } 311758657e5SAleksandr Urakov 312758657e5SAleksandr Urakov class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor { 313758657e5SAleksandr Urakov public: 314758657e5SAleksandr Urakov FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {} 315758657e5SAleksandr Urakov 316*94cd0667SPavel Labath void Emit(FPOProgramNode &program); 317758657e5SAleksandr Urakov 318758657e5SAleksandr Urakov private: 319*94cd0667SPavel Labath void Visit(FPOProgramNodeRegisterRef &node) override; 320*94cd0667SPavel Labath void Visit(FPOProgramNodeIntegerLiteral &node) override; 321*94cd0667SPavel Labath void Visit(FPOProgramNodeBinaryOp &node) override; 322*94cd0667SPavel Labath void Visit(FPOProgramNodeUnaryOp &node) override; 323758657e5SAleksandr Urakov 324758657e5SAleksandr Urakov private: 325758657e5SAleksandr Urakov Stream &m_out_stream; 326758657e5SAleksandr Urakov }; 327758657e5SAleksandr Urakov 328*94cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Emit(FPOProgramNode &program) { 329*94cd0667SPavel Labath program.Accept(*this); 330758657e5SAleksandr Urakov } 331758657e5SAleksandr Urakov 332*94cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef &node) { 333758657e5SAleksandr Urakov 334*94cd0667SPavel Labath uint32_t reg_num = node.GetLLDBRegNum(); 335758657e5SAleksandr Urakov lldbassert(reg_num != LLDB_INVALID_REGNUM); 336758657e5SAleksandr Urakov 337758657e5SAleksandr Urakov if (reg_num > 31) { 338758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_bregx); 339758657e5SAleksandr Urakov m_out_stream.PutULEB128(reg_num); 340758657e5SAleksandr Urakov } else 341758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_breg0 + reg_num); 342758657e5SAleksandr Urakov 343758657e5SAleksandr Urakov m_out_stream.PutSLEB128(0); 344758657e5SAleksandr Urakov } 345758657e5SAleksandr Urakov 346758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit( 347*94cd0667SPavel Labath FPOProgramNodeIntegerLiteral &node) { 348*94cd0667SPavel Labath uint32_t value = node.GetValue(); 349758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_constu); 350758657e5SAleksandr Urakov m_out_stream.PutULEB128(value); 351758657e5SAleksandr Urakov } 352758657e5SAleksandr Urakov 353*94cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &node) { 354758657e5SAleksandr Urakov 355*94cd0667SPavel Labath Emit(*node.Left()); 356*94cd0667SPavel Labath Emit(*node.Right()); 357758657e5SAleksandr Urakov 358*94cd0667SPavel Labath switch (node.GetOpType()) { 359758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Plus: 360758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_plus); 361758657e5SAleksandr Urakov // NOTE: can be optimized by using DW_OP_plus_uconst opcpode 362758657e5SAleksandr Urakov // if right child node is constant value 363758657e5SAleksandr Urakov break; 364758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Minus: 365758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_minus); 366758657e5SAleksandr Urakov break; 367758657e5SAleksandr Urakov case FPOProgramNodeBinaryOp::Align: 368758657e5SAleksandr Urakov // emit align operator a @ b as 369758657e5SAleksandr Urakov // a & ~(b - 1) 370758657e5SAleksandr Urakov // NOTE: implicitly assuming that b is power of 2 371758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_lit1); 372758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_minus); 373758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_not); 374758657e5SAleksandr Urakov 375758657e5SAleksandr Urakov m_out_stream.PutHex8(DW_OP_and); 376758657e5SAleksandr Urakov break; 377758657e5SAleksandr Urakov } 378758657e5SAleksandr Urakov } 379758657e5SAleksandr Urakov 380*94cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp &node) { 381*94cd0667SPavel Labath Emit(*node.Operand()); 382758657e5SAleksandr Urakov 383*94cd0667SPavel Labath switch (node.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>( 430*94cd0667SPavel 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 = 443*94cd0667SPavel 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 508758657e5SAleksandr Urakov FPOProgramASTVisitorResolveRegisterRefs resolver(dependent_programs, 5091c4ee160SPavel Labath arch_type, alloc); 510758657e5SAleksandr Urakov if (!resolver.Resolve(rvalue_ast)) { 511758657e5SAleksandr Urakov return nullptr; 512758657e5SAleksandr Urakov } 513758657e5SAleksandr Urakov 514758657e5SAleksandr Urakov if (lvalue_name == register_name) { 515758657e5SAleksandr Urakov // found target assignment program - no need to parse further 516758657e5SAleksandr Urakov 517758657e5SAleksandr Urakov // emplace valid dependent subtrees to make target assignment independent 518758657e5SAleksandr Urakov // from predecessors 519758657e5SAleksandr Urakov FPOProgramASTVisitorMergeDependent merger(dependent_programs); 520758657e5SAleksandr Urakov merger.Merge(rvalue_ast); 521758657e5SAleksandr Urakov 522758657e5SAleksandr Urakov return rvalue_ast; 523758657e5SAleksandr Urakov } 524758657e5SAleksandr Urakov 525758657e5SAleksandr Urakov dependent_programs[lvalue_name] = rvalue_ast; 526758657e5SAleksandr Urakov cur = assign_index + 1; 527758657e5SAleksandr Urakov } 528758657e5SAleksandr Urakov 529758657e5SAleksandr Urakov return nullptr; 530758657e5SAleksandr Urakov } 531758657e5SAleksandr Urakov 532758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression( 533758657e5SAleksandr Urakov llvm::StringRef program, llvm::StringRef register_name, 534758657e5SAleksandr Urakov llvm::Triple::ArchType arch_type, Stream &stream) { 535758657e5SAleksandr Urakov NodeAllocator node_alloc; 536758657e5SAleksandr Urakov FPOProgramNode *target_program = 537758657e5SAleksandr Urakov ParseFPOProgram(program, register_name, arch_type, node_alloc); 538758657e5SAleksandr Urakov if (target_program == nullptr) { 539758657e5SAleksandr Urakov return false; 540758657e5SAleksandr Urakov } 541758657e5SAleksandr Urakov 542758657e5SAleksandr Urakov FPOProgramASTVisitorDWARFCodegen codegen(stream); 543*94cd0667SPavel Labath codegen.Emit(*target_program); 544758657e5SAleksandr Urakov return true; 545758657e5SAleksandr Urakov } 546