microdump_processor_unittest.cc
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: 62 MicrodumpProcessorTest() 63 : files_path_(string(getenv("srcdir") ? getenv("srcdir") : ".") + 64 "/src/processor/testdata/") { 65 } 66 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 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 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 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 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 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 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 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 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 V@104.0 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 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 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 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 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 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 285 int main(int argc, char* argv[]) { 286 ::testing::InitGoogleTest(&argc, argv); 287 return RUN_ALL_TESTS(); 288 }