PERFORCE change 49655 for review

Marcel Moolenaar marcel at FreeBSD.org
Wed Mar 24 23:56:49 PST 2004


http://perforce.freebsd.org/chv.cgi?CH=49655

Change 49655 by marcel at marcel_nfs on 2004/03/24 23:56:09

	Save a pointer to the trapframe (or intrframe on i386) on
	every kernel entry. We save the pointer in td_last_frame.
	This way, we always have the right context in the debugger
	without having to muck around with td_frame itself. I like
	only having td_frame better, but I only got panics so it
	needs more thought. This way I can at least make progress.
	
	Introduce the global variable kdb_frame, which normally
	caches kdb_thread->td_last_frame, but when the thread has
	never run, will cache kdb_thread->td_frame. We don't
	need this global variable if we only have td_frame of
	course.
	
	A thread list of my ia64 kernel with an i386 cross-debugger,
	now gives:
	
	(gdb) target remote /dev/uart1
	Remote debugging using /dev/uart1
	0xe000000004294161 in kdb_enter (
	    msg=0x9c1632009c16320 <Address 0x9c1632009c16320 out of bounds>)
	    at machine/cpufunc.h:47
	47              __asm __volatile("break.m %0" :: "i"(IA64_FIXED_BREAK));
	(gdb) info thread
	  56 Thread 10  critical_exit () at machine/cpufunc.h:197
	  55 Thread 1  0x2000000000018740 in ?? ()
	  54 Thread 11  0xe000000004294161 in kdb_enter (
	    msg=0x9c1632009c16320 <Address 0x9c1632009c16320 out of bounds>)
	    at machine/cpufunc.h:47
	  53 Thread 12  DELAY (n=166888144) at machine/ia64_cpu.h:320
	  52 Thread 13  0x0000000000000000 in ?? ()
	  51 Thread 14  critical_exit () at machine/cpufunc.h:197
	  50 Thread 2  critical_exit () at machine/cpufunc.h:197
	  49 Thread 3  critical_exit () at machine/cpufunc.h:197
	  48 Thread 4  g_io_schedule_down (tp=0x9c142b409c142b4)
	    at ../../../geom/geom_io.c:311
	  47 Thread 15  SHA256_Transform (context=0x9bf412c09bf412c,
	    data=0x9bf42f409bf42f4) at ../../../crypto/sha2/sha2.c:476
		:
	
	The arguments are bogus, but that's because of something
	else. Thread 13 has never run, and thread 1 is in userland.
	
	Rewrite the way we get registers. All regisers are identified
	by the gdb register number. The gdb_cpu_getreg() function
	returns a pointer to the register's value, or NULL if the
	register is unavailable. The advantage of this is that we
	encode register values in the same way we encode memory
	contents and we can tell gdb about unavailable registers.
	This also means that there's less MD code.
	
	Still only i386 and ia64 for now.

Affected files ...

.. //depot/projects/gdb/sys/ddb/db_main.c#3 edit
.. //depot/projects/gdb/sys/gdb/gdb_int.h#5 edit
.. //depot/projects/gdb/sys/gdb/gdb_main.c#9 edit
.. //depot/projects/gdb/sys/gdb/gdb_packet.c#6 edit
.. //depot/projects/gdb/sys/i386/i386/gdb_machdep.c#5 edit
.. //depot/projects/gdb/sys/i386/i386/intr_machdep.c#2 edit
.. //depot/projects/gdb/sys/i386/i386/trap.c#6 edit
.. //depot/projects/gdb/sys/i386/include/gdb_machdep.h#4 edit
.. //depot/projects/gdb/sys/i386/include/kdb.h#2 edit
.. //depot/projects/gdb/sys/ia64/ia64/gdb_machdep.c#5 edit
.. //depot/projects/gdb/sys/ia64/ia64/interrupt.c#3 edit
.. //depot/projects/gdb/sys/ia64/ia64/trap.c#5 edit
.. //depot/projects/gdb/sys/ia64/include/gdb_machdep.h#4 edit
.. //depot/projects/gdb/sys/ia64/include/kdb.h#2 edit
.. //depot/projects/gdb/sys/kern/subr_kdb.c#9 edit
.. //depot/projects/gdb/sys/sys/kdb.h#7 edit
.. //depot/projects/gdb/sys/sys/proc.h#5 edit

Differences ...

==== //depot/projects/gdb/sys/ddb/db_main.c#3 (text+ko) ====

@@ -129,7 +129,7 @@
 	if (cnunavailable())
 		return (0);
 
-	ddb_regs = *kdb_thread->td_frame;
+	ddb_regs = *kdb_frame;
 
 	bkpt = IS_BREAKPOINT_TRAP(type, code);
 	watchpt = IS_WATCHPOINT_TRAP(type, code);
@@ -153,7 +153,7 @@
 
 	db_restart_at_pc(watchpt);
 
-	*kdb_thread->td_frame = ddb_regs;
+	*kdb_frame = ddb_regs;
 
 	return (1);
 }

==== //depot/projects/gdb/sys/gdb/gdb_int.h#5 (text+ko) ====

@@ -54,9 +54,8 @@
 
 void gdb_tx_begin(char);
 int gdb_tx_end(void);
-int gdb_tx_memory(const unsigned char *, size_t);
+void gdb_tx_mem(const unsigned char *, size_t);
 void gdb_tx_reg(int);
-int gdb_tx_regs(void);
 
 static __inline void
 gdb_tx_char(char c)

==== //depot/projects/gdb/sys/gdb/gdb_main.c#9 (text+ko) ====

@@ -92,7 +92,6 @@
 static int
 gdb_trap(int type, int code)
 {
-	uintmax_t addr, size;
 	struct proc *thr_iter;
 
 	/*
@@ -101,12 +100,10 @@
 	 */
 	gdb_tx_begin('T');
 	gdb_tx_hex(gdb_cpu_signal(type, code), 2);
+	gdb_tx_varhex(GDB_REG_PC);
+	gdb_tx_char(':');
 	gdb_tx_reg(GDB_REG_PC);
 	gdb_tx_char(';');
-	gdb_tx_reg(GDB_REG_FP);
-	gdb_tx_char(';');
-	gdb_tx_reg(GDB_REG_SP);
-	gdb_tx_char(';');
 	gdb_tx_str("thread:");
 	gdb_tx_varhex(kdb_thread->td_tid);
 	gdb_tx_char(';');
@@ -121,14 +118,21 @@
 			gdb_tx_hex(gdb_cpu_signal(type, code), 2);
 			gdb_tx_end();
 			break;
-		case 'c':	/* continue */
+		case 'c': {	/* continue */
+			uintmax_t addr;
 			if (!gdb_rx_varhex(&addr))
 				gdb_cpu_setreg(GDB_REG_PC, addr);
 			kdb_cpu_clear_singlestep();
 			return (1);
-		case 'g':
-			gdb_tx_regs();
+		}
+		case 'g': {
+			size_t r;
+			gdb_tx_begin(0);
+			for (r = 0; r < GDB_NREGS; r++)
+				gdb_tx_reg(r);
+			gdb_tx_end();
 			break;
+		}
 		case 'G':
 			gdb_tx_err(0);
 			break;
@@ -144,13 +148,18 @@
 		case 'k':
 			kdb_cpu_clear_singlestep();
 			return (1);
-		case 'm':
+		case 'm': {
+			uintmax_t addr, size;
 			if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
-			    gdb_rx_varhex(&size))
+			    gdb_rx_varhex(&size)) {
 				gdb_tx_err(EINVAL);
-			else
-				gdb_tx_memory((char *)(uintptr_t)addr, size);
+				break;
+			}
+			gdb_tx_begin(0);
+			gdb_tx_mem((char *)(uintptr_t)addr, size);
+			gdb_tx_end();
 			break;
+		}
 		case 'M':
 			gdb_tx_err(0);
 			break;
@@ -177,11 +186,13 @@
 			} else
 				gdb_tx_empty();
 			break;
-		case 's':	/* single step */
+		case 's': {	/* single step */
+			uintmax_t addr;
 			if (!gdb_rx_varhex(&addr))
 				gdb_cpu_setreg(GDB_REG_PC, addr);
 			kdb_cpu_set_singlestep();
 			return (1);
+		}
 		case -1:
 			/* Empty command. Treat as unknown command. */
 			/* FALLTHROUGH */

==== //depot/projects/gdb/sys/gdb/gdb_packet.c#6 (text+ko) ====

@@ -226,39 +226,30 @@
 	return (0);
 }
 
-int
-gdb_tx_memory(const unsigned char *addr, size_t size)
+void
+gdb_tx_mem(const unsigned char *addr, size_t size)
 {
 
-	if (size > (sizeof(gdb_txbuf) << 1))
-		return (gdb_tx_err(ENOSPC));
-	gdb_tx_begin(0);
 	while (size-- > 0) {
 		*gdb_txp++ = N2C(*addr >> 4);
 		*gdb_txp++ = N2C(*addr & 0x0f);
 		addr++;
 	}
-	*gdb_txp = 0;
-	printf("`%s'\n", gdb_txbuf);
-	return (gdb_tx_end());
 }
 
 void
 gdb_tx_reg(int regnum)
 {
+	unsigned char *regp;
+	size_t regsz;
 
-	gdb_tx_varhex(regnum);
-	gdb_tx_char(':');
-	gdb_tx_hex(gdb_cpu_getreg(regnum), gdb_cpu_regsz(regnum) << 1);
-}
-
-int
-gdb_tx_regs(void)
-{
-	ssize_t regsz;
-
-	regsz = gdb_cpu_getregs(gdb_rxbuf, sizeof(gdb_rxbuf));
-	if (regsz < 0)
-		return (gdb_tx_err(ENOSPC));
-	return (gdb_tx_memory(gdb_rxbuf, regsz));
+	regp = gdb_cpu_getreg(regnum, &regsz);
+	if (regp == NULL) {
+		/* Register unavailable. */
+		while (regsz--) {
+			gdb_tx_char('x');
+			gdb_tx_char('x');
+		}
+	} else
+		gdb_tx_mem(regp, regsz);
 }

==== //depot/projects/gdb/sys/i386/i386/gdb_machdep.c#5 (text+ko) ====

@@ -42,55 +42,38 @@
 
 #include <gdb/gdb.h>
 
-register_t
-gdb_cpu_getreg(int regnum)
+void *
+gdb_cpu_getreg(int regnum, size_t *regsz)
 {
-	struct trapframe *tf = kdb_thread->td_frame;
+	struct trapframe *tf = kdb_frame;
 
+	*regsz = gdb_cpu_regsz(regnum);
 	switch (regnum) {
-	case GDB_REG_FP: return (tf->tf_ebp);
-	case GDB_REG_PC: return (tf->tf_eip);
-	case GDB_REG_SP: return (tf->tf_esp);
+	case 0:  return (&tf->tf_eax);
+	case 1:  return (&tf->tf_ecx);
+	case 2:  return (&tf->tf_edx);
+	case 3:  return (&tf->tf_ebx);
+	case 4:  return (&tf->tf_esp);
+	case 5:  return (&tf->tf_ebp);
+	case 6:  return (&tf->tf_esi);
+	case 7:  return (&tf->tf_edi);
+	case 8:  return (&tf->tf_eip);
+	case 9:  return (&tf->tf_eflags);
+	case 10: return (&tf->tf_cs);
+	case 11: return (&tf->tf_ss);
+	case 12: return (&tf->tf_ds);
+	case 13: return (&tf->tf_es);
 	}
-	return (0);
+	return (NULL);
 }
 
-ssize_t
-gdb_cpu_getregs(void *buf, size_t bufsz)
-{
-	struct trapframe *tf = kdb_thread->td_frame;
-	struct reg *r = buf;
-
-	if (sizeof(*r) > bufsz)
-		return (-1);
-	r->r_cs = tf->tf_cs;
-	r->r_ds = tf->tf_ds;
-	r->r_eax = tf->tf_eax;
-	r->r_ebp = tf->tf_ebp;
-	r->r_ebx = tf->tf_ebx;
-	r->r_ecx = tf->tf_ecx;
-	r->r_edi = tf->tf_edi;
-	r->r_edx = tf->tf_edx;
-	r->r_eflags = tf->tf_eflags;
-	r->r_eip = tf->tf_eip;
-	r->r_es = tf->tf_es;
-	r->r_esi = tf->tf_esi;
-	r->r_esp = tf->tf_esp;
-	r->r_fs = tf->tf_fs;
-	r->r_gs = 0;
-	r->r_ss = tf->tf_ss;
-	return (sizeof(*r));
-}
-
 void
 gdb_cpu_setreg(int regnum, register_t val)
 {
-	struct trapframe *tf = kdb_thread->td_frame;
+	struct trapframe *tf = kdb_frame;
 
 	switch (regnum) {
-	case GDB_REG_FP: tf->tf_ebp = val; break;
 	case GDB_REG_PC: tf->tf_eip = val; break;
-	case GDB_REG_SP: tf->tf_esp = val; break;
 	}
 }
 

==== //depot/projects/gdb/sys/i386/i386/intr_machdep.c#2 (text+ko) ====

@@ -147,6 +147,7 @@
 	int error, vector;
 
 	td = curthread;
+	td->td_last_frame = INTR_TO_TRAPFRAME(iframe);
 	td->td_intr_nesting_level++;
 
 	/*

==== //depot/projects/gdb/sys/i386/i386/trap.c#6 (text+ko) ====

@@ -188,6 +188,7 @@
 
 	atomic_add_int(&cnt.v_trap, 1);
 	type = frame.tf_trapno;
+	td->td_last_frame = &frame;
 
 #ifdef KDB
 	if (kdb_active) {
@@ -929,6 +930,7 @@
 
 	sticks = td->td_sticks;
 	td->td_frame = &frame;
+	td->td_last_frame = &frame;
 	if (td->td_ucred != p->p_ucred) 
 		cred_update_thread(td);
 	if (p->p_flag & P_SA)

==== //depot/projects/gdb/sys/i386/include/gdb_machdep.h#4 (text+ko) ====

@@ -30,19 +30,16 @@
 #define	_MACHINE_GDB_MACHDEP_H_
 
 #define	GDB_BUFSZ	400
-
-#define	GDB_REG_FP	5
+#define	GDB_NREGS	14
 #define	GDB_REG_PC	8
-#define	GDB_REG_SP	4
 
-static __inline int
+static __inline size_t
 gdb_cpu_regsz(int regnum)
 {
-	return (4);		/* XXX not really. */
+	return (sizeof(int));
 }
 
-register_t gdb_cpu_getreg(int);
-ssize_t gdb_cpu_getregs(void *, size_t);
+void *gdb_cpu_getreg(int, size_t *);
 void gdb_cpu_setreg(int, register_t);
 int gdb_cpu_signal(int, int);
 

==== //depot/projects/gdb/sys/i386/include/kdb.h#2 (text+ko) ====

@@ -35,13 +35,13 @@
 static __inline void
 kdb_cpu_clear_singlestep(void)
 {
-	kdb_thread->td_frame->tf_eflags &= ~PSL_T;
+	kdb_frame->tf_eflags &= ~PSL_T;
 }
 
 static __inline void
 kdb_cpu_set_singlestep(void)
 {
-	kdb_thread->td_frame->tf_eflags |= PSL_T;
+	kdb_frame->tf_eflags |= PSL_T;
 }
 
 static __inline void

==== //depot/projects/gdb/sys/ia64/ia64/gdb_machdep.c#5 (text+ko) ====

@@ -40,43 +40,85 @@
 
 #include <gdb/gdb.h>
 
-register_t
-gdb_cpu_getreg(int regnum)
+void *
+gdb_cpu_getreg(int regnum, size_t *regsz)
 {
-	struct trapframe *tf = kdb_thread->td_frame;
+	struct trapframe *tf = kdb_frame;
+	static uint64_t bsp;
 
+	*regsz = gdb_cpu_regsz(regnum);
 	switch (regnum) {
-	case GDB_REG_FP:
-		return (tf->tf_special.bspstore + tf->tf_special.ndirty);
-	case GDB_REG_PC:
-		return (tf->tf_special.iip + ((tf->tf_special.psr >> 41) & 3));
-	case GDB_REG_SP:
-		return (tf->tf_special.sp);
+	/* Registers 0-127: general registers. */
+	case 1:  return (&tf->tf_special.gp);
+	case 2:  return (&tf->tf_scratch.gr2);
+	case 3:  return (&tf->tf_scratch.gr3);
+	case 8:  return (&tf->tf_scratch.gr8);
+	case 9:  return (&tf->tf_scratch.gr9);
+	case 10: return (&tf->tf_scratch.gr10);
+	case 11: return (&tf->tf_scratch.gr11);
+	case 12: return (&tf->tf_special.sp);
+	case 13: return (&tf->tf_special.tp);
+	case 14: return (&tf->tf_scratch.gr14);
+	case 15: return (&tf->tf_scratch.gr15);
+	case 16: return (&tf->tf_scratch.gr16);
+	case 17: return (&tf->tf_scratch.gr17);
+	case 18: return (&tf->tf_scratch.gr18);
+	case 19: return (&tf->tf_scratch.gr19);
+	case 20: return (&tf->tf_scratch.gr20);
+	case 21: return (&tf->tf_scratch.gr21);
+	case 22: return (&tf->tf_scratch.gr22);
+	case 23: return (&tf->tf_scratch.gr23);
+	case 24: return (&tf->tf_scratch.gr24);
+	case 25: return (&tf->tf_scratch.gr25);
+	case 26: return (&tf->tf_scratch.gr26);
+	case 27: return (&tf->tf_scratch.gr27);
+	case 28: return (&tf->tf_scratch.gr28);
+	case 29: return (&tf->tf_scratch.gr29);
+	case 30: return (&tf->tf_scratch.gr30);
+	case 31: return (&tf->tf_scratch.gr31);
+	/* Registers 128-255: floating-point registers. */
+	case 134: return (&tf->tf_scratch_fp.fr6);
+	case 135: return (&tf->tf_scratch_fp.fr7);
+	case 136: return (&tf->tf_scratch_fp.fr8);
+	case 137: return (&tf->tf_scratch_fp.fr9);
+	case 138: return (&tf->tf_scratch_fp.fr10);
+	case 139: return (&tf->tf_scratch_fp.fr11);
+	case 140: return (&tf->tf_scratch_fp.fr12);
+	case 141: return (&tf->tf_scratch_fp.fr13);
+	case 142: return (&tf->tf_scratch_fp.fr14);
+	case 143: return (&tf->tf_scratch_fp.fr15);
+	/* Registers 320-327: branch registers. */
+	case 320: return (&tf->tf_special.rp);
+	case 326: return (&tf->tf_scratch.br6);
+	case 327: return (&tf->tf_scratch.br7);
+	/* Registers 328-333: misc. other registers. */
+	case 330: return (&tf->tf_special.pr);
+	case 331: return (&tf->tf_special.iip);
+	case 332: return (&tf->tf_special.psr);
+	case 333: return (&tf->tf_special.cfm);
+	/* Registers 334-461: application registers. */
+	case 350: return (&tf->tf_special.rsc);
+	case 352: return (&tf->tf_special.bspstore);
+	case 353: return (&tf->tf_special.rnat);
+	case 359: return (&tf->tf_scratch.csd);
+	case 360: return (&tf->tf_scratch.ssd);
+	case 366: return (&tf->tf_scratch.ccv);
+	case 370: return (&tf->tf_special.unat);
+	case 374: return (&tf->tf_special.fpsr);
+	case 398: return (&tf->tf_special.pfs);
+	/* Synthesized registers. */
+	case 351:
+		bsp = tf->tf_special.bspstore + tf->tf_special.ndirty;
+		return (&bsp);
 	}
-	return (0);
+	return (NULL);
 }
 
-ssize_t
-gdb_cpu_getregs(void *buf, size_t bufsz)
-{
-	struct trapframe *tf = kdb_thread->td_frame;
-	struct reg *r = buf;
-
-	if (sizeof(*r) > bufsz)
-		return (-1);
-	r->r_special = tf->tf_special;
-	r->r_scratch = tf->tf_scratch;
-	bzero(&r->r_preserved, sizeof(r->r_preserved));
-	return (sizeof(*r));
-}
-
 void
 gdb_cpu_setreg(int regnum, register_t val)
 {
 
 	switch (regnum) {
-	case GDB_REG_FP: break;
 	case GDB_REG_PC: break;
-	case GDB_REG_SP: break;
 	}
 }

==== //depot/projects/gdb/sys/ia64/ia64/interrupt.c#3 (text+ko) ====

@@ -133,6 +133,7 @@
 	int count;
 
 	td = curthread;
+	td->td_last_frame = tf;
 	atomic_add_int(&td->td_intr_nesting_level, 1);
 
 	/*

==== //depot/projects/gdb/sys/ia64/ia64/trap.c#5 (text+ko) ====

@@ -365,6 +365,7 @@
 	atomic_add_int(&cnt.v_trap, 1);
 
 	td = curthread;
+	td->td_last_frame = tf;
 	p = td->td_proc;
 	ucode = 0;
 
@@ -901,9 +902,10 @@
 	atomic_add_int(&cnt.v_syscall, 1);
 
 	td = curthread;
+	td->td_frame = tf;
+	td->td_last_frame = tf;
 	p = td->td_proc;
 
-	td->td_frame = tf;
 	sticks = td->td_sticks;
 	if (td->td_ucred != p->p_ucred)
 		cred_update_thread(td);

==== //depot/projects/gdb/sys/ia64/include/gdb_machdep.h#4 (text+ko) ====

@@ -29,16 +29,15 @@
 #ifndef _MACHINE_GDB_MACHDEP_H_
 #define	_MACHINE_GDB_MACHDEP_H_
 
-#define	GDB_BUFSZ	4096
+#define GDB_NREGS	462
+#define	GDB_REG_PC	331
 
-#define	GDB_REG_FP	328
-#define	GDB_REG_PC	331
-#define	GDB_REG_SP	12
+#define	GDB_BUFSZ	(GDB_NREGS*16+128*16)
 
-static __inline int
+static __inline size_t
 gdb_cpu_regsz(int regnum)
 {
-	return (8);	/* XXX not really. */
+	return ((regnum >= 128 && regnum < 256) ? 16 : 8);
 }
 
 static __inline int
@@ -47,8 +46,7 @@
 	return (vector);
 }
 
-register_t gdb_cpu_getreg(int);
-ssize_t gdb_cpu_getregs(void *, size_t);
+void *gdb_cpu_getreg(int, size_t *);
 void gdb_cpu_setreg(int, register_t);
 
 #endif /* !_MACHINE_GDB_MACHDEP_H_ */

==== //depot/projects/gdb/sys/ia64/include/kdb.h#2 (text+ko) ====

@@ -47,8 +47,8 @@
 	__asm __volatile("flushrs;;");
 
 	if (vector == IA64_VEC_BREAK &&
-	    kdb_thread->td_frame->tf_special.ifa == IA64_FIXED_BREAK)
-                kdb_thread->td_frame->tf_special.psr += IA64_PSR_RI_1;
+	    kdb_frame->tf_special.ifa == IA64_FIXED_BREAK)
+                kdb_frame->tf_special.psr += IA64_PSR_RI_1;
 }
 
 #endif /* _MACHINE_KDB_H_ */

==== //depot/projects/gdb/sys/kern/subr_kdb.c#9 (text+ko) ====

@@ -40,6 +40,7 @@
 int kdb_active = 0;
 struct kdb_dbbe *kdb_dbbe = NULL;
 struct thread *kdb_thread = NULL;
+struct trapframe *kdb_frame = NULL;
 
 KDB_BACKEND(null, NULL, NULL, NULL);
 SET_DECLARE(kdb_dbbe_set, struct kdb_dbbe);
@@ -165,8 +166,12 @@
 	p = LIST_FIRST(&allproc);
 	while (p != NULL && p->p_pid != tid)
 		p = LIST_NEXT(p, p_list);
-	if (p != NULL)
+	if (p != NULL) {
 		kdb_thread = FIRST_THREAD_IN_PROC(p);
+		kdb_frame = kdb_thread->td_last_frame;
+		if (kdb_frame == NULL)
+			kdb_frame = kdb_thread->td_frame;
+	}
 	return ((p != NULL) ? 1 : 0);
 }
 
@@ -186,7 +191,7 @@
 
 	kdb_active++;
 	kdb_thread = curthread;
-	kdb_thread->td_frame = tf;
+	kdb_frame = tf;
 
 #ifdef SMP
 	stop_cpus(PCPU_GET(other_cpus));

==== //depot/projects/gdb/sys/sys/kdb.h#7 (text+ko) ====

@@ -56,6 +56,7 @@
 extern int kdb_active;			/* Non-zero while in debugger. */
 extern struct kdb_dbbe *kdb_dbbe;	/* Default debugger backend or NULL. */
 extern struct thread *kdb_thread;	/* Current thread. */
+extern struct trapframe *kdb_frame;	/* Current frame. */
 
 int	kdb_alt_break(int, int *);
 void	kdb_backtrace(void);

==== //depot/projects/gdb/sys/sys/proc.h#5 (text+ko) ====

@@ -275,6 +275,7 @@
 	int		td_inhibitors;	/* (j) Why can not run. */
 	int		td_pflags;	/* (k) Private thread (TDP_*) flags. */
 	int		td_tid;		/* XXX currently unused. */
+	struct trapframe *td_last_frame;
 	struct kse	*td_last_kse;	/* (j) Previous value of td_kse. */
 	struct kse	*td_kse;	/* (j) Current KSE if running. */
 	int		td_dupfd;	/* (k) Ret value from fdopen. XXX */


More information about the p4-projects mailing list