1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "test/gtest_and_gmock.h"
18
19 #include "perfetto/ext/base/file_utils.h"
20 #include "perfetto/ext/base/temp_file.h"
21 #include "src/profiling/symbolizer/breakpad_parser.h"
22
23 namespace perfetto {
24 namespace profiling {
25
26 namespace {
27
28 // Used to initialize parser objects.
29 constexpr char kFakeFilePath[] = "bad/file/path";
30
TEST(BreakpadParserTest,FileIsEmpty)31 TEST(BreakpadParserTest, FileIsEmpty) {
32 base::TempFile file = base::TempFile::Create();
33 BreakpadParser parser(file.path());
34 ASSERT_TRUE(parser.ParseFile());
35 EXPECT_TRUE(parser.symbols_for_testing().empty());
36 }
37
TEST(BreakpadParserTest,FileNotOpened)38 TEST(BreakpadParserTest, FileNotOpened) {
39 BreakpadParser parser(kFakeFilePath);
40 ASSERT_FALSE(parser.ParseFile());
41 EXPECT_TRUE(parser.symbols_for_testing().empty());
42 }
43
TEST(BreakpadParserTest,ContainsNoFuncRecord)44 TEST(BreakpadParserTest, ContainsNoFuncRecord) {
45 BreakpadParser parser(kFakeFilePath);
46 constexpr char kTestFileContents[] =
47 "MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
48 "FILE 0 /Applications/../MacOSX10.10.sdk/usr/include/ctype.h\n"
49 "1031 2 39 4\n"
50 "PUBLIC 313c0 0 items\n"
51 "STACK CFI 1014 .cfa: $rbp 16 +\n";
52 ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
53 EXPECT_TRUE(parser.symbols_for_testing().empty());
54 }
55
TEST(BreakpadParserTest,ContainsOneFuncRecord)56 TEST(BreakpadParserTest, ContainsOneFuncRecord) {
57 BreakpadParser parser(kFakeFilePath);
58 constexpr char kTestFileContents[] =
59 "MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
60 "FUNC 1010 23 0 foo::bar()\n"
61 "1031 2 39 4\n"
62 "PUBLIC 2e7c0 0 items\n";
63 ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
64 ASSERT_EQ(parser.symbols_for_testing().size(), 1u);
65 EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(),
66 "foo::bar()");
67 EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
68 static_cast<uint64_t>(0x1010));
69 }
70
TEST(BreakpadParserTest,ContainsManyFuncRecords)71 TEST(BreakpadParserTest, ContainsManyFuncRecords) {
72 BreakpadParser parser(kFakeFilePath);
73 constexpr char kTestFileContents[] =
74 "MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
75 "FUNC 1010 23 0 foo_foo\n"
76 "1031 2 39 4\n"
77 "FUNC 1040 84 0 bar_1\n"
78 "1040 4 44 5\n"
79 "FUNC 10d0 6b 0 baz_baz()\n";
80 ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
81 ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
82 EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(), "foo_foo");
83 EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
84 static_cast<uint64_t>(0x1010));
85 EXPECT_EQ(parser.symbols_for_testing()[0].function_size, 35u);
86 EXPECT_STREQ(parser.symbols_for_testing()[1].symbol_name.c_str(), "bar_1");
87 EXPECT_EQ(parser.symbols_for_testing()[1].start_address,
88 static_cast<uint64_t>(0x1040));
89 EXPECT_EQ(parser.symbols_for_testing()[1].function_size, 132u);
90 EXPECT_STREQ(parser.symbols_for_testing()[2].symbol_name.c_str(),
91 "baz_baz()");
92 EXPECT_EQ(parser.symbols_for_testing()[2].start_address,
93 static_cast<uint64_t>(0x10d0));
94 EXPECT_EQ(parser.symbols_for_testing()[2].function_size, 107u);
95 }
96
TEST(BreakpadParserTest,OptionalArgument)97 TEST(BreakpadParserTest, OptionalArgument) {
98 BreakpadParser parser(kFakeFilePath);
99 constexpr char kTestFileContents[] =
100 "MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
101 "FUNC m 1010 23 0 foo_foo()\n"
102 "1031 2 39 4\n"
103 "FUNC m 1040 84 0 bar_1\n";
104 ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
105 ASSERT_EQ(parser.symbols_for_testing().size(), 2u);
106 EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(),
107 "foo_foo()");
108 EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
109 static_cast<uint64_t>(0x1010));
110 EXPECT_STREQ(parser.symbols_for_testing()[1].symbol_name.c_str(), "bar_1");
111 EXPECT_EQ(parser.symbols_for_testing()[1].start_address,
112 static_cast<uint64_t>(0x1040));
113 }
114
TEST(BreakpadParserTest,FuncNameWithSpaces)115 TEST(BreakpadParserTest, FuncNameWithSpaces) {
116 BreakpadParser parser(kFakeFilePath);
117 constexpr char kTestFileContents[] =
118 "MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
119 "FUNC 1010 23 0 foo foo foo\n"
120 "1031 2 39 4\n"
121 "FUNC 1040 84 0 bar\n"
122 "1040 4 44 5\n"
123 "FUNC 10d0 6b 0 baz\n";
124 ASSERT_TRUE(parser.ParseFromString(kTestFileContents));
125 ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
126 EXPECT_STREQ(parser.symbols_for_testing()[0].symbol_name.c_str(),
127 "foo foo foo");
128 EXPECT_EQ(parser.symbols_for_testing()[0].start_address,
129 static_cast<uint64_t>(0x1010));
130 EXPECT_STREQ(parser.symbols_for_testing()[2].symbol_name.c_str(), "baz");
131 EXPECT_EQ(parser.symbols_for_testing()[2].start_address,
132 static_cast<uint64_t>(0x10d0));
133 }
134
TEST(BreakpadParserTest,NonHexAddress)135 TEST(BreakpadParserTest, NonHexAddress) {
136 BreakpadParser parser(kFakeFilePath);
137 constexpr char kTestFileContents[] =
138 "MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
139 "FUNC foo 23 0 foo\n"
140 "1031 2 39 4\n"
141 "FUNC 1040 84 0 bar\n"
142 "1040 4 44 5\n"
143 "FUNC 10d0 6b 0 baz\n";
144 ASSERT_FALSE(parser.ParseFromString(kTestFileContents));
145 EXPECT_TRUE(parser.symbols_for_testing().empty());
146 }
147
TEST(BreakpadParserTest,NoModuleRecord)148 TEST(BreakpadParserTest, NoModuleRecord) {
149 BreakpadParser parser(kFakeFilePath);
150 constexpr char kTestFileContents[] =
151 "FUNC foo 23 0 foo()\n"
152 "1031 2 39 4\n"
153 "FUNC 1040 84 0 bar\n"
154 "1040 4 44 5\n"
155 "FUNC 10d0 6b 0 baz\n";
156 ASSERT_FALSE(parser.ParseFromString(kTestFileContents));
157 EXPECT_TRUE(parser.symbols_for_testing().empty());
158 }
159
160 // To make it easy to read, each FUNC record is followed by two LINE records:
161 // one showing the start address of the ending instruction and one showing the
162 // address where the function ends.
163 constexpr char kGetSymbolTestContents[] =
164 "MODULE mac x86_64 E3A0F28FBCB43C15986D8608AF1DD2380 exif.so\n"
165 "FUNC 1010 23 0 foo\n"
166 "1031 2 39 4\n"
167 "1033 0 0 0\n"
168 "FUNC 1040 84 0 bar\n"
169 "10b6 e 44 5\n"
170 "10c4 0 0 0\n"
171 "FUNC 10d0 6b 0 baz\n"
172 "1136 5 44 5\n"
173 "113b 0 0 0\n";
174
TEST(BreakpadParserTest,GivenStartAddr)175 TEST(BreakpadParserTest, GivenStartAddr) {
176 BreakpadParser parser(kFakeFilePath);
177 ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
178 ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
179 EXPECT_EQ(*parser.GetSymbol(0x1010U), "foo");
180 EXPECT_EQ(*parser.GetSymbol(0x10d0U), "baz");
181 }
182
TEST(BreakpadParserTest,GivenAddrInRange)183 TEST(BreakpadParserTest, GivenAddrInRange) {
184 BreakpadParser parser(kFakeFilePath);
185 ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
186 ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
187 EXPECT_EQ(*parser.GetSymbol(0x1030U), "foo");
188 EXPECT_EQ(*parser.GetSymbol(0x10c0U), "bar");
189 }
190
TEST(BreakpadParserTest,AddrTooLow)191 TEST(BreakpadParserTest, AddrTooLow) {
192 BreakpadParser parser(kFakeFilePath);
193 ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
194 ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
195 EXPECT_FALSE(parser.GetSymbol(0x1000U));
196 }
197
TEST(BreakpadParserTest,AddrTooHigh)198 TEST(BreakpadParserTest, AddrTooHigh) {
199 BreakpadParser parser(kFakeFilePath);
200 ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
201 ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
202 EXPECT_FALSE(parser.GetSymbol(0x3000U));
203 }
204
TEST(BreakpadParserTest,AddrBetweenFunctions)205 TEST(BreakpadParserTest, AddrBetweenFunctions) {
206 BreakpadParser parser(kFakeFilePath);
207 ASSERT_TRUE(parser.ParseFromString(kGetSymbolTestContents));
208 ASSERT_EQ(parser.symbols_for_testing().size(), 3u);
209 EXPECT_FALSE(parser.GetSymbol(0x1036U));
210 }
211
212 } // namespace
213 } // namespace profiling
214 } // namespace perfetto
215