haiku/headers/os/kernel/debugger.h

643 lines
20 KiB
C

/*
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
* Distributed under the terms of the MIT License.
*/
#ifndef _DEBUGGER_H
#define _DEBUGGER_H
#include <signal.h>
#include <image.h>
#include <OS.h>
// include architecture specific definitions
#include <arch/x86/arch_debugger.h>
#include <arch/ppc/arch_debugger.h>
#include <arch/m68k/arch_debugger.h>
#include <arch/mipsel/arch_debugger.h>
#include <arch/arm/arch_debugger.h>
#ifdef __INTEL__
typedef struct x86_debug_cpu_state debug_cpu_state;
#elif __POWERPC__
typedef struct ppc_debug_cpu_state debug_cpu_state;
#elif __M68K__
typedef struct m68k_debug_cpu_state debug_cpu_state;
#elif __MIPSEL__
typedef struct mipsel_debug_cpu_state debug_cpu_state;
#elif __ARM__
typedef struct arm_debug_cpu_state debug_cpu_state;
#else
#error unsupported architecture
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern status_t install_default_debugger(port_id debuggerPort);
extern port_id install_team_debugger(team_id team, port_id debuggerPort);
extern status_t remove_team_debugger(team_id team);
extern status_t debug_thread(thread_id thread);
extern void wait_for_debugger(void);
// EXPERIMENTAL: Self-debugging functions. Will fail when a team debugger is
// installed. A breakpoint/watchpoint hit will cause the default debugger to
// be installed for the team.
extern status_t set_debugger_breakpoint(void *address);
extern status_t clear_debugger_breakpoint(void *address);
extern status_t set_debugger_watchpoint(void *address, uint32 type,
int32 length);
extern status_t clear_debugger_watchpoint(void *address);
// team debugging flags
enum {
// event mask: If a flag is set, any of the team's threads will stop when
// the respective event occurs. None of the flags are enabled by default.
// Always enabled are debugger() calls and hardware exceptions, as well as
// the deletion of the debugged team.
B_TEAM_DEBUG_SIGNALS = 0x00010000,
B_TEAM_DEBUG_PRE_SYSCALL = 0x00020000,
B_TEAM_DEBUG_POST_SYSCALL = 0x00040000,
B_TEAM_DEBUG_TEAM_CREATION = 0x00080000,
B_TEAM_DEBUG_THREADS = 0x00100000,
B_TEAM_DEBUG_IMAGES = 0x00200000,
B_TEAM_DEBUG_PREVENT_EXIT = 0x00400000,
// new thread handling
B_TEAM_DEBUG_STOP_NEW_THREADS = 0x01000000,
B_TEAM_DEBUG_USER_FLAG_MASK = 0xffff0000,
};
// per-thread debugging flags
enum {
// event mask: If a flag is set, the thread will stop when the respective
// event occurs. If there is a corresponding team flag, it is sufficient,
// if either is set. Per default none of the flags is set.
B_THREAD_DEBUG_PRE_SYSCALL = 0x00010000,
B_THREAD_DEBUG_POST_SYSCALL = 0x00020000,
// child thread handling
B_THREAD_DEBUG_STOP_CHILD_THREADS = 0x00100000,
B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS = 0x00200000,
B_THREAD_DEBUG_USER_FLAG_MASK = 0xffff0000,
};
// in case of a B_EXCEPTION_OCCURRED event: the type of the exception
typedef enum {
B_NON_MASKABLE_INTERRUPT = 0,
B_MACHINE_CHECK_EXCEPTION,
B_SEGMENT_VIOLATION,
B_ALIGNMENT_EXCEPTION,
B_DIVIDE_ERROR,
B_OVERFLOW_EXCEPTION,
B_BOUNDS_CHECK_EXCEPTION,
B_INVALID_OPCODE_EXCEPTION,
B_SEGMENT_NOT_PRESENT,
B_STACK_FAULT,
B_GENERAL_PROTECTION_FAULT,
B_FLOATING_POINT_EXCEPTION,
} debug_exception_type;
// Value indicating how a stopped thread shall continue.
enum {
B_THREAD_DEBUG_HANDLE_EVENT = 0, // handle the event normally
// (e.g. a signal is delivered, a
// CPU fault kills the team,...)
B_THREAD_DEBUG_IGNORE_EVENT, // ignore the event and continue as if
// it didn't occur (e.g. a signal or
// a CPU fault will be ignored)
};
// watchpoint types (ToDo: Check PPC support.)
enum {
B_DATA_READ_WATCHPOINT = 0, // !x86
B_DATA_WRITE_WATCHPOINT,
B_DATA_READ_WRITE_WATCHPOINT,
};
// how to apply signal ignore masks
typedef enum {
B_DEBUG_SIGNAL_MASK_AND = 0,
B_DEBUG_SIGNAL_MASK_OR,
B_DEBUG_SIGNAL_MASK_SET,
} debug_signal_mask_op;
#define B_DEBUG_SIGNAL_TO_MASK(signal) (1ULL << ((signal) - 1))
// maximal number of bytes to read/write via B_DEBUG_MESSAGE_{READ,WRITE]_MEMORY
enum {
B_MAX_READ_WRITE_MEMORY_SIZE = 1024,
};
// messages to the debug nub thread
typedef enum {
B_DEBUG_MESSAGE_READ_MEMORY = 0, // read from the team's memory
B_DEBUG_MESSAGE_WRITE_MEMORY, // write to the team's memory
B_DEBUG_MESSAGE_SET_TEAM_FLAGS, // set the team's debugging flags
B_DEBUG_MESSAGE_SET_THREAD_FLAGS, // set a thread's debugging flags
B_DEBUG_MESSAGE_CONTINUE_THREAD, // continue a stopped thread
B_DEBUG_MESSAGE_SET_CPU_STATE, // change a stopped thread's CPU state
B_DEBUG_MESSAGE_GET_CPU_STATE, // get the thread's current CPU state
B_DEBUG_MESSAGE_SET_BREAKPOINT, // set a breakpoint
B_DEBUG_MESSAGE_CLEAR_BREAKPOINT, // clear a breakpoint
B_DEBUG_MESSAGE_SET_WATCHPOINT, // set a watchpoint
B_DEBUG_MESSAGE_CLEAR_WATCHPOINT, // clear a watchpoint
B_DEBUG_MESSAGE_SET_SIGNAL_MASKS, // set/get a thread's masks of signals
B_DEBUG_MESSAGE_GET_SIGNAL_MASKS, // the debugger is interested in
B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER, // set/get a thread's signal handler for
B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER, // a signal
B_DEBUG_MESSAGE_PREPARE_HANDOVER, // prepares the debugged team for being
// handed over to another debugger;
// the new debugger can just invoke
// install_team_debugger()
B_DEBUG_START_PROFILER, // start/stop sampling
B_DEBUG_STOP_PROFILER //
} debug_nub_message;
// messages sent to the debugger
typedef enum {
B_DEBUGGER_MESSAGE_THREAD_DEBUGGED = 0, // debugger message in reaction to
// an invocation of debug_thread()
B_DEBUGGER_MESSAGE_DEBUGGER_CALL, // thread called debugger()
B_DEBUGGER_MESSAGE_BREAKPOINT_HIT, // thread hit a breakpoint
B_DEBUGGER_MESSAGE_WATCHPOINT_HIT, // thread hit a watchpoint
B_DEBUGGER_MESSAGE_SINGLE_STEP, // thread was single-stepped
B_DEBUGGER_MESSAGE_PRE_SYSCALL, // begin of a syscall
B_DEBUGGER_MESSAGE_POST_SYSCALL, // end of a syscall
B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED, // thread received a signal
B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED, // an exception occurred
B_DEBUGGER_MESSAGE_TEAM_CREATED, // the debugged team created a new
// one
B_DEBUGGER_MESSAGE_TEAM_DELETED, // the debugged team is gone
B_DEBUGGER_MESSAGE_TEAM_EXEC, // the debugged team executes exec()
B_DEBUGGER_MESSAGE_THREAD_CREATED, // a thread has been created
B_DEBUGGER_MESSAGE_THREAD_DELETED, // a thread has been deleted
B_DEBUGGER_MESSAGE_IMAGE_CREATED, // an image has been created
B_DEBUGGER_MESSAGE_IMAGE_DELETED, // an image has been deleted
B_DEBUGGER_MESSAGE_PROFILER_UPDATE, // flush the profiling buffer for a
// thread
B_DEBUGGER_MESSAGE_HANDED_OVER, // the debugged team has been
// handed over to another debugger,
// sent to both debuggers
} debug_debugger_message;
// profile events -- when the buffer is in variable stack depth format, a sample
// count entry >= B_DEBUG_PROFILE_EVENT_BASE indicates a profile event
enum {
B_DEBUG_PROFILE_EVENT_BASE = 0x80000000,
B_DEBUG_PROFILE_EVENT_PARAMETER_MASK = 0x0000ffff,
// & with to get the event's parameter count
B_DEBUG_PROFILE_IMAGE_EVENT = 0x80010001
// single parameter: the respective image event counter
};
// #pragma mark -
// #pragma mark ----- messages to the debug nub thread -----
// B_DEBUG_MESSAGE_READ_MEMORY
typedef struct {
port_id reply_port; // port to send the reply to
void *address; // address from which to read
int32 size; // number of bytes to read
} debug_nub_read_memory;
typedef struct {
status_t error; // B_OK, if reading went fine
int32 size; // the number of bytes actually read
// > 0, iff error == B_OK
char data[B_MAX_READ_WRITE_MEMORY_SIZE];
// the read data
} debug_nub_read_memory_reply;
// B_DEBUG_MESSAGE_WRITE_MEMORY
typedef struct {
port_id reply_port; // port to send the reply to
void *address; // address to which to write
int32 size; // number of bytes to write
char data[B_MAX_READ_WRITE_MEMORY_SIZE];
// data to write
} debug_nub_write_memory;
typedef struct {
status_t error; // B_OK, if writing went fine
int32 size; // the number of bytes actually written
} debug_nub_write_memory_reply;
// B_DEBUG_MESSAGE_SET_TEAM_FLAGS
typedef struct {
int32 flags; // the new team debugging flags
} debug_nub_set_team_flags;
// B_DEBUG_MESSAGE_SET_THREAD_FLAGS
typedef struct {
thread_id thread; // the thread
int32 flags; // the new thread debugging flags
} debug_nub_set_thread_flags;
// B_DEBUG_MESSAGE_CONTINUE_THREAD
typedef struct {
thread_id thread; // the thread
uint32 handle_event; // how to handle the occurred event
bool single_step; // true == single step, false == run full speed
} debug_nub_continue_thread;
// B_DEBUG_MESSAGE_SET_CPU_STATE
typedef struct {
thread_id thread; // the thread
debug_cpu_state cpu_state; // the new CPU state
} debug_nub_set_cpu_state;
// B_DEBUG_MESSAGE_GET_CPU_STATE
typedef struct {
port_id reply_port; // port to send the reply to
thread_id thread; // the thread
} debug_nub_get_cpu_state;
typedef struct {
status_t error; // != B_OK, if something went wrong
// (bad thread ID, thread not stopped)
debug_debugger_message message; // the reason why the thread stopped
debug_cpu_state cpu_state; // the thread's CPU state
} debug_nub_get_cpu_state_reply;
// B_DEBUG_MESSAGE_SET_BREAKPOINT
typedef struct {
port_id reply_port; // port to send the reply to
void *address; // breakpoint address
} debug_nub_set_breakpoint;
typedef struct {
status_t error; // B_OK, if the breakpoint has been set
// successfully
} debug_nub_set_breakpoint_reply;
// B_DEBUG_MESSAGE_CLEAR_BREAKPOINT
typedef struct {
void *address; // breakpoint address
} debug_nub_clear_breakpoint;
// B_DEBUG_MESSAGE_SET_WATCHPOINT
typedef struct {
port_id reply_port; // port to send the reply to
void *address; // watchpoint address
uint32 type; // watchpoint type (see type constants above)
int32 length; // number of bytes to watch (typically 1, 2,
// 4); architecture specific alignment
// restrictions apply.
} debug_nub_set_watchpoint;
typedef struct {
status_t error; // B_OK, if the watchpoint has been set
// successfully
} debug_nub_set_watchpoint_reply;
// B_DEBUG_MESSAGE_CLEAR_WATCHPOINT
typedef struct {
void *address; // watchpoint address
} debug_nub_clear_watchpoint;
// B_DEBUG_MESSAGE_SET_SIGNAL_MASKS
typedef struct {
thread_id thread; // the thread
uint64 ignore_mask; // the mask for signals the
// debugger wishes not to be
// notified of
uint64 ignore_once_mask; // the mask for signals the
// debugger wishes not to be
// notified of when they next
// occur
debug_signal_mask_op ignore_op; // what to do with ignore_mask
debug_signal_mask_op ignore_once_op; // what to do with
// ignore_once_mask
} debug_nub_set_signal_masks;
// B_DEBUG_MESSAGE_GET_SIGNAL_MASKS
typedef struct {
port_id reply_port; // port to send the reply to
thread_id thread; // the thread
} debug_nub_get_signal_masks;
typedef struct {
status_t error; // B_OK, if the thread exists
uint64 ignore_mask; // the mask for signals the debugger wishes
// not to be notified of
uint64 ignore_once_mask; // the mask for signals the debugger wishes
// not to be notified of when they next
// occur
} debug_nub_get_signal_masks_reply;
// B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER
typedef struct {
thread_id thread; // the thread
int signal; // the signal
struct sigaction handler; // the new signal handler
} debug_nub_set_signal_handler;
// B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER
typedef struct {
port_id reply_port; // port to send the reply to
thread_id thread; // the thread
int signal; // the signal
} debug_nub_get_signal_handler;
typedef struct {
status_t error; // B_OK, if the thread exists
struct sigaction handler; // the signal handler
} debug_nub_get_signal_handler_reply;
// B_DEBUG_MESSAGE_PREPARE_HANDOVER
// no parameters, no reply
// B_DEBUG_START_PROFILER
struct debug_profile_function {
addr_t base; // function base address
size_t size; // function size
};
typedef struct {
port_id reply_port; // port to send the reply to
thread_id thread; // thread to profile
bigtime_t interval; // sample interval
area_id sample_area; // area into which the sample will be
// written
int32 stack_depth; // number of return address per hit
bool variable_stack_depth;
// variable number of samples per hit;
// cf. debug_profiler_update
} debug_nub_start_profiler;
typedef struct {
status_t error;
int32 image_event; // number of the last image event
bigtime_t interval; // actual sample interval (might
// differ from the requested one)
} debug_nub_start_profiler_reply;
// B_DEBUG_STOP_PROFILER
typedef struct {
port_id reply_port; // port to send the reply to
thread_id thread; // thread to profile
} debug_nub_stop_profiler;
// reply is debug_profiler_update
// union of all messages structures sent to the debug nub thread
typedef union {
debug_nub_read_memory read_memory;
debug_nub_write_memory write_memory;
debug_nub_set_team_flags set_team_flags;
debug_nub_set_thread_flags set_thread_flags;
debug_nub_continue_thread continue_thread;
debug_nub_set_cpu_state set_cpu_state;
debug_nub_get_cpu_state get_cpu_state;
debug_nub_set_breakpoint set_breakpoint;
debug_nub_clear_breakpoint clear_breakpoint;
debug_nub_set_watchpoint set_watchpoint;
debug_nub_clear_watchpoint clear_watchpoint;
debug_nub_set_signal_masks set_signal_masks;
debug_nub_get_signal_masks get_signal_masks;
debug_nub_set_signal_handler set_signal_handler;
debug_nub_get_signal_handler get_signal_handler;
debug_nub_start_profiler start_profiler;
debug_nub_stop_profiler stop_profiler;
} debug_nub_message_data;
// #pragma mark -
// #pragma mark ----- messages to the debugger -----
// first member of all debugger messages -- not a message by itself
typedef struct {
thread_id thread; // the thread being the event origin
team_id team; // the thread's team
port_id nub_port; // port to debug nub for this team (only set
// for synchronous messages)
} debug_origin;
// B_DEBUGGER_MESSAGE_THREAD_DEBUGGED
typedef struct {
debug_origin origin;
} debug_thread_debugged;
// B_DEBUGGER_MESSAGE_DEBUGGER_CALL
typedef struct {
debug_origin origin;
void *message; // address of the message passed to
// debugger()
} debug_debugger_call;
// B_DEBUGGER_MESSAGE_BREAKPOINT_HIT
typedef struct {
debug_origin origin;
debug_cpu_state cpu_state; // cpu state
} debug_breakpoint_hit;
// B_DEBUGGER_MESSAGE_WATCHPOINT_HIT
typedef struct {
debug_origin origin;
debug_cpu_state cpu_state; // cpu state
} debug_watchpoint_hit;
// B_DEBUGGER_MESSAGE_SINGLE_STEP
typedef struct {
debug_origin origin;
debug_cpu_state cpu_state; // cpu state
} debug_single_step;
// B_DEBUGGER_MESSAGE_PRE_SYSCALL
typedef struct {
debug_origin origin;
uint32 syscall; // the syscall number
uint32 args[16]; // syscall arguments
} debug_pre_syscall;
// B_DEBUGGER_MESSAGE_POST_SYSCALL
typedef struct {
debug_origin origin;
bigtime_t start_time; // time of syscall start
bigtime_t end_time; // time of syscall completion
uint64 return_value; // the syscall's return value
uint32 syscall; // the syscall number
uint32 args[16]; // syscall arguments
} debug_post_syscall;
// B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED
typedef struct {
debug_origin origin;
int signal; // the signal
struct sigaction handler; // the signal handler
bool deadly; // true, if handling the signal will kill
// the team
} debug_signal_received;
// B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED
typedef struct {
debug_origin origin;
debug_exception_type exception; // the exception
int signal; // the signal that will be sent,
// when the thread continues
// normally
} debug_exception_occurred;
// B_DEBUGGER_MESSAGE_TEAM_CREATED
typedef struct {
debug_origin origin;
team_id new_team; // the newly created team
} debug_team_created;
// B_DEBUGGER_MESSAGE_TEAM_DELETED
typedef struct {
debug_origin origin; // thread is < 0, team is the deleted team
// (asynchronous message)
} debug_team_deleted;
// B_DEBUGGER_MESSAGE_TEAM_EXEC
typedef struct {
debug_origin origin;
int32 image_event; // number of the image event
} debug_team_exec;
// B_DEBUGGER_MESSAGE_THREAD_CREATED
typedef struct {
debug_origin origin; // the thread that created the new thread
team_id new_thread; // the newly created thread
} debug_thread_created;
// B_DEBUGGER_MESSAGE_THREAD_DELETED
typedef struct {
debug_origin origin; // the deleted thread (asynchronous message)
} debug_thread_deleted;
// B_DEBUGGER_MESSAGE_IMAGE_CREATED
typedef struct {
debug_origin origin;
image_info info; // info for the image
int32 image_event; // number of the image event
} debug_image_created;
// B_DEBUGGER_MESSAGE_IMAGE_DELETED
typedef struct {
debug_origin origin;
image_info info; // info for the image
int32 image_event; // number of the image event
} debug_image_deleted;
// B_DEBUGGER_MESSAGE_PROFILER_UPDATE
typedef struct {
debug_origin origin;
int32 image_event; // number of the last image event; all
// samples were recorded after this
// event and before the next one
int32 stack_depth; // number of return addresses per tick
int32 sample_count; // number of samples in the buffer
int32 dropped_ticks; // number of ticks that had been
// dropped, since the buffer was full
bool variable_stack_depth;
// the number of samples per hit is
// variable, i.e. the format for the
// samples of a hit in the buffer is
// <n> <sample 1> ... <sample n>
// instead of
// <sample 1> ... <sample stack_depth>
bool stopped; // if true, the thread is no longer
// being profiled
} debug_profiler_update;
// B_DEBUGGER_MESSAGE_HANDED_OVER
typedef struct {
debug_origin origin; // thread is < 0, team is the deleted team
// (asynchronous message)
team_id debugger; // the new debugger
port_id debugger_port; // the port the new debugger uses
thread_id causing_thread; // the thread that caused entering the
// debugger in the first place, -1 if the
// debugger wasn't attached automatically
} debug_handed_over;
// union of all messages structures sent to the debugger
typedef union {
debug_thread_debugged thread_debugged;
debug_debugger_call debugger_call;
debug_breakpoint_hit breakpoint_hit;
debug_watchpoint_hit watchpoint_hit;
debug_single_step single_step;
debug_pre_syscall pre_syscall;
debug_post_syscall post_syscall;
debug_signal_received signal_received;
debug_exception_occurred exception_occurred;
debug_team_created team_created;
debug_team_deleted team_deleted;
debug_team_exec team_exec;
debug_thread_created thread_created;
debug_thread_deleted thread_deleted;
debug_image_created image_created;
debug_image_deleted image_deleted;
debug_profiler_update profiler_update;
debug_handed_over handed_over;
debug_origin origin; // for convenience (no real message)
} debug_debugger_message_data;
extern void get_debug_message_string(debug_debugger_message message,
char *buffer, int32 bufferSize);
extern void get_debug_exception_string(debug_exception_type exception,
char *buffer, int32 bufferSize);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _DEBUGGER_H