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) { ...@@ -2161,7 +2161,7 @@ if (is_win) {
} }
if (is_win || is_mac) { 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. # Must be a shared library so that it can be unloaded during testing.
shared_library("base_profiler_test_support_library") { shared_library("base_profiler_test_support_library") {
sources = [ sources = [
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#if defined(OS_WIN) #if defined(OS_WIN)
#include <windows.h> #include <windows.h>
#include <malloc.h>
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX)
#include <malloc/malloc.h> #include <malloc/malloc.h>
#include "base/allocator/allocator_interception_mac.h" #include "base/allocator/allocator_interception_mac.h"
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "build/build_config.h"
namespace base { namespace base {
...@@ -157,10 +158,19 @@ void RewritePointersToStackMemory(uintptr_t top, ...@@ -157,10 +158,19 @@ void RewritePointersToStackMemory(uintptr_t top,
uintptr_t bottom, uintptr_t bottom,
CONTEXT* context, CONTEXT* context,
void* stack_copy) { void* stack_copy) {
#if defined(_WIN64) #if defined(ARCH_CPU_64_BITS)
DWORD64 CONTEXT::*const nonvolatile_registers[] = { DWORD64 CONTEXT::*const nonvolatile_registers[] = {
#if defined(ARCH_CPU_X86_64)
&CONTEXT::R12, &CONTEXT::R13, &CONTEXT::R14, &CONTEXT::R15, &CONTEXT::Rdi, &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. // Rewrite pointers in the context.
for (size_t i = 0; i < size(nonvolatile_registers); ++i) { for (size_t i = 0; i < size(nonvolatile_registers); ++i) {
...@@ -213,9 +223,9 @@ NativeStackSamplerError RecordStack(CONTEXT* context, ...@@ -213,9 +223,9 @@ NativeStackSamplerError RecordStack(CONTEXT* context,
stack->reserve(128); stack->reserve(128);
Win32StackFrameUnwinder frame_unwinder; Win32StackFrameUnwinder frame_unwinder;
while (context->Rip) { while (ContextPC(context)) {
const void* instruction_pointer = const void* instruction_pointer =
reinterpret_cast<const void*>(context->Rip); reinterpret_cast<const void*>(ContextPC(context));
ScopedModuleHandle module; ScopedModuleHandle module;
if (!frame_unwinder.TryUnwind(context, &module)) if (!frame_unwinder.TryUnwind(context, &module))
return NATIVE_STACK_SAMPLER_TRY_UNWIND_FAILED; return NATIVE_STACK_SAMPLER_TRY_UNWIND_FAILED;
...@@ -355,8 +365,10 @@ NativeStackSamplerError SuspendThreadAndRecordStack( ...@@ -355,8 +365,10 @@ NativeStackSamplerError SuspendThreadAndRecordStack(
if (!::GetThreadContext(thread_handle, &thread_context)) if (!::GetThreadContext(thread_handle, &thread_context))
return NATIVE_STACK_SAMPLER_GET_THREAD_CONTEXT_FAILED; return NATIVE_STACK_SAMPLER_GET_THREAD_CONTEXT_FAILED;
#if defined(_WIN64) #if defined(ARCH_CPU_X86_64)
bottom = thread_context.Rsp; bottom = thread_context.Rsp;
#elif defined(ARCH_CPU_ARM64)
bottom = thread_context.Sp;
#else #else
bottom = thread_context.Esp; bottom = thread_context.Esp;
#endif #endif
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <utility> #include <utility>
#include "base/macros.h" #include "base/macros.h"
#include "build/build_config.h"
namespace base { namespace base {
...@@ -121,7 +122,7 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context, ...@@ -121,7 +122,7 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
// TODO(chengx): update base::ModuleCache to return a ScopedModuleHandle and // TODO(chengx): update base::ModuleCache to return a ScopedModuleHandle and
// use it for this module lookup. // use it for this module lookup.
ScopedModuleHandle frame_module = ScopedModuleHandle frame_module =
unwind_functions_->GetModuleForProgramCounter(context->Rip); unwind_functions_->GetModuleForProgramCounter(ContextPC(context));
if (!frame_module.IsValid()) { if (!frame_module.IsValid()) {
// There's no loaded module containing the instruction pointer. This can be // There's no loaded module containing the instruction pointer. This can be
// due to executing code that is not in a module. In particular, // due to executing code that is not in a module. In particular,
...@@ -142,20 +143,31 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context, ...@@ -142,20 +143,31 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
ULONG64 image_base; ULONG64 image_base;
// Try to look up unwind metadata for the current function. // Try to look up unwind metadata for the current function.
PRUNTIME_FUNCTION runtime_function = PRUNTIME_FUNCTION runtime_function =
unwind_functions_->LookupFunctionEntry(context->Rip, &image_base); unwind_functions_->LookupFunctionEntry(ContextPC(context), &image_base);
if (runtime_function) { if (runtime_function) {
unwind_functions_->VirtualUnwind(image_base, context->Rip, runtime_function, unwind_functions_->VirtualUnwind(image_base, ContextPC(context),
context); runtime_function, context);
at_top_frame_ = false; at_top_frame_ = false;
} else { } else {
if (at_top_frame_) { if (at_top_frame_) {
at_top_frame_ = false; at_top_frame_ = false;
// This is a leaf function (i.e. a function that neither calls a function, // 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->Rip = *reinterpret_cast<DWORD64*>(context->Rsp);
context->Rsp += 8; 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 { } else {
// In theory we shouldn't get here, as it means we've encountered a // 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 // function without unwind information below the top of the stack, which
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
#include "build/build_config.h"
namespace base { namespace base {
...@@ -25,6 +26,18 @@ struct RUNTIME_FUNCTION { ...@@ -25,6 +26,18 @@ struct RUNTIME_FUNCTION {
using PRUNTIME_FUNCTION = RUNTIME_FUNCTION*; using PRUNTIME_FUNCTION = RUNTIME_FUNCTION*;
#endif // !defined(_WIN64) #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. // Traits class to adapt GenericScopedHandle for HMODULES.
class ModuleHandleTraits : public win::HandleTraits { class ModuleHandleTraits : public win::HandleTraits {
public: 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