haiku/headers/os/kernel/debugger.h
Ingo Weinhold 44b5d72b5a Added new functions to the debugger API:
{set,clear}_debugger_{break,watch}point(), allowing to set/clear break
and watchpoints for the calling team. When a break/watchpoint is hit,
the team enters the debugger. Handy in situations when the program in
question can't really be started in a debugger (or it would be
complicated to do so). The functions work only as long as no debugger is
installed for the team.

We clear the arch specific team and thread debug infos now, when a new
debugger is installed, thus clearing break- and watchpoints.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20396 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-03-20 16:20:13 +00:00

537 lines
16 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
#ifdef __INTEL__
#include <arch/x86/arch_debugger.h>
#elif __POWERPC__
#include <arch/ppc/arch_debugger.h>
#endif
typedef struct debug_cpu_state debug_cpu_state;
#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. All 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,
// 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()
} 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_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_HANDED_OVER, // the debugged team has been
// handed over to another debugger
} debug_debugger_message;
// #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
// 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_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
bool software; // true, if the is a software breakpoint
// (i.e. caused by a respective trap
// instruction)
} 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_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
} debug_image_created;
// B_DEBUGGER_MESSAGE_IMAGE_DELETED
typedef struct {
debug_origin origin;
image_info info; // info for the image
} debug_image_deleted;
// 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
} 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_thread_created thread_created;
debug_thread_deleted thread_deleted;
debug_image_created image_created;
debug_image_deleted image_deleted;
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