Splitting up debugger.h.

This commit is contained in:
Ben Vanik 2016-01-01 15:52:43 -08:00
parent 07ba1be7f5
commit 16c97189dd
4 changed files with 193 additions and 112 deletions

View File

@ -0,0 +1,63 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_DEBUG_DEBUG_LISTENER_H_
#define XENIA_DEBUG_DEBUG_LISTENER_H_
#include "xenia/cpu/thread_state.h"
#include "xenia/debug/breakpoint.h"
namespace xe {
namespace kernel {
class XThread;
} // namespace kernel
} // namespace xe
namespace xe {
namespace debug {
// Debug event listener interface.
// Implementations will receive calls from arbitrary threads and must marshal
// them as required.
class DebugListener {
public:
// Handles request for debugger focus (such as when the user requests the
// debugger be brought to the front).
virtual void OnFocus() = 0;
// Handles the debugger detaching from the target.
// This will be called on shutdown or when the user requests the debug session
// end.
virtual void OnDetached() = 0;
// Handles execution being interrupted and transitioning to
// ExceutionState::kPaused.
virtual void OnExecutionPaused() = 0;
// Handles execution continuing when transitioning to
// ExecutionState::kRunning or ExecutionState::kStepping.
virtual void OnExecutionContinued() = 0;
// Handles execution ending when transitioning to ExecutionState::kEnded.
virtual void OnExecutionEnded() = 0;
// Handles step completion events when a requested step operation completes.
// The thread is the one that hit its step target. Note that because multiple
// threads could be stepping simultaneously (such as a run-to-cursor) use the
// thread passed instead of keeping any other state.
virtual void OnStepCompleted(xe::kernel::XThread* thread) = 0;
// Handles breakpoint events as they are hit per-thread.
// Breakpoints may be hit during stepping.
virtual void OnBreakpointHit(Breakpoint* breakpoint,
xe::kernel::XThread* thread) = 0;
};
} // namespace debug
} // namespace xe
#endif // XENIA_DEBUG_DEBUG_LISTENER_H_

View File

@ -26,6 +26,8 @@
#include "xenia/cpu/processor.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/debug/breakpoint.h"
#include "xenia/debug/debug_listener.h"
#include "xenia/debug/thread_execution_info.h"
DECLARE_bool(debug);
@ -53,118 +55,6 @@ enum class ExecutionState {
kEnded,
};
// Per-XThread structure holding debugger state and a cache of the sampled call
// stack.
//
// In most cases debug consumers should rely only on data in this structure as
// it is never removed (even when a thread is destroyed) and always available
// even when running.
struct ThreadExecutionInfo {
ThreadExecutionInfo();
~ThreadExecutionInfo();
enum class State {
// Thread is alive and running.
kAlive,
// Thread is in a wait state.
kWaiting,
// Thread has exited but not yet been killed.
kExited,
// Thread has been killed.
kZombie,
};
// XThread::thread_id(), unique to the thread for the run of the emulator.
uint32_t thread_id = 0;
// XThread::handle() of the thread.
// This will be invalidated when the thread dies.
uint32_t thread_handle = 0;
// Target XThread, if it has not been destroyed.
// TODO(benvanik): hold a ref here to keep zombie threads around?
kernel::XThread* thread = nullptr;
// Current state of the thread.
State state = State::kAlive;
// Whether the debugger has forcefully suspended this thread.
bool suspended = false;
// A breakpoint managed by the stepping system, installed as required to
// trigger a break at the next instruction.
std::unique_ptr<StepBreakpoint> step_breakpoint;
// A breakpoint managed by the stepping system, installed as required to
// trigger after a step over a disabled breakpoint.
// When this breakpoint is hit the breakpoint referenced in
// restore_original_breakpoint will be reinstalled.
// Breakpoint restore_step_breakpoint;
// If the thread is stepping over a disabled breakpoint this will point to
// that breakpoint so it can be restored.
// Breakpoint* restore_original_breakpoint = nullptr;
// Last-sampled PPC context.
// This is updated whenever the debugger stops.
xe::cpu::ppc::PPCContext guest_context;
// Last-sampled host x64 context.
// This is updated whenever the debugger stops and must be used instead of any
// value taken from the StackWalker as it properly respects exception stacks.
X64Context host_context;
// A single frame in a call stack.
struct Frame {
// PC of the current instruction in host code.
uint64_t host_pc = 0;
// Base of the function the current host_pc is located within.
uint64_t host_function_address = 0;
// PC of the current instruction in guest code.
// 0 if not a guest address or not known.
uint32_t guest_pc = 0;
// Base of the function the current guest_pc is located within.
uint32_t guest_function_address = 0;
// Function the current guest_pc is located within.
cpu::Function* guest_function = nullptr;
// Name of the function, if known.
// TODO(benvanik): string table?
char name[256] = {0};
};
// Last-sampled call stack.
// This is updated whenever the debugger stops.
std::vector<Frame> frames;
};
// Debug event listener interface.
// Implementations will receive calls from arbitrary threads and must marshal
// them as required.
class DebugListener {
public:
// Handles request for debugger focus (such as when the user requests the
// debugger be brought to the front).
virtual void OnFocus() = 0;
// Handles the debugger detaching from the target.
// This will be called on shutdown or when the user requests the debug session
// end.
virtual void OnDetached() = 0;
// Handles execution being interrupted and transitioning to
// ExceutionState::kPaused.
virtual void OnExecutionPaused() = 0;
// Handles execution continuing when transitioning to
// ExecutionState::kRunning or ExecutionState::kStepping.
virtual void OnExecutionContinued() = 0;
// Handles execution ending when transitioning to ExecutionState::kEnded.
virtual void OnExecutionEnded() = 0;
// Handles step completion events when a requested step operation completes.
// The thread is the one that hit its step target. Note that because multiple
// threads could be stepping simultaneously (such as a run-to-cursor) use the
// thread passed instead of keeping any other state.
virtual void OnStepCompleted(xe::kernel::XThread* thread) = 0;
// Handles breakpoint events as they are hit per-thread.
// Breakpoints may be hit during stepping.
virtual void OnBreakpointHit(Breakpoint* breakpoint,
xe::kernel::XThread* thread) = 0;
};
class Debugger {
public:
explicit Debugger(Emulator* emulator);

View File

@ -0,0 +1,20 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/debug/thread_execution_info.h"
namespace xe {
namespace debug {
ThreadExecutionInfo::ThreadExecutionInfo() = default;
ThreadExecutionInfo::~ThreadExecutionInfo() = default;
} // namespace debug
} // namespace xe

View File

@ -0,0 +1,108 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_DEBUG_THREAD_EXECUTION_INFO_H_
#define XENIA_DEBUG_THREAD_EXECUTION_INFO_H_
#include <vector>
#include "xenia/base/x64_context.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/debug/breakpoint.h"
namespace xe {
namespace kernel {
class XThread;
} // namespace kernel
} // namespace xe
namespace xe {
namespace debug {
// Per-XThread structure holding debugger state and a cache of the sampled call
// stack.
//
// In most cases debug consumers should rely only on data in this structure as
// it is never removed (even when a thread is destroyed) and always available
// even when running.
struct ThreadExecutionInfo {
ThreadExecutionInfo();
~ThreadExecutionInfo();
enum class State {
// Thread is alive and running.
kAlive,
// Thread is in a wait state.
kWaiting,
// Thread has exited but not yet been killed.
kExited,
// Thread has been killed.
kZombie,
};
// XThread::thread_id(), unique to the thread for the run of the emulator.
uint32_t thread_id = 0;
// XThread::handle() of the thread.
// This will be invalidated when the thread dies.
uint32_t thread_handle = 0;
// Target XThread, if it has not been destroyed.
// TODO(benvanik): hold a ref here to keep zombie threads around?
kernel::XThread* thread = nullptr;
// Current state of the thread.
State state = State::kAlive;
// Whether the debugger has forcefully suspended this thread.
bool suspended = false;
// A breakpoint managed by the stepping system, installed as required to
// trigger a break at the next instruction.
std::unique_ptr<StepBreakpoint> step_breakpoint;
// A breakpoint managed by the stepping system, installed as required to
// trigger after a step over a disabled breakpoint.
// When this breakpoint is hit the breakpoint referenced in
// restore_original_breakpoint will be reinstalled.
// Breakpoint restore_step_breakpoint;
// If the thread is stepping over a disabled breakpoint this will point to
// that breakpoint so it can be restored.
// Breakpoint* restore_original_breakpoint = nullptr;
// Last-sampled PPC context.
// This is updated whenever the debugger stops.
xe::cpu::ppc::PPCContext guest_context;
// Last-sampled host x64 context.
// This is updated whenever the debugger stops and must be used instead of any
// value taken from the StackWalker as it properly respects exception stacks.
X64Context host_context;
// A single frame in a call stack.
struct Frame {
// PC of the current instruction in host code.
uint64_t host_pc = 0;
// Base of the function the current host_pc is located within.
uint64_t host_function_address = 0;
// PC of the current instruction in guest code.
// 0 if not a guest address or not known.
uint32_t guest_pc = 0;
// Base of the function the current guest_pc is located within.
uint32_t guest_function_address = 0;
// Function the current guest_pc is located within.
cpu::Function* guest_function = nullptr;
// Name of the function, if known.
// TODO(benvanik): string table?
char name[256] = {0};
};
// Last-sampled call stack.
// This is updated whenever the debugger stops.
std::vector<Frame> frames;
};
} // namespace debug
} // namespace xe
#endif // XENIA_DEBUG_THREAD_EXECUTION_INFO_H_