Commit 3e2cc183 authored by Mike Wittman's avatar Mike Wittman Committed by Commit Bot

[Sampling profiler] Record frame from context before unwinding (Mac)

The frame that's currently executing can be immediately recorded from
the values in the register context, independent of any unwinding.
This change separates the initial frame recording from the recording
within the native unwinding, which will be required to support restarting
native unwinding after v8 unwinding.

Also adds comments documenting the overall structure of the frame unwind
algorithm.

Bug: 909957
Change-Id: I981fe7c7c8b6019d8fc34dcdb08c22ec744b08ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1540314
Commit-Queue: Mike Wittman <wittman@chromium.org>
Reviewed-by: default avatarLeonard Grey <lgrey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#645310}
parent 57c21ec7
...@@ -231,6 +231,12 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames( ...@@ -231,6 +231,12 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames(
uintptr_t stack_top, uintptr_t stack_top,
ModuleCache* module_cache, ModuleCache* module_cache,
std::vector<ProfileBuilder::Frame>* stack) { std::vector<ProfileBuilder::Frame>* stack) {
// Record the first frame from the context values.
unw_word_t instruction_pointer = thread_context->__rip;
const ModuleCache::Module* module =
module_cache->GetModuleForAddress(instruction_pointer);
stack->emplace_back(instruction_pointer, module);
// There isn't an official way to create a unw_context other than to create it // There isn't an official way to create a unw_context other than to create it
// from the current state of the current thread's stack. Since we're walking a // from the current state of the current thread's stack. Since we're walking a
// different thread's stack we must forge a context. The unw_context is just a // different thread's stack we must forge a context. The unw_context is just a
...@@ -245,23 +251,18 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames( ...@@ -245,23 +251,18 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames(
// circumstances. If we're subject to that case, just record the first frame // circumstances. If we're subject to that case, just record the first frame
// and bail. See MayTriggerUnwInitLocalCrash for details. // and bail. See MayTriggerUnwInitLocalCrash for details.
const ModuleCache::Module* leaf_frame_module = const ModuleCache::Module* leaf_frame_module =
module_cache->GetModuleForAddress(thread_context->__rip); module_cache->GetModuleForAddress(instruction_pointer);
if (leaf_frame_module && MayTriggerUnwInitLocalCrash(leaf_frame_module)) { if (leaf_frame_module && MayTriggerUnwInitLocalCrash(leaf_frame_module))
stack->emplace_back(thread_context->__rip, leaf_frame_module);
return UnwindResult::ABORTED; return UnwindResult::ABORTED;
}
unw_cursor_t unwind_cursor; unw_cursor_t unwind_cursor;
unw_init_local(&unwind_cursor, &unwind_context); unw_init_local(&unwind_cursor, &unwind_context);
bool at_top_frame = true; bool at_top_frame = true;
int step_result; int step_result;
do { for (;;) {
unw_word_t instruction_pointer; // First frame unwind step, check pre-conditions for attempting a frame
unw_get_reg(&unwind_cursor, UNW_REG_IP, &instruction_pointer); // unwind.
const ModuleCache::Module* module =
module_cache->GetModuleForAddress(instruction_pointer);
if (!module) { if (!module) {
// There's no loaded module containing the instruction pointer. This is // There's no loaded module containing the instruction pointer. This is
// due to either executing code that is not in a module (e.g. V8 // due to either executing code that is not in a module (e.g. V8
...@@ -284,9 +285,6 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames( ...@@ -284,9 +285,6 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames(
return UnwindResult::UNRECOGNIZED_FRAME; return UnwindResult::UNRECOGNIZED_FRAME;
} }
// Record the frame.
stack->emplace_back(instruction_pointer, module);
// Don't continue if we're in sigtramp. Unwinding this from another thread // Don't continue if we're in sigtramp. Unwinding this from another thread
// is very fragile. It's a complex DWARF unwind that needs to restore the // is very fragile. It's a complex DWARF unwind that needs to restore the
// entire thread context which was saved by the kernel when the interrupt // entire thread context which was saved by the kernel when the interrupt
...@@ -301,6 +299,7 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames( ...@@ -301,6 +299,7 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames(
if (!HasValidRbp(&unwind_cursor, stack_top)) if (!HasValidRbp(&unwind_cursor, stack_top))
return UnwindResult::ABORTED; return UnwindResult::ABORTED;
// Second frame unwind step: do the unwind.
step_result = unw_step(&unwind_cursor); step_result = unw_step(&unwind_cursor);
if (step_result == 0 && at_top_frame) { if (step_result == 0 && at_top_frame) {
...@@ -325,9 +324,22 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames( ...@@ -325,9 +324,22 @@ UnwindResult ThreadDelegateMac::WalkNativeFrames(
} }
} }
// Third frame unwind step: check the result of the unwind.
if (step_result < 0)
return UnwindResult::ABORTED;
if (step_result == 0)
return UnwindResult::COMPLETED;
// Fourth frame unwind step: record the frame to which we just unwound.
unw_get_reg(&unwind_cursor, UNW_REG_IP, &instruction_pointer);
module = module_cache->GetModuleForAddress(instruction_pointer);
stack->emplace_back(instruction_pointer, module);
at_top_frame = false; at_top_frame = false;
} while (step_result > 0); }
NOTREACHED();
return UnwindResult::COMPLETED; return UnwindResult::COMPLETED;
} }
......
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