// Copyright 2016 The Crashpad Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "minidump/minidump_unloaded_module_writer.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" #include "minidump/minidump_file_writer.h" #include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" namespace crashpad { namespace test { namespace { void ExpectUnloadedModule(const MINIDUMP_UNLOADED_MODULE* expected, const MINIDUMP_UNLOADED_MODULE* observed, const std::string& file_contents, const std::string& expected_module_name) { EXPECT_EQ(observed->BaseOfImage, expected->BaseOfImage); EXPECT_EQ(observed->SizeOfImage, expected->SizeOfImage); EXPECT_EQ(observed->CheckSum, expected->CheckSum); EXPECT_EQ(observed->TimeDateStamp, expected->TimeDateStamp); EXPECT_NE(observed->ModuleNameRva, 0u); std::u16string observed_module_name_utf16 = MinidumpStringAtRVAAsString(file_contents, observed->ModuleNameRva); std::u16string expected_module_name_utf16 = base::UTF8ToUTF16(expected_module_name); EXPECT_EQ(observed_module_name_utf16, expected_module_name_utf16); } void GetUnloadedModuleListStream( const std::string& file_contents, const MINIDUMP_UNLOADED_MODULE_LIST** unloaded_module_list) { constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); constexpr size_t kUnloadedModuleListStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); constexpr size_t kUnloadedModulesOffset = kUnloadedModuleListStreamOffset + sizeof(MINIDUMP_UNLOADED_MODULE_LIST); ASSERT_GE(file_contents.size(), kUnloadedModulesOffset); const MINIDUMP_DIRECTORY* directory; const MINIDUMP_HEADER* header = MinidumpHeaderAtStart(file_contents, &directory); ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_TRUE(directory); ASSERT_EQ(directory[0].StreamType, kMinidumpStreamTypeUnloadedModuleList); EXPECT_EQ(directory[0].Location.Rva, kUnloadedModuleListStreamOffset); *unloaded_module_list = MinidumpWritableAtLocationDescriptor( file_contents, directory[0].Location); ASSERT_TRUE(unloaded_module_list); } TEST(MinidumpUnloadedModuleWriter, EmptyModule) { MinidumpFileWriter minidump_file_writer; auto unloaded_module_list_writer = std::make_unique(); static constexpr char kModuleName[] = "test_dll"; auto unloaded_module_writer = std::make_unique(); unloaded_module_writer->SetName(kModuleName); unloaded_module_list_writer->AddUnloadedModule( std::move(unloaded_module_writer)); ASSERT_TRUE( minidump_file_writer.AddStream(std::move(unloaded_module_list_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); ASSERT_GT(string_file.string().size(), sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + sizeof(MINIDUMP_UNLOADED_MODULE_LIST) + 1 * sizeof(MINIDUMP_UNLOADED_MODULE)); const MINIDUMP_UNLOADED_MODULE_LIST* unloaded_module_list = nullptr; ASSERT_NO_FATAL_FAILURE( GetUnloadedModuleListStream(string_file.string(), &unloaded_module_list)); EXPECT_EQ(unloaded_module_list->NumberOfEntries, 1u); MINIDUMP_UNLOADED_MODULE expected = {}; ASSERT_NO_FATAL_FAILURE( ExpectUnloadedModule(&expected, reinterpret_cast( &unloaded_module_list[1]), string_file.string(), kModuleName)); } TEST(MinidumpUnloadedModuleWriter, OneModule) { MinidumpFileWriter minidump_file_writer; auto unloaded_module_list_writer = std::make_unique(); static constexpr char kModuleName[] = "statically_linked"; constexpr uint64_t kModuleBase = 0x10da69000; constexpr uint32_t kModuleSize = 0x1000; constexpr uint32_t kChecksum = 0x76543210; constexpr time_t kTimestamp = 0x386d4380; auto unloaded_module_writer = std::make_unique(); unloaded_module_writer->SetName(kModuleName); unloaded_module_writer->SetImageBaseAddress(kModuleBase); unloaded_module_writer->SetImageSize(kModuleSize); unloaded_module_writer->SetChecksum(kChecksum); unloaded_module_writer->SetTimestamp(kTimestamp); unloaded_module_list_writer->AddUnloadedModule( std::move(unloaded_module_writer)); ASSERT_TRUE( minidump_file_writer.AddStream(std::move(unloaded_module_list_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); ASSERT_GT(string_file.string().size(), sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + sizeof(MINIDUMP_UNLOADED_MODULE_LIST) + 1 * sizeof(MINIDUMP_UNLOADED_MODULE)); const MINIDUMP_UNLOADED_MODULE_LIST* unloaded_module_list = nullptr; ASSERT_NO_FATAL_FAILURE( GetUnloadedModuleListStream(string_file.string(), &unloaded_module_list)); EXPECT_EQ(unloaded_module_list->NumberOfEntries, 1u); MINIDUMP_UNLOADED_MODULE expected = {}; expected.BaseOfImage = kModuleBase; expected.SizeOfImage = kModuleSize; expected.CheckSum = kChecksum; expected.TimeDateStamp = kTimestamp; ASSERT_NO_FATAL_FAILURE( ExpectUnloadedModule(&expected, reinterpret_cast( &unloaded_module_list[1]), string_file.string(), kModuleName)); } } // namespace } // namespace test } // namespace crashpad