Skip to content

Commit

Permalink
Reland "Reland "Mac: use frame-pointer unwind for macOS 10.14+ and ARM""
Browse files Browse the repository at this point in the history
This is a reland of 62de5d0

Previous reland didn't include https://chromium-review.googlesource.com/c/chromium/src/+/3465714

Original change's description:
> Reland "Mac: use frame-pointer unwind for macOS 10.14+ and ARM"
>
> This is a reland of 1fe207f
>
> Fix in patchset 2
>
> Original change's description:
> > Mac: use frame-pointer unwind for macOS 10.14+ and ARM
> >
> > This change keeps NativeMacUnwinder for now. In a future change
> > (possibly after this bakes), we can backport pthread_stack_frame_decode_np
> > and remove it.
> >
> > For convenience, since I renamed the file, here's a separate diff
> > of TryUnwind: https://gist.github.com/speednoisemovement/5545f236ebe674360528895d1ae5c0de
> >
> > Bug: 1101399, 1102197
> > Change-Id: Id2ca3f8e34d5f91d9adc668831a3f1ea7b46b1ad
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3336376
> > Reviewed-by: David Jean <djean@chromium.org>
> > Reviewed-by: Mike Wittman <wittman@chromium.org>
> > Reviewed-by: Eric Seckler <eseckler@chromium.org>
> > Commit-Queue: Leonard Grey <lgrey@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#971214}
>
> Bug: 1101399, 1102197
> Change-Id: If8446743a5b82cd54ca620f575c4d0ea4efeab42
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3466814
> Reviewed-by: Mike Wittman <wittman@chromium.org>
> Reviewed-by: David Jean <djean@chromium.org>
> Reviewed-by: Eric Seckler <eseckler@chromium.org>
> Commit-Queue: Leonard Grey <lgrey@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#972478}

Bug: 1101399, 1102197
Change-Id: Ie40d25a9e2ac67cfe5f314b8d2718f4fd1d23c7f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3472124
Auto-Submit: Leonard Grey <lgrey@chromium.org>
Reviewed-by: Mike Wittman <wittman@chromium.org>
Reviewed-by: Eric Seckler <eseckler@chromium.org>
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Cr-Commit-Position: refs/heads/main@{#972861}
  • Loading branch information
speednoisemovement authored and Chromium LUCI CQ committed Feb 18, 2022
1 parent c4f1b84 commit e5cab0e
Show file tree
Hide file tree
Showing 15 changed files with 491 additions and 207 deletions.
9 changes: 7 additions & 2 deletions base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,8 @@ mixed_component("base") {
"process/process_mac.cc",
"process/process_metrics_mac.cc",
"profiler/module_cache_mac.cc",
"profiler/native_unwinder_apple.cc",
"profiler/native_unwinder_apple.h",
"profiler/native_unwinder_mac.cc",
"profiler/native_unwinder_mac.h",
"profiler/stack_sampler_mac.cc",
Expand Down Expand Up @@ -1310,8 +1312,8 @@ mixed_component("base") {

if (ios_stack_profiler_enabled) {
sources += [
"profiler/native_unwinder_ios.cc",
"profiler/native_unwinder_ios.h",
"profiler/native_unwinder_apple.cc",
"profiler/native_unwinder_apple.h",
"profiler/suspendable_thread_delegate_mac.cc",
"profiler/suspendable_thread_delegate_mac.h",
]
Expand Down Expand Up @@ -3817,6 +3819,9 @@ test("base_unittests") {
}
sources += [ "files/os_validation_win_unittest.cc" ]
}
if (is_apple) {
sources += [ "profiler/native_unwinder_apple_unittest.cc" ]
}

if (use_allocator_shim) {
sources += [
Expand Down
92 changes: 92 additions & 0 deletions base/profiler/native_unwinder_apple.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2021 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/native_unwinder_apple.h"

#include <pthread/stack_np.h>

#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/clamped_math.h"
#include "base/profiler/module_cache.h"
#include "base/profiler/native_unwinder.h"
#include "build/build_config.h"

namespace base {

NativeUnwinderApple::NativeUnwinderApple() = default;

bool NativeUnwinderApple::CanUnwindFrom(const Frame& current_frame) const {
return current_frame.module && current_frame.module->IsNative();
}

UnwindResult NativeUnwinderApple::TryUnwind(RegisterContext* thread_context,
uintptr_t stack_top,
std::vector<Frame>* stack) const {
// We expect the frame corresponding to the |thread_context| register state to
// exist within |stack|.
DCHECK_GT(stack->size(), 0u);
#if defined(ARCH_CPU_ARM64)
constexpr uintptr_t align_mask = 0x1;
#elif defined(ARCH_CPU_X86_64)
constexpr uintptr_t align_mask = 0xf;
#endif

uintptr_t next_frame = RegisterContextFramePointer(thread_context);
uintptr_t frame_lower_bound = RegisterContextStackPointer(thread_context);
const auto is_fp_valid = [&](uintptr_t fp) {
// Ensure there's space on the stack to read two values: the caller's
// frame pointer and the return address.
return next_frame >= frame_lower_bound &&
ClampAdd(next_frame, sizeof(uintptr_t) * 2) <= stack_top &&
(next_frame & align_mask) == 0;
};
if (!is_fp_valid(next_frame))
return UnwindResult::kAborted;

for (;;) {
if (!stack->back().module) {
return UnwindResult::kAborted;
}
if (!stack->back().module->IsNative()) {
// This is a non-native module associated with the auxiliary unwinder
// (e.g. corresponding to a frame in V8 generated code). Report as
// UNRECOGNIZED_FRAME to allow that unwinder to unwind the frame.
return UnwindResult::kUnrecognizedFrame;
}
uintptr_t retaddr;
uintptr_t frame = next_frame;
next_frame = pthread_stack_frame_decode_np(frame, &retaddr);
frame_lower_bound = frame + 1;
// If `next_frame` is 0, we've hit the root and `retaddr` isn't useful.
// Bail without recording the frame.
if (next_frame == 0)
return UnwindResult::kCompleted;
const ModuleCache::Module* module =
module_cache()->GetModuleForAddress(retaddr);
// V8 doesn't conform to the x86_64 ABI re: stack alignment. For V8 frames,
// let the V8 unwinder determine whether the FP is valid or not.
bool is_non_native_module = module && !module->IsNative();
// If the FP doesn't look correct, don't record this frame.
if (!is_non_native_module && !is_fp_valid(next_frame))
return UnwindResult::kAborted;

RegisterContextFramePointer(thread_context) = next_frame;
RegisterContextInstructionPointer(thread_context) = retaddr;
RegisterContextStackPointer(thread_context) = frame + sizeof(uintptr_t) * 2;
stack->emplace_back(retaddr, module);
}

NOTREACHED();
return UnwindResult::kCompleted;
}

// Mac version is defined in NativeUnwinderMac
#if BUILDFLAG(IS_IOS)
std::unique_ptr<Unwinder> CreateNativeUnwinder(ModuleCache* module_cache) {
return std::make_unique<NativeUnwinderApple>();
}
#endif

} // namespace base
35 changes: 35 additions & 0 deletions base/profiler/native_unwinder_apple.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2021 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.

#ifndef BASE_PROFILER_NATIVE_UNWINDER_APPLE_H_
#define BASE_PROFILER_NATIVE_UNWINDER_APPLE_H_

#include <vector>

#include <os/availability.h>

#include "base/base_export.h"
#include "base/profiler/unwinder.h"

namespace base {

// Native unwinder implementation for iOS, ARM64 and X86_64, and macOS 10.14+.
class BASE_EXPORT API_AVAILABLE(ios(12), macosx(10.14)) NativeUnwinderApple
: public Unwinder {
public:
NativeUnwinderApple();

NativeUnwinderApple(const NativeUnwinderApple&) = delete;
NativeUnwinderApple& operator=(const NativeUnwinderApple&) = delete;

// Unwinder:
bool CanUnwindFrom(const Frame& current_frame) const override;
UnwindResult TryUnwind(RegisterContext* thread_context,
uintptr_t stack_top,
std::vector<Frame>* stack) const override;
};

} // namespace base

#endif // BASE_PROFILER_NATIVE_UNWINDER_APPLE_H_
Loading

0 comments on commit e5cab0e

Please sign in to comment.