File:  [Atari MiNT] / MiNT / doc / ptracer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:56:12 2018 UTC (8 years, 1 month ago) by root
Branches: mint, MAIN
CVS tags: mint096, HEAD
MiNT 0.96 pl14

/*

 * sample program for demonstrating the debugging calls

 * Written by Alex Kiernan

 */



#include <mintbind.h>

#include <stddef.h>



typedef struct _context {

	long	regs[15];	/* registers d0-d7, a0-a6 */

	long	usp;		/* user stack pointer (a7) */

	short	sr;		/* status register */

	long	pc;		/* program counter */

	long	ssp;		/* supervisor stack pointer */

	long	term_vec;	/* GEMDOS terminate vector (0x102) */

/*

 * AGK: if running on a TT and the user is playing with the FPU then we

 * must save and restore the context. We should also consider this for

 * I/O based co-processors, although this may be difficult due to

 * possibility of a context switch in the middle of an I/O handshaking

 * exchange.

 */

	unsigned char	fstate[216];	/* FPU internal state */

	long	fregs[3*8];	/* registers fp0-fp7 */

	long	fctrl[3];	/* FPCR/FPSR/FPIAR */

/*

 * AGK: for long (time-wise) co-processor instructions (FMUL etc.), the

 * FPU returns NULL, come-again with interrupts allowed primitives. It

 * is highly likely that a context switch will occur in one of these if

 * running a mathematically intensive application, hence we must handle

 * the mid-instruction interrupt stack. We do this by saving the extra

 * 3 long words and the stack format word here.

 */

	unsigned short	sfmt;	/* stack frame format identifier */

	short	internal[42];	/* internal state -- see framesizes[] for size */

	char	ptrace;		/* trace exception is pending */

} CONTEXT;



#define PPROCADDR	(('P'<< 8) | 1)

#define PBASEADDR	(('P'<< 8) | 2)

#define PCTXTSIZE	(('P'<< 8) | 3)

#define PSETFLAGS	(('P'<< 8) | 4)

#define PGETFLAGS	(('P'<< 8) | 5)

#define PTRACESFLAGS	(('P'<< 8) | 6)

#define PTRACEGFLAGS	(('P'<< 8) | 7)

#	define	P_ENABLE	(1 << 0)	/* enable tracing */

#ifdef NOTYETDEFINED

#	define	P_DOS		(1 << 1)	/* trace DOS calls - unimplemented */

#	define	P_BIOS		(1 << 2)	/* trace BIOS calls - unimplemented */

#	define	P_XBIOS		(1 << 3)	/* trace XBIOS calls - unimplemented */

#endif



#define PTRACEGO	(('P'<< 8) | 8)	/* these 4 must be together */

#define PTRACEFLOW	(('P'<< 8) | 9)

#define PTRACESTEP	(('P'<< 8) | 10)

#define PTRACE11	(('P'<< 8) | 11)



/* lseek() origins */

#define	SEEK_SET	0		/* from beginning of file */

#define	SEEK_CUR	1		/* from current location */

#define	SEEK_END	2		/* from end of file */



#define WNOHANG	 1

#define WUNTRACED	2



/* these definitions are incompatible with <sys/wait.h> */

#define WIFEXITED(x)	((int)((x) & 0xFF00) == 0)

#define WEXITSTATUS(x)	((int)((x) & 0xFF))



#define WIFSIGNALED(x)	(((int)((x) & 0xFF00) > 0) && ((int)(((x) & 0xFF) == 0)))

#define WTERMSIG(x)	((int)(((x) & 0xFF00) >> 8))



#define WIFSTOPPED(x)	(((int)((x) & 0xFF) == 0x7F) && ((int)(((x) >> 8) & 0xFF) != 0))

#define WSTOPSIG(x)	((int)(((x) >> 8) & 0xFF))



#define SIGTRAP		5		/* trace trap */



void

dumpCTXT(ctxt)

	CONTEXT *ctxt;

{

	int i, j;



	for (i = 0; i < 16; i += 4) {

		for (j = 0; j < 4; j++) {

			/* oh dear... we output too many commas - c'est la vie */

			printf("%c%d=$%08lx, ", i < 8 ? 'D' : 'A',

			  i + j - (i >= 8 ? 8 : 0),

			  ctxt[0].regs[i + j]);

		}

		putchar('\n');

	}

	printf("SR=$%04x\n", ctxt[0].sr);

	printf("PC=$%08lx\n", ctxt[0].pc);

	printf("SSP=$%08lx\n", ctxt[0].ssp);

	printf("term_vec=$%08lx\n", ctxt[0].term_vec);

	printf("fstate[0]=%u\n", ctxt[0].fstate[0]);

	for (i = 0; i < 8; i++) {

		printf("FP%d=$%08lx%08lx%08lx\n",

		  i,

		  ctxt[0].fregs[i * 3 + 0],

		  ctxt[0].fregs[i * 3 + 1],

		  ctxt[0].fregs[i * 3 + 2]);

	}

	printf("frame format=%u\n", ctxt[0].sfmt >> 12);

	printf("vector offset=$%x\n", ctxt[0].sfmt & 0xfff);

	/* could print internal state here internal[0..41] */

}



int

main(argc,argv)

	int argc;

	char *argv[];

{

	int pid;

	unsigned long status;

	int fd;

	char fpid[13];

	CONTEXT ctxt;

	long pctxt;

	long sizeof_ctxt;

	unsigned short sig;

	

	if (isdigit(*argv[1])) {

		pid = atoi(argv[1]);

		sprintf(fpid, "U:\\PROC\\.%03d", pid);

		fd = Fopen(fpid, 0);

		sig = 1;

		Fcntl(fd, (long)&sig, PTRACESFLAGS);	/* capture it */

		Pkill(pid, SIGTRAP);		/* and stop it */

	}

	else {

		pid = Pexec(0x8000 | 100, argv[1], "\0", NULL);

		/* check pid */

		printf("pid = %d\n", pid);

		sprintf(fpid, "U:\\PROC\\.%03d", pid);

		fd = Fopen(fpid, 0);

	}

	/* check fd */

	Fcntl(fd, (long)&pctxt, PPROCADDR);

	Fcntl(fd, (long)&sizeof_ctxt, PCTXTSIZE);

	pctxt -= 2 * sizeof_ctxt;



	do {

		status = Pwait3(WUNTRACED, NULL);

		if (WIFSTOPPED(status)) {

			printf("pid = %d\, WSTOPSIG = %d\n", (int)(status >> 16), WSTOPSIG(status));

			Fseek((long)pctxt, fd, SEEK_SET);

			Fread(fd, sizeof(ctxt), &ctxt);	/* note _not_ sizeof_ctxt */

			dumpCTXT(&ctxt);

			switch (Cconin() & 0xff) {

				case 's':

				case 'S':

					Fcntl(fd, (long)NULL, PTRACESTEP);	/* single step */

					break;

					

				case 'g':

				case 'G':

					Fcntl(fd, (long)NULL, PTRACEGO);	/* go */

					break;

					

				case 'f':

				case 'F':

					Fcntl(fd, (long)NULL, PTRACEFLOW);	/* go to flow change */

					break;

					

				case 'x':

				case 'X':

					sig = WSTOPSIG(status);

					Fcntl(fd, (long)&sig, PTRACEGO);	/* kill it */

					break;

			}

		}

		putchar('\n');

	} while (!WIFEXITED(status) && !WIFSIGNALED(status));

	if (WIFEXITED(status))

		printf("pid = %d, WEXITSTATUS = %d\n", (int)(status >> 16), WEXITSTATUS(status));

	else

		printf("pid = %d, WTERMSIG = %d\n", (int)(status >> 16), WTERMSIG(status));

	Fclose(fd);	/* but the process is dead... (Jim!) */

	return 0;

}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.