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_writable.h" |
| 16 |
| 17 #include <string> |
| 18 #include <vector> |
| 19 |
| 20 #include "base/basictypes.h" |
| 21 #include "gtest/gtest.h" |
| 22 #include "util/file/string_file_writer.h" |
| 23 |
| 24 namespace { |
| 25 |
| 26 using namespace crashpad; |
| 27 using namespace testing; |
| 28 |
| 29 class BaseTestMinidumpWritable : public crashpad::internal::MinidumpWritable { |
| 30 public: |
| 31 BaseTestMinidumpWritable() |
| 32 : MinidumpWritable(), |
| 33 children_(), |
| 34 expected_offset_(-1), |
| 35 alignment_(0), |
| 36 phase_(kPhaseEarly), |
| 37 has_alignment_(false), |
| 38 has_phase_(false), |
| 39 verified_(false) {} |
| 40 |
| 41 ~BaseTestMinidumpWritable() { EXPECT_TRUE(verified_); } |
| 42 |
| 43 void SetAlignment(size_t alignment) { |
| 44 alignment_ = alignment; |
| 45 has_alignment_ = true; |
| 46 } |
| 47 |
| 48 void AddChild(BaseTestMinidumpWritable* child) { children_.push_back(child); } |
| 49 |
| 50 void SetPhaseLate() { |
| 51 phase_ = kPhaseLate; |
| 52 has_phase_ = true; |
| 53 } |
| 54 |
| 55 void Verify() { |
| 56 verified_ = true; |
| 57 EXPECT_EQ(kStateWritten, state()); |
| 58 for (BaseTestMinidumpWritable* child : children_) { |
| 59 child->Verify(); |
| 60 } |
| 61 } |
| 62 |
| 63 protected: |
| 64 virtual bool Freeze() override { |
| 65 EXPECT_EQ(kStateMutable, state()); |
| 66 bool rv = MinidumpWritable::Freeze(); |
| 67 EXPECT_TRUE(rv); |
| 68 EXPECT_EQ(kStateFrozen, state()); |
| 69 return rv; |
| 70 } |
| 71 |
| 72 virtual size_t Alignment() override { |
| 73 EXPECT_GE(state(), kStateFrozen); |
| 74 return has_alignment_ ? alignment_ : MinidumpWritable::Alignment(); |
| 75 } |
| 76 |
| 77 virtual std::vector<MinidumpWritable*> Children() override { |
| 78 EXPECT_GE(state(), kStateFrozen); |
| 79 if (!children_.empty()) { |
| 80 std::vector<MinidumpWritable*> children; |
| 81 for (BaseTestMinidumpWritable* child : children_) { |
| 82 children.push_back(child); |
| 83 } |
| 84 return children; |
| 85 } |
| 86 return MinidumpWritable::Children(); |
| 87 } |
| 88 |
| 89 virtual Phase WritePhase() override { |
| 90 return has_phase_ ? phase_ : MinidumpWritable::Phase(); |
| 91 } |
| 92 |
| 93 virtual bool WillWriteAtOffsetImpl(off_t offset) override { |
| 94 EXPECT_EQ(state(), kStateFrozen); |
| 95 expected_offset_ = offset; |
| 96 bool rv = MinidumpWritable::WillWriteAtOffsetImpl(offset); |
| 97 EXPECT_TRUE(rv); |
| 98 return rv; |
| 99 } |
| 100 |
| 101 virtual bool WriteObject(FileWriterInterface* file_writer) override { |
| 102 EXPECT_EQ(state(), kStateWritable); |
| 103 EXPECT_EQ(expected_offset_, file_writer->Seek(0, SEEK_CUR)); |
| 104 |
| 105 // Subclasses must override this. |
| 106 return false; |
| 107 } |
| 108 |
| 109 private: |
| 110 std::vector<BaseTestMinidumpWritable*> children_; |
| 111 off_t expected_offset_; |
| 112 size_t alignment_; |
| 113 Phase phase_; |
| 114 bool has_alignment_; |
| 115 bool has_phase_; |
| 116 bool verified_; |
| 117 |
| 118 DISALLOW_COPY_AND_ASSIGN(BaseTestMinidumpWritable); |
| 119 }; |
| 120 |
| 121 class TestStringMinidumpWritable final : public BaseTestMinidumpWritable { |
| 122 public: |
| 123 TestStringMinidumpWritable() : BaseTestMinidumpWritable(), data_() {} |
| 124 |
| 125 ~TestStringMinidumpWritable() {} |
| 126 |
| 127 void SetData(const std::string& string) { data_ = string; } |
| 128 |
| 129 protected: |
| 130 virtual size_t SizeOfObject() override { |
| 131 EXPECT_GE(state(), kStateFrozen); |
| 132 return data_.size(); |
| 133 } |
| 134 |
| 135 virtual bool WriteObject(FileWriterInterface* file_writer) override { |
| 136 BaseTestMinidumpWritable::WriteObject(file_writer); |
| 137 EXPECT_TRUE(file_writer->Write(&data_[0], data_.size())); |
| 138 return true; |
| 139 } |
| 140 |
| 141 private: |
| 142 std::string data_; |
| 143 |
| 144 DISALLOW_COPY_AND_ASSIGN(TestStringMinidumpWritable); |
| 145 }; |
| 146 |
| 147 TEST(MinidumpWritable, MinidumpWritable) { |
| 148 StringFileWriter writer; |
| 149 |
| 150 { |
| 151 SCOPED_TRACE("empty"); |
| 152 writer.Reset(); |
| 153 TestStringMinidumpWritable string_writable; |
| 154 EXPECT_TRUE(string_writable.WriteEverything(&writer)); |
| 155 EXPECT_TRUE(writer.string().empty()); |
| 156 string_writable.Verify(); |
| 157 } |
| 158 |
| 159 { |
| 160 SCOPED_TRACE("childless"); |
| 161 writer.Reset(); |
| 162 TestStringMinidumpWritable string_writable; |
| 163 string_writable.SetData("a"); |
| 164 EXPECT_TRUE(string_writable.WriteEverything(&writer)); |
| 165 EXPECT_EQ(1u, writer.string().size()); |
| 166 EXPECT_EQ("a", writer.string()); |
| 167 string_writable.Verify(); |
| 168 } |
| 169 |
| 170 { |
| 171 SCOPED_TRACE("parent-child"); |
| 172 writer.Reset(); |
| 173 TestStringMinidumpWritable parent; |
| 174 parent.SetData("b"); |
| 175 TestStringMinidumpWritable child; |
| 176 child.SetData("c"); |
| 177 parent.AddChild(&child); |
| 178 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 179 EXPECT_EQ(5u, writer.string().size()); |
| 180 EXPECT_EQ(std::string("b\0\0\0c", 5), writer.string()); |
| 181 parent.Verify(); |
| 182 } |
| 183 |
| 184 { |
| 185 SCOPED_TRACE("base alignment 2"); |
| 186 writer.Reset(); |
| 187 TestStringMinidumpWritable parent; |
| 188 parent.SetData("de"); |
| 189 TestStringMinidumpWritable child; |
| 190 child.SetData("f"); |
| 191 parent.AddChild(&child); |
| 192 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 193 EXPECT_EQ(5u, writer.string().size()); |
| 194 EXPECT_EQ(std::string("de\0\0f", 5), writer.string()); |
| 195 parent.Verify(); |
| 196 } |
| 197 |
| 198 { |
| 199 SCOPED_TRACE("base alignment 3"); |
| 200 writer.Reset(); |
| 201 TestStringMinidumpWritable parent; |
| 202 parent.SetData("ghi"); |
| 203 TestStringMinidumpWritable child; |
| 204 child.SetData("j"); |
| 205 parent.AddChild(&child); |
| 206 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 207 EXPECT_EQ(5u, writer.string().size()); |
| 208 EXPECT_EQ(std::string("ghi\0j", 5), writer.string()); |
| 209 parent.Verify(); |
| 210 } |
| 211 |
| 212 { |
| 213 SCOPED_TRACE("base alignment 4"); |
| 214 writer.Reset(); |
| 215 TestStringMinidumpWritable parent; |
| 216 parent.SetData("klmn"); |
| 217 TestStringMinidumpWritable child; |
| 218 child.SetData("o"); |
| 219 parent.AddChild(&child); |
| 220 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 221 EXPECT_EQ(5u, writer.string().size()); |
| 222 EXPECT_EQ("klmno", writer.string()); |
| 223 parent.Verify(); |
| 224 } |
| 225 |
| 226 { |
| 227 SCOPED_TRACE("base alignment 5"); |
| 228 writer.Reset(); |
| 229 TestStringMinidumpWritable parent; |
| 230 parent.SetData("pqrst"); |
| 231 TestStringMinidumpWritable child; |
| 232 child.SetData("u"); |
| 233 parent.AddChild(&child); |
| 234 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 235 EXPECT_EQ(9u, writer.string().size()); |
| 236 EXPECT_EQ(std::string("pqrst\0\0\0u", 9), writer.string()); |
| 237 parent.Verify(); |
| 238 } |
| 239 |
| 240 { |
| 241 SCOPED_TRACE("two children"); |
| 242 writer.Reset(); |
| 243 TestStringMinidumpWritable parent; |
| 244 parent.SetData("parent"); |
| 245 TestStringMinidumpWritable child_0; |
| 246 child_0.SetData("child_0"); |
| 247 parent.AddChild(&child_0); |
| 248 TestStringMinidumpWritable child_1; |
| 249 child_1.SetData("child_1"); |
| 250 parent.AddChild(&child_1); |
| 251 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 252 EXPECT_EQ(23u, writer.string().size()); |
| 253 EXPECT_EQ(std::string("parent\0\0child_0\0child_1", 23), writer.string()); |
| 254 parent.Verify(); |
| 255 } |
| 256 |
| 257 { |
| 258 SCOPED_TRACE("grandchild"); |
| 259 writer.Reset(); |
| 260 TestStringMinidumpWritable parent; |
| 261 parent.SetData("parent"); |
| 262 TestStringMinidumpWritable child; |
| 263 child.SetData("child"); |
| 264 parent.AddChild(&child); |
| 265 TestStringMinidumpWritable grandchild; |
| 266 grandchild.SetData("grandchild"); |
| 267 child.AddChild(&grandchild); |
| 268 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 269 EXPECT_EQ(26u, writer.string().size()); |
| 270 EXPECT_EQ(std::string("parent\0\0child\0\0\0grandchild", 26), |
| 271 writer.string()); |
| 272 parent.Verify(); |
| 273 } |
| 274 |
| 275 { |
| 276 SCOPED_TRACE("grandchild with empty parent"); |
| 277 writer.Reset(); |
| 278 TestStringMinidumpWritable parent; |
| 279 TestStringMinidumpWritable child; |
| 280 child.SetData("child"); |
| 281 parent.AddChild(&child); |
| 282 TestStringMinidumpWritable grandchild; |
| 283 grandchild.SetData("grandchild"); |
| 284 child.AddChild(&grandchild); |
| 285 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 286 EXPECT_EQ(18u, writer.string().size()); |
| 287 EXPECT_EQ(std::string("child\0\0\0grandchild", 18), writer.string()); |
| 288 parent.Verify(); |
| 289 } |
| 290 |
| 291 { |
| 292 SCOPED_TRACE("grandchild with empty child"); |
| 293 writer.Reset(); |
| 294 TestStringMinidumpWritable parent; |
| 295 parent.SetData("parent"); |
| 296 TestStringMinidumpWritable child; |
| 297 parent.AddChild(&child); |
| 298 TestStringMinidumpWritable grandchild; |
| 299 grandchild.SetData("grandchild"); |
| 300 child.AddChild(&grandchild); |
| 301 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 302 EXPECT_EQ(18u, writer.string().size()); |
| 303 EXPECT_EQ(std::string("parent\0\0grandchild", 18), writer.string()); |
| 304 parent.Verify(); |
| 305 } |
| 306 |
| 307 { |
| 308 SCOPED_TRACE("grandchild with empty grandchild"); |
| 309 writer.Reset(); |
| 310 TestStringMinidumpWritable parent; |
| 311 parent.SetData("parent"); |
| 312 TestStringMinidumpWritable child; |
| 313 child.SetData("child"); |
| 314 parent.AddChild(&child); |
| 315 TestStringMinidumpWritable grandchild; |
| 316 child.AddChild(&grandchild); |
| 317 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 318 EXPECT_EQ(13u, writer.string().size()); |
| 319 EXPECT_EQ(std::string("parent\0\0child", 13), writer.string()); |
| 320 parent.Verify(); |
| 321 } |
| 322 |
| 323 { |
| 324 SCOPED_TRACE("grandchild with late-phase grandchild"); |
| 325 writer.Reset(); |
| 326 TestStringMinidumpWritable parent; |
| 327 parent.SetData("parent"); |
| 328 TestStringMinidumpWritable child; |
| 329 child.SetData("child"); |
| 330 parent.AddChild(&child); |
| 331 TestStringMinidumpWritable grandchild; |
| 332 grandchild.SetData("grandchild"); |
| 333 grandchild.SetPhaseLate(); |
| 334 child.AddChild(&grandchild); |
| 335 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 336 EXPECT_EQ(26u, writer.string().size()); |
| 337 EXPECT_EQ(std::string("parent\0\0child\0\0\0grandchild", 26), |
| 338 writer.string()); |
| 339 parent.Verify(); |
| 340 } |
| 341 |
| 342 { |
| 343 SCOPED_TRACE("grandchild with late-phase child"); |
| 344 writer.Reset(); |
| 345 TestStringMinidumpWritable parent; |
| 346 parent.SetData("parent"); |
| 347 TestStringMinidumpWritable child; |
| 348 child.SetData("child"); |
| 349 child.SetPhaseLate(); |
| 350 parent.AddChild(&child); |
| 351 TestStringMinidumpWritable grandchild; |
| 352 grandchild.SetData("grandchild"); |
| 353 child.AddChild(&grandchild); |
| 354 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 355 EXPECT_EQ(25u, writer.string().size()); |
| 356 EXPECT_EQ(std::string("parent\0\0grandchild\0\0child", 25), |
| 357 writer.string()); |
| 358 parent.Verify(); |
| 359 } |
| 360 |
| 361 { |
| 362 SCOPED_TRACE("family tree"); |
| 363 writer.Reset(); |
| 364 TestStringMinidumpWritable parent; |
| 365 parent.SetData("P.."); |
| 366 TestStringMinidumpWritable child_0; |
| 367 child_0.SetData("C0."); |
| 368 parent.AddChild(&child_0); |
| 369 TestStringMinidumpWritable child_1; |
| 370 child_1.SetData("C1."); |
| 371 parent.AddChild(&child_1); |
| 372 TestStringMinidumpWritable grandchild_00; |
| 373 grandchild_00.SetData("G00"); |
| 374 child_0.AddChild(&grandchild_00); |
| 375 TestStringMinidumpWritable grandchild_01; |
| 376 grandchild_01.SetData("G01"); |
| 377 child_0.AddChild(&grandchild_01); |
| 378 TestStringMinidumpWritable grandchild_10; |
| 379 grandchild_10.SetData("G10"); |
| 380 child_1.AddChild(&grandchild_10); |
| 381 TestStringMinidumpWritable grandchild_11; |
| 382 grandchild_11.SetData("G11"); |
| 383 child_1.AddChild(&grandchild_11); |
| 384 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 385 EXPECT_EQ(27u, writer.string().size()); |
| 386 EXPECT_EQ(std::string("P..\0C0.\0G00\0G01\0C1.\0G10\0G11", 27), |
| 387 writer.string()); |
| 388 parent.Verify(); |
| 389 } |
| 390 |
| 391 { |
| 392 SCOPED_TRACE("family tree with C0 late"); |
| 393 writer.Reset(); |
| 394 TestStringMinidumpWritable parent; |
| 395 parent.SetData("P.."); |
| 396 TestStringMinidumpWritable child_0; |
| 397 child_0.SetData("C0."); |
| 398 child_0.SetPhaseLate(); |
| 399 parent.AddChild(&child_0); |
| 400 TestStringMinidumpWritable child_1; |
| 401 child_1.SetData("C1."); |
| 402 parent.AddChild(&child_1); |
| 403 TestStringMinidumpWritable grandchild_00; |
| 404 grandchild_00.SetData("G00"); |
| 405 child_0.AddChild(&grandchild_00); |
| 406 TestStringMinidumpWritable grandchild_01; |
| 407 grandchild_01.SetData("G01"); |
| 408 child_0.AddChild(&grandchild_01); |
| 409 TestStringMinidumpWritable grandchild_10; |
| 410 grandchild_10.SetData("G10"); |
| 411 child_1.AddChild(&grandchild_10); |
| 412 TestStringMinidumpWritable grandchild_11; |
| 413 grandchild_11.SetData("G11"); |
| 414 child_1.AddChild(&grandchild_11); |
| 415 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 416 EXPECT_EQ(27u, writer.string().size()); |
| 417 EXPECT_EQ(std::string("P..\0G00\0G01\0C1.\0G10\0G11\0C0.", 27), |
| 418 writer.string()); |
| 419 parent.Verify(); |
| 420 } |
| 421 |
| 422 { |
| 423 SCOPED_TRACE("family tree with G0 late"); |
| 424 writer.Reset(); |
| 425 TestStringMinidumpWritable parent; |
| 426 parent.SetData("P.."); |
| 427 TestStringMinidumpWritable child_0; |
| 428 child_0.SetData("C0."); |
| 429 parent.AddChild(&child_0); |
| 430 TestStringMinidumpWritable child_1; |
| 431 child_1.SetData("C1."); |
| 432 parent.AddChild(&child_1); |
| 433 TestStringMinidumpWritable grandchild_00; |
| 434 grandchild_00.SetData("G00"); |
| 435 grandchild_00.SetPhaseLate(); |
| 436 child_0.AddChild(&grandchild_00); |
| 437 TestStringMinidumpWritable grandchild_01; |
| 438 grandchild_01.SetData("G01"); |
| 439 grandchild_01.SetPhaseLate(); |
| 440 child_0.AddChild(&grandchild_01); |
| 441 TestStringMinidumpWritable grandchild_10; |
| 442 grandchild_10.SetData("G10"); |
| 443 child_1.AddChild(&grandchild_10); |
| 444 TestStringMinidumpWritable grandchild_11; |
| 445 grandchild_11.SetData("G11"); |
| 446 child_1.AddChild(&grandchild_11); |
| 447 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 448 EXPECT_EQ(27u, writer.string().size()); |
| 449 EXPECT_EQ(std::string("P..\0C0.\0C1.\0G10\0G11\0G00\0G01", 27), |
| 450 writer.string()); |
| 451 parent.Verify(); |
| 452 } |
| 453 |
| 454 { |
| 455 SCOPED_TRACE("align 1"); |
| 456 writer.Reset(); |
| 457 TestStringMinidumpWritable parent; |
| 458 parent.SetData("p"); |
| 459 TestStringMinidumpWritable child; |
| 460 child.SetData("c"); |
| 461 child.SetAlignment(1); |
| 462 parent.AddChild(&child); |
| 463 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 464 EXPECT_EQ(2u, writer.string().size()); |
| 465 EXPECT_EQ("pc", writer.string()); |
| 466 parent.Verify(); |
| 467 } |
| 468 |
| 469 { |
| 470 SCOPED_TRACE("align 2"); |
| 471 writer.Reset(); |
| 472 TestStringMinidumpWritable parent; |
| 473 parent.SetData("p"); |
| 474 TestStringMinidumpWritable child; |
| 475 child.SetData("c"); |
| 476 child.SetAlignment(2); |
| 477 parent.AddChild(&child); |
| 478 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 479 EXPECT_EQ(3u, writer.string().size()); |
| 480 EXPECT_EQ(std::string("p\0c", 3), writer.string()); |
| 481 parent.Verify(); |
| 482 } |
| 483 } |
| 484 |
| 485 class TestRVAMinidumpWritable final : public BaseTestMinidumpWritable { |
| 486 public: |
| 487 TestRVAMinidumpWritable() : BaseTestMinidumpWritable(), rva_() {} |
| 488 |
| 489 ~TestRVAMinidumpWritable() {} |
| 490 |
| 491 void SetRVA(MinidumpWritable* other) { other->RegisterRVA(&rva_); } |
| 492 |
| 493 protected: |
| 494 virtual size_t SizeOfObject() override { |
| 495 EXPECT_GE(state(), kStateFrozen); |
| 496 return sizeof(rva_); |
| 497 } |
| 498 |
| 499 virtual bool WriteObject(FileWriterInterface* file_writer) override { |
| 500 BaseTestMinidumpWritable::WriteObject(file_writer); |
| 501 EXPECT_TRUE(file_writer->Write(&rva_, sizeof(rva_))); |
| 502 return true; |
| 503 } |
| 504 |
| 505 private: |
| 506 RVA rva_; |
| 507 |
| 508 DISALLOW_COPY_AND_ASSIGN(TestRVAMinidumpWritable); |
| 509 }; |
| 510 |
| 511 RVA RVAAtIndex(const std::string& string, size_t index) { |
| 512 return *reinterpret_cast<const RVA*>(&string[index * sizeof(RVA)]); |
| 513 } |
| 514 |
| 515 TEST(MinidumpWritable, RVA) { |
| 516 StringFileWriter writer; |
| 517 |
| 518 { |
| 519 SCOPED_TRACE("unset"); |
| 520 writer.Reset(); |
| 521 TestRVAMinidumpWritable rva_writable; |
| 522 EXPECT_TRUE(rva_writable.WriteEverything(&writer)); |
| 523 |
| 524 ASSERT_EQ(sizeof(RVA), writer.string().size()); |
| 525 EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 0)); |
| 526 rva_writable.Verify(); |
| 527 } |
| 528 |
| 529 { |
| 530 SCOPED_TRACE("self"); |
| 531 writer.Reset(); |
| 532 TestRVAMinidumpWritable rva_writable; |
| 533 rva_writable.SetRVA(&rva_writable); |
| 534 EXPECT_TRUE(rva_writable.WriteEverything(&writer)); |
| 535 |
| 536 ASSERT_EQ(sizeof(RVA), writer.string().size()); |
| 537 EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 0)); |
| 538 rva_writable.Verify(); |
| 539 } |
| 540 |
| 541 { |
| 542 SCOPED_TRACE("parent-child self"); |
| 543 writer.Reset(); |
| 544 TestRVAMinidumpWritable parent; |
| 545 parent.SetRVA(&parent); |
| 546 TestRVAMinidumpWritable child; |
| 547 child.SetRVA(&child); |
| 548 parent.AddChild(&child); |
| 549 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 550 |
| 551 ASSERT_EQ(2 * sizeof(RVA), writer.string().size()); |
| 552 EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 0)); |
| 553 EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 1)); |
| 554 parent.Verify(); |
| 555 } |
| 556 |
| 557 { |
| 558 SCOPED_TRACE("parent-child only"); |
| 559 writer.Reset(); |
| 560 TestRVAMinidumpWritable parent; |
| 561 TestRVAMinidumpWritable child; |
| 562 parent.SetRVA(&child); |
| 563 parent.AddChild(&child); |
| 564 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 565 |
| 566 ASSERT_EQ(2 * sizeof(RVA), writer.string().size()); |
| 567 EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 0)); |
| 568 EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 1)); |
| 569 parent.Verify(); |
| 570 } |
| 571 |
| 572 { |
| 573 SCOPED_TRACE("parent-child circular"); |
| 574 writer.Reset(); |
| 575 TestRVAMinidumpWritable parent; |
| 576 TestRVAMinidumpWritable child; |
| 577 parent.SetRVA(&child); |
| 578 child.SetRVA(&parent); |
| 579 parent.AddChild(&child); |
| 580 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 581 |
| 582 ASSERT_EQ(2 * sizeof(RVA), writer.string().size()); |
| 583 EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 0)); |
| 584 EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 1)); |
| 585 parent.Verify(); |
| 586 } |
| 587 |
| 588 { |
| 589 SCOPED_TRACE("grandchildren"); |
| 590 writer.Reset(); |
| 591 TestRVAMinidumpWritable parent; |
| 592 TestRVAMinidumpWritable child; |
| 593 parent.SetRVA(&child); |
| 594 parent.AddChild(&child); |
| 595 TestRVAMinidumpWritable grandchild_0; |
| 596 grandchild_0.SetRVA(&child); |
| 597 child.AddChild(&grandchild_0); |
| 598 TestRVAMinidumpWritable grandchild_1; |
| 599 grandchild_1.SetRVA(&child); |
| 600 child.AddChild(&grandchild_1); |
| 601 TestRVAMinidumpWritable grandchild_2; |
| 602 grandchild_2.SetRVA(&child); |
| 603 child.AddChild(&grandchild_2); |
| 604 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 605 |
| 606 ASSERT_EQ(5 * sizeof(RVA), writer.string().size()); |
| 607 EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 0)); |
| 608 EXPECT_EQ(0 * sizeof(RVA), RVAAtIndex(writer.string(), 1)); |
| 609 EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 2)); |
| 610 EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 3)); |
| 611 EXPECT_EQ(1 * sizeof(RVA), RVAAtIndex(writer.string(), 4)); |
| 612 parent.Verify(); |
| 613 } |
| 614 } |
| 615 |
| 616 class TestLocationDescriptorMinidumpWritable final |
| 617 : public BaseTestMinidumpWritable { |
| 618 public: |
| 619 TestLocationDescriptorMinidumpWritable() |
| 620 : BaseTestMinidumpWritable(), location_descriptor_(), string_() {} |
| 621 |
| 622 ~TestLocationDescriptorMinidumpWritable() {} |
| 623 |
| 624 void SetLocationDescriptor(MinidumpWritable* other) { |
| 625 other->RegisterLocationDescriptor(&location_descriptor_); |
| 626 } |
| 627 |
| 628 void SetString(const std::string& string) { string_ = string; } |
| 629 |
| 630 protected: |
| 631 virtual size_t SizeOfObject() override { |
| 632 EXPECT_GE(state(), kStateFrozen); |
| 633 // NUL-terminate. |
| 634 return sizeof(location_descriptor_) + string_.size() + 1; |
| 635 } |
| 636 |
| 637 virtual bool WriteObject(FileWriterInterface* file_writer) override { |
| 638 BaseTestMinidumpWritable::WriteObject(file_writer); |
| 639 WritableIoVec iov; |
| 640 iov.iov_base = &location_descriptor_; |
| 641 iov.iov_len = sizeof(location_descriptor_); |
| 642 std::vector<WritableIoVec> iovecs(1, iov); |
| 643 // NUL-terminate. |
| 644 iov.iov_base = &string_[0]; |
| 645 iov.iov_len = string_.size() + 1; |
| 646 iovecs.push_back(iov); |
| 647 EXPECT_TRUE(file_writer->WriteIoVec(&iovecs)); |
| 648 return true; |
| 649 } |
| 650 |
| 651 private: |
| 652 MINIDUMP_LOCATION_DESCRIPTOR location_descriptor_; |
| 653 std::string string_; |
| 654 |
| 655 DISALLOW_COPY_AND_ASSIGN(TestLocationDescriptorMinidumpWritable); |
| 656 }; |
| 657 |
| 658 struct LocationDescriptorAndData { |
| 659 MINIDUMP_LOCATION_DESCRIPTOR location_descriptor; |
| 660 char string[1]; |
| 661 }; |
| 662 |
| 663 const LocationDescriptorAndData* LDDAtIndex(const std::string& string, |
| 664 size_t index) { |
| 665 return reinterpret_cast<const LocationDescriptorAndData*>(&string[index]); |
| 666 } |
| 667 |
| 668 TEST(MinidumpWritable, LocationDescriptor) { |
| 669 StringFileWriter writer; |
| 670 |
| 671 { |
| 672 SCOPED_TRACE("unset"); |
| 673 writer.Reset(); |
| 674 TestLocationDescriptorMinidumpWritable location_descriptor_writable; |
| 675 EXPECT_TRUE(location_descriptor_writable.WriteEverything(&writer)); |
| 676 |
| 677 ASSERT_EQ(9u, writer.string().size()); |
| 678 const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0); |
| 679 EXPECT_EQ(0u, ldd->location_descriptor.DataSize); |
| 680 EXPECT_EQ(0u, ldd->location_descriptor.Rva); |
| 681 location_descriptor_writable.Verify(); |
| 682 } |
| 683 |
| 684 { |
| 685 SCOPED_TRACE("self"); |
| 686 writer.Reset(); |
| 687 TestLocationDescriptorMinidumpWritable location_descriptor_writable; |
| 688 location_descriptor_writable.SetLocationDescriptor( |
| 689 &location_descriptor_writable); |
| 690 EXPECT_TRUE(location_descriptor_writable.WriteEverything(&writer)); |
| 691 |
| 692 ASSERT_EQ(9u, writer.string().size()); |
| 693 const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0); |
| 694 EXPECT_EQ(9u, ldd->location_descriptor.DataSize); |
| 695 EXPECT_EQ(0u, ldd->location_descriptor.Rva); |
| 696 location_descriptor_writable.Verify(); |
| 697 } |
| 698 |
| 699 { |
| 700 SCOPED_TRACE("self with data"); |
| 701 writer.Reset(); |
| 702 TestLocationDescriptorMinidumpWritable location_descriptor_writable; |
| 703 location_descriptor_writable.SetLocationDescriptor( |
| 704 &location_descriptor_writable); |
| 705 location_descriptor_writable.SetString("zz"); |
| 706 EXPECT_TRUE(location_descriptor_writable.WriteEverything(&writer)); |
| 707 |
| 708 ASSERT_EQ(11u, writer.string().size()); |
| 709 const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0); |
| 710 EXPECT_EQ(11u, ldd->location_descriptor.DataSize); |
| 711 EXPECT_EQ(0u, ldd->location_descriptor.Rva); |
| 712 EXPECT_STREQ("zz", ldd->string); |
| 713 location_descriptor_writable.Verify(); |
| 714 } |
| 715 |
| 716 { |
| 717 SCOPED_TRACE("parent-child self"); |
| 718 writer.Reset(); |
| 719 TestLocationDescriptorMinidumpWritable parent; |
| 720 parent.SetLocationDescriptor(&parent); |
| 721 parent.SetString("yy"); |
| 722 TestLocationDescriptorMinidumpWritable child; |
| 723 child.SetLocationDescriptor(&child); |
| 724 child.SetString("x"); |
| 725 parent.AddChild(&child); |
| 726 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 727 |
| 728 ASSERT_EQ(22u, writer.string().size()); |
| 729 const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0); |
| 730 EXPECT_EQ(11u, ldd->location_descriptor.DataSize); |
| 731 EXPECT_EQ(0u, ldd->location_descriptor.Rva); |
| 732 EXPECT_STREQ("yy", ldd->string); |
| 733 ldd = LDDAtIndex(writer.string(), 12); |
| 734 EXPECT_EQ(10u, ldd->location_descriptor.DataSize); |
| 735 EXPECT_EQ(12u, ldd->location_descriptor.Rva); |
| 736 EXPECT_STREQ("x", ldd->string); |
| 737 parent.Verify(); |
| 738 } |
| 739 |
| 740 { |
| 741 SCOPED_TRACE("parent-child only"); |
| 742 writer.Reset(); |
| 743 TestLocationDescriptorMinidumpWritable parent; |
| 744 TestLocationDescriptorMinidumpWritable child; |
| 745 parent.SetLocationDescriptor(&child); |
| 746 parent.SetString("www"); |
| 747 child.SetString("vv"); |
| 748 parent.AddChild(&child); |
| 749 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 750 |
| 751 ASSERT_EQ(23u, writer.string().size()); |
| 752 const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0); |
| 753 EXPECT_EQ(11u, ldd->location_descriptor.DataSize); |
| 754 EXPECT_EQ(12u, ldd->location_descriptor.Rva); |
| 755 EXPECT_STREQ("www", ldd->string); |
| 756 ldd = LDDAtIndex(writer.string(), 12); |
| 757 EXPECT_EQ(0u, ldd->location_descriptor.DataSize); |
| 758 EXPECT_EQ(0u, ldd->location_descriptor.Rva); |
| 759 EXPECT_STREQ("vv", ldd->string); |
| 760 parent.Verify(); |
| 761 } |
| 762 |
| 763 { |
| 764 SCOPED_TRACE("parent-child circular"); |
| 765 writer.Reset(); |
| 766 TestLocationDescriptorMinidumpWritable parent; |
| 767 TestLocationDescriptorMinidumpWritable child; |
| 768 parent.SetLocationDescriptor(&child); |
| 769 parent.SetString("uuuu"); |
| 770 child.SetLocationDescriptor(&parent); |
| 771 child.SetString("tttt"); |
| 772 parent.AddChild(&child); |
| 773 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 774 |
| 775 ASSERT_EQ(29u, writer.string().size()); |
| 776 const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0); |
| 777 EXPECT_EQ(13u, ldd->location_descriptor.DataSize); |
| 778 EXPECT_EQ(16u, ldd->location_descriptor.Rva); |
| 779 EXPECT_STREQ("uuuu", ldd->string); |
| 780 ldd = LDDAtIndex(writer.string(), 16); |
| 781 EXPECT_EQ(13u, ldd->location_descriptor.DataSize); |
| 782 EXPECT_EQ(0u, ldd->location_descriptor.Rva); |
| 783 EXPECT_STREQ("tttt", ldd->string); |
| 784 parent.Verify(); |
| 785 } |
| 786 |
| 787 { |
| 788 SCOPED_TRACE("grandchildren"); |
| 789 writer.Reset(); |
| 790 TestLocationDescriptorMinidumpWritable parent; |
| 791 TestLocationDescriptorMinidumpWritable child; |
| 792 parent.SetLocationDescriptor(&child); |
| 793 parent.SetString("s"); |
| 794 parent.AddChild(&child); |
| 795 child.SetString("r"); |
| 796 TestLocationDescriptorMinidumpWritable grandchild_0; |
| 797 grandchild_0.SetLocationDescriptor(&child); |
| 798 grandchild_0.SetString("q"); |
| 799 child.AddChild(&grandchild_0); |
| 800 TestLocationDescriptorMinidumpWritable grandchild_1; |
| 801 grandchild_1.SetLocationDescriptor(&child); |
| 802 grandchild_1.SetString("p"); |
| 803 child.AddChild(&grandchild_1); |
| 804 TestLocationDescriptorMinidumpWritable grandchild_2; |
| 805 grandchild_2.SetLocationDescriptor(&child); |
| 806 grandchild_2.SetString("o"); |
| 807 child.AddChild(&grandchild_2); |
| 808 EXPECT_TRUE(parent.WriteEverything(&writer)); |
| 809 |
| 810 ASSERT_EQ(58u, writer.string().size()); |
| 811 const LocationDescriptorAndData* ldd = LDDAtIndex(writer.string(), 0); |
| 812 EXPECT_EQ(10u, ldd->location_descriptor.DataSize); |
| 813 EXPECT_EQ(12u, ldd->location_descriptor.Rva); |
| 814 EXPECT_STREQ("s", ldd->string); |
| 815 ldd = LDDAtIndex(writer.string(), 12); |
| 816 EXPECT_EQ(0u, ldd->location_descriptor.DataSize); |
| 817 EXPECT_EQ(0u, ldd->location_descriptor.Rva); |
| 818 EXPECT_STREQ("r", ldd->string); |
| 819 ldd = LDDAtIndex(writer.string(), 24); |
| 820 EXPECT_EQ(10u, ldd->location_descriptor.DataSize); |
| 821 EXPECT_EQ(12u, ldd->location_descriptor.Rva); |
| 822 EXPECT_STREQ("q", ldd->string); |
| 823 ldd = LDDAtIndex(writer.string(), 36); |
| 824 EXPECT_EQ(10u, ldd->location_descriptor.DataSize); |
| 825 EXPECT_EQ(12u, ldd->location_descriptor.Rva); |
| 826 EXPECT_STREQ("p", ldd->string); |
| 827 ldd = LDDAtIndex(writer.string(), 48); |
| 828 EXPECT_EQ(10u, ldd->location_descriptor.DataSize); |
| 829 EXPECT_EQ(12u, ldd->location_descriptor.Rva); |
| 830 EXPECT_STREQ("o", ldd->string); |
| 831 parent.Verify(); |
| 832 } |
| 833 } |
| 834 |
| 835 } // namespace |
OLD | NEW |