forked from OSchip/llvm-project
195 lines
7.0 KiB
C++
195 lines
7.0 KiB
C++
//===-- PostfixExpressionTest.cpp -----------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Symbol/PostfixExpression.h"
|
|
#include "lldb/Utility/DataExtractor.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::postfix;
|
|
|
|
static std::string ToString(BinaryOpNode::OpType type) {
|
|
switch (type) {
|
|
case BinaryOpNode::Align:
|
|
return "@";
|
|
case BinaryOpNode::Minus:
|
|
return "-";
|
|
case BinaryOpNode::Plus:
|
|
return "+";
|
|
}
|
|
llvm_unreachable("Fully covered switch!");
|
|
}
|
|
|
|
static std::string ToString(UnaryOpNode::OpType type) {
|
|
switch (type) {
|
|
case UnaryOpNode::Deref:
|
|
return "^";
|
|
}
|
|
llvm_unreachable("Fully covered switch!");
|
|
}
|
|
|
|
struct ASTPrinter : public Visitor<std::string> {
|
|
protected:
|
|
std::string Visit(BinaryOpNode &binary, Node *&) override {
|
|
return std::string(
|
|
llvm::formatv("{0}({1}, {2})", ToString(binary.GetOpType()),
|
|
Dispatch(binary.Left()), Dispatch(binary.Right())));
|
|
}
|
|
|
|
std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; }
|
|
|
|
std::string Visit(IntegerNode &integer, Node *&) override {
|
|
return std::string(llvm::formatv("int({0})", integer.GetValue()));
|
|
}
|
|
|
|
std::string Visit(RegisterNode ®, Node *&) override {
|
|
return std::string(llvm::formatv("reg({0})", reg.GetRegNum()));
|
|
}
|
|
|
|
std::string Visit(SymbolNode &symbol, Node *&) override {
|
|
return std::string(symbol.GetName());
|
|
}
|
|
|
|
std::string Visit(UnaryOpNode &unary, Node *&) override {
|
|
return std::string(llvm::formatv("{0}({1})", ToString(unary.GetOpType()),
|
|
Dispatch(unary.Operand())));
|
|
}
|
|
|
|
public:
|
|
static std::string Print(Node *node) {
|
|
if (node)
|
|
return ASTPrinter().Dispatch(node);
|
|
return "nullptr";
|
|
}
|
|
};
|
|
|
|
static std::string ParseOneAndStringify(llvm::StringRef expr) {
|
|
llvm::BumpPtrAllocator alloc;
|
|
return ASTPrinter::Print(ParseOneExpression(expr, alloc));
|
|
}
|
|
|
|
TEST(PostfixExpression, ParseOneExpression) {
|
|
EXPECT_EQ("int(47)", ParseOneAndStringify("47"));
|
|
EXPECT_EQ("$foo", ParseOneAndStringify("$foo"));
|
|
EXPECT_EQ("+(int(1), int(2))", ParseOneAndStringify("1 2 +"));
|
|
EXPECT_EQ("-(int(1), int(2))", ParseOneAndStringify("1 2 -"));
|
|
EXPECT_EQ("@(int(1), int(2))", ParseOneAndStringify("1 2 @"));
|
|
EXPECT_EQ("+(int(1), +(int(2), int(3)))", ParseOneAndStringify("1 2 3 + +"));
|
|
EXPECT_EQ("+(+(int(1), int(2)), int(3))", ParseOneAndStringify("1 2 + 3 +"));
|
|
EXPECT_EQ("^(int(1))", ParseOneAndStringify("1 ^"));
|
|
EXPECT_EQ("^(^(int(1)))", ParseOneAndStringify("1 ^ ^"));
|
|
EXPECT_EQ("^(+(int(1), ^(int(2))))", ParseOneAndStringify("1 2 ^ + ^"));
|
|
EXPECT_EQ("-($foo, int(47))", ParseOneAndStringify("$foo 47 -"));
|
|
EXPECT_EQ("+(int(47), int(-42))", ParseOneAndStringify("47 -42 +"));
|
|
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("+"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("^"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("1 +"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 ^"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 3 +"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("^ 1"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("+ 1 2"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("1 + 2"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify("1 2"));
|
|
EXPECT_EQ("nullptr", ParseOneAndStringify(""));
|
|
}
|
|
|
|
static std::vector<std::pair<std::string, std::string>>
|
|
ParseFPOAndStringify(llvm::StringRef prog) {
|
|
llvm::BumpPtrAllocator alloc;
|
|
std::vector<std::pair<llvm::StringRef, Node *>> parsed =
|
|
ParseFPOProgram(prog, alloc);
|
|
std::vector<std::pair<std::string, std::string>> result;
|
|
for (const auto &p : parsed)
|
|
result.emplace_back(p.first.str(), ASTPrinter::Print(p.second));
|
|
return result;
|
|
}
|
|
|
|
TEST(PostfixExpression, ParseFPOProgram) {
|
|
EXPECT_THAT(ParseFPOAndStringify("a 1 ="),
|
|
testing::ElementsAre(std::make_pair("a", "int(1)")));
|
|
EXPECT_THAT(ParseFPOAndStringify("a 1 = b 2 3 + ="),
|
|
testing::ElementsAre(std::make_pair("a", "int(1)"),
|
|
std::make_pair("b", "+(int(2), int(3))")));
|
|
|
|
EXPECT_THAT(ParseFPOAndStringify(""), testing::IsEmpty());
|
|
EXPECT_THAT(ParseFPOAndStringify("="), testing::IsEmpty());
|
|
EXPECT_THAT(ParseFPOAndStringify("a 1"), testing::IsEmpty());
|
|
EXPECT_THAT(ParseFPOAndStringify("a 1 = ="), testing::IsEmpty());
|
|
EXPECT_THAT(ParseFPOAndStringify("a 1 + ="), testing::IsEmpty());
|
|
EXPECT_THAT(ParseFPOAndStringify("= a 1 ="), testing::IsEmpty());
|
|
}
|
|
|
|
static std::string ParseAndGenerateDWARF(llvm::StringRef expr) {
|
|
llvm::BumpPtrAllocator alloc;
|
|
Node *ast = ParseOneExpression(expr, alloc);
|
|
if (!ast)
|
|
return "Parse failed.";
|
|
if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * {
|
|
if (symbol.GetName() == "INIT")
|
|
return MakeNode<InitialValueNode>(alloc);
|
|
|
|
uint32_t num;
|
|
if (to_integer(symbol.GetName().drop_front(), num))
|
|
return MakeNode<RegisterNode>(alloc, num);
|
|
return nullptr;
|
|
})) {
|
|
return "Resolution failed.";
|
|
}
|
|
|
|
const size_t addr_size = 4;
|
|
StreamString dwarf(Stream::eBinary, addr_size, lldb::eByteOrderLittle);
|
|
ToDWARF(*ast, dwarf);
|
|
|
|
// print dwarf expression to comparable textual representation
|
|
llvm::DataExtractor extractor(dwarf.GetString(), /*IsLittleEndian=*/true,
|
|
addr_size);
|
|
|
|
std::string result;
|
|
llvm::raw_string_ostream os(result);
|
|
llvm::DWARFExpression(extractor, addr_size, llvm::dwarf::DWARF32)
|
|
.print(os, llvm::DIDumpOptions(), nullptr, nullptr);
|
|
return std::move(os.str());
|
|
}
|
|
|
|
TEST(PostfixExpression, ToDWARF) {
|
|
EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0"));
|
|
|
|
EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1"));
|
|
|
|
EXPECT_EQ("DW_OP_bregx 0x41 +0", ParseAndGenerateDWARF("R65"));
|
|
|
|
EXPECT_EQ("DW_OP_pick 0x0", ParseAndGenerateDWARF("INIT"));
|
|
|
|
EXPECT_EQ("DW_OP_pick 0x0, DW_OP_pick 0x1, DW_OP_plus",
|
|
ParseAndGenerateDWARF("INIT INIT +"));
|
|
|
|
EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x1, DW_OP_plus",
|
|
ParseAndGenerateDWARF("R1 INIT +"));
|
|
|
|
EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x1, DW_OP_deref, DW_OP_plus",
|
|
ParseAndGenerateDWARF("1 INIT ^ +"));
|
|
|
|
EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus",
|
|
ParseAndGenerateDWARF("4 5 +"));
|
|
|
|
EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus",
|
|
ParseAndGenerateDWARF("4 5 -"));
|
|
|
|
EXPECT_EQ("DW_OP_consts +4, DW_OP_deref", ParseAndGenerateDWARF("4 ^"));
|
|
|
|
EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1, DW_OP_minus, "
|
|
"DW_OP_not, DW_OP_and",
|
|
ParseAndGenerateDWARF("R6 128 @"));
|
|
}
|