/* * Copyright 2005-2016 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef _DEBUGGER_H #define _DEBUGGER_H #include #include #include // include architecture specific definitions #include #include #include #include #include #include #include #include #include #if defined(__x86_64__) typedef struct x86_64_debug_cpu_state debug_cpu_state; #elif defined(__i386__) typedef struct x86_debug_cpu_state debug_cpu_state; #elif defined(__POWERPC__) typedef struct ppc_debug_cpu_state debug_cpu_state; #elif defined(__M68K__) typedef struct m68k_debug_cpu_state debug_cpu_state; #elif defined(__MIPSEL__) typedef struct mipsel_debug_cpu_state debug_cpu_state; #elif defined(__arm__) typedef struct arm_debug_cpu_state debug_cpu_state; #elif (defined(__riscv) && __riscv_xlen == 64) typedef struct riscv64_debug_cpu_state debug_cpu_state; #elif defined(__sparc64__) typedef struct sparc_debug_cpu_state debug_cpu_state; #elif defined(__aarch64__) || defined(__arm64__) typedef struct arm64_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 the team'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, // B_DEBUG_WRITE_CORE_FILE // write a core file } 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 { 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 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; // B_DEBUG_WRITE_CORE_FILE typedef struct { port_id reply_port; // port to send the reply to char path[B_PATH_NAME_LENGTH]; // path of the core file; must not exist // yet; must be absolute } debug_nub_write_core_file; typedef struct { status_t error; // B_OK on success } debug_nub_write_core_file_reply; // 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_write_core_file write_core_file; } 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 uint8 args[128]; // 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 uint8 args[128]; // 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 siginfo_t info; // the signal info 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 // ... // instead of // ... 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