/******************************************************************************* / / 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