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 EXPECT_EQ("+(int(47), int(-42))", ParseAndStringify("47 -42 +")); 92 93 EXPECT_EQ("nullptr", ParseAndStringify("+")); 94 EXPECT_EQ("nullptr", ParseAndStringify("^")); 95 EXPECT_EQ("nullptr", ParseAndStringify("1 +")); 96 EXPECT_EQ("nullptr", ParseAndStringify("1 2 ^")); 97 EXPECT_EQ("nullptr", ParseAndStringify("1 2 3 +")); 98 EXPECT_EQ("nullptr", ParseAndStringify("^ 1")); 99 EXPECT_EQ("nullptr", ParseAndStringify("+ 1 2")); 100 EXPECT_EQ("nullptr", ParseAndStringify("1 + 2")); 101 EXPECT_EQ("nullptr", ParseAndStringify("1 2")); 102 EXPECT_EQ("nullptr", ParseAndStringify("")); 103 } 104 105 static std::string ParseAndGenerateDWARF(llvm::StringRef expr) { 106 llvm::BumpPtrAllocator alloc; 107 Node *ast = Parse(expr, alloc); 108 if (!ast) 109 return "Parse failed."; 110 if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * { 111 if (symbol.GetName() == "INIT") 112 return MakeNode<InitialValueNode>(alloc); 113 114 uint32_t num; 115 if (to_integer(symbol.GetName().drop_front(), num)) 116 return MakeNode<RegisterNode>(alloc, num); 117 return nullptr; 118 })) { 119 return "Resolution failed."; 120 } 121 122 const size_t addr_size = 4; 123 StreamString dwarf(Stream::eBinary, addr_size, lldb::eByteOrderLittle); 124 ToDWARF(*ast, dwarf); 125 126 // print dwarf expression to comparable textual representation 127 DataExtractor extractor(dwarf.GetData(), dwarf.GetSize(), 128 lldb::eByteOrderLittle, addr_size); 129 130 StreamString result; 131 if (!DWARFExpression::PrintDWARFExpression(result, extractor, addr_size, 132 /*dwarf_ref_size*/ 4, 133 /*location_expression*/ false)) { 134 return "DWARF printing failed."; 135 } 136 137 return result.GetString(); 138 } 139 140 TEST(PostfixExpression, ToDWARF) { 141 EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0")); 142 143 EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1")); 144 145 EXPECT_EQ("DW_OP_bregx 65 0", ParseAndGenerateDWARF("R65")); 146 147 EXPECT_EQ("DW_OP_pick 0x00", ParseAndGenerateDWARF("INIT")); 148 149 EXPECT_EQ("DW_OP_pick 0x00, DW_OP_pick 0x01, DW_OP_plus ", 150 ParseAndGenerateDWARF("INIT INIT +")); 151 152 EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x01, DW_OP_plus ", 153 ParseAndGenerateDWARF("R1 INIT +")); 154 155 EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x01, DW_OP_deref , DW_OP_plus ", 156 ParseAndGenerateDWARF("1 INIT ^ +")); 157 158 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus ", 159 ParseAndGenerateDWARF("4 5 +")); 160 161 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus ", 162 ParseAndGenerateDWARF("4 5 -")); 163 164 EXPECT_EQ("DW_OP_consts +4, DW_OP_deref ", ParseAndGenerateDWARF("4 ^")); 165 166 EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1 " 167 ", DW_OP_minus , DW_OP_not , DW_OP_and ", 168 ParseAndGenerateDWARF("R6 128 @")); 169 } 170