// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/profiler/stack_copier.h" #include "base/bits.h" #include "base/compiler_specific.h" namespace base { StackCopier::~StackCopier() = default; // static uintptr_t StackCopier::RewritePointerIfInOriginalStack( const uint8_t* original_stack_bottom, const uintptr_t* original_stack_top, const uint8_t* stack_copy_bottom, uintptr_t pointer) { auto original_stack_bottom_uint = reinterpret_cast(original_stack_bottom); auto original_stack_top_uint = reinterpret_cast(original_stack_top); auto stack_copy_bottom_uint = reinterpret_cast(stack_copy_bottom); if (pointer < original_stack_bottom_uint || pointer >= original_stack_top_uint) return pointer; return stack_copy_bottom_uint + (pointer - original_stack_bottom_uint); } // static NO_SANITIZE("address") const uint8_t* StackCopier::CopyStackContentsAndRewritePointers( const uint8_t* original_stack_bottom, const uintptr_t* original_stack_top, size_t platform_stack_alignment, uintptr_t* stack_buffer_bottom) { const uint8_t* byte_src = original_stack_bottom; // The first address in the stack with pointer alignment. Pointer-aligned // values from this point to the end of the stack are possibly rewritten using // RewritePointerIfInOriginalStack(). Bytes before this cannot be a pointer // because they occupy less space than a pointer would. const uint8_t* first_aligned_address = bits::AlignUp(byte_src, sizeof(uintptr_t)); // The stack copy bottom, which is offset from |stack_buffer_bottom| by the // same alignment as in the original stack. This guarantees identical // alignment between values in the original stack and the copy. This uses the // platform stack alignment rather than pointer alignment so that the stack // copy is aligned to platform expectations. uint8_t* stack_copy_bottom = reinterpret_cast(stack_buffer_bottom) + (byte_src - bits::AlignDown(byte_src, platform_stack_alignment)); uint8_t* byte_dst = stack_copy_bottom; // Copy bytes verbatim up to the first aligned address. for (; byte_src < first_aligned_address; ++byte_src, ++byte_dst) *byte_dst = *byte_src; // Copy the remaining stack by pointer-sized values, rewriting anything that // looks like a pointer into the stack. const uintptr_t* src = reinterpret_cast(byte_src); uintptr_t* dst = reinterpret_cast(byte_dst); for (; src < original_stack_top; ++src, ++dst) { *dst = RewritePointerIfInOriginalStack( original_stack_bottom, original_stack_top, stack_copy_bottom, *src); } return stack_copy_bottom; } } // namespace base