blob: d42b6daf35c1cc0f0cd99e0d3750bb465451f503 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "test/gtest_and_gmock.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/temp_file.h"
#include "src/profiling/symbolizer/breakpad_parser.h"
namespace perfetto {
namespace profiling {
namespace {
// Used to initialize parser objects.
constexpr char kFakeFilePath[] = "bad/file/path";
TEST(BreakpadParserTest, FileIsEmpty) {
base::TempFile file = base::TempFile::Create();
BreakpadParser parser(file.path());
ASSERT_TRUE(parser.ParseFile());
EXPECT_TRUE(parser.symbols_for_testing().empty());
}
TEST(BreakpadParserTest, FileNotOpened) {
BreakpadParser parser(kFakeFilePath);
ASSERT_FALSE(parser.ParseFile());
EXPECT_TRUE(parser.symbols_for_testing().empty());
}
TEST(BreakpadParserTest, ContainsNoFuncRecord) {
BreakpadParser parser(kFakeFilePath);
constexpr char kTestFileContents[] =
"MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
"FILE 0 /Applications/../MacOSX10.10.sdk/usr/include/ctype.h\n"
"1031 2 39 4\n"
"PUBLIC 313c0 0 items\n"
"STACK CFI 1014 .cfa: $rbp 16 +\n";
ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
EXPECT_TRUE(parser.symbols_for_testing().empty());
}
TEST(BreakpadParserTest, ContainsOneFuncRecord) {
BreakpadParser parser(kFakeFilePath);
constexpr char kTestFileContents[] =
"MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
"FUNC 1010 23 0 foo::bar()\n"
"1031 2 39 4\n"
"PUBLIC 2e7c0 0 items\n";
ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 1u);
EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(),
"foo::bar()");
EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
static_cast<uint64_t>(0x1010));
}
TEST(BreakpadParserTest, ContainsManyFuncRecords) {
BreakpadParser parser(kFakeFilePath);
constexpr char kTestFileContents[] =
"MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
"FUNC 1010 23 0 foo_foo\n"
"1031 2 39 4\n"
"FUNC 1040 84 0 bar_1\n"
"1040 4 44 5\n"
"FUNC 10d0 6b 0 baz_baz()\n";
ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(), "foo_foo");
EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
static_cast<uint64_t>(0x1010));
EXPECT_EQ(parser.symbols_for_testing()[0].function_size, 35u);
EXPECT_STREQ(parser.symbols_for_testing()[1].symbol_name.c_str(), "bar_1");
EXPECT_EQ(parser.symbols_for_testing()[1].start_address,
static_cast<uint64_t>(0x1040));
EXPECT_EQ(parser.symbols_for_testing()[1].function_size, 132u);
EXPECT_STREQ(parser.symbols_for_testing()[2].symbol_name.c_str(),
"baz_baz()");
EXPECT_EQ(parser.symbols_for_testing()[2].start_address,
static_cast<uint64_t>(0x10d0));
EXPECT_EQ(parser.symbols_for_testing()[2].function_size, 107u);
}
TEST(BreakpadParserTest, OptionalArgument) {
BreakpadParser parser(kFakeFilePath);
constexpr char kTestFileContents[] =
"MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
"FUNC m 1010 23 0 foo_foo()\n"
"1031 2 39 4\n"
"FUNC m 1040 84 0 bar_1\n";
ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 2u);
EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(),
"foo_foo()");
EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
static_cast<uint64_t>(0x1010));
EXPECT_STREQ(parser.symbols_for_testing()[1].symbol_name.c_str(), "bar_1");
EXPECT_EQ(parser.symbols_for_testing()[1].start_address,
static_cast<uint64_t>(0x1040));
}
TEST(BreakpadParserTest, FuncNameWithSpaces) {
BreakpadParser parser(kFakeFilePath);
constexpr char kTestFileContents[] =
"MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
"FUNC 1010 23 0 foo foo foo\n"
"1031 2 39 4\n"
"FUNC 1040 84 0 bar\n"
"1040 4 44 5\n"
"FUNC 10d0 6b 0 baz\n";
ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(),
"foo foo foo");
EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
static_cast<uint64_t>(0x1010));
EXPECT_STREQ(parser.symbols_for_testing()[2].symbol_name.c_str(), "baz");
EXPECT_EQ(parser.symbols_for_testing()[2].start_address,
static_cast<uint64_t>(0x10d0));
}
TEST(BreakpadParserTest, NonHexAddress) {
BreakpadParser parser(kFakeFilePath);
constexpr char kTestFileContents[] =
"MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
"FUNC foo 23 0 foo\n"
"1031 2 39 4\n"
"FUNC 1040 84 0 bar\n"
"1040 4 44 5\n"
"FUNC 10d0 6b 0 baz\n";
ASSERT_FALSE(parser.ParseFromString(kTestFileContents));
EXPECT_TRUE(parser.symbols_for_testing().empty());
}
TEST(BreakpadParserTest, NoModuleRecord) {
BreakpadParser parser(kFakeFilePath);
constexpr char kTestFileContents[] =
"FUNC foo 23 0 foo()\n"
"1031 2 39 4\n"
"FUNC 1040 84 0 bar\n"
"1040 4 44 5\n"
"FUNC 10d0 6b 0 baz\n";
ASSERT_FALSE(parser.ParseFromString(kTestFileContents));
EXPECT_TRUE(parser.symbols_for_testing().empty());
}
// To make it easy to read, each FUNC record is followed by two LINE records:
// one showing the start address of the ending instruction and one showing the
// address where the function ends.
constexpr char kGetSymbolTestContents[] =
"MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
"FUNC 1010 23 0 foo\n"
"1031 2 39 4\n"
"1033 0 0 0\n"
"FUNC 1040 84 0 bar\n"
"10b6 e 44 5\n"
"10c4 0 0 0\n"
"FUNC 10d0 6b 0 baz\n"
"1136 5 44 5\n"
"113b 0 0 0\n";
TEST(BreakpadParserTest, GivenStartAddr) {
BreakpadParser parser(kFakeFilePath);
ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
EXPECT_EQ(*parser.GetSymbol(0x1010U), "foo");
EXPECT_EQ(*parser.GetSymbol(0x10d0U), "baz");
}
TEST(BreakpadParserTest, GivenAddrInRange) {
BreakpadParser parser(kFakeFilePath);
ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
EXPECT_EQ(*parser.GetSymbol(0x1030U), "foo");
EXPECT_EQ(*parser.GetSymbol(0x10c0U), "bar");
}
TEST(BreakpadParserTest, AddrTooLow) {
BreakpadParser parser(kFakeFilePath);
ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
EXPECT_FALSE(parser.GetSymbol(0x1000U));
}
TEST(BreakpadParserTest, AddrTooHigh) {
BreakpadParser parser(kFakeFilePath);
ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
EXPECT_FALSE(parser.GetSymbol(0x3000U));
}
TEST(BreakpadParserTest, AddrBetweenFunctions) {
BreakpadParser parser(kFakeFilePath);
ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
EXPECT_FALSE(parser.GetSymbol(0x1036U));
}
} // namespace
} // namespace profiling
} // namespace perfetto