#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "base/profiler/stack_copier.h"
#include <vector>
#include "base/bits.h"
#include "base/compiler_specific.h"
#include "base/profiler/stack_buffer.h"
#if PA_BUILDFLAG(USE_PARTITION_ALLOC)
#include "partition_alloc/tagging.h"
#endif
namespace base {
StackCopier::~StackCopier() = default;
std::unique_ptr<StackBuffer> StackCopier::CloneStack(
const StackBuffer& stack_buffer,
uintptr_t* stack_top,
RegisterContext* thread_context) {
const uintptr_t original_top = *stack_top;
const uintptr_t original_bottom =
reinterpret_cast<uintptr_t>(stack_buffer.buffer());
size_t stack_size = original_top - original_bottom;
auto cloned_stack_buffer = std::make_unique<StackBuffer>(stack_size);
const uint8_t* stack_copy_bottom = CopyStackContentsAndRewritePointers(
reinterpret_cast<const uint8_t*>(stack_buffer.buffer()),
reinterpret_cast<const uintptr_t*>(original_top),
StackBuffer::kPlatformStackAlignment, cloned_stack_buffer->buffer());
CHECK(stack_copy_bottom ==
reinterpret_cast<uint8_t*>(cloned_stack_buffer->buffer()));
*stack_top =
reinterpret_cast<const uintptr_t>(stack_copy_bottom) + stack_size;
for (uintptr_t* reg : GetRegistersToRewrite(thread_context)) {
*reg = RewritePointerIfInOriginalStack(
reinterpret_cast<const uint8_t*>(original_bottom),
reinterpret_cast<const uintptr_t*>(original_top), stack_copy_bottom,
*reg);
}
return cloned_stack_buffer;
}
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<uintptr_t>(original_stack_bottom);
auto original_stack_top_uint =
reinterpret_cast<uintptr_t>(original_stack_top);
auto stack_copy_bottom_uint = reinterpret_cast<uintptr_t>(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);
}
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) {
#if PA_BUILDFLAG(USE_PARTITION_ALLOC)
partition_alloc::SuspendTagCheckingScope suspend_tag_checking_scope;
#endif
const uint8_t* byte_src = original_stack_bottom;
const uint8_t* first_aligned_address =
bits::AlignUp(byte_src, sizeof(uintptr_t));
uint8_t* stack_copy_bottom =
reinterpret_cast<uint8_t*>(stack_buffer_bottom) +
(byte_src - bits::AlignDown(byte_src, platform_stack_alignment));
uint8_t* byte_dst = stack_copy_bottom;
for (; byte_src < first_aligned_address; ++byte_src, ++byte_dst) {
*byte_dst = *byte_src;
}
const uintptr_t* src = reinterpret_cast<const uintptr_t*>(byte_src);
uintptr_t* dst = reinterpret_cast<uintptr_t*>(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;
}
}