capture_memory.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2016 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. #include "snapshot/capture_memory.h"
  15. #include <stdint.h>
  16. #include <limits>
  17. #include <memory>
  18. #include "snapshot/memory_snapshot.h"
  19. namespace crashpad {
  20. namespace internal {
  21. namespace {
  22. void MaybeCaptureMemoryAround(CaptureMemory::Delegate* delegate,
  23. uint64_t address) {
  24. constexpr uint64_t non_address_offset = 0x10000;
  25. if (address < non_address_offset)
  26. return;
  27. const uint64_t max_address = delegate->Is64Bit() ?
  28. std::numeric_limits<uint64_t>::max() :
  29. std::numeric_limits<uint32_t>::max();
  30. if (address > max_address - non_address_offset)
  31. return;
  32. constexpr uint64_t kRegisterByteOffset = 128;
  33. const uint64_t target = address - kRegisterByteOffset;
  34. constexpr uint64_t size = 512;
  35. static_assert(kRegisterByteOffset <= size / 2,
  36. "negative offset too large");
  37. auto ranges =
  38. delegate->GetReadableRanges(CheckedRange<uint64_t>(target, size));
  39. for (const auto& range : ranges) {
  40. delegate->AddNewMemorySnapshot(range);
  41. }
  42. }
  43. template <class T>
  44. void CaptureAtPointersInRange(uint8_t* buffer,
  45. uint64_t buffer_size,
  46. CaptureMemory::Delegate* delegate) {
  47. for (uint64_t address_offset = 0; address_offset < buffer_size;
  48. address_offset += sizeof(T)) {
  49. uint64_t target_address = *reinterpret_cast<T*>(&buffer[address_offset]);
  50. MaybeCaptureMemoryAround(delegate, target_address);
  51. }
  52. }
  53. } // namespace
  54. // static
  55. void CaptureMemory::PointedToByContext(const CPUContext& context,
  56. Delegate* delegate) {
  57. #if defined(ARCH_CPU_X86_FAMILY)
  58. if (context.architecture == kCPUArchitectureX86_64) {
  59. MaybeCaptureMemoryAround(delegate, context.x86_64->rax);
  60. MaybeCaptureMemoryAround(delegate, context.x86_64->rbx);
  61. MaybeCaptureMemoryAround(delegate, context.x86_64->rcx);
  62. MaybeCaptureMemoryAround(delegate, context.x86_64->rdx);
  63. MaybeCaptureMemoryAround(delegate, context.x86_64->rdi);
  64. MaybeCaptureMemoryAround(delegate, context.x86_64->rsi);
  65. MaybeCaptureMemoryAround(delegate, context.x86_64->rbp);
  66. MaybeCaptureMemoryAround(delegate, context.x86_64->r8);
  67. MaybeCaptureMemoryAround(delegate, context.x86_64->r9);
  68. MaybeCaptureMemoryAround(delegate, context.x86_64->r10);
  69. MaybeCaptureMemoryAround(delegate, context.x86_64->r11);
  70. MaybeCaptureMemoryAround(delegate, context.x86_64->r12);
  71. MaybeCaptureMemoryAround(delegate, context.x86_64->r13);
  72. MaybeCaptureMemoryAround(delegate, context.x86_64->r14);
  73. MaybeCaptureMemoryAround(delegate, context.x86_64->r15);
  74. MaybeCaptureMemoryAround(delegate, context.x86_64->rip);
  75. } else {
  76. MaybeCaptureMemoryAround(delegate, context.x86->eax);
  77. MaybeCaptureMemoryAround(delegate, context.x86->ebx);
  78. MaybeCaptureMemoryAround(delegate, context.x86->ecx);
  79. MaybeCaptureMemoryAround(delegate, context.x86->edx);
  80. MaybeCaptureMemoryAround(delegate, context.x86->edi);
  81. MaybeCaptureMemoryAround(delegate, context.x86->esi);
  82. MaybeCaptureMemoryAround(delegate, context.x86->ebp);
  83. MaybeCaptureMemoryAround(delegate, context.x86->eip);
  84. }
  85. #else
  86. #error non-x86
  87. #endif
  88. }
  89. // static
  90. void CaptureMemory::PointedToByMemoryRange(const MemorySnapshot& memory,
  91. Delegate* delegate) {
  92. if (memory.Size() == 0)
  93. return;
  94. const size_t alignment =
  95. delegate->Is64Bit() ? sizeof(uint64_t) : sizeof(uint32_t);
  96. if (memory.Address() % alignment != 0 || memory.Size() % alignment != 0) {
  97. LOG(ERROR) << "unaligned range";
  98. return;
  99. }
  100. std::unique_ptr<uint8_t[]> buffer(new uint8_t[memory.Size()]);
  101. if (!delegate->ReadMemory(memory.Address(), memory.Size(), buffer.get())) {
  102. LOG(ERROR) << "ReadMemory";
  103. return;
  104. }
  105. if (delegate->Is64Bit())
  106. CaptureAtPointersInRange<uint64_t>(buffer.get(), memory.Size(), delegate);
  107. else
  108. CaptureAtPointersInRange<uint32_t>(buffer.get(), memory.Size(), delegate);
  109. }
  110. } // namespace internal
  111. } // namespace crashpad