stack_copier.cc 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/profiler/stack_copier.h"
  5. #include "base/bits.h"
  6. #include "base/compiler_specific.h"
  7. namespace base {
  8. StackCopier::~StackCopier() = default;
  9. // static
  10. uintptr_t StackCopier::RewritePointerIfInOriginalStack(
  11. const uint8_t* original_stack_bottom,
  12. const uintptr_t* original_stack_top,
  13. const uint8_t* stack_copy_bottom,
  14. uintptr_t pointer) {
  15. auto original_stack_bottom_uint =
  16. reinterpret_cast<uintptr_t>(original_stack_bottom);
  17. auto original_stack_top_uint =
  18. reinterpret_cast<uintptr_t>(original_stack_top);
  19. auto stack_copy_bottom_uint = reinterpret_cast<uintptr_t>(stack_copy_bottom);
  20. if (pointer < original_stack_bottom_uint ||
  21. pointer >= original_stack_top_uint)
  22. return pointer;
  23. return stack_copy_bottom_uint + (pointer - original_stack_bottom_uint);
  24. }
  25. // static
  26. NO_SANITIZE("address")
  27. const uint8_t* StackCopier::CopyStackContentsAndRewritePointers(
  28. const uint8_t* original_stack_bottom,
  29. const uintptr_t* original_stack_top,
  30. size_t platform_stack_alignment,
  31. uintptr_t* stack_buffer_bottom) {
  32. const uint8_t* byte_src = original_stack_bottom;
  33. // The first address in the stack with pointer alignment. Pointer-aligned
  34. // values from this point to the end of the stack are possibly rewritten using
  35. // RewritePointerIfInOriginalStack(). Bytes before this cannot be a pointer
  36. // because they occupy less space than a pointer would.
  37. const uint8_t* first_aligned_address =
  38. bits::AlignUp(byte_src, sizeof(uintptr_t));
  39. // The stack copy bottom, which is offset from |stack_buffer_bottom| by the
  40. // same alignment as in the original stack. This guarantees identical
  41. // alignment between values in the original stack and the copy. This uses the
  42. // platform stack alignment rather than pointer alignment so that the stack
  43. // copy is aligned to platform expectations.
  44. uint8_t* stack_copy_bottom =
  45. reinterpret_cast<uint8_t*>(stack_buffer_bottom) +
  46. (byte_src - bits::AlignDown(byte_src, platform_stack_alignment));
  47. uint8_t* byte_dst = stack_copy_bottom;
  48. // Copy bytes verbatim up to the first aligned address.
  49. for (; byte_src < first_aligned_address; ++byte_src, ++byte_dst)
  50. *byte_dst = *byte_src;
  51. // Copy the remaining stack by pointer-sized values, rewriting anything that
  52. // looks like a pointer into the stack.
  53. const uintptr_t* src = reinterpret_cast<const uintptr_t*>(byte_src);
  54. uintptr_t* dst = reinterpret_cast<uintptr_t*>(byte_dst);
  55. for (; src < original_stack_top; ++src, ++dst) {
  56. *dst = RewritePointerIfInOriginalStack(
  57. original_stack_bottom, original_stack_top, stack_copy_bottom, *src);
  58. }
  59. return stack_copy_bottom;
  60. }
  61. } // namespace base