1 //===-- PostfixExpressionTest.cpp -------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Symbol/PostfixExpression.h" 10 #include "lldb/Expression/DWARFExpression.h" 11 #include "lldb/Utility/DataExtractor.h" 12 #include "lldb/Utility/StreamString.h" 13 #include "llvm/Support/FormatVariadic.h" 14 #include "llvm/Support/raw_ostream.h" 15 #include "gtest/gtest.h" 16 17 using namespace lldb_private; 18 using namespace lldb_private::postfix; 19 20 static std::string ToString(BinaryOpNode::OpType type) { 21 switch (type) { 22 case BinaryOpNode::Align: 23 return "@"; 24 case BinaryOpNode::Minus: 25 return "-"; 26 case BinaryOpNode::Plus: 27 return "+"; 28 } 29 llvm_unreachable("Fully covered switch!"); 30 } 31 32 static std::string ToString(UnaryOpNode::OpType type) { 33 switch (type) { 34 case UnaryOpNode::Deref: 35 return "^"; 36 } 37 llvm_unreachable("Fully covered switch!"); 38 } 39 40 struct ASTPrinter : public Visitor<std::string> { 41 protected: 42 std::string Visit(BinaryOpNode &binary, Node *&) override { 43 return llvm::formatv("{0}({1}, {2})", ToString(binary.GetOpType()), 44 Dispatch(binary.Left()), Dispatch(binary.Right())); 45 } 46 47 std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; } 48 49 std::string Visit(IntegerNode &integer, Node *&) override { 50 return llvm::formatv("int({0})", integer.GetValue()); 51 } 52 53 std::string Visit(RegisterNode ®, Node *&) override { 54 return llvm::formatv("reg({0})", reg.GetRegNum()); 55 } 56 57 std::string Visit(SymbolNode &symbol, Node *&) override { 58 return symbol.GetName(); 59 } 60 61 std::string Visit(UnaryOpNode &unary, Node *&) override { 62 return llvm::formatv("{0}({1})", ToString(unary.GetOpType()), 63 Dispatch(unary.Operand())); 64 } 65 66 public: 67 static std::string Print(Node *node) { 68 if (node) 69 return ASTPrinter().Dispatch(node); 70 return "nullptr"; 71 } 72 }; 73 74 static std::string ParseAndStringify(llvm::StringRef expr) { 75 llvm::BumpPtrAllocator alloc; 76 return ASTPrinter::Print(Parse(expr, alloc)); 77 } 78 79 TEST(PostfixExpression, Parse) { 80 EXPECT_EQ("int(47)", ParseAndStringify("47")); 81 EXPECT_EQ("$foo", ParseAndStringify("$foo")); 82 EXPECT_EQ("+(int(1), int(2))", ParseAndStringify("1 2 +")); 83 EXPECT_EQ("-(int(1), int(2))", ParseAndStringify("1 2 -")); 84 EXPECT_EQ("@(int(1), int(2))", ParseAndStringify("1 2 @")); 85 EXPECT_EQ("+(int(1), +(int(2), int(3)))", ParseAndStringify("1 2 3 + +")); 86 EXPECT_EQ("+(+(int(1), int(2)), int(3))", ParseAndStringify("1 2 + 3 +")); 87 EXPECT_EQ("^(int(1))", ParseAndStringify("1 ^")); 88 EXPECT_EQ("^(^(int(1)))", ParseAndStringify("1 ^ ^")); 89 EXPECT_EQ("^(+(int(1), ^(int(2))))", ParseAndStringify("1 2 ^ + ^")); 90 EXPECT_EQ("-($foo, int(47))", ParseAndStringify("$foo 47 -")); 91 92 EXPECT_EQ("nullptr", ParseAndStringify("+")); 93 EXPECT_EQ("nullptr", ParseAndStringify("^")); 94 EXPECT_EQ("nullptr", ParseAndStringify("1 +")); 95 EXPECT_EQ("nullptr", ParseAndStringify("1 2 ^")); 96 EXPECT_EQ("nullptr", ParseAndStringify("1 2 3 +")); 97 EXPECT_EQ("nullptr", ParseAndStringify("^ 1")); 98 EXPECT_EQ("nullptr", ParseAndStringify("+ 1 2")); 99 EXPECT_EQ("nullptr", ParseAndStringify("1 + 2")); 100 EXPECT_EQ("nullptr", ParseAndStringify("1 2")); 101 EXPECT_EQ("nullptr", ParseAndStringify("")); 102 } 103 104 static std::string ParseAndGenerateDWARF(llvm::StringRef expr) { 105 llvm::BumpPtrAllocator alloc; 106 Node *ast = Parse(expr, alloc); 107 if (!ast) 108 return "Parse failed."; 109 if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * { 110 if (symbol.GetName() == "INIT") 111 return MakeNode<InitialValueNode>(alloc); 112 113 uint32_t num; 114 if (to_integer(symbol.GetName().drop_front(), num)) 115 return MakeNode<RegisterNode>(alloc, num); 116 return nullptr; 117 })) { 118 return "Resolution failed."; 119 } 120 121 const size_t addr_size = 4; 122 StreamString dwarf(Stream::eBinary, addr_size, lldb::eByteOrderLittle); 123 ToDWARF(*ast, dwarf); 124 125 // print dwarf expression to comparable textual representation 126 DataExtractor extractor(dwarf.GetData(), dwarf.GetSize(), 127 lldb::eByteOrderLittle, addr_size); 128 129 StreamString result; 130 if (!DWARFExpression::PrintDWARFExpression(result, extractor, addr_size, 131 /*dwarf_ref_size*/ 4, 132 /*location_expression*/ false)) { 133 return "DWARF printing failed."; 134 } 135 136 return result.GetString(); 137 } 138 139 TEST(PostfixExpression, ToDWARF) { 140 EXPECT_EQ("DW_OP_constu 0x0", ParseAndGenerateDWARF("0")); 141 142 EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1")); 143 144 EXPECT_EQ("DW_OP_bregx 65 0", ParseAndGenerateDWARF("R65")); 145 146 EXPECT_EQ("DW_OP_pick 0x00", ParseAndGenerateDWARF("INIT")); 147 148 EXPECT_EQ("DW_OP_pick 0x00, DW_OP_pick 0x01, DW_OP_plus ", 149 ParseAndGenerateDWARF("INIT INIT +")); 150 151 EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x01, DW_OP_plus ", 152 ParseAndGenerateDWARF("R1 INIT +")); 153 154 EXPECT_EQ("DW_OP_constu 0x1, DW_OP_pick 0x01, DW_OP_deref , DW_OP_plus ", 155 ParseAndGenerateDWARF("1 INIT ^ +")); 156 157 EXPECT_EQ("DW_OP_constu 0x4, DW_OP_constu 0x5, DW_OP_plus ", 158 ParseAndGenerateDWARF("4 5 +")); 159 160 EXPECT_EQ("DW_OP_constu 0x4, DW_OP_constu 0x5, DW_OP_minus ", 161 ParseAndGenerateDWARF("4 5 -")); 162 163 EXPECT_EQ("DW_OP_constu 0x4, DW_OP_deref ", ParseAndGenerateDWARF("4 ^")); 164 165 EXPECT_EQ("DW_OP_breg6 +0, DW_OP_constu 0x80, DW_OP_lit1 " 166 ", DW_OP_minus , DW_OP_not , DW_OP_and ", 167 ParseAndGenerateDWARF("R6 128 @")); 168 } 169