| // Copyright 2018 The Fuchsia 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 "src/developer/debug/zxdb/client/thread_controller.h" | |
| #include <stdarg.h> | |
| #include "src/developer/debug/zxdb/client/frame.h" | |
| #include "src/developer/debug/zxdb/client/setting_schema_definition.h" | |
| #include "src/developer/debug/zxdb/client/thread.h" | |
| #include "src/developer/debug/zxdb/symbols/function.h" | |
| namespace zxdb { | |
| ThreadController::ThreadController() = default; | |
| ThreadController::~ThreadController() = default; | |
| void ThreadController::Log(const char* format, ...) const { | |
| FX_DCHECK(thread_); // If uninitialized, the log setting hasn't been read yet. | |
| if (!enable_debug_logging_) | |
| return; | |
| va_list ap; | |
| va_start(ap, format); | |
| printf("%s controller: ", GetName()); | |
| vprintf(format, ap); | |
| // Manually add \r so output will be reasonable even if the terminal is in | |
| // raw mode. | |
| printf("\r\n"); | |
| va_end(ap); | |
| } | |
| // static | |
| std::string ThreadController::FrameFunctionNameForLog(const Frame* frame) { | |
| const char kNone[] = "<none>"; | |
| const Location& loc = frame->GetLocation(); | |
| if (!loc.symbol()) | |
| return kNone; | |
| const Function* func = loc.symbol().Get()->AsFunction(); | |
| if (!func) | |
| return kNone; | |
| return func->GetFullName(); | |
| } | |
| void ThreadController::SetThread(Thread* thread) { | |
| thread_ = thread; | |
| enable_debug_logging_ = thread_->settings().GetBool(ClientSettings::Thread::kDebugStepping); | |
| } | |
| void ThreadController::SetInlineFrameIfAmbiguous(InlineFrameIs comparison, | |
| FrameFingerprint fingerprint) { | |
| Stack& stack = thread()->GetStack(); | |
| // Reset any hidden inline frames so we can iterate through all of them (and we'll leave this | |
| // reset to 0 if the requested one isn't found). | |
| size_t old_hide_count = stack.hide_ambiguous_inline_frame_count(); | |
| stack.SetHideAmbiguousInlineFrameCount(0); | |
| for (size_t i = 0; i < stack.size(); i++) { | |
| const Frame* frame = stack[i]; | |
| auto found = stack.GetFrameFingerprint(i); | |
| // To be ambiguous, all frames to here need to be at the same address and all inline frames need | |
| // to be at the beginning of one of their ranges. (the physical frame also needs matching but | |
| // its range doesn't count). | |
| bool is_inline = frame->IsInline(); | |
| if (found == fingerprint) { | |
| // Found it. | |
| if (comparison == InlineFrameIs::kEqual) { | |
| // Make this one the top of the stack. | |
| stack.SetHideAmbiguousInlineFrameCount(i); | |
| return; | |
| } else { // comparison == InlineFrameIs::kOneBefore. | |
| // Make the one below this frame topmost. That requires the current frame be inline since it | |
| // will be hidden. | |
| if (is_inline) { | |
| stack.SetHideAmbiguousInlineFrameCount(i + 1); | |
| return; | |
| } | |
| } | |
| break; | |
| } | |
| if (!is_inline) | |
| break; // Don't check below the first physical frame. | |
| // The fingerprint can be set on a frame as long as all frames above it were ambiguous, but the | |
| // frame being set to is usually not ambiguous (it's often the physical frame that calls an | |
| // inline function, for example). | |
| if (!frame->IsAmbiguousInlineLocation()) | |
| break; | |
| } | |
| if (old_hide_count) | |
| stack.SetHideAmbiguousInlineFrameCount(old_hide_count); | |
| } | |
| void ThreadController::NotifyControllerDone() { | |
| thread_->NotifyControllerDone(this); | |
| // Warning: |this| is likely deleted. | |
| } | |
| } // namespace zxdb |