2019-04-24 15:27:05 +08:00
|
|
|
//===-- PostfixExpressionTest.cpp -------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// 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"
|
2019-04-26 16:52:04 +08:00
|
|
|
#include "lldb/Expression/DWARFExpression.h"
|
|
|
|
#include "lldb/Utility/DataExtractor.h"
|
|
|
|
#include "lldb/Utility/StreamString.h"
|
2019-04-24 15:27:05 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2019-08-26 19:44:14 +08:00
|
|
|
#include "gmock/gmock.h"
|
2019-04-24 15:27:05 +08:00
|
|
|
#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 llvm::formatv("{0}({1}, {2})", ToString(binary.GetOpType()),
|
|
|
|
Dispatch(binary.Left()), Dispatch(binary.Right()));
|
|
|
|
}
|
|
|
|
|
2019-04-30 21:33:18 +08:00
|
|
|
std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; }
|
|
|
|
|
2019-04-24 15:27:05 +08:00
|
|
|
std::string Visit(IntegerNode &integer, Node *&) override {
|
|
|
|
return llvm::formatv("int({0})", integer.GetValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Visit(RegisterNode ®, Node *&) override {
|
|
|
|
return llvm::formatv("reg({0})", reg.GetRegNum());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Visit(SymbolNode &symbol, Node *&) override {
|
|
|
|
return symbol.GetName();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Visit(UnaryOpNode &unary, Node *&) override {
|
|
|
|
return 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";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-08-26 19:44:14 +08:00
|
|
|
static std::string ParseOneAndStringify(llvm::StringRef expr) {
|
2019-04-24 15:27:05 +08:00
|
|
|
llvm::BumpPtrAllocator alloc;
|
2019-08-26 19:44:14 +08:00
|
|
|
return ASTPrinter::Print(ParseOneExpression(expr, alloc));
|
2019-04-24 15:27:05 +08:00
|
|
|
}
|
|
|
|
|
2019-08-26 19:44:14 +08:00
|
|
|
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);
|
2019-08-26 20:42:32 +08:00
|
|
|
std::vector<std::pair<std::string, std::string>> result;
|
|
|
|
for (const auto &p : parsed)
|
|
|
|
result.emplace_back(p.first, ASTPrinter::Print(p.second));
|
|
|
|
return result;
|
2019-08-26 19:44:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
2019-04-24 15:27:05 +08:00
|
|
|
}
|
2019-04-26 16:52:04 +08:00
|
|
|
|
|
|
|
static std::string ParseAndGenerateDWARF(llvm::StringRef expr) {
|
|
|
|
llvm::BumpPtrAllocator alloc;
|
2019-08-26 19:44:14 +08:00
|
|
|
Node *ast = ParseOneExpression(expr, alloc);
|
2019-04-26 16:52:04 +08:00
|
|
|
if (!ast)
|
|
|
|
return "Parse failed.";
|
|
|
|
if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * {
|
2019-04-30 21:33:18 +08:00
|
|
|
if (symbol.GetName() == "INIT")
|
|
|
|
return MakeNode<InitialValueNode>(alloc);
|
|
|
|
|
2019-04-26 16:52:04 +08:00
|
|
|
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
|
|
|
|
DataExtractor extractor(dwarf.GetData(), dwarf.GetSize(),
|
|
|
|
lldb::eByteOrderLittle, addr_size);
|
|
|
|
|
|
|
|
StreamString result;
|
|
|
|
if (!DWARFExpression::PrintDWARFExpression(result, extractor, addr_size,
|
|
|
|
/*dwarf_ref_size*/ 4,
|
|
|
|
/*location_expression*/ false)) {
|
|
|
|
return "DWARF printing failed.";
|
|
|
|
}
|
|
|
|
|
|
|
|
return result.GetString();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PostfixExpression, ToDWARF) {
|
PostfixExpression: Use signed integers in IntegerNode
Summary:
This is necessary to support parsing expressions like ".cfa -16 + ^", as
that format is used in breakpad STACK CFI expressions.
Since the PDB expressions use the same parser, this change will affect
them too, but I don't believe that should be a problem in practice. If
PDBs do contain the negative values, it's very likely that they are
intended to be parsed the same way, and if they don't, then it doesn't
matter.
In case that we do ever need to handle this differently, we can always
make the parser behavior customizable, or just use a different parser.
To make sure that the integer size is big enough for everyone, I switch
from using a (unsigned) 32-bit integer to a 64-bit (signed) one.
Reviewers: amccarth, clayborg, aleksandr.urakov
Subscribers: markmentovai, lldb-commits
Differential Revision: https://reviews.llvm.org/D61311
llvm-svn: 360166
2019-05-07 23:58:20 +08:00
|
|
|
EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0"));
|
2019-04-26 16:52:04 +08:00
|
|
|
|
|
|
|
EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1"));
|
|
|
|
|
|
|
|
EXPECT_EQ("DW_OP_bregx 65 0", ParseAndGenerateDWARF("R65"));
|
|
|
|
|
2019-04-30 21:33:18 +08:00
|
|
|
EXPECT_EQ("DW_OP_pick 0x00", ParseAndGenerateDWARF("INIT"));
|
|
|
|
|
|
|
|
EXPECT_EQ("DW_OP_pick 0x00, DW_OP_pick 0x01, DW_OP_plus ",
|
|
|
|
ParseAndGenerateDWARF("INIT INIT +"));
|
|
|
|
|
|
|
|
EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x01, DW_OP_plus ",
|
|
|
|
ParseAndGenerateDWARF("R1 INIT +"));
|
|
|
|
|
PostfixExpression: Use signed integers in IntegerNode
Summary:
This is necessary to support parsing expressions like ".cfa -16 + ^", as
that format is used in breakpad STACK CFI expressions.
Since the PDB expressions use the same parser, this change will affect
them too, but I don't believe that should be a problem in practice. If
PDBs do contain the negative values, it's very likely that they are
intended to be parsed the same way, and if they don't, then it doesn't
matter.
In case that we do ever need to handle this differently, we can always
make the parser behavior customizable, or just use a different parser.
To make sure that the integer size is big enough for everyone, I switch
from using a (unsigned) 32-bit integer to a 64-bit (signed) one.
Reviewers: amccarth, clayborg, aleksandr.urakov
Subscribers: markmentovai, lldb-commits
Differential Revision: https://reviews.llvm.org/D61311
llvm-svn: 360166
2019-05-07 23:58:20 +08:00
|
|
|
EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x01, DW_OP_deref , DW_OP_plus ",
|
2019-04-30 21:33:18 +08:00
|
|
|
ParseAndGenerateDWARF("1 INIT ^ +"));
|
|
|
|
|
PostfixExpression: Use signed integers in IntegerNode
Summary:
This is necessary to support parsing expressions like ".cfa -16 + ^", as
that format is used in breakpad STACK CFI expressions.
Since the PDB expressions use the same parser, this change will affect
them too, but I don't believe that should be a problem in practice. If
PDBs do contain the negative values, it's very likely that they are
intended to be parsed the same way, and if they don't, then it doesn't
matter.
In case that we do ever need to handle this differently, we can always
make the parser behavior customizable, or just use a different parser.
To make sure that the integer size is big enough for everyone, I switch
from using a (unsigned) 32-bit integer to a 64-bit (signed) one.
Reviewers: amccarth, clayborg, aleksandr.urakov
Subscribers: markmentovai, lldb-commits
Differential Revision: https://reviews.llvm.org/D61311
llvm-svn: 360166
2019-05-07 23:58:20 +08:00
|
|
|
EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus ",
|
2019-04-26 16:52:04 +08:00
|
|
|
ParseAndGenerateDWARF("4 5 +"));
|
|
|
|
|
PostfixExpression: Use signed integers in IntegerNode
Summary:
This is necessary to support parsing expressions like ".cfa -16 + ^", as
that format is used in breakpad STACK CFI expressions.
Since the PDB expressions use the same parser, this change will affect
them too, but I don't believe that should be a problem in practice. If
PDBs do contain the negative values, it's very likely that they are
intended to be parsed the same way, and if they don't, then it doesn't
matter.
In case that we do ever need to handle this differently, we can always
make the parser behavior customizable, or just use a different parser.
To make sure that the integer size is big enough for everyone, I switch
from using a (unsigned) 32-bit integer to a 64-bit (signed) one.
Reviewers: amccarth, clayborg, aleksandr.urakov
Subscribers: markmentovai, lldb-commits
Differential Revision: https://reviews.llvm.org/D61311
llvm-svn: 360166
2019-05-07 23:58:20 +08:00
|
|
|
EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus ",
|
2019-04-26 16:52:04 +08:00
|
|
|
ParseAndGenerateDWARF("4 5 -"));
|
|
|
|
|
PostfixExpression: Use signed integers in IntegerNode
Summary:
This is necessary to support parsing expressions like ".cfa -16 + ^", as
that format is used in breakpad STACK CFI expressions.
Since the PDB expressions use the same parser, this change will affect
them too, but I don't believe that should be a problem in practice. If
PDBs do contain the negative values, it's very likely that they are
intended to be parsed the same way, and if they don't, then it doesn't
matter.
In case that we do ever need to handle this differently, we can always
make the parser behavior customizable, or just use a different parser.
To make sure that the integer size is big enough for everyone, I switch
from using a (unsigned) 32-bit integer to a 64-bit (signed) one.
Reviewers: amccarth, clayborg, aleksandr.urakov
Subscribers: markmentovai, lldb-commits
Differential Revision: https://reviews.llvm.org/D61311
llvm-svn: 360166
2019-05-07 23:58:20 +08:00
|
|
|
EXPECT_EQ("DW_OP_consts +4, DW_OP_deref ", ParseAndGenerateDWARF("4 ^"));
|
2019-04-26 16:52:04 +08:00
|
|
|
|
PostfixExpression: Use signed integers in IntegerNode
Summary:
This is necessary to support parsing expressions like ".cfa -16 + ^", as
that format is used in breakpad STACK CFI expressions.
Since the PDB expressions use the same parser, this change will affect
them too, but I don't believe that should be a problem in practice. If
PDBs do contain the negative values, it's very likely that they are
intended to be parsed the same way, and if they don't, then it doesn't
matter.
In case that we do ever need to handle this differently, we can always
make the parser behavior customizable, or just use a different parser.
To make sure that the integer size is big enough for everyone, I switch
from using a (unsigned) 32-bit integer to a 64-bit (signed) one.
Reviewers: amccarth, clayborg, aleksandr.urakov
Subscribers: markmentovai, lldb-commits
Differential Revision: https://reviews.llvm.org/D61311
llvm-svn: 360166
2019-05-07 23:58:20 +08:00
|
|
|
EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1 "
|
2019-04-26 16:52:04 +08:00
|
|
|
", DW_OP_minus , DW_OP_not , DW_OP_and ",
|
|
|
|
ParseAndGenerateDWARF("R6 128 @"));
|
|
|
|
}
|