xref: /aosp_15_r20/external/cronet/base/profiler/stack_copier.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors
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 
7 #include "base/bits.h"
8 #include "base/compiler_specific.h"
9 
10 namespace base {
11 
12 StackCopier::~StackCopier() = default;
13 
14 // static
RewritePointerIfInOriginalStack(const uint8_t * original_stack_bottom,const uintptr_t * original_stack_top,const uint8_t * stack_copy_bottom,uintptr_t pointer)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")
CopyStackContentsAndRewritePointers(const uint8_t * original_stack_bottom,const uintptr_t * original_stack_top,size_t platform_stack_alignment,uintptr_t * stack_buffer_bottom)35 const uint8_t* StackCopier::CopyStackContentsAndRewritePointers(
36     const uint8_t* original_stack_bottom,
37     const uintptr_t* original_stack_top,
38     size_t platform_stack_alignment,
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.
45   const uint8_t* first_aligned_address =
46       bits::AlignUp(byte_src, sizeof(uintptr_t));
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) +
55       (byte_src - bits::AlignDown(byte_src, platform_stack_alignment));
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
75