Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 #include "snapshot/minidump/process_snapshot_minidump.h" | 15 #include "snapshot/minidump/process_snapshot_minidump.h" |
| 16 | 16 |
| 17 #include <string.h> | 17 #include <string.h> |
| 18 #include <windows.h> | 18 #include <windows.h> |
| 19 #include <dbghelp.h> | 19 #include <dbghelp.h> |
| 20 | 20 |
| 21 #include "base/memory/scoped_ptr.h" | 21 #include "base/memory/scoped_ptr.h" |
| 22 #include "gtest/gtest.h" | 22 #include "gtest/gtest.h" |
| 23 #include "snapshot/module_snapshot.h" | |
| 23 #include "util/file/string_file.h" | 24 #include "util/file/string_file.h" |
| 24 | 25 |
| 25 namespace crashpad { | 26 namespace crashpad { |
| 26 namespace test { | 27 namespace test { |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 29 TEST(ProcessSnapshotMinidump, EmptyFile) { | 30 TEST(ProcessSnapshotMinidump, EmptyFile) { |
| 30 StringFile string_file; | 31 StringFile string_file; |
| 31 ProcessSnapshotMinidump process_snapshot; | 32 ProcessSnapshotMinidump process_snapshot; |
| 32 | 33 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 50 MINIDUMP_HEADER header = {}; | 51 MINIDUMP_HEADER header = {}; |
| 51 header.Signature = MINIDUMP_SIGNATURE; | 52 header.Signature = MINIDUMP_SIGNATURE; |
| 52 header.Version = MINIDUMP_VERSION; | 53 header.Version = MINIDUMP_VERSION; |
| 53 | 54 |
| 54 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); | 55 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); |
| 55 | 56 |
| 56 ProcessSnapshotMinidump process_snapshot; | 57 ProcessSnapshotMinidump process_snapshot; |
| 57 EXPECT_TRUE(process_snapshot.Initialize(&string_file)); | 58 EXPECT_TRUE(process_snapshot.Initialize(&string_file)); |
| 58 } | 59 } |
| 59 | 60 |
| 61 // Writes |string| to |writer| as a MinidumpUTF8String, and returns the file | |
| 62 // offst of the beginning of the string. | |
| 63 RVA WriteString(FileWriterInterface* writer, const std::string& string) { | |
| 64 RVA rva = static_cast<RVA>(writer->SeekGet()); | |
| 65 | |
| 66 uint32_t string_size = string.size(); | |
| 67 EXPECT_TRUE(writer->Write(&string_size, sizeof(string_size))); | |
| 68 EXPECT_TRUE(writer->Write(string.c_str(), string.size() + 1)); // include NUL | |
|
Robert Sesek
2015/03/04 01:52:25
nit: punctuation and capitalization (yes I know th
Mark Mentovai
2015/03/04 16:24:24
Robert Sesek wrote:
| |
| 69 | |
| 70 return rva; | |
| 71 } | |
| 72 | |
| 73 // Writes |dictionary| to |writer| as a MinidumpSimpleStringDictionary, and | |
| 74 // populates |location| with a location descriptor identifying what was written. | |
| 75 void WriteMinidumpSimpleStringDictionary( | |
| 76 MINIDUMP_LOCATION_DESCRIPTOR* location, | |
| 77 FileWriterInterface* writer, | |
| 78 const std::map<std::string, std::string>& dictionary) { | |
| 79 std::vector<MinidumpSimpleStringDictionaryEntry> entries; | |
| 80 for (const auto& it : dictionary) { | |
| 81 MinidumpSimpleStringDictionaryEntry entry; | |
| 82 entry.key = WriteString(writer, it.first); | |
| 83 entry.value = WriteString(writer, it.second); | |
| 84 entries.push_back(entry); | |
| 85 } | |
| 86 | |
| 87 location->Rva = static_cast<RVA>(writer->SeekGet()); | |
| 88 | |
| 89 const uint32_t simple_string_dictionary_entries = entries.size(); | |
| 90 EXPECT_TRUE(writer->Write(&simple_string_dictionary_entries, | |
| 91 sizeof(simple_string_dictionary_entries))); | |
| 92 for (const MinidumpSimpleStringDictionaryEntry& entry : entries) { | |
| 93 EXPECT_TRUE(writer->Write(&entry, sizeof(entry))); | |
| 94 } | |
| 95 | |
| 96 location->DataSize = | |
| 97 sizeof(simple_string_dictionary_entries) + | |
| 98 entries.size() * sizeof(MinidumpSimpleStringDictionaryEntry); | |
| 99 } | |
| 100 | |
| 101 // Writes |strings| to |writer| as a MinidumpRVAList referencing | |
| 102 // MinidumpUTF8String objects, and populates |location| with a location | |
| 103 // descriptor identifying what was written. | |
| 104 void WriteMinidumpStringList(MINIDUMP_LOCATION_DESCRIPTOR* location, | |
| 105 FileWriterInterface* writer, | |
| 106 const std::vector<std::string>& strings) { | |
| 107 std::vector<RVA> rvas; | |
| 108 for (const std::string& string : strings) { | |
| 109 rvas.push_back(WriteString(writer, string)); | |
| 110 } | |
| 111 | |
| 112 location->Rva = static_cast<RVA>(writer->SeekGet()); | |
| 113 | |
| 114 const uint32_t string_list_entries = rvas.size(); | |
| 115 EXPECT_TRUE(writer->Write(&string_list_entries, sizeof(string_list_entries))); | |
| 116 for (RVA rva : rvas) { | |
| 117 EXPECT_TRUE(writer->Write(&rva, sizeof(rva))); | |
| 118 } | |
| 119 | |
| 120 location->DataSize = sizeof(string_list_entries) + rvas.size() * sizeof(RVA); | |
| 121 } | |
| 122 | |
| 60 TEST(ProcessSnapshotMinidump, AnnotationsSimpleMap) { | 123 TEST(ProcessSnapshotMinidump, AnnotationsSimpleMap) { |
| 61 StringFile string_file; | 124 StringFile string_file; |
| 62 | 125 |
| 63 MINIDUMP_HEADER header = {}; | 126 MINIDUMP_HEADER header = {}; |
| 64 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); | 127 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); |
| 65 | 128 |
| 66 MinidumpSimpleStringDictionaryEntry entry0 = {}; | |
| 67 entry0.key = static_cast<RVA>(string_file.SeekGet()); | |
| 68 const char kKey0[] = "the first key"; | |
| 69 uint32_t string_size = strlen(kKey0); | |
| 70 EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); | |
| 71 EXPECT_TRUE(string_file.Write(kKey0, sizeof(kKey0))); | |
| 72 | |
| 73 entry0.value = static_cast<RVA>(string_file.SeekGet()); | |
| 74 const char kValue0[] = "THE FIRST VALUE EVER!"; | |
| 75 string_size = strlen(kValue0); | |
| 76 EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); | |
| 77 EXPECT_TRUE(string_file.Write(kValue0, sizeof(kValue0))); | |
| 78 | |
| 79 MinidumpSimpleStringDictionaryEntry entry1 = {}; | |
| 80 entry1.key = static_cast<RVA>(string_file.SeekGet()); | |
| 81 const char kKey1[] = "2key"; | |
| 82 string_size = strlen(kKey1); | |
| 83 EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); | |
| 84 EXPECT_TRUE(string_file.Write(kKey1, sizeof(kKey1))); | |
| 85 | |
| 86 entry1.value = static_cast<RVA>(string_file.SeekGet()); | |
| 87 const char kValue1[] = "a lowly second value"; | |
| 88 string_size = strlen(kValue1); | |
| 89 EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); | |
| 90 EXPECT_TRUE(string_file.Write(kValue1, sizeof(kValue1))); | |
| 91 | |
| 92 MinidumpCrashpadInfo crashpad_info = {}; | 129 MinidumpCrashpadInfo crashpad_info = {}; |
| 93 crashpad_info.version = MinidumpCrashpadInfo::kVersion; | 130 crashpad_info.version = MinidumpCrashpadInfo::kVersion; |
| 94 | 131 |
| 95 crashpad_info.simple_annotations.Rva = | 132 std::map<std::string, std::string> dictionary; |
| 96 static_cast<RVA>(string_file.SeekGet()); | 133 dictionary["the first key"] = "THE FIRST VALUE EVER!"; |
| 97 uint32_t simple_string_dictionary_entries = 2; | 134 dictionary["2key"] = "a lowly second value"; |
| 98 EXPECT_TRUE(string_file.Write(&simple_string_dictionary_entries, | 135 WriteMinidumpSimpleStringDictionary( |
| 99 sizeof(simple_string_dictionary_entries))); | 136 &crashpad_info.simple_annotations, &string_file, dictionary); |
| 100 EXPECT_TRUE(string_file.Write(&entry0, sizeof(entry0))); | |
| 101 EXPECT_TRUE(string_file.Write(&entry1, sizeof(entry1))); | |
| 102 crashpad_info.simple_annotations.DataSize = | |
| 103 simple_string_dictionary_entries * | |
| 104 sizeof(MinidumpSimpleStringDictionaryEntry); | |
| 105 | 137 |
| 106 MINIDUMP_DIRECTORY crashpad_info_directory = {}; | 138 MINIDUMP_DIRECTORY crashpad_info_directory = {}; |
| 107 crashpad_info_directory.StreamType = kMinidumpStreamTypeCrashpadInfo; | 139 crashpad_info_directory.StreamType = kMinidumpStreamTypeCrashpadInfo; |
| 108 crashpad_info_directory.Location.Rva = | 140 crashpad_info_directory.Location.Rva = |
| 109 static_cast<RVA>(string_file.SeekGet()); | 141 static_cast<RVA>(string_file.SeekGet()); |
| 110 EXPECT_TRUE(string_file.Write(&crashpad_info, sizeof(crashpad_info))); | 142 EXPECT_TRUE(string_file.Write(&crashpad_info, sizeof(crashpad_info))); |
| 111 crashpad_info_directory.Location.DataSize = sizeof(crashpad_info); | 143 crashpad_info_directory.Location.DataSize = sizeof(crashpad_info); |
| 112 | 144 |
| 113 header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); | 145 header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); |
| 114 EXPECT_TRUE(string_file.Write(&crashpad_info_directory, | 146 EXPECT_TRUE(string_file.Write(&crashpad_info_directory, |
| 115 sizeof(crashpad_info_directory))); | 147 sizeof(crashpad_info_directory))); |
| 116 | 148 |
| 117 header.Signature = MINIDUMP_SIGNATURE; | 149 header.Signature = MINIDUMP_SIGNATURE; |
| 118 header.Version = MINIDUMP_VERSION; | 150 header.Version = MINIDUMP_VERSION; |
| 119 header.NumberOfStreams = 1; | 151 header.NumberOfStreams = 1; |
| 120 EXPECT_TRUE(string_file.SeekSet(0)); | 152 EXPECT_TRUE(string_file.SeekSet(0)); |
| 121 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); | 153 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); |
| 122 | 154 |
| 123 ProcessSnapshotMinidump process_snapshot; | 155 ProcessSnapshotMinidump process_snapshot; |
| 124 EXPECT_TRUE(process_snapshot.Initialize(&string_file)); | 156 EXPECT_TRUE(process_snapshot.Initialize(&string_file)); |
| 125 | 157 |
| 126 const auto annotations_simple_map = process_snapshot.AnnotationsSimpleMap(); | 158 const auto annotations_simple_map = process_snapshot.AnnotationsSimpleMap(); |
| 127 EXPECT_EQ(2u, annotations_simple_map.size()); | 159 EXPECT_EQ(dictionary, annotations_simple_map); |
| 160 } | |
| 128 | 161 |
| 129 auto it = annotations_simple_map.find(kKey0); | 162 TEST(ProcessSnapshotMinidump, Modules) { |
| 130 ASSERT_NE(it, annotations_simple_map.end()); | 163 StringFile string_file; |
| 131 EXPECT_EQ(kValue0, it->second); | |
| 132 | 164 |
| 133 it = annotations_simple_map.find(kKey1); | 165 MINIDUMP_HEADER header = {}; |
| 134 ASSERT_NE(it, annotations_simple_map.end()); | 166 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); |
| 135 EXPECT_EQ(kValue1, it->second); | 167 |
| 168 MINIDUMP_MODULE minidump_module = {}; | |
| 169 uint32_t minidump_module_count = 3; | |
| 170 | |
| 171 MINIDUMP_DIRECTORY minidump_module_list_directory = {}; | |
| 172 minidump_module_list_directory.StreamType = kMinidumpStreamTypeModuleList; | |
| 173 minidump_module_list_directory.Location.DataSize = | |
| 174 sizeof(MINIDUMP_MODULE_LIST) + | |
| 175 minidump_module_count * sizeof(MINIDUMP_MODULE); | |
| 176 minidump_module_list_directory.Location.Rva = | |
| 177 static_cast<RVA>(string_file.SeekGet()); | |
| 178 | |
| 179 EXPECT_TRUE( | |
| 180 string_file.Write(&minidump_module_count, sizeof(minidump_module_count))); | |
| 181 for (uint32_t minidump_module_index = 0; | |
| 182 minidump_module_index < minidump_module_count; | |
| 183 ++minidump_module_index) { | |
| 184 EXPECT_TRUE(string_file.Write(&minidump_module, sizeof(minidump_module))); | |
| 185 } | |
| 186 | |
| 187 MinidumpModuleCrashpadInfo crashpad_module_0 = {}; | |
| 188 crashpad_module_0.version = MinidumpModuleCrashpadInfo::kVersion; | |
| 189 std::map<std::string, std::string> dictionary_0; | |
| 190 dictionary_0["ptype"] = "browser"; | |
| 191 dictionary_0["pid"] = "12345"; | |
| 192 WriteMinidumpSimpleStringDictionary( | |
| 193 &crashpad_module_0.simple_annotations, &string_file, dictionary_0); | |
| 194 | |
| 195 MinidumpModuleCrashpadInfoLink crashpad_module_0_link = {}; | |
| 196 crashpad_module_0_link.minidump_module_list_index = 0; | |
| 197 crashpad_module_0_link.location.DataSize = sizeof(crashpad_module_0); | |
| 198 crashpad_module_0_link.location.Rva = static_cast<RVA>(string_file.SeekGet()); | |
| 199 EXPECT_TRUE(string_file.Write(&crashpad_module_0, sizeof(crashpad_module_0))); | |
| 200 | |
| 201 MinidumpModuleCrashpadInfo crashpad_module_2 = {}; | |
| 202 crashpad_module_2.version = MinidumpModuleCrashpadInfo::kVersion; | |
| 203 std::map<std::string, std::string> dictionary_2; | |
| 204 dictionary_2["fakemodule"] = "yes"; | |
| 205 WriteMinidumpSimpleStringDictionary( | |
| 206 &crashpad_module_2.simple_annotations, &string_file, dictionary_2); | |
| 207 | |
| 208 std::vector<std::string> list_annotations_2; | |
| 209 list_annotations_2.push_back("first string"); | |
| 210 list_annotations_2.push_back("last string"); | |
| 211 WriteMinidumpStringList( | |
| 212 &crashpad_module_2.list_annotations, &string_file, list_annotations_2); | |
| 213 | |
| 214 MinidumpModuleCrashpadInfoLink crashpad_module_2_link = {}; | |
| 215 crashpad_module_2_link.minidump_module_list_index = 2; | |
| 216 crashpad_module_2_link.location.DataSize = sizeof(crashpad_module_2); | |
| 217 crashpad_module_2_link.location.Rva = static_cast<RVA>(string_file.SeekGet()); | |
| 218 EXPECT_TRUE(string_file.Write(&crashpad_module_2, sizeof(crashpad_module_2))); | |
| 219 | |
| 220 MinidumpCrashpadInfo crashpad_info = {}; | |
| 221 crashpad_info.version = MinidumpCrashpadInfo::kVersion; | |
| 222 | |
| 223 uint32_t crashpad_module_count = 2; | |
| 224 | |
| 225 crashpad_info.module_list.DataSize = | |
| 226 sizeof(MinidumpModuleCrashpadInfoList) + | |
| 227 crashpad_module_count * sizeof(MinidumpModuleCrashpadInfoLink); | |
| 228 crashpad_info.module_list.Rva = static_cast<RVA>(string_file.SeekGet()); | |
| 229 | |
| 230 EXPECT_TRUE( | |
| 231 string_file.Write(&crashpad_module_count, sizeof(crashpad_module_count))); | |
| 232 EXPECT_TRUE(string_file.Write(&crashpad_module_0_link, | |
| 233 sizeof(crashpad_module_0_link))); | |
| 234 EXPECT_TRUE(string_file.Write(&crashpad_module_2_link, | |
| 235 sizeof(crashpad_module_2_link))); | |
| 236 | |
| 237 MINIDUMP_DIRECTORY crashpad_info_directory = {}; | |
| 238 crashpad_info_directory.StreamType = kMinidumpStreamTypeCrashpadInfo; | |
| 239 crashpad_info_directory.Location.DataSize = sizeof(crashpad_info); | |
| 240 crashpad_info_directory.Location.Rva = | |
| 241 static_cast<RVA>(string_file.SeekGet()); | |
| 242 EXPECT_TRUE(string_file.Write(&crashpad_info, sizeof(crashpad_info))); | |
| 243 | |
| 244 header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); | |
| 245 EXPECT_TRUE(string_file.Write(&minidump_module_list_directory, | |
| 246 sizeof(minidump_module_list_directory))); | |
| 247 EXPECT_TRUE(string_file.Write(&crashpad_info_directory, | |
| 248 sizeof(crashpad_info_directory))); | |
| 249 | |
| 250 header.Signature = MINIDUMP_SIGNATURE; | |
| 251 header.Version = MINIDUMP_VERSION; | |
| 252 header.NumberOfStreams = 2; | |
| 253 EXPECT_TRUE(string_file.SeekSet(0)); | |
| 254 EXPECT_TRUE(string_file.Write(&header, sizeof(header))); | |
| 255 | |
| 256 ProcessSnapshotMinidump process_snapshot; | |
| 257 EXPECT_TRUE(process_snapshot.Initialize(&string_file)); | |
| 258 | |
| 259 std::vector<const ModuleSnapshot*> modules = process_snapshot.Modules(); | |
| 260 ASSERT_EQ(minidump_module_count, modules.size()); | |
| 261 | |
| 262 auto annotations_simple_map = modules[0]->AnnotationsSimpleMap(); | |
| 263 EXPECT_EQ(dictionary_0, annotations_simple_map); | |
| 264 | |
| 265 auto annotations_vector = modules[0]->AnnotationsVector(); | |
| 266 EXPECT_TRUE(annotations_vector.empty()); | |
| 267 | |
| 268 annotations_simple_map = modules[1]->AnnotationsSimpleMap(); | |
| 269 EXPECT_TRUE(annotations_simple_map.empty()); | |
| 270 | |
| 271 annotations_vector = modules[1]->AnnotationsVector(); | |
| 272 EXPECT_TRUE(annotations_vector.empty()); | |
| 273 | |
| 274 annotations_simple_map = modules[2]->AnnotationsSimpleMap(); | |
| 275 EXPECT_EQ(dictionary_2, annotations_simple_map); | |
| 276 | |
| 277 annotations_vector = modules[2]->AnnotationsVector(); | |
| 278 EXPECT_EQ(list_annotations_2, annotations_vector); | |
| 136 } | 279 } |
| 137 | 280 |
| 138 } // namespace | 281 } // namespace |
| 139 } // namespace test | 282 } // namespace test |
| 140 } // namespace crashpad | 283 } // namespace crashpad |
| OLD | NEW |