OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (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 |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 #include "minidump/minidump_memory_writer.h" |
| 16 |
| 17 #include <dbghelp.h> |
| 18 #include <stdint.h> |
| 19 |
| 20 #include "base/basictypes.h" |
| 21 #include "gtest/gtest.h" |
| 22 #include "minidump/minidump_file_writer.h" |
| 23 #include "minidump/minidump_stream_writer.h" |
| 24 #include "minidump/minidump_test_util.h" |
| 25 #include "util/file/string_file_writer.h" |
| 26 |
| 27 namespace { |
| 28 |
| 29 using namespace crashpad; |
| 30 using namespace crashpad::test; |
| 31 |
| 32 const MinidumpStreamType kBogusStreamType = |
| 33 static_cast<MinidumpStreamType>(1234); |
| 34 |
| 35 // expected_streams is the expected number of streams in the file. The memory |
| 36 // list must be the last stream. If there is another stream, it must come first, |
| 37 // have stream type kBogusStreamType, and have zero-length data. |
| 38 void GetMemoryListStream(const std::string& file_contents, |
| 39 const MINIDUMP_MEMORY_LIST** memory_list, |
| 40 const uint32_t expected_streams) { |
| 41 const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); |
| 42 const size_t kMemoryListStreamOffset = |
| 43 kDirectoryOffset + expected_streams * sizeof(MINIDUMP_DIRECTORY); |
| 44 const size_t kMemoryDescriptorsOffset = |
| 45 kMemoryListStreamOffset + sizeof(MINIDUMP_MEMORY_LIST); |
| 46 |
| 47 ASSERT_GE(file_contents.size(), kMemoryDescriptorsOffset); |
| 48 |
| 49 const MINIDUMP_HEADER* header = |
| 50 reinterpret_cast<const MINIDUMP_HEADER*>(&file_contents[0]); |
| 51 |
| 52 VerifyMinidumpHeader(header, expected_streams, 0); |
| 53 if (testing::Test::HasFatalFailure()) { |
| 54 return; |
| 55 } |
| 56 |
| 57 const MINIDUMP_DIRECTORY* directory = |
| 58 reinterpret_cast<const MINIDUMP_DIRECTORY*>( |
| 59 &file_contents[kDirectoryOffset]); |
| 60 |
| 61 if (expected_streams > 1) { |
| 62 ASSERT_EQ(kBogusStreamType, directory->StreamType); |
| 63 ASSERT_EQ(0u, directory->Location.DataSize); |
| 64 ASSERT_EQ(kMemoryListStreamOffset, directory->Location.Rva); |
| 65 ++directory; |
| 66 } |
| 67 |
| 68 ASSERT_EQ(kMinidumpStreamTypeMemoryList, directory->StreamType); |
| 69 ASSERT_GE(directory->Location.DataSize, sizeof(MINIDUMP_MEMORY_LIST)); |
| 70 ASSERT_EQ(kMemoryListStreamOffset, directory->Location.Rva); |
| 71 |
| 72 *memory_list = reinterpret_cast<const MINIDUMP_MEMORY_LIST*>( |
| 73 &file_contents[kMemoryListStreamOffset]); |
| 74 |
| 75 ASSERT_EQ(sizeof(MINIDUMP_MEMORY_LIST) + |
| 76 (*memory_list)->NumberOfMemoryRanges * |
| 77 sizeof(MINIDUMP_MEMORY_DESCRIPTOR), |
| 78 directory->Location.DataSize); |
| 79 } |
| 80 |
| 81 TEST(MinidumpMemoryWriter, EmptyMemoryList) { |
| 82 MinidumpFileWriter minidump_file_writer; |
| 83 MinidumpMemoryListWriter memory_list_writer; |
| 84 |
| 85 minidump_file_writer.AddStream(&memory_list_writer); |
| 86 |
| 87 StringFileWriter file_writer; |
| 88 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 89 |
| 90 ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| 91 sizeof(MINIDUMP_MEMORY_LIST), |
| 92 file_writer.string().size()); |
| 93 |
| 94 const MINIDUMP_MEMORY_LIST* memory_list; |
| 95 GetMemoryListStream(file_writer.string(), &memory_list, 1); |
| 96 if (Test::HasFatalFailure()) { |
| 97 return; |
| 98 } |
| 99 |
| 100 EXPECT_EQ(0u, memory_list->NumberOfMemoryRanges); |
| 101 } |
| 102 |
| 103 class TestMemoryWriter final : public MinidumpMemoryWriter { |
| 104 public: |
| 105 TestMemoryWriter(uint64_t base_address, size_t size, uint8_t value) |
| 106 : MinidumpMemoryWriter(), |
| 107 base_address_(base_address), |
| 108 expected_offset_(-1), |
| 109 size_(size), |
| 110 value_(value) {} |
| 111 |
| 112 ~TestMemoryWriter() {} |
| 113 |
| 114 protected: |
| 115 // MinidumpMemoryWriter: |
| 116 virtual uint64_t MemoryRangeBaseAddress() const override { |
| 117 EXPECT_EQ(state(), kStateFrozen); |
| 118 return base_address_; |
| 119 } |
| 120 |
| 121 virtual size_t MemoryRangeSize() const override { |
| 122 EXPECT_GE(state(), kStateFrozen); |
| 123 return size_; |
| 124 } |
| 125 |
| 126 // MinidumpWritable: |
| 127 virtual bool WillWriteAtOffsetImpl(off_t offset) override { |
| 128 EXPECT_EQ(state(), kStateFrozen); |
| 129 expected_offset_ = offset; |
| 130 bool rv = MinidumpMemoryWriter::WillWriteAtOffsetImpl(offset); |
| 131 EXPECT_TRUE(rv); |
| 132 return rv; |
| 133 } |
| 134 |
| 135 virtual bool WriteObject(FileWriterInterface* file_writer) override { |
| 136 EXPECT_EQ(state(), kStateWritable); |
| 137 EXPECT_EQ(expected_offset_, file_writer->Seek(0, SEEK_CUR)); |
| 138 |
| 139 bool rv = true; |
| 140 if (size_ > 0) { |
| 141 std::string data(size_, value_); |
| 142 rv = file_writer->Write(&data[0], size_); |
| 143 EXPECT_TRUE(rv); |
| 144 } |
| 145 |
| 146 return rv; |
| 147 } |
| 148 |
| 149 private: |
| 150 uint64_t base_address_; |
| 151 off_t expected_offset_; |
| 152 size_t size_; |
| 153 uint8_t value_; |
| 154 |
| 155 DISALLOW_COPY_AND_ASSIGN(TestMemoryWriter); |
| 156 }; |
| 157 |
| 158 void ExpectMemoryDescriptorAndContents( |
| 159 const MINIDUMP_MEMORY_DESCRIPTOR* expected, |
| 160 const MINIDUMP_MEMORY_DESCRIPTOR* observed, |
| 161 const std::string& file_contents, |
| 162 uint8_t value, |
| 163 bool at_eof) { |
| 164 const uint32_t kMemoryAlignment = 16; |
| 165 |
| 166 EXPECT_EQ(expected->StartOfMemoryRange, observed->StartOfMemoryRange); |
| 167 EXPECT_EQ(expected->Memory.DataSize, observed->Memory.DataSize); |
| 168 EXPECT_EQ( |
| 169 (expected->Memory.Rva + kMemoryAlignment - 1) & ~(kMemoryAlignment - 1), |
| 170 observed->Memory.Rva); |
| 171 if (at_eof) { |
| 172 EXPECT_EQ(file_contents.size(), |
| 173 observed->Memory.Rva + observed->Memory.DataSize); |
| 174 } else { |
| 175 EXPECT_GE(file_contents.size(), |
| 176 observed->Memory.Rva + observed->Memory.DataSize); |
| 177 } |
| 178 |
| 179 std::string expected_data(expected->Memory.DataSize, value); |
| 180 std::string observed_data(&file_contents[observed->Memory.Rva], |
| 181 observed->Memory.DataSize); |
| 182 EXPECT_EQ(expected_data, observed_data); |
| 183 } |
| 184 |
| 185 TEST(MinidumpMemoryWriter, OneMemoryRegion) { |
| 186 MinidumpFileWriter minidump_file_writer; |
| 187 MinidumpMemoryListWriter memory_list_writer; |
| 188 |
| 189 const uint64_t kBaseAddress = 0xfedcba9876543210ull; |
| 190 const uint64_t kSize = 0x1000; |
| 191 const uint8_t kValue = 'm'; |
| 192 |
| 193 TestMemoryWriter memory_writer(kBaseAddress, kSize, kValue); |
| 194 memory_list_writer.AddMemory(&memory_writer); |
| 195 |
| 196 minidump_file_writer.AddStream(&memory_list_writer); |
| 197 |
| 198 StringFileWriter file_writer; |
| 199 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 200 |
| 201 const MINIDUMP_MEMORY_LIST* memory_list; |
| 202 GetMemoryListStream(file_writer.string(), &memory_list, 1); |
| 203 if (Test::HasFatalFailure()) { |
| 204 return; |
| 205 } |
| 206 |
| 207 MINIDUMP_MEMORY_DESCRIPTOR expected; |
| 208 expected.StartOfMemoryRange = kBaseAddress; |
| 209 expected.Memory.DataSize = kSize; |
| 210 expected.Memory.Rva = |
| 211 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| 212 sizeof(MINIDUMP_MEMORY_LIST) + |
| 213 memory_list->NumberOfMemoryRanges * sizeof(MINIDUMP_MEMORY_DESCRIPTOR); |
| 214 ExpectMemoryDescriptorAndContents(&expected, |
| 215 &memory_list->MemoryRanges[0], |
| 216 file_writer.string(), |
| 217 kValue, |
| 218 true); |
| 219 } |
| 220 |
| 221 TEST(MinidumpMemoryWriter, TwoMemoryRegions) { |
| 222 MinidumpFileWriter minidump_file_writer; |
| 223 MinidumpMemoryListWriter memory_list_writer; |
| 224 |
| 225 const uint64_t kBaseAddress1 = 0x00c0ffeeull; |
| 226 const uint64_t kSize1 = 0x0100; |
| 227 const uint8_t kValue1 = '6'; |
| 228 const uint64_t kBaseAddress2 = 0xfac00facull; |
| 229 const uint64_t kSize2 = 0x0200; |
| 230 const uint8_t kValue2 = '!'; |
| 231 |
| 232 TestMemoryWriter memory_writer_1(kBaseAddress1, kSize1, kValue1); |
| 233 memory_list_writer.AddMemory(&memory_writer_1); |
| 234 TestMemoryWriter memory_writer_2(kBaseAddress2, kSize2, kValue2); |
| 235 memory_list_writer.AddMemory(&memory_writer_2); |
| 236 |
| 237 minidump_file_writer.AddStream(&memory_list_writer); |
| 238 |
| 239 StringFileWriter file_writer; |
| 240 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 241 |
| 242 const MINIDUMP_MEMORY_LIST* memory_list; |
| 243 GetMemoryListStream(file_writer.string(), &memory_list, 1); |
| 244 if (Test::HasFatalFailure()) { |
| 245 return; |
| 246 } |
| 247 |
| 248 EXPECT_EQ(2u, memory_list->NumberOfMemoryRanges); |
| 249 |
| 250 MINIDUMP_MEMORY_DESCRIPTOR expected; |
| 251 expected.StartOfMemoryRange = kBaseAddress1; |
| 252 expected.Memory.DataSize = kSize1; |
| 253 expected.Memory.Rva = |
| 254 sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + |
| 255 sizeof(MINIDUMP_MEMORY_LIST) + |
| 256 memory_list->NumberOfMemoryRanges * sizeof(MINIDUMP_MEMORY_DESCRIPTOR); |
| 257 ExpectMemoryDescriptorAndContents(&expected, |
| 258 &memory_list->MemoryRanges[0], |
| 259 file_writer.string(), |
| 260 kValue1, |
| 261 false); |
| 262 |
| 263 expected.StartOfMemoryRange = kBaseAddress2; |
| 264 expected.Memory.DataSize = kSize2; |
| 265 expected.Memory.Rva = memory_list->MemoryRanges[0].Memory.Rva + |
| 266 memory_list->MemoryRanges[0].Memory.DataSize; |
| 267 ExpectMemoryDescriptorAndContents(&expected, |
| 268 &memory_list->MemoryRanges[1], |
| 269 file_writer.string(), |
| 270 kValue2, |
| 271 true); |
| 272 } |
| 273 |
| 274 class TestMemoryStream final : public internal::MinidumpStreamWriter { |
| 275 public: |
| 276 TestMemoryStream(uint64_t base_address, size_t size, uint8_t value) |
| 277 : MinidumpStreamWriter(), memory_(base_address, size, value) {} |
| 278 |
| 279 ~TestMemoryStream() {} |
| 280 |
| 281 TestMemoryWriter* memory() { return &memory_; } |
| 282 |
| 283 // MinidumpStreamWriter: |
| 284 virtual MinidumpStreamType StreamType() const override { |
| 285 return kBogusStreamType; |
| 286 } |
| 287 |
| 288 protected: |
| 289 // MinidumpWritable: |
| 290 virtual size_t SizeOfObject() override { |
| 291 EXPECT_GE(state(), kStateFrozen); |
| 292 return 0; |
| 293 } |
| 294 |
| 295 virtual std::vector<MinidumpWritable*> Children() override { |
| 296 EXPECT_GE(state(), kStateFrozen); |
| 297 std::vector<MinidumpWritable*> children(1, memory()); |
| 298 return children; |
| 299 } |
| 300 |
| 301 virtual bool WriteObject(FileWriterInterface* file_writer) override { |
| 302 EXPECT_EQ(kStateWritable, state()); |
| 303 return true; |
| 304 } |
| 305 |
| 306 private: |
| 307 TestMemoryWriter memory_; |
| 308 |
| 309 DISALLOW_COPY_AND_ASSIGN(TestMemoryStream); |
| 310 }; |
| 311 |
| 312 TEST(MinidumpMemoryWriter, ExtraMemory) { |
| 313 // This tests MinidumpMemoryListWriter::AddExtraMemory(). That method adds |
| 314 // a MinidumpMemoryWriter to the MinidumpMemoryListWriter without making the |
| 315 // memory writer a child of the memory list writer. |
| 316 MinidumpFileWriter minidump_file_writer; |
| 317 |
| 318 const uint64_t kBaseAddress1 = 0x0000000000001000ull; |
| 319 const uint64_t kSize1 = 0x0400; |
| 320 const uint8_t kValue1 = '1'; |
| 321 TestMemoryStream test_memory_stream(kBaseAddress1, kSize1, kValue1); |
| 322 |
| 323 MinidumpMemoryListWriter memory_list_writer; |
| 324 memory_list_writer.AddExtraMemory(test_memory_stream.memory()); |
| 325 |
| 326 minidump_file_writer.AddStream(&test_memory_stream); |
| 327 |
| 328 const uint64_t kBaseAddress2 = 0x0000000000002000ull; |
| 329 const uint64_t kSize2 = 0x0400; |
| 330 const uint8_t kValue2 = 'm'; |
| 331 |
| 332 TestMemoryWriter memory_writer(kBaseAddress2, kSize2, kValue2); |
| 333 memory_list_writer.AddMemory(&memory_writer); |
| 334 |
| 335 minidump_file_writer.AddStream(&memory_list_writer); |
| 336 |
| 337 StringFileWriter file_writer; |
| 338 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 339 |
| 340 const MINIDUMP_MEMORY_LIST* memory_list; |
| 341 GetMemoryListStream(file_writer.string(), &memory_list, 2); |
| 342 if (Test::HasFatalFailure()) { |
| 343 return; |
| 344 } |
| 345 |
| 346 EXPECT_EQ(2u, memory_list->NumberOfMemoryRanges); |
| 347 |
| 348 MINIDUMP_MEMORY_DESCRIPTOR expected; |
| 349 expected.StartOfMemoryRange = kBaseAddress1; |
| 350 expected.Memory.DataSize = kSize1; |
| 351 expected.Memory.Rva = |
| 352 sizeof(MINIDUMP_HEADER) + 2 * sizeof(MINIDUMP_DIRECTORY) + |
| 353 sizeof(MINIDUMP_MEMORY_LIST) + |
| 354 memory_list->NumberOfMemoryRanges * sizeof(MINIDUMP_MEMORY_DESCRIPTOR); |
| 355 ExpectMemoryDescriptorAndContents(&expected, |
| 356 &memory_list->MemoryRanges[0], |
| 357 file_writer.string(), |
| 358 kValue1, |
| 359 false); |
| 360 |
| 361 expected.StartOfMemoryRange = kBaseAddress2; |
| 362 expected.Memory.DataSize = kSize2; |
| 363 expected.Memory.Rva = memory_list->MemoryRanges[0].Memory.Rva + |
| 364 memory_list->MemoryRanges[0].Memory.DataSize; |
| 365 ExpectMemoryDescriptorAndContents(&expected, |
| 366 &memory_list->MemoryRanges[1], |
| 367 file_writer.string(), |
| 368 kValue2, |
| 369 true); |
| 370 } |
| 371 |
| 372 } // namespace |
OLD | NEW |