unsigned num;
db_expr_t num;
db_stack_trace_print(db_regs_t *addr,		   int have_addr,		   db_expr_t count,		   char *modif,		   int (*pr)(const char *, ...)){	enum {		Default, Stack, Frame	} style = Default;	db_regs_t frame; /* a m88100_saved_state */	db_regs_t *regs;	union {		db_regs_t *frame;		unsigned num;	} arg;	arg.frame = addr;	trace_flags = 0; /* flags will be set via modifers */	while (modif && *modif) {		switch (*modif++) {		case 'd':#ifdef TRACE_DEBUG			trace_flags |= TRACE_DEBUG_FLAG;#else			db_printtf("<debug trace not compiled in, ignoring>\n");#endif			break;		case 's': style = Stack  ; break;		case 'f': style = Frame  ; break;		case 'p': trace_flags |= TRACE_SHOWCALLPRESERVED_FLAG; break;		case 'a': trace_flags |= TRACE_SHOWADDRESS_FLAG; break;		case 'F': trace_flags |= TRACE_SHOWFRAME_FLAG; break;		case 'u': trace_flags |= TRACE_USER_FLAG; break;		default:			(*pr)("unknown trace modifier [%c]\n", modif[-1]);			/*FALLTHROUGH*/		case 'h':			(*pr)("usage: trace/[MODIFIER]  [ARG]\n");			(*pr)("  u = include user trace\n");			(*pr)("  F = print stack frames\n");			(*pr)("  a = show return addresses\n");			(*pr)("  p = show call-preserved registers\n");			(*pr)("  s = ARG is a stack pointer\n");			(*pr)("  f = ARG is a frame pointer\n");#ifdef TRACE_DEBUG			(*pr)("  d = trace-debugging output\n");#endif			return;		}	}	if (!have_addr && style != Default) {		(*pr)("expecting argument with /s or /f\n");		return;	}	if (have_addr && style == Default)		style = Frame;	switch (style) {	case Default:		regs = DDB_REGS;		break;	case Frame:		regs = arg.frame;		break;	case Stack:		{			unsigned val1, val2, sxip;			unsigned ptr;			bzero((void *)&frame, sizeof(frame));#define REASONABLE_FRAME_DISTANCE 2048			/*			 * We've got to find the top of a stack frame so we can get both			 * a PC and and real SP.			 */			for (ptr = arg.num;/**/; ptr += 4) {				/* Read a word from the named stack */				if (db_trace_get_val(ptr, &val1) == 0) {					(*pr)("can't read from %x, aborting.\n", ptr);					return;				}				/*				 * See if it's a frame pointer.... if so it will be larger than				 * the address it was taken from (i.e. point back up the stack)				 * and we'll be able to read where it points.				 */				if (val1 <= ptr ||				    (val1 & 3)  ||				    val1 > (ptr + REASONABLE_FRAME_DISTANCE))					continue;				/* peek at the next word to see if it could be a return address */				if (db_trace_get_val(ptr, &sxip) == 0) {					(*pr)("can't read from %x, aborting.\n", ptr);					return;				}				if (sxip == 0 || !db_trace_get_val(sxip, &val2))					continue;				if (db_trace_get_val(val1, &val2) == 0) {					(*pr)("can't read from %x, aborting.\n", val1);					continue;				}				/*				 * The value we've just read will be either another frame pointer,				 * or the start of another exception frame.				 */				if (#ifdef JEFF_DEBUG				   val2 == 0#else				   val2 == 0x12345678#endif				   && db_trace_get_val(val1-4, &val2) && val2 == val1				   && db_trace_get_val(val1-8, &val2) && val2 == val1) {					/* we've found a frame, so the stack must have been good */					(*pr)("%x looks like a frame, accepting %x\n",val1,ptr);					break;				}				if (val2 > val1 && (val2 & 3) == 0) {					/* well, looks close enough to be another frame pointer */					(*pr)("*%x = %x looks like a stack frame pointer, accepting %x\n", val1, val2, ptr);					break;				}			}                        frame.r[31] = ptr;			frame.epsr = 0x800003f0U;			if (cputyp != CPU_88110) {				frame.sxip = sxip | 2;				frame.snip = frame.sxip + 4;				frame.sfip = frame.snip + 4;			}			(*pr)("[r31=%x, %sxip=%x]\n", frame.r[31],				  cputyp == CPU_88110 ? "e" : "s", frame.sxip);			regs = &frame;		}	}	db_stack_trace_cmd2(regs, pr);}