| // Copyright (c) 2014, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // Unit test for MicrodumpProcessor. |
| |
| #include <fstream> |
| #include <iostream> |
| #include <string> |
| #include <vector> |
| |
| #include "breakpad_googletest_includes.h" |
| #include "google_breakpad/processor/basic_source_line_resolver.h" |
| #include "google_breakpad/processor/call_stack.h" |
| #include "google_breakpad/processor/microdump_processor.h" |
| #include "google_breakpad/processor/process_state.h" |
| #include "google_breakpad/processor/stack_frame.h" |
| #include "google_breakpad/processor/stack_frame_symbolizer.h" |
| #include "processor/simple_symbol_supplier.h" |
| #include "processor/stackwalker_unittest_utils.h" |
| |
| namespace { |
| |
| using google_breakpad::BasicSourceLineResolver; |
| using google_breakpad::MicrodumpProcessor; |
| using google_breakpad::ProcessState; |
| using google_breakpad::SimpleSymbolSupplier; |
| using google_breakpad::StackFrameSymbolizer; |
| |
| class MicrodumpProcessorTest : public ::testing::Test { |
| public: |
| MicrodumpProcessorTest() |
| : files_path_(string(getenv("srcdir") ? getenv("srcdir") : ".") + |
| "/src/processor/testdata/") { |
| } |
| |
| void ReadFile(const string& file_name, string* file_contents) { |
| assert(file_contents); |
| std::ifstream file_stream(file_name.c_str(), std::ios::in); |
| ASSERT_TRUE(file_stream.good()); |
| std::vector<char> bytes; |
| file_stream.seekg(0, std::ios_base::end); |
| ASSERT_TRUE(file_stream.good()); |
| bytes.resize(file_stream.tellg()); |
| file_stream.seekg(0, std::ios_base::beg); |
| ASSERT_TRUE(file_stream.good()); |
| file_stream.read(&bytes[0], bytes.size()); |
| ASSERT_TRUE(file_stream.good()); |
| *file_contents = string(&bytes[0], bytes.size()); |
| } |
| |
| google_breakpad::ProcessResult ProcessMicrodump( |
| const string& symbols_file, |
| const string& microdump_contents, |
| ProcessState* state) { |
| SimpleSymbolSupplier supplier(symbols_file); |
| BasicSourceLineResolver resolver; |
| StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
| MicrodumpProcessor processor(&frame_symbolizer); |
| |
| return processor.Process(microdump_contents, state); |
| } |
| |
| void AnalyzeDump(const string& microdump_file_name, ProcessState* state, |
| bool omit_symbols) { |
| string symbols_file = omit_symbols ? "" : files_path_ + "symbols/microdump"; |
| string microdump_file_path = files_path_ + microdump_file_name; |
| string microdump_contents; |
| ReadFile(microdump_file_path, µdump_contents); |
| |
| google_breakpad::ProcessResult result = |
| ProcessMicrodump(symbols_file, microdump_contents, state); |
| |
| ASSERT_EQ(google_breakpad::PROCESS_OK, result); |
| ASSERT_TRUE(state->crashed()); |
| ASSERT_EQ(0, state->requesting_thread()); |
| ASSERT_EQ(1U, state->threads()->size()); |
| |
| ASSERT_EQ(2, state->system_info()->cpu_count); |
| ASSERT_EQ("android", state->system_info()->os_short); |
| ASSERT_EQ("Android", state->system_info()->os); |
| } |
| |
| string files_path_; |
| }; |
| |
| TEST_F(MicrodumpProcessorTest, TestProcess_Empty) { |
| ProcessState state; |
| google_breakpad::ProcessResult result = |
| ProcessMicrodump("", "", &state); |
| ASSERT_EQ(google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND, result); |
| } |
| |
| TEST_F(MicrodumpProcessorTest, TestProcess_Invalid) { |
| ProcessState state; |
| google_breakpad::ProcessResult result = |
| ProcessMicrodump("", "This is not a valid microdump", &state); |
| ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result); |
| } |
| |
| TEST_F(MicrodumpProcessorTest, TestProcess_MissingSymbols) { |
| ProcessState state; |
| AnalyzeDump("microdump-arm64.dmp", &state, true /* omit_symbols */); |
| |
| ASSERT_EQ(8U, state.modules()->module_count()); |
| ASSERT_EQ("aarch64", state.system_info()->cpu); |
| ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version); |
| ASSERT_EQ(1U, state.threads()->size()); |
| ASSERT_EQ(12U, state.threads()->at(0)->frames()->size()); |
| |
| ASSERT_EQ("", |
| state.threads()->at(0)->frames()->at(0)->function_name); |
| ASSERT_EQ("", |
| state.threads()->at(0)->frames()->at(3)->function_name); |
| } |
| |
| TEST_F(MicrodumpProcessorTest, TestProcess_UnsupportedArch) { |
| string microdump_contents = |
| "W/google-breakpad(26491): -----BEGIN BREAKPAD MICRODUMP-----\n" |
| "W/google-breakpad(26491): O A \"unsupported-arch\"\n" |
| "W/google-breakpad(26491): S 0 A48BD840 A48BD000 00002000\n"; |
| |
| ProcessState state; |
| |
| google_breakpad::ProcessResult result = |
| ProcessMicrodump("", microdump_contents, &state); |
| |
| ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result); |
| } |
| |
| TEST_F(MicrodumpProcessorTest, TestProcessArm) { |
| ProcessState state; |
| AnalyzeDump("microdump-arm.dmp", &state, false /* omit_symbols */); |
| |
| ASSERT_EQ(6U, state.modules()->module_count()); |
| ASSERT_EQ("armv7l", state.system_info()->cpu); |
| ASSERT_EQ("OS VERSION INFO", state.system_info()->os_version); |
| ASSERT_EQ(8U, state.threads()->at(0)->frames()->size()); |
| ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody", |
| state.threads()->at(0)->frames()->at(0)->function_name); |
| ASSERT_EQ("testing::Test::Run", |
| state.threads()->at(0)->frames()->at(1)->function_name); |
| ASSERT_EQ("main", |
| state.threads()->at(0)->frames()->at(6)->function_name); |
| ASSERT_EQ("breakpad_unittests", |
| state.threads()->at(0)->frames()->at(6)->module->code_file()); |
| } |
| |
| TEST_F(MicrodumpProcessorTest, TestProcessArm64) { |
| ProcessState state; |
| AnalyzeDump("microdump-arm64.dmp", &state, false /* omit_symbols */); |
| |
| ASSERT_EQ(8U, state.modules()->module_count()); |
| ASSERT_EQ("aarch64", state.system_info()->cpu); |
| ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version); |
| ASSERT_EQ(9U, state.threads()->at(0)->frames()->size()); |
| ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody", |
| state.threads()->at(0)->frames()->at(0)->function_name); |
| ASSERT_EQ("testing::Test::Run", |
| state.threads()->at(0)->frames()->at(2)->function_name); |
| ASSERT_EQ("main", |
| state.threads()->at(0)->frames()->at(7)->function_name); |
| ASSERT_EQ("breakpad_unittests", |
| state.threads()->at(0)->frames()->at(7)->module->code_file()); |
| } |
| |
| } // namespace |
| |
| int main(int argc, char* argv[]) { |
| ::testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |