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