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