Coherent4.2.10/i386/user_bt.c

Compare this file to the similar file:
Show the results in this format:

/*
 * user_bt.c - console display of user eip stack backtrace.
 */

#include <common/_gregset.h>
#include <sys/types.h>
#include <sys/cmn_err.h>

#define _KERNEL		1

#include <kernel/reg.h>
#include <sys/seg.h>
#include <sys/proc.h>
#include <sys/mmu.h>

extern	unsigned char	do_user_bt;

/* User backtrace. */
void
user_bt (regsetp)
gregset_t	* regsetp;
{
	unsigned	bp, next_bp;
	unsigned	text_addr;
	register SEG *	segp;
	unsigned	splo;
	unsigned	bt_limit;

	/* Only do the user backtrace stuff if the feature is enabled. */

	if (do_user_bt == 0)
		return;

	/* Only bother with COFF's - no l.out's for now. */

	if (__xmode_286 (regsetp)) {
		return;
	}

	/* Get user stack limits, to make sure we stay inside them. */

	segp = SELF->p_segl [SISTACK].sr_segp;
	splo = (unsigned) (__xmode_286 (regsetp) ? ISP_286 : ISP_386);
	splo -= segp->s_size;

	/* Print user eip. */

	cmn_err (CE_CONT, "User backtrace (COFF): %x ", regsetp->_i386._eip);

	/*
	 * Loop as long as it looks as if we're tracking user stack frame.
	 *
	 * User stack frames look like this:
	 *	...
	 *	arguments for function foo
	 *	return address on return from foo
	 * ebp->previous stack frame
	 *	...
	 */

	bp = (unsigned) (regsetp->_i386._ebp);

	for (bt_limit = 0 ; bt_limit < 50 ; bt_limit ++) {
		/* Stop backtrace if frame pointer aims outside stack. */
		if (bp < splo || bp >= 0x80000000)
			break;

		/* Fetch and print a return address. */
		if (copyin((caddr_t)(bp + 4), & text_addr, 4))
			break;
		cmn_err (CE_CONT, " -> %x", text_addr);
		
		/* Stop backtrace if text pointer goes out of range. */
		/* Sorry about the magic constants - hal */
		if (text_addr < 0xA8 || text_addr >= 0x400000)
			break;

		/* Advance to the next older stack frame. */
		if (copyin((caddr_t) bp, & next_bp, 4))
			break;

		/* Stop backtrace if frame pointer goes down instead of up. */
		if (next_bp <= bp)
			break;

		bp = next_bp;
	}
	if (bt_limit == 50)
		cmn_err (CE_CONT, " ... (there's more)");

	cmn_err (CE_CONT, "\n");
}