diff --git a/headers/os/kernel/debugger.h b/headers/os/kernel/debugger.h new file mode 100644 index 0000000000..dab762f37c --- /dev/null +++ b/headers/os/kernel/debugger.h @@ -0,0 +1,574 @@ +/******************************************************************************* +/ +/ File: debugger.h +/ +/ Description: kernel interface for a debugger. +/ +/ Copyright 1993-98, Be Incorporated, All Rights Reserved. +/ +*******************************************************************************/ + +#ifndef _DEBUGGER_H +#define _DEBUGGER_H + +#include +#include +#include +#include +#include +#if __GNUC__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- + kernel calls +----- */ + +extern status_t install_default_debugger (port_id to_debugger_port); +extern port_id install_team_debugger (team_id team, port_id to_debugger_port); +extern status_t remove_team_debugger (team_id team); +extern status_t debug_thread (thread_id thread); + + +/* ----- + per-thread debugging flags (returned by the get_thread_debug_info + request to the debugging nub) +----- */ + +#define B_STOP_CHILD_THREADS 0x01 + +/* ----- + ids for why a thread is invoking the debugger +----- */ + +#if __POWERPC__ +typedef enum { + B_THREAD_NOT_RUNNING, + B_DEBUGGER_CALL, + B_BREAKPOINT_HIT, + B_NMI, + B_MACHINE_CHECK_EXCEPTION, + B_DATA_ACCESS_EXCEPTION, + B_INSTRUCTION_ACCESS_EXCEPTION, + B_ALIGNMENT_EXCEPTION, + B_PROGRAM_EXCEPTION, + B_GET_PROFILING_INFO, + B_WATCHPOINT_HIT, + B_SYSCALL_HIT +} db_why_stopped; +#endif + +#if __arm__ /* FIXME! This is probably neither complete, nor right. Placeholder for now. */ +typedef enum { + B_THREAD_NOT_RUNNING, + B_DEBUGGER_CALL, + B_BREAKPOINT_HIT, + B_NMI, + B_MACHINE_CHECK_EXCEPTION, + B_GET_PROFILING_INFO, + B_WATCHPOINT_HIT, + B_SYSCALL_HIT +} db_why_stopped; +#endif + +#if __INTEL__ +typedef enum { + B_THREAD_NOT_RUNNING, + B_DEBUGGER_CALL, + B_BREAKPOINT_HIT, + B_SNGLSTP, + B_NMI, + 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, + B_GET_PROFILING_INFO, + B_WATCHPOINT_HIT, + B_SYSCALL_HIT +} db_why_stopped; +#endif + +/* ----- + cpu state. It is arranged to be useable by the kernel, hence all the + C volatile regs are grouped at the beginning. The non-volatile ones + are only saved when neccessary. +----- */ + +#if __POWERPC__ +typedef struct { + int32 filler1; + int32 fpscr; + int32 pc; + int32 msr; + int32 lr; + int32 ctr; + int32 xer; + int32 cr; + int32 sprg0; + int32 filler2; /* force alignment on quad-word */ + int32 filler3; + int32 filler4; + int32 r0; + int32 r1; /* stack ptr */ + int32 r2; + int32 r3; + int32 r4; + int32 r5; + int32 r6; + int32 r7; + int32 r8; + int32 r9; + int32 r10; + int32 r11; + int32 r12; + int32 r13; + int32 r14; + int32 r15; + int32 r16; + int32 r17; + int32 r18; + int32 r19; + int32 r20; + int32 r21; + int32 r22; + int32 r23; + int32 r24; + int32 r25; + int32 r26; + int32 r27; + int32 r28; + int32 r29; + int32 r30; + int32 r31; + double f0; + double f1; + double f2; + double f3; + double f4; + double f5; + double f6; + double f7; + double f8; + double f9; + double f10; + double f11; + double f12; + double f13; /* C non-volatile regs start here */ + double f14; + double f15; + double f16; + double f17; + double f18; + double f19; + double f20; + double f21; + double f22; + double f23; + double f24; + double f25; + double f26; + double f27; + double f28; + double f29; + double f30; + double f31; +} cpu_state; +#endif + + +/* + * all the 486 registers including the segment registers and the + * general registers. + */ + +typedef struct { +#if __INTEL__ + extended_regs xregs; /* fpu/mmx/xmm registers */ +#else + char xregs[516]; /* Use placeholder array of right size for now */ +#endif + uint16 gs; + uint16 reserved0; + uint16 fs; + uint16 reserved1; + uint16 es; + uint16 reserved2; + uint16 ds; + uint16 reserved3; + ulong edi; + ulong esi; + ulong ebp; + ulong esp_res; + ulong ebx; + ulong edx; + ulong ecx; + ulong eax; + ulong trap_no; /* trap or int number */ + ulong error_code; /* trap error code */ + ulong eip; /* user eip */ + uint16 cs; /* user cs */ + uint16 reserved4; + ulong eflags; /* user elfags */ + ulong uesp; /* user esp */ + uint16 ss; /* user ss */ + uint16 reserved5; +} x86_cpu_state; + +typedef struct +{ + /* !!!XXX This is a placeholder and will need to be fixed */ + int32 r0; + int32 r1; + int32 r2; + int32 r3; + int32 r4; + int32 r5; + int32 r6; + int32 r7; /* WR - Thumb-state work register */ + int32 r8; + int32 r9; /* SB */ + int32 r10; /* SL */ + int32 r11; /* FP - ARM-state frame pointer */ + int32 r12; /* IP - intra-procedure-call scratch pointer */ + int32 r13; /* SP - stack pointer */ + int32 r14; /* LR - link register */ + int32 r15; /* PC */ +} arm_cpu_state; + +#if __INTEL__ +typedef x86_cpu_state cpu_state; +#elif __arm__ +typedef arm_cpu_state cpu_state; +#endif + +/* ----- + messages from debug server to the nub running in a target + thread's address space. +----- */ + +enum debug_nub_message { + B_READ_MEMORY = 0, /* read some memory */ + B_WRITE_MEMORY, /* write some memory */ + B_RUN_THREAD, /* run thread full speed */ + B_STEP_THREAD, /* step thread while pc in range */ + B_STEP_OVER_THREAD, /* step thread while pc in range, skip calls */ + B_STEP_OUT_THREAD, /* step thread till exit current proc */ + B_SET_BREAKPOINT, /* set a breakpoint */ + B_CLEAR_BREAKPOINT, /* set a breakpoint */ + B_STOP_NEW_THREADS, /* en/disable stopping of child threads */ + B_GET_THREAD_DEBUG_INFO, /* get debugging info */ + B_ACKNOWLEGE_IMAGE_CREATED, /* acknowlege image created */ + B_START_PROFILER, /* start profiler */ + B_STOP_PROFILER, /* stop profiler */ + B_SET_WATCHPOINT, /* set a watchpoint */ + B_CLEAR_WATCHPOINT, /* clear a watchpoint */ + B_STOP_ON_DEBUG, /* stop all threads in team when one enters db*/ + B_GET_THREAD_STACK_TOP, /* get top of ustack of a thread in the kernel*/ + B_HANDOFF_TO_OTHER_DEBUGGER,/* prepare debug nub for handing off to another debugger */ + B_GET_WHY_STOPPED /* ask why the thread is stopped */ +}; + +/* ----- + structures passed to the nub +----- */ + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + int32 count; /* # bytes */ + char *addr; /* address to read */ +} nub_read_memory_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + int32 count; /* # bytes */ + char *addr; /* address to write */ +} nub_write_memory_msg; + +typedef struct { + thread_id thread; /* thread id */ + int32 align_to_double; /* for alignment */ + cpu_state cpu; /* cpu state */ +} nub_run_thread_msg; + +typedef struct { + thread_id thread; /* thread id */ + int32 align_to_double; /* for alignment */ + cpu_state cpu; /* cpu state */ + char *low_pc; /* low end of pc range */ + char *high_pc; /* highend of pc range */ +} nub_step_thread_msg; + +typedef struct { + thread_id thread; /* thread id */ + int32 align_to_double; /* for alignment */ + cpu_state cpu; /* cpu state */ + char *low_pc; /* low end of pc range */ + char *high_pc; /* highend of pc range */ +} nub_step_over_thread_msg; + +typedef struct { + thread_id thread; /* thread id */ + int32 align_to_double; /* for alignment */ + cpu_state cpu; /* cpu state */ +} nub_step_out_thread_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + char *addr; /* breakpoint address */ +} nub_set_breakpoint_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + char *addr; /* breakpoint address */ +} nub_clear_breakpoint_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + thread_id thread; + bool enabled; /* en/disable stop of child threads */ +} nub_stop_new_threads_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + thread_id thread; +} nub_get_thread_debug_info_msg; + +typedef struct { + int32 debug_flags; /* returned thread debugging flags */ +} nub_get_thread_debug_info_reply; + +typedef struct { + int32 token; +} nub_acknowlege_image_created_msg; + + + +typedef enum +{ + PERFMON_USER_MODE = 0, + PERFMON_KERNEL_MODE, + PERFMON_KERNEL_AND_USER_MODE +} perfmon_privilege; + + +typedef struct +{ + uint32 event; + uint32 event_qualifier; + perfmon_privilege privilege; + int32 init_val; /* usually should be 0; should be negative for interrupts */ + uint32 flags; /* HW-specific bits, usually 0 */ +} perfmon_event_selector; + + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + thread_id thid; + int32 perfmon_counter; + perfmon_event_selector perfmon_event; + int32 num; + int32 slots[1]; +} nub_start_profiler_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + thread_id thid; + int32 perfmon_counter; +} nub_stop_profiler_msg; + +typedef struct { + int32 num; + int32 slots[1]; +} nub_stop_profiler_reply; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + char *addr; /* watchpoint address */ + int type; /* watchpoint type */ +} nub_set_watchpoint_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + char *addr; /* watchpoint address */ +} nub_clear_watchpoint_msg; + +typedef struct { + port_id reply_port; /* port for reply from kernel */ + thread_id thread; /* thid of thread to set this for */ + bool enabled; +} nub_stop_on_debug_msg; + +typedef struct { + port_id reply_port; + thread_id thread; +} nub_get_thread_stack_top_msg; + +typedef struct { + void *stack_top; /* stack ptr at entry to the kernel */ + void *pc; /* program ctr at entry to the kernel */ +} nub_get_thread_stack_top_reply; + +typedef struct { + port_id reply_port; + port_id new_db_port; +} nub_handoff_msg; + +typedef struct { + thread_id thread; +} nub_get_why_stopped_msg; + +/* ----- + union of all stuctures passed to the nub +----- */ + +typedef union { + nub_read_memory_msg nub_read_memory; + nub_write_memory_msg nub_write_memory; + nub_run_thread_msg nub_run_thread; + nub_step_thread_msg nub_step_thread; + nub_step_over_thread_msg nub_step_over_thread; + nub_step_out_thread_msg nub_step_out_thread; + nub_set_breakpoint_msg nub_set_breakpoint; + nub_clear_breakpoint_msg nub_clear_breakpoint; + nub_stop_new_threads_msg nub_stop_new_threads; + nub_get_thread_debug_info_msg nub_get_thread_debug_info; + nub_acknowlege_image_created_msg nub_acknowlege_image_created; + nub_start_profiler_msg nub_start_profiler; + nub_stop_profiler_msg nub_stop_profiler; + nub_set_watchpoint_msg nub_set_watchpoint; + nub_clear_watchpoint_msg nub_clear_watchpoint; + nub_stop_on_debug_msg nub_stop_on_debug; + nub_get_thread_stack_top_msg nub_get_thread_stack_top; + nub_handoff_msg nub_handoff; + nub_get_why_stopped_msg nub_get_why_stopped; +} to_nub_msg; + + +/* ----- + messages passed to the external debugger + + *** DANGER WILL ROBINSON!! *** Don't change the ordering/numbering + of these messages. Doing so will break 3rd party debuggers (i.e., + MWDebug) between releases. +----- */ + +enum debugger_message { + B_THREAD_STOPPED = 0, /* thread stopped, here is its state */ + B_TEAM_CREATED = 1, /* team was created */ + B_TEAM_DELETED = 2, /* team was deleted */ +#if __ELF__ + B_ELF_IMAGE_CREATED = 3, /* pe image was created */ + B_ELF_IMAGE_DELETED = 4, /* pe image was deleted */ +#else + B_PEF_IMAGE_CREATED = 3, /* pef image was created */ + B_PEF_IMAGE_DELETED = 4, /* pef image was deleted */ +#endif + B_THREAD_CREATED = 5, /* thread was created */ + B_THREAD_DELETED = 6, /* thread was deleted */ + B_SYSCALL_POST = 7 /* end of syscall */ +}; + +/* ---------- + structures passed to the external debugger +----- */ + +typedef struct { + thread_id thread; /* thread id */ + team_id team; /* team id */ + db_why_stopped why; /* reason for contacting debugger */ + port_id nub_port; /* port to nub for this team */ + cpu_state cpu; /* cpu state */ + void *data; /* additional data */ +} db_thread_stopped_msg; + +typedef struct { + team_id team; /* id of new team */ +} db_team_created_msg; + +typedef struct { + team_id team; /* id of deleted team */ +} db_team_deleted_msg; + +typedef struct { + int32 reply_token; /* token to acknowledge receipt (REQUIRED!) */ + team_id team; /* team id */ + thread_id thread; /* id of thread that is loading the image */ + image_info info; /* info for the image */ + port_id nub_port; /* port to nub for this team */ +} db_pef_image_created_msg; + +typedef struct { + team_id team; + image_info info; /* info for the image */ +} db_pef_image_deleted_msg; + +typedef struct { + thread_id thread; /* thread id */ + team_id team; /* team id */ +} db_thread_created_msg; + +typedef struct { + thread_id thread; /* thread id */ + team_id team; /* team id */ +} db_thread_deleted_msg; + +typedef struct { + thread_id thread; +} db_get_profile_info_msg; + +typedef struct { + thread_id thread; /* thread id */ + team_id team; /* team id */ + bigtime_t start_time; /* time of syscall start */ + bigtime_t end_time; /* time of syscall completion */ + uint32 rethi; /* upper word of return value */ + uint32 retlo; /* lower word of return value */ + uint32 syscall; /* the syscall number */ + uint32 args[8]; /* syscall args */ +} db_syscall_post_msg; + +/* ----- + union of all structures passed to external debugger +----- */ + +typedef union { + db_thread_stopped_msg thread_stopped; + db_team_created_msg team_created; + db_team_deleted_msg team_deleted; + db_pef_image_created_msg pef_image_created; + db_pef_image_deleted_msg pef_image_deleted; + db_thread_created_msg thread_created; + db_thread_deleted_msg thread_deleted; + db_get_profile_info_msg get_profile_info; + db_syscall_post_msg syscall_post; +} to_debugger_msg; + +/* + * debugger flags, state constants. + * Bottom sixteen bits of a word are reserved for Kernel use. + * Rest are used for user-level control by debuggers + * using the debugging API. See nukernel/inc/thread.h. + */ +#define DEBUG_USER_FLAGS_MASK 0xffff0000 + +#define DEBUG_syscall_tracing_only 0x00010000 /* used by _kstrace_init_ */ +#define DEBUG_syscall_fast_trace 0x00020000 +#define DEBUG_syscall_trace_through_spawns 0x00040000 +#define DEBUG_syscall_trace_whole_team 0x00080000 + +#ifdef __cplusplus +} +#endif + +#endif