1 // Copyright 2014 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 // Unit test for MicrodumpProcessor.
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h> // Must come first
33 #endif
34
35 #include <fstream>
36 #include <iostream>
37 #include <string>
38 #include <vector>
39
40 #include "breakpad_googletest_includes.h"
41 #include "google_breakpad/processor/basic_source_line_resolver.h"
42 #include "google_breakpad/processor/call_stack.h"
43 #include "google_breakpad/processor/microdump.h"
44 #include "google_breakpad/processor/microdump_processor.h"
45 #include "google_breakpad/processor/process_state.h"
46 #include "google_breakpad/processor/stack_frame.h"
47 #include "google_breakpad/processor/stack_frame_symbolizer.h"
48 #include "processor/simple_symbol_supplier.h"
49 #include "processor/stackwalker_unittest_utils.h"
50
51 namespace {
52
53 using google_breakpad::BasicSourceLineResolver;
54 using google_breakpad::Microdump;
55 using google_breakpad::MicrodumpProcessor;
56 using google_breakpad::ProcessState;
57 using google_breakpad::SimpleSymbolSupplier;
58 using google_breakpad::StackFrameSymbolizer;
59
60 class MicrodumpProcessorTest : public ::testing::Test {
61 public:
MicrodumpProcessorTest()62 MicrodumpProcessorTest()
63 : files_path_(string(getenv("srcdir") ? getenv("srcdir") : ".") +
64 "/src/processor/testdata/") {
65 }
66
ReadFile(const string & file_name,string * file_contents)67 void ReadFile(const string& file_name, string* file_contents) {
68 assert(file_contents);
69 std::ifstream file_stream(file_name.c_str(), std::ios::in);
70 ASSERT_TRUE(file_stream.good());
71 std::vector<char> bytes;
72 file_stream.seekg(0, std::ios_base::end);
73 ASSERT_TRUE(file_stream.good());
74 bytes.resize(file_stream.tellg());
75 file_stream.seekg(0, std::ios_base::beg);
76 ASSERT_TRUE(file_stream.good());
77 file_stream.read(&bytes[0], bytes.size());
78 ASSERT_TRUE(file_stream.good());
79 *file_contents = string(&bytes[0], bytes.size());
80 }
81
ProcessMicrodump(const string & symbols_file,const string & microdump_contents,ProcessState * state)82 google_breakpad::ProcessResult ProcessMicrodump(
83 const string& symbols_file,
84 const string& microdump_contents,
85 ProcessState* state) {
86 SimpleSymbolSupplier supplier(symbols_file);
87 BasicSourceLineResolver resolver;
88 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
89 MicrodumpProcessor processor(&frame_symbolizer);
90
91 Microdump microdump(microdump_contents);
92 return processor.Process(µdump, state);
93 }
94
AnalyzeDump(const string & microdump_file_name,bool omit_symbols,int expected_cpu_count,ProcessState * state)95 void AnalyzeDump(const string& microdump_file_name, bool omit_symbols,
96 int expected_cpu_count, ProcessState* state) {
97 string symbols_file = omit_symbols ? "" : files_path_ + "symbols/microdump";
98 string microdump_file_path = files_path_ + microdump_file_name;
99 string microdump_contents;
100 ReadFile(microdump_file_path, µdump_contents);
101
102 google_breakpad::ProcessResult result =
103 ProcessMicrodump(symbols_file, microdump_contents, state);
104
105 ASSERT_EQ(google_breakpad::PROCESS_OK, result);
106 ASSERT_TRUE(state->crashed());
107 ASSERT_EQ(0, state->requesting_thread());
108 ASSERT_EQ(1U, state->threads()->size());
109
110 ASSERT_EQ(expected_cpu_count, state->system_info()->cpu_count);
111 ASSERT_EQ("android", state->system_info()->os_short);
112 ASSERT_EQ("Android", state->system_info()->os);
113 }
114
115 string files_path_;
116 };
117
TEST_F(MicrodumpProcessorTest,TestProcess_Invalid)118 TEST_F(MicrodumpProcessorTest, TestProcess_Invalid) {
119 ProcessState state;
120 google_breakpad::ProcessResult result =
121 ProcessMicrodump("", "This is not a valid microdump", &state);
122 ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result);
123 }
124
TEST_F(MicrodumpProcessorTest,TestProcess_WithoutCrashReason)125 TEST_F(MicrodumpProcessorTest, TestProcess_WithoutCrashReason) {
126 ProcessState state;
127 AnalyzeDump("microdump-arm64.dmp", true /* omit_symbols */,
128 2 /* expected_cpu_count */, &state);
129 ASSERT_EQ(state.crash_reason(), "");
130 ASSERT_EQ(state.crash_address(), 0x0u);
131 }
132
TEST_F(MicrodumpProcessorTest,TestProcess_WithCrashReason)133 TEST_F(MicrodumpProcessorTest, TestProcess_WithCrashReason) {
134 ProcessState state;
135 AnalyzeDump("microdump-withcrashreason.dmp", true /* omit_symbols */,
136 8 /* expected_cpu_count */, &state);
137 ASSERT_EQ(state.crash_reason(), "SIGTRAP");
138 ASSERT_EQ(state.crash_address(), 0x4A7CB000u);
139 }
140
TEST_F(MicrodumpProcessorTest,TestProcess_MissingSymbols)141 TEST_F(MicrodumpProcessorTest, TestProcess_MissingSymbols) {
142 ProcessState state;
143 AnalyzeDump("microdump-arm64.dmp", true /* omit_symbols */,
144 2 /* expected_cpu_count */, &state);
145
146 ASSERT_EQ(8U, state.modules()->module_count());
147 ASSERT_EQ("arm64", state.system_info()->cpu);
148 ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version);
149 ASSERT_EQ(1U, state.threads()->size());
150 ASSERT_EQ(11U, state.threads()->at(0)->frames()->size());
151
152 ASSERT_EQ("",
153 state.threads()->at(0)->frames()->at(0)->function_name);
154 ASSERT_EQ("",
155 state.threads()->at(0)->frames()->at(3)->function_name);
156 }
157
TEST_F(MicrodumpProcessorTest,TestProcess_UnsupportedArch)158 TEST_F(MicrodumpProcessorTest, TestProcess_UnsupportedArch) {
159 string microdump_contents =
160 "W/google-breakpad(26491): -----BEGIN BREAKPAD MICRODUMP-----\n"
161 "W/google-breakpad(26491): O A \"unsupported-arch\"\n"
162 "W/google-breakpad(26491): S 0 A48BD840 A48BD000 00002000\n";
163
164 ProcessState state;
165
166 google_breakpad::ProcessResult result =
167 ProcessMicrodump("", microdump_contents, &state);
168
169 ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result);
170 }
171
TEST_F(MicrodumpProcessorTest,TestProcessArm)172 TEST_F(MicrodumpProcessorTest, TestProcessArm) {
173 ProcessState state;
174 AnalyzeDump("microdump-arm.dmp", false /* omit_symbols */,
175 2 /* expected_cpu_count*/, &state);
176
177 ASSERT_EQ(6U, state.modules()->module_count());
178 ASSERT_EQ("arm", state.system_info()->cpu);
179 ASSERT_EQ("OpenGL ES 3.0 [email protected] AU@ (GIT@Id3510ff6dc)",
180 state.system_info()->gl_version);
181 ASSERT_EQ("Qualcomm", state.system_info()->gl_vendor);
182 ASSERT_EQ("Adreno (TM) 330", state.system_info()->gl_renderer);
183 ASSERT_EQ("OS VERSION INFO", state.system_info()->os_version);
184 ASSERT_EQ(8U, state.threads()->at(0)->frames()->size());
185 ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody",
186 state.threads()->at(0)->frames()->at(0)->function_name);
187 ASSERT_EQ("testing::Test::Run",
188 state.threads()->at(0)->frames()->at(1)->function_name);
189 ASSERT_EQ("main",
190 state.threads()->at(0)->frames()->at(6)->function_name);
191 ASSERT_EQ("breakpad_unittests",
192 state.threads()->at(0)->frames()->at(6)->module->code_file());
193 }
194
TEST_F(MicrodumpProcessorTest,TestProcessArm64)195 TEST_F(MicrodumpProcessorTest, TestProcessArm64) {
196 ProcessState state;
197 AnalyzeDump("microdump-arm64.dmp", false /* omit_symbols */,
198 2 /* expected_cpu_count*/, &state);
199
200 ASSERT_EQ(8U, state.modules()->module_count());
201 ASSERT_EQ("arm64", state.system_info()->cpu);
202 ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version);
203 ASSERT_EQ(9U, state.threads()->at(0)->frames()->size());
204 ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody",
205 state.threads()->at(0)->frames()->at(0)->function_name);
206 ASSERT_EQ("testing::Test::Run",
207 state.threads()->at(0)->frames()->at(2)->function_name);
208 ASSERT_EQ("main",
209 state.threads()->at(0)->frames()->at(7)->function_name);
210 ASSERT_EQ("breakpad_unittests",
211 state.threads()->at(0)->frames()->at(7)->module->code_file());
212 }
213
TEST_F(MicrodumpProcessorTest,TestProcessX86)214 TEST_F(MicrodumpProcessorTest, TestProcessX86) {
215 ProcessState state;
216 AnalyzeDump("microdump-x86.dmp", false /* omit_symbols */,
217 4 /* expected_cpu_count */, &state);
218
219 ASSERT_EQ(124U, state.modules()->module_count());
220 ASSERT_EQ("x86", state.system_info()->cpu);
221 ASSERT_EQ("asus/WW_Z00A/Z00A:5.0/LRX21V/2.19.40.22_20150627_5104_user:user/"
222 "release-keys", state.system_info()->os_version);
223 ASSERT_EQ(17U, state.threads()->at(0)->frames()->size());
224 ASSERT_EQ("libc.so",
225 state.threads()->at(0)->frames()->at(0)->module->debug_file());
226 // TODO(mmandlis): Get symbols for the test X86 microdump and test function
227 // names.
228 }
229
TEST_F(MicrodumpProcessorTest,TestProcessMultiple)230 TEST_F(MicrodumpProcessorTest, TestProcessMultiple) {
231 ProcessState state;
232 AnalyzeDump("microdump-multiple.dmp", false /* omit_symbols */,
233 6 /* expected_cpu_count */, &state);
234 ASSERT_EQ(156U, state.modules()->module_count());
235 ASSERT_EQ("arm", state.system_info()->cpu);
236 ASSERT_EQ("lge/p1_tmo_us/p1:6.0/MRA58K/1603210524c8d:user/release-keys",
237 state.system_info()->os_version);
238 ASSERT_EQ(5U, state.threads()->at(0)->frames()->size());
239 }
240
TEST_F(MicrodumpProcessorTest,TestProcessMips)241 TEST_F(MicrodumpProcessorTest, TestProcessMips) {
242 ProcessState state;
243 AnalyzeDump("microdump-mips32.dmp", false /* omit_symbols */,
244 2 /* expected_cpu_count */, &state);
245
246 ASSERT_EQ(7U, state.modules()->module_count());
247 ASSERT_EQ("mips", state.system_info()->cpu);
248 ASSERT_EQ("3.0.8-g893bf16 #7 SMP PREEMPT Fri Jul 10 15:20:59 PDT 2015",
249 state.system_info()->os_version);
250 ASSERT_EQ(4U, state.threads()->at(0)->frames()->size());
251
252 ASSERT_EQ("blaTest",
253 state.threads()->at(0)->frames()->at(0)->function_name);
254 ASSERT_EQ("Crash",
255 state.threads()->at(0)->frames()->at(1)->function_name);
256 ASSERT_EQ("main",
257 state.threads()->at(0)->frames()->at(2)->function_name);
258 ASSERT_EQ("crash_example",
259 state.threads()->at(0)->frames()->at(0)->module->debug_file());
260 }
261
TEST_F(MicrodumpProcessorTest,TestProcessMips64)262 TEST_F(MicrodumpProcessorTest, TestProcessMips64) {
263 ProcessState state;
264 AnalyzeDump("microdump-mips64.dmp", false /* omit_symbols */,
265 1 /* expected_cpu_count */, &state);
266
267 ASSERT_EQ(8U, state.modules()->module_count());
268 ASSERT_EQ("mips64", state.system_info()->cpu);
269 ASSERT_EQ("3.10.0-gf185e20 #112 PREEMPT Mon Oct 5 11:12:49 PDT 2015",
270 state.system_info()->os_version);
271 ASSERT_EQ(4U, state.threads()->at(0)->frames()->size());
272
273 ASSERT_EQ("blaTest",
274 state.threads()->at(0)->frames()->at(0)->function_name);
275 ASSERT_EQ("Crash",
276 state.threads()->at(0)->frames()->at(1)->function_name);
277 ASSERT_EQ("main",
278 state.threads()->at(0)->frames()->at(2)->function_name);
279 ASSERT_EQ("crash_example",
280 state.threads()->at(0)->frames()->at(0)->module->debug_file());
281 }
282
283 } // namespace
284
main(int argc,char * argv[])285 int main(int argc, char* argv[]) {
286 ::testing::InitGoogleTest(&argc, argv);
287 return RUN_ALL_TESTS();
288 }
289