1 // Copyright (c) 2014, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 // Unit test for MicrodumpProcessor.
31 
32 #include <fstream>
33 #include <iostream>
34 #include <string>
35 #include <vector>
36 
37 #include "breakpad_googletest_includes.h"
38 #include "google_breakpad/processor/basic_source_line_resolver.h"
39 #include "google_breakpad/processor/call_stack.h"
40 #include "google_breakpad/processor/microdump_processor.h"
41 #include "google_breakpad/processor/process_state.h"
42 #include "google_breakpad/processor/stack_frame.h"
43 #include "google_breakpad/processor/stack_frame_symbolizer.h"
44 #include "processor/simple_symbol_supplier.h"
45 #include "processor/stackwalker_unittest_utils.h"
46 
47 namespace {
48 
49 using google_breakpad::BasicSourceLineResolver;
50 using google_breakpad::MicrodumpProcessor;
51 using google_breakpad::ProcessState;
52 using google_breakpad::SimpleSymbolSupplier;
53 using google_breakpad::StackFrameSymbolizer;
54 
55 class MicrodumpProcessorTest : public ::testing::Test {
56  public:
MicrodumpProcessorTest()57   MicrodumpProcessorTest()
58     : files_path_(string(getenv("srcdir") ? getenv("srcdir") : ".") +
59                   "/src/processor/testdata/") {
60   }
61 
ReadFile(const string & file_name,string * file_contents)62   void ReadFile(const string& file_name, string* file_contents) {
63     assert(file_contents);
64     std::ifstream file_stream(file_name.c_str(), std::ios::in);
65     ASSERT_TRUE(file_stream.good());
66     std::vector<char> bytes;
67     file_stream.seekg(0, std::ios_base::end);
68     ASSERT_TRUE(file_stream.good());
69     bytes.resize(file_stream.tellg());
70     file_stream.seekg(0, std::ios_base::beg);
71     ASSERT_TRUE(file_stream.good());
72     file_stream.read(&bytes[0], bytes.size());
73     ASSERT_TRUE(file_stream.good());
74     *file_contents = string(&bytes[0], bytes.size());
75   }
76 
ProcessMicrodump(const string & symbols_file,const string & microdump_contents,ProcessState * state)77   google_breakpad::ProcessResult ProcessMicrodump(
78       const string& symbols_file,
79       const string& microdump_contents,
80       ProcessState* state) {
81     SimpleSymbolSupplier supplier(symbols_file);
82     BasicSourceLineResolver resolver;
83     StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
84     MicrodumpProcessor processor(&frame_symbolizer);
85 
86     return processor.Process(microdump_contents, state);
87   }
88 
AnalyzeDump(const string & microdump_file_name,ProcessState * state,bool omit_symbols)89   void AnalyzeDump(const string& microdump_file_name, ProcessState* state,
90                    bool omit_symbols) {
91     string symbols_file = omit_symbols ? "" : files_path_ + "symbols/microdump";
92     string microdump_file_path = files_path_ + microdump_file_name;
93     string microdump_contents;
94     ReadFile(microdump_file_path, &microdump_contents);
95 
96     google_breakpad::ProcessResult result =
97         ProcessMicrodump(symbols_file, microdump_contents, state);
98 
99     ASSERT_EQ(google_breakpad::PROCESS_OK, result);
100     ASSERT_TRUE(state->crashed());
101     ASSERT_EQ(0, state->requesting_thread());
102     ASSERT_EQ(1U, state->threads()->size());
103 
104     ASSERT_EQ(2, state->system_info()->cpu_count);
105     ASSERT_EQ("android", state->system_info()->os_short);
106     ASSERT_EQ("Android", state->system_info()->os);
107   }
108 
109   string files_path_;
110 };
111 
TEST_F(MicrodumpProcessorTest,TestProcess_Empty)112 TEST_F(MicrodumpProcessorTest, TestProcess_Empty) {
113   ProcessState state;
114   google_breakpad::ProcessResult result =
115       ProcessMicrodump("", "", &state);
116   ASSERT_EQ(google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND, result);
117 }
118 
TEST_F(MicrodumpProcessorTest,TestProcess_Invalid)119 TEST_F(MicrodumpProcessorTest, TestProcess_Invalid) {
120   ProcessState state;
121   google_breakpad::ProcessResult result =
122       ProcessMicrodump("", "This is not a valid microdump", &state);
123   ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result);
124 }
125 
TEST_F(MicrodumpProcessorTest,TestProcess_MissingSymbols)126 TEST_F(MicrodumpProcessorTest, TestProcess_MissingSymbols) {
127   ProcessState state;
128   AnalyzeDump("microdump-arm64.dmp", &state, true /* omit_symbols */);
129 
130   ASSERT_EQ(8U, state.modules()->module_count());
131   ASSERT_EQ("aarch64", state.system_info()->cpu);
132   ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version);
133   ASSERT_EQ(1U, state.threads()->size());
134   ASSERT_EQ(12U, state.threads()->at(0)->frames()->size());
135 
136   ASSERT_EQ("",
137             state.threads()->at(0)->frames()->at(0)->function_name);
138   ASSERT_EQ("",
139             state.threads()->at(0)->frames()->at(3)->function_name);
140 }
141 
TEST_F(MicrodumpProcessorTest,TestProcess_UnsupportedArch)142 TEST_F(MicrodumpProcessorTest, TestProcess_UnsupportedArch) {
143   string microdump_contents =
144       "W/google-breakpad(26491): -----BEGIN BREAKPAD MICRODUMP-----\n"
145       "W/google-breakpad(26491): O A \"unsupported-arch\"\n"
146       "W/google-breakpad(26491): S 0 A48BD840 A48BD000 00002000\n";
147 
148   ProcessState state;
149 
150   google_breakpad::ProcessResult result =
151       ProcessMicrodump("", microdump_contents, &state);
152 
153   ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result);
154 }
155 
TEST_F(MicrodumpProcessorTest,TestProcessArm)156 TEST_F(MicrodumpProcessorTest, TestProcessArm) {
157   ProcessState state;
158   AnalyzeDump("microdump-arm.dmp", &state, false /* omit_symbols */);
159 
160   ASSERT_EQ(6U, state.modules()->module_count());
161   ASSERT_EQ("armv7l", state.system_info()->cpu);
162   ASSERT_EQ("OS VERSION INFO", state.system_info()->os_version);
163   ASSERT_EQ(8U, state.threads()->at(0)->frames()->size());
164   ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody",
165             state.threads()->at(0)->frames()->at(0)->function_name);
166   ASSERT_EQ("testing::Test::Run",
167             state.threads()->at(0)->frames()->at(1)->function_name);
168   ASSERT_EQ("main",
169             state.threads()->at(0)->frames()->at(6)->function_name);
170   ASSERT_EQ("breakpad_unittests",
171             state.threads()->at(0)->frames()->at(6)->module->code_file());
172 }
173 
TEST_F(MicrodumpProcessorTest,TestProcessArm64)174 TEST_F(MicrodumpProcessorTest, TestProcessArm64) {
175   ProcessState state;
176   AnalyzeDump("microdump-arm64.dmp", &state, false /* omit_symbols */);
177 
178   ASSERT_EQ(8U, state.modules()->module_count());
179   ASSERT_EQ("aarch64", state.system_info()->cpu);
180   ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version);
181   ASSERT_EQ(9U, state.threads()->at(0)->frames()->size());
182   ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody",
183             state.threads()->at(0)->frames()->at(0)->function_name);
184   ASSERT_EQ("testing::Test::Run",
185             state.threads()->at(0)->frames()->at(2)->function_name);
186   ASSERT_EQ("main",
187             state.threads()->at(0)->frames()->at(7)->function_name);
188   ASSERT_EQ("breakpad_unittests",
189             state.threads()->at(0)->frames()->at(7)->module->code_file());
190 }
191 
192 }  // namespace
193 
main(int argc,char * argv[])194 int main(int argc, char* argv[]) {
195   ::testing::InitGoogleTest(&argc, argv);
196   return RUN_ALL_TESTS();
197 }
198