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