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/Utility/DataExtractor.h" 11 #include "lldb/Utility/StreamString.h" 12 #include "llvm/DebugInfo/DWARF/DWARFExpression.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.str(), 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 llvm::DataExtractor extractor(dwarf.GetString(), /*IsLittleEndian=*/true, 156 addr_size); 157 158 std::string result; 159 llvm::raw_string_ostream os(result); 160 llvm::DWARFExpression(extractor, addr_size, llvm::dwarf::DWARF32) 161 .print(os, nullptr, nullptr); 162 return std::move(os.str()); 163 } 164 165 TEST(PostfixExpression, ToDWARF) { 166 EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0")); 167 168 EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1")); 169 170 EXPECT_EQ("DW_OP_bregx 0x41 +0", ParseAndGenerateDWARF("R65")); 171 172 EXPECT_EQ("DW_OP_pick 0x0", ParseAndGenerateDWARF("INIT")); 173 174 EXPECT_EQ("DW_OP_pick 0x0, DW_OP_pick 0x1, DW_OP_plus", 175 ParseAndGenerateDWARF("INIT INIT +")); 176 177 EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x1, DW_OP_plus", 178 ParseAndGenerateDWARF("R1 INIT +")); 179 180 EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x1, DW_OP_deref, DW_OP_plus", 181 ParseAndGenerateDWARF("1 INIT ^ +")); 182 183 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus", 184 ParseAndGenerateDWARF("4 5 +")); 185 186 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus", 187 ParseAndGenerateDWARF("4 5 -")); 188 189 EXPECT_EQ("DW_OP_consts +4, DW_OP_deref", ParseAndGenerateDWARF("4 ^")); 190 191 EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1, DW_OP_minus, " 192 "DW_OP_not, DW_OP_and", 193 ParseAndGenerateDWARF("R6 128 @")); 194 } 195