/*******************************************************************************
/
/	File:		debugger.h
/
/	Description:	kernel interface for a debugger.
/
/	Copyright 1993-98, Be Incorporated, All Rights Reserved.
/
*******************************************************************************/

#ifndef _DEBUGGER_H
#define _DEBUGGER_H

#include <BeBuild.h>
#include <OS.h>
#include <image.h>
#include <sys/types.h>
#include <be_prim.h>
#if __GNUC__
#include <signal.h>
#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
