xref: /llvm-project/lldb/unittests/Symbol/PostfixExpressionTest.cpp (revision d7796855b87911b8ae6c726ab5df4949f173dbd2)
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 &reg, 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