180814287SRaphael Isemann //===-- PostfixExpressionTest.cpp -----------------------------------------===// 288813103SPavel Labath // 388813103SPavel Labath // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 488813103SPavel Labath // See https://llvm.org/LICENSE.txt for license information. 588813103SPavel Labath // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 688813103SPavel Labath // 788813103SPavel Labath //===----------------------------------------------------------------------===// 888813103SPavel Labath 988813103SPavel Labath #include "lldb/Symbol/PostfixExpression.h" 100eadd988SPavel Labath #include "lldb/Utility/DataExtractor.h" 110eadd988SPavel Labath #include "lldb/Utility/StreamString.h" 123ff3af30SElliot Goodrich #include "llvm/ADT/StringExtras.h" 13290e4823Sserge-sans-paille #include "llvm/DebugInfo/DIContext.h" 14ba03bcbcSPavel Labath #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 1588813103SPavel Labath #include "llvm/Support/FormatVariadic.h" 1688813103SPavel Labath #include "llvm/Support/raw_ostream.h" 17c7deb7f8SPavel Labath #include "gmock/gmock.h" 1888813103SPavel Labath #include "gtest/gtest.h" 1988813103SPavel Labath 2088813103SPavel Labath using namespace lldb_private; 2188813103SPavel Labath using namespace lldb_private::postfix; 2288813103SPavel Labath 2388813103SPavel Labath static std::string ToString(BinaryOpNode::OpType type) { 2488813103SPavel Labath switch (type) { 2588813103SPavel Labath case BinaryOpNode::Align: 2688813103SPavel Labath return "@"; 2788813103SPavel Labath case BinaryOpNode::Minus: 2888813103SPavel Labath return "-"; 2988813103SPavel Labath case BinaryOpNode::Plus: 3088813103SPavel Labath return "+"; 3188813103SPavel Labath } 3288813103SPavel Labath llvm_unreachable("Fully covered switch!"); 3388813103SPavel Labath } 3488813103SPavel Labath 3588813103SPavel Labath static std::string ToString(UnaryOpNode::OpType type) { 3688813103SPavel Labath switch (type) { 3788813103SPavel Labath case UnaryOpNode::Deref: 3888813103SPavel Labath return "^"; 3988813103SPavel Labath } 4088813103SPavel Labath llvm_unreachable("Fully covered switch!"); 4188813103SPavel Labath } 4288813103SPavel Labath 4388813103SPavel Labath struct ASTPrinter : public Visitor<std::string> { 4488813103SPavel Labath protected: 4588813103SPavel Labath std::string Visit(BinaryOpNode &binary, Node *&) override { 46adcd0268SBenjamin Kramer return std::string( 47adcd0268SBenjamin Kramer llvm::formatv("{0}({1}, {2})", ToString(binary.GetOpType()), 48adcd0268SBenjamin Kramer Dispatch(binary.Left()), Dispatch(binary.Right()))); 4988813103SPavel Labath } 5088813103SPavel Labath 5103db32b3SPavel Labath std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; } 5203db32b3SPavel Labath 5388813103SPavel Labath std::string Visit(IntegerNode &integer, Node *&) override { 54adcd0268SBenjamin Kramer return std::string(llvm::formatv("int({0})", integer.GetValue())); 5588813103SPavel Labath } 5688813103SPavel Labath 5788813103SPavel Labath std::string Visit(RegisterNode ®, Node *&) override { 58adcd0268SBenjamin Kramer return std::string(llvm::formatv("reg({0})", reg.GetRegNum())); 5988813103SPavel Labath } 6088813103SPavel Labath 6188813103SPavel Labath std::string Visit(SymbolNode &symbol, Node *&) override { 62adcd0268SBenjamin Kramer return std::string(symbol.GetName()); 6388813103SPavel Labath } 6488813103SPavel Labath 6588813103SPavel Labath std::string Visit(UnaryOpNode &unary, Node *&) override { 66adcd0268SBenjamin Kramer return std::string(llvm::formatv("{0}({1})", ToString(unary.GetOpType()), 67adcd0268SBenjamin Kramer Dispatch(unary.Operand()))); 6888813103SPavel Labath } 6988813103SPavel Labath 7088813103SPavel Labath public: 7188813103SPavel Labath static std::string Print(Node *node) { 7288813103SPavel Labath if (node) 7388813103SPavel Labath return ASTPrinter().Dispatch(node); 7488813103SPavel Labath return "nullptr"; 7588813103SPavel Labath } 7688813103SPavel Labath }; 7788813103SPavel Labath 78c7deb7f8SPavel Labath static std::string ParseOneAndStringify(llvm::StringRef expr) { 7988813103SPavel Labath llvm::BumpPtrAllocator alloc; 80c7deb7f8SPavel Labath return ASTPrinter::Print(ParseOneExpression(expr, alloc)); 8188813103SPavel Labath } 8288813103SPavel Labath 83c7deb7f8SPavel Labath TEST(PostfixExpression, ParseOneExpression) { 84c7deb7f8SPavel Labath EXPECT_EQ("int(47)", ParseOneAndStringify("47")); 85c7deb7f8SPavel Labath EXPECT_EQ("$foo", ParseOneAndStringify("$foo")); 86c7deb7f8SPavel Labath EXPECT_EQ("+(int(1), int(2))", ParseOneAndStringify("1 2 +")); 87c7deb7f8SPavel Labath EXPECT_EQ("-(int(1), int(2))", ParseOneAndStringify("1 2 -")); 88c7deb7f8SPavel Labath EXPECT_EQ("@(int(1), int(2))", ParseOneAndStringify("1 2 @")); 89c7deb7f8SPavel Labath EXPECT_EQ("+(int(1), +(int(2), int(3)))", ParseOneAndStringify("1 2 3 + +")); 90c7deb7f8SPavel Labath EXPECT_EQ("+(+(int(1), int(2)), int(3))", ParseOneAndStringify("1 2 + 3 +")); 91c7deb7f8SPavel Labath EXPECT_EQ("^(int(1))", ParseOneAndStringify("1 ^")); 92c7deb7f8SPavel Labath EXPECT_EQ("^(^(int(1)))", ParseOneAndStringify("1 ^ ^")); 93c7deb7f8SPavel Labath EXPECT_EQ("^(+(int(1), ^(int(2))))", ParseOneAndStringify("1 2 ^ + ^")); 94c7deb7f8SPavel Labath EXPECT_EQ("-($foo, int(47))", ParseOneAndStringify("$foo 47 -")); 95c7deb7f8SPavel Labath EXPECT_EQ("+(int(47), int(-42))", ParseOneAndStringify("47 -42 +")); 9688813103SPavel Labath 97c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("+")); 98c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("^")); 99c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("1 +")); 100c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 ^")); 101c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 3 +")); 102c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("^ 1")); 103c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("+ 1 2")); 104c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("1 + 2")); 105c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("1 2")); 106c7deb7f8SPavel Labath EXPECT_EQ("nullptr", ParseOneAndStringify("")); 107c7deb7f8SPavel Labath } 108c7deb7f8SPavel Labath 109c7deb7f8SPavel Labath static std::vector<std::pair<std::string, std::string>> 110c7deb7f8SPavel Labath ParseFPOAndStringify(llvm::StringRef prog) { 111c7deb7f8SPavel Labath llvm::BumpPtrAllocator alloc; 112c7deb7f8SPavel Labath std::vector<std::pair<llvm::StringRef, Node *>> parsed = 113c7deb7f8SPavel Labath ParseFPOProgram(prog, alloc); 114f899bf13SPavel Labath std::vector<std::pair<std::string, std::string>> result; 115f899bf13SPavel Labath for (const auto &p : parsed) 1167f717b6dSJonas Devlieghere result.emplace_back(p.first.str(), ASTPrinter::Print(p.second)); 117f899bf13SPavel Labath return result; 118c7deb7f8SPavel Labath } 119c7deb7f8SPavel Labath 120c7deb7f8SPavel Labath TEST(PostfixExpression, ParseFPOProgram) { 121c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify("a 1 ="), 122c7deb7f8SPavel Labath testing::ElementsAre(std::make_pair("a", "int(1)"))); 123c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify("a 1 = b 2 3 + ="), 124c7deb7f8SPavel Labath testing::ElementsAre(std::make_pair("a", "int(1)"), 125c7deb7f8SPavel Labath std::make_pair("b", "+(int(2), int(3))"))); 126c7deb7f8SPavel Labath 127c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify(""), testing::IsEmpty()); 128c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify("="), testing::IsEmpty()); 129c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify("a 1"), testing::IsEmpty()); 130c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify("a 1 = ="), testing::IsEmpty()); 131c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify("a 1 + ="), testing::IsEmpty()); 132c7deb7f8SPavel Labath EXPECT_THAT(ParseFPOAndStringify("= a 1 ="), testing::IsEmpty()); 13388813103SPavel Labath } 1340eadd988SPavel Labath 1350eadd988SPavel Labath static std::string ParseAndGenerateDWARF(llvm::StringRef expr) { 1360eadd988SPavel Labath llvm::BumpPtrAllocator alloc; 137c7deb7f8SPavel Labath Node *ast = ParseOneExpression(expr, alloc); 1380eadd988SPavel Labath if (!ast) 1390eadd988SPavel Labath return "Parse failed."; 1400eadd988SPavel Labath if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * { 14103db32b3SPavel Labath if (symbol.GetName() == "INIT") 14203db32b3SPavel Labath return MakeNode<InitialValueNode>(alloc); 14303db32b3SPavel Labath 1440eadd988SPavel Labath uint32_t num; 1450eadd988SPavel Labath if (to_integer(symbol.GetName().drop_front(), num)) 1460eadd988SPavel Labath return MakeNode<RegisterNode>(alloc, num); 1470eadd988SPavel Labath return nullptr; 1480eadd988SPavel Labath })) { 1490eadd988SPavel Labath return "Resolution failed."; 1500eadd988SPavel Labath } 1510eadd988SPavel Labath 1520eadd988SPavel Labath const size_t addr_size = 4; 1530eadd988SPavel Labath StreamString dwarf(Stream::eBinary, addr_size, lldb::eByteOrderLittle); 1540eadd988SPavel Labath ToDWARF(*ast, dwarf); 1550eadd988SPavel Labath 1560eadd988SPavel Labath // print dwarf expression to comparable textual representation 157ba03bcbcSPavel Labath llvm::DataExtractor extractor(dwarf.GetString(), /*IsLittleEndian=*/true, 158ba03bcbcSPavel Labath addr_size); 1590eadd988SPavel Labath 160ba03bcbcSPavel Labath std::string result; 161ba03bcbcSPavel Labath llvm::raw_string_ostream os(result); 162ba03bcbcSPavel Labath llvm::DWARFExpression(extractor, addr_size, llvm::dwarf::DWARF32) 163617ed4f0SShubham Sandeep Rastogi .print(os, llvm::DIDumpOptions(), nullptr); 164*d7796855SYoungsuk Kim return result; 1650eadd988SPavel Labath } 1660eadd988SPavel Labath 1670eadd988SPavel Labath TEST(PostfixExpression, ToDWARF) { 1680ff89dacSPavel Labath EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0")); 1690eadd988SPavel Labath 1700eadd988SPavel Labath EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1")); 1710eadd988SPavel Labath 172ba03bcbcSPavel Labath EXPECT_EQ("DW_OP_bregx 0x41 +0", ParseAndGenerateDWARF("R65")); 1730eadd988SPavel Labath 174ba03bcbcSPavel Labath EXPECT_EQ("DW_OP_pick 0x0", ParseAndGenerateDWARF("INIT")); 17503db32b3SPavel Labath 176ba03bcbcSPavel Labath EXPECT_EQ("DW_OP_pick 0x0, DW_OP_pick 0x1, DW_OP_plus", 17703db32b3SPavel Labath ParseAndGenerateDWARF("INIT INIT +")); 17803db32b3SPavel Labath 179ba03bcbcSPavel Labath EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x1, DW_OP_plus", 18003db32b3SPavel Labath ParseAndGenerateDWARF("R1 INIT +")); 18103db32b3SPavel Labath 182ba03bcbcSPavel Labath EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x1, DW_OP_deref, DW_OP_plus", 18303db32b3SPavel Labath ParseAndGenerateDWARF("1 INIT ^ +")); 18403db32b3SPavel Labath 1850ff89dacSPavel Labath EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus", 1860eadd988SPavel Labath ParseAndGenerateDWARF("4 5 +")); 1870eadd988SPavel Labath 1880ff89dacSPavel Labath EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus", 1890eadd988SPavel Labath ParseAndGenerateDWARF("4 5 -")); 1900eadd988SPavel Labath 1910ff89dacSPavel Labath EXPECT_EQ("DW_OP_consts +4, DW_OP_deref", ParseAndGenerateDWARF("4 ^")); 1920eadd988SPavel Labath 193ba03bcbcSPavel Labath EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1, DW_OP_minus, " 194ba03bcbcSPavel Labath "DW_OP_not, DW_OP_and", 1950eadd988SPavel Labath ParseAndGenerateDWARF("R6 128 @")); 1960eadd988SPavel Labath } 197