Commit df3fde1f authored by Tom Tan's avatar Tom Tan Committed by Commit Bot

Support stack walk on Windows ARM64 in base profiler

Bug: 893460
Change-Id: I9def3ef624b5121c7e902efc01a18754f448b8ce
Reviewed-on: https://chromium-review.googlesource.com/c/1332698Reviewed-by: default avatarMike Wittman <wittman@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarBruce Dawson <brucedawson@chromium.org>
Commit-Queue: Tom Tan <Tom.Tan@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#608119}
parent 182c04cf
......@@ -2161,7 +2161,7 @@ if (is_win) {
}
if (is_win || is_mac) {
if (current_cpu == "x64") {
if (current_cpu == "x64" || (current_cpu == "arm64" && is_win)) {
# Must be a shared library so that it can be unloaded during testing.
shared_library("base_profiler_test_support_library") {
sources = [
......
......@@ -24,6 +24,7 @@
#if defined(OS_WIN)
#include <windows.h>
#include <malloc.h>
#elif defined(OS_MACOSX)
#include <malloc/malloc.h>
#include "base/allocator/allocator_interception_mac.h"
......
......@@ -24,6 +24,7 @@
#include "base/stl_util.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
namespace base {
......@@ -157,10 +158,19 @@ void RewritePointersToStackMemory(uintptr_t top,
uintptr_t bottom,
CONTEXT* context,
void* stack_copy) {
#if defined(_WIN64)
#if defined(ARCH_CPU_64_BITS)
DWORD64 CONTEXT::*const nonvolatile_registers[] = {
#if defined(ARCH_CPU_X86_64)
&CONTEXT::R12, &CONTEXT::R13, &CONTEXT::R14, &CONTEXT::R15, &CONTEXT::Rdi,
&CONTEXT::Rsi, &CONTEXT::Rbx, &CONTEXT::Rbp, &CONTEXT::Rsp};
&CONTEXT::Rsi, &CONTEXT::Rbx, &CONTEXT::Rbp, &CONTEXT::Rsp
#elif defined(ARCH_CPU_ARM64)
&CONTEXT::X19, &CONTEXT::X20, &CONTEXT::X21, &CONTEXT::X22, &CONTEXT::X23,
&CONTEXT::X24, &CONTEXT::X25, &CONTEXT::X26, &CONTEXT::X27, &CONTEXT::X28,
&CONTEXT::Fp, &CONTEXT::Lr
#else
#error Unsupported Windows 64-bit Arch
#endif
};
// Rewrite pointers in the context.
for (size_t i = 0; i < size(nonvolatile_registers); ++i) {
......@@ -213,9 +223,9 @@ NativeStackSamplerError RecordStack(CONTEXT* context,
stack->reserve(128);
Win32StackFrameUnwinder frame_unwinder;
while (context->Rip) {
while (ContextPC(context)) {
const void* instruction_pointer =
reinterpret_cast<const void*>(context->Rip);
reinterpret_cast<const void*>(ContextPC(context));
ScopedModuleHandle module;
if (!frame_unwinder.TryUnwind(context, &module))
return NATIVE_STACK_SAMPLER_TRY_UNWIND_FAILED;
......@@ -355,8 +365,10 @@ NativeStackSamplerError SuspendThreadAndRecordStack(
if (!::GetThreadContext(thread_handle, &thread_context))
return NATIVE_STACK_SAMPLER_GET_THREAD_CONTEXT_FAILED;
#if defined(_WIN64)
#if defined(ARCH_CPU_X86_64)
bottom = thread_context.Rsp;
#elif defined(ARCH_CPU_ARM64)
bottom = thread_context.Sp;
#else
bottom = thread_context.Esp;
#endif
......
......@@ -9,6 +9,7 @@
#include <utility>
#include "base/macros.h"
#include "build/build_config.h"
namespace base {
......@@ -121,7 +122,7 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
// TODO(chengx): update base::ModuleCache to return a ScopedModuleHandle and
// use it for this module lookup.
ScopedModuleHandle frame_module =
unwind_functions_->GetModuleForProgramCounter(context->Rip);
unwind_functions_->GetModuleForProgramCounter(ContextPC(context));
if (!frame_module.IsValid()) {
// There's no loaded module containing the instruction pointer. This can be
// due to executing code that is not in a module. In particular,
......@@ -142,20 +143,31 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
ULONG64 image_base;
// Try to look up unwind metadata for the current function.
PRUNTIME_FUNCTION runtime_function =
unwind_functions_->LookupFunctionEntry(context->Rip, &image_base);
unwind_functions_->LookupFunctionEntry(ContextPC(context), &image_base);
if (runtime_function) {
unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function,
context);
unwind_functions_->VirtualUnwind(image_base, ContextPC(context),
runtime_function, context);
at_top_frame_ = false;
} else {
if (at_top_frame_) {
at_top_frame_ = false;
// This is a leaf function (i.e. a function that neither calls a function,
// nor allocates any stack space itself) so the return address is at RSP.
// nor allocates any stack space itself).
#if defined(ARCH_CPU_X86_64)
// For X64, return address is at RSP.
context->Rip = *reinterpret_cast<DWORD64*>(context->Rsp);
context->Rsp += 8;
#elif defined(ARCH_CPU_ARM64)
// For leaf function on Windows ARM64, return address is at LR(X30).
// Add CONTEXT_UNWOUND_TO_CALL flag to avoid unwind ambiguity for tailcall
// on ARM64, because padding after tailcall is not guaranteed.
context->Pc = context->Lr;
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
#else
#error Unsupported Windows 64-bit Arch
#endif
} else {
// In theory we shouldn't get here, as it means we've encountered a
// function without unwind information below the top of the stack, which
......
......@@ -12,6 +12,7 @@
#include "base/base_export.h"
#include "base/macros.h"
#include "base/win/scoped_handle.h"
#include "build/build_config.h"
namespace base {
......@@ -25,6 +26,18 @@ struct RUNTIME_FUNCTION {
using PRUNTIME_FUNCTION = RUNTIME_FUNCTION*;
#endif // !defined(_WIN64)
#if defined(ARCH_CPU_64_BITS)
inline ULONG64 ContextPC(CONTEXT* context) {
#if defined(ARCH_CPU_X86_64)
return context->Rip;
#elif defined(ARCH_CPU_ARM64)
return context->Pc;
#else
#error Unsupported Windows 64-bit Arch
#endif
}
#endif
// Traits class to adapt GenericScopedHandle for HMODULES.
class ModuleHandleTraits : public win::HandleTraits {
public:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment