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