xref: /aosp_15_r20/external/perfetto/src/profiling/symbolizer/breakpad_parser_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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