1 //===-- PostfixExpressionTest.cpp -----------------------------------------===// 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 "gmock/gmock.h" 16 #include "gtest/gtest.h" 17 18 using namespace lldb_private; 19 using namespace lldb_private::postfix; 20 21 static std::string ToString(BinaryOpNode::OpType type) { 22 switch (type) { 23 case BinaryOpNode::Align: 24 return "@"; 25 case BinaryOpNode::Minus: 26 return "-"; 27 case BinaryOpNode::Plus: 28 return "+"; 29 } 30 llvm_unreachable("Fully covered switch!"); 31 } 32 33 static std::string ToString(UnaryOpNode::OpType type) { 34 switch (type) { 35 case UnaryOpNode::Deref: 36 return "^"; 37 } 38 llvm_unreachable("Fully covered switch!"); 39 } 40 41 struct ASTPrinter : public Visitor<std::string> { 42 protected: 43 std::string Visit(BinaryOpNode &binary, Node *&) override { 44 return std::string( 45 llvm::formatv("{0}({1}, {2})", ToString(binary.GetOpType()), 46 Dispatch(binary.Left()), Dispatch(binary.Right()))); 47 } 48 49 std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; } 50 51 std::string Visit(IntegerNode &integer, Node *&) override { 52 return std::string(llvm::formatv("int({0})", integer.GetValue())); 53 } 54 55 std::string Visit(RegisterNode ®, Node *&) override { 56 return std::string(llvm::formatv("reg({0})", reg.GetRegNum())); 57 } 58 59 std::string Visit(SymbolNode &symbol, Node *&) override { 60 return std::string(symbol.GetName()); 61 } 62 63 std::string Visit(UnaryOpNode &unary, Node *&) override { 64 return std::string(llvm::formatv("{0}({1})", ToString(unary.GetOpType()), 65 Dispatch(unary.Operand()))); 66 } 67 68 public: 69 static std::string Print(Node *node) { 70 if (node) 71 return ASTPrinter().Dispatch(node); 72 return "nullptr"; 73 } 74 }; 75 76 static std::string ParseOneAndStringify(llvm::StringRef expr) { 77 llvm::BumpPtrAllocator alloc; 78 return ASTPrinter::Print(ParseOneExpression(expr, alloc)); 79 } 80 81 TEST(PostfixExpression, ParseOneExpression) { 82 EXPECT_EQ("int(47)", ParseOneAndStringify("47")); 83 EXPECT_EQ("$foo", ParseOneAndStringify("$foo")); 84 EXPECT_EQ("+(int(1), int(2))", ParseOneAndStringify("1 2 +")); 85 EXPECT_EQ("-(int(1), int(2))", ParseOneAndStringify("1 2 -")); 86 EXPECT_EQ("@(int(1), int(2))", ParseOneAndStringify("1 2 @")); 87 EXPECT_EQ("+(int(1), +(int(2), int(3)))", ParseOneAndStringify("1 2 3 + +")); 88 EXPECT_EQ("+(+(int(1), int(2)), int(3))", ParseOneAndStringify("1 2 + 3 +")); 89 EXPECT_EQ("^(int(1))", ParseOneAndStringify("1 ^")); 90 EXPECT_EQ("^(^(int(1)))", ParseOneAndStringify("1 ^ ^")); 91 EXPECT_EQ("^(+(int(1), ^(int(2))))", ParseOneAndStringify("1 2 ^ + ^")); 92 EXPECT_EQ("-($foo, int(47))", ParseOneAndStringify("$foo 47 -")); 93 EXPECT_EQ("+(int(47), int(-42))", ParseOneAndStringify("47 -42 +")); 94 95 EXPECT_EQ("nullptr", ParseOneAndStringify("+")); 96 EXPECT_EQ("nullptr", ParseOneAndStringify("^")); 97 EXPECT_EQ("nullptr", ParseOneAndStringify("1 +")); 98 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 ^")); 99 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 3 +")); 100 EXPECT_EQ("nullptr", ParseOneAndStringify("^ 1")); 101 EXPECT_EQ("nullptr", ParseOneAndStringify("+ 1 2")); 102 EXPECT_EQ("nullptr", ParseOneAndStringify("1 + 2")); 103 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2")); 104 EXPECT_EQ("nullptr", ParseOneAndStringify("")); 105 } 106 107 static std::vector<std::pair<std::string, std::string>> 108 ParseFPOAndStringify(llvm::StringRef prog) { 109 llvm::BumpPtrAllocator alloc; 110 std::vector<std::pair<llvm::StringRef, Node *>> parsed = 111 ParseFPOProgram(prog, alloc); 112 std::vector<std::pair<std::string, std::string>> result; 113 for (const auto &p : parsed) 114 result.emplace_back(p.first, ASTPrinter::Print(p.second)); 115 return result; 116 } 117 118 TEST(PostfixExpression, ParseFPOProgram) { 119 EXPECT_THAT(ParseFPOAndStringify("a 1 ="), 120 testing::ElementsAre(std::make_pair("a", "int(1)"))); 121 EXPECT_THAT(ParseFPOAndStringify("a 1 = b 2 3 + ="), 122 testing::ElementsAre(std::make_pair("a", "int(1)"), 123 std::make_pair("b", "+(int(2), int(3))"))); 124 125 EXPECT_THAT(ParseFPOAndStringify(""), testing::IsEmpty()); 126 EXPECT_THAT(ParseFPOAndStringify("="), testing::IsEmpty()); 127 EXPECT_THAT(ParseFPOAndStringify("a 1"), testing::IsEmpty()); 128 EXPECT_THAT(ParseFPOAndStringify("a 1 = ="), testing::IsEmpty()); 129 EXPECT_THAT(ParseFPOAndStringify("a 1 + ="), testing::IsEmpty()); 130 EXPECT_THAT(ParseFPOAndStringify("= a 1 ="), testing::IsEmpty()); 131 } 132 133 static std::string ParseAndGenerateDWARF(llvm::StringRef expr) { 134 llvm::BumpPtrAllocator alloc; 135 Node *ast = ParseOneExpression(expr, alloc); 136 if (!ast) 137 return "Parse failed."; 138 if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * { 139 if (symbol.GetName() == "INIT") 140 return MakeNode<InitialValueNode>(alloc); 141 142 uint32_t num; 143 if (to_integer(symbol.GetName().drop_front(), num)) 144 return MakeNode<RegisterNode>(alloc, num); 145 return nullptr; 146 })) { 147 return "Resolution failed."; 148 } 149 150 const size_t addr_size = 4; 151 StreamString dwarf(Stream::eBinary, addr_size, lldb::eByteOrderLittle); 152 ToDWARF(*ast, dwarf); 153 154 // print dwarf expression to comparable textual representation 155 DataExtractor extractor(dwarf.GetData(), dwarf.GetSize(), 156 lldb::eByteOrderLittle, addr_size); 157 158 StreamString result; 159 if (!DWARFExpression::PrintDWARFExpression(result, extractor, addr_size, 160 /*dwarf_ref_size*/ 4, 161 /*location_expression*/ false)) { 162 return "DWARF printing failed."; 163 } 164 165 return std::string(result.GetString()); 166 } 167 168 TEST(PostfixExpression, ToDWARF) { 169 EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0")); 170 171 EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1")); 172 173 EXPECT_EQ("DW_OP_bregx 65 0", ParseAndGenerateDWARF("R65")); 174 175 EXPECT_EQ("DW_OP_pick 0x00", ParseAndGenerateDWARF("INIT")); 176 177 EXPECT_EQ("DW_OP_pick 0x00, DW_OP_pick 0x01, DW_OP_plus ", 178 ParseAndGenerateDWARF("INIT INIT +")); 179 180 EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x01, DW_OP_plus ", 181 ParseAndGenerateDWARF("R1 INIT +")); 182 183 EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x01, DW_OP_deref , DW_OP_plus ", 184 ParseAndGenerateDWARF("1 INIT ^ +")); 185 186 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus ", 187 ParseAndGenerateDWARF("4 5 +")); 188 189 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus ", 190 ParseAndGenerateDWARF("4 5 -")); 191 192 EXPECT_EQ("DW_OP_consts +4, DW_OP_deref ", ParseAndGenerateDWARF("4 ^")); 193 194 EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1 " 195 ", DW_OP_minus , DW_OP_not , DW_OP_and ", 196 ParseAndGenerateDWARF("R6 128 @")); 197 } 198