FreeBSD/sys/dev/hwpmc/hwpmc_x86.c
/*
 * Attempt to walk a user call stack using a too-simple algorithm.
 * In the general case we need unwind information associated with
 * the executable to be able to walk the user stack.
 *
 * We are handed a trap frame laid down at the time the PMC interrupt
 * was taken.  If the application is using frame pointers, the saved
 * PC value could be:
 * a. at the beginning of a function before the stack frame is laid
 *    down,
 * b. just before a 'ret', after the stack frame has been taken off,
 * c. somewhere else in the function with a valid stack frame being
 *    present,
 *
 * If the application is not using frame pointers, this algorithm will
 * fail to yield an interesting call chain.
 *
 * TODO: figure out a way to use unwind information.
 */
Attempt to walk a user call stack using a too-simple algorithm.
In the general case we need unwind information associated with
the executable to be able to walk the user stack.

We are handed a trap frame laid down at the time the PMC interrupt
was taken.  If the application is using frame pointers, the saved
PC value could be:
a. at the beginning of a function before the stack frame is laid
down,
b. just before a 'ret', after the stack frame has been taken off,
c. somewhere else in the function with a valid stack frame being
present.

If the application is not using frame pointers, this algorithm will
fail to yield an interesting call chain.

figure out a way to use unwind information.
Attempt to walk a user call stack using a too - simple algorithm . In the general case we need unwind information associated with the executable to be able to walk the user stack . We are handed a trap frame laid down at the time the PMC interrupt was taken . If the application is using frame pointers the saved PC value could be : a . at the beginning of a function before the stack frame is laid down b . just before a ' ret ' after the stack frame has been taken off c . somewhere else in the function with a valid stack frame being present . If the application is not using frame pointers this algorithm will fail to yield an interesting call chain . figure out a way to use unwind information .
int
pmc_save_user_callchain(uintptr_t *cc, int nframes, struct trapframe *tf)
{
	int n;
	uint32_t instr;
	uintptr_t fp, oldfp, pc, r, sp;
	KASSERT(TRAPF_USERMODE(tf), ("[x86,%d] Not a user trap frame tf=%p",
	    __LINE__, (void *) tf));
	pc = PMC_TRAPFRAME_TO_PC(tf);
	oldfp = fp = PMC_TRAPFRAME_TO_FP(tf);
	sp = PMC_TRAPFRAME_TO_USER_SP(tf);
	*cc++ = pc; n = 1;
	r = fp + sizeof(uintptr_t); 
	if (!PMC_IN_USERSPACE(pc))
		return (n);
	if (copyin((void *) pc, &instr, sizeof(instr)) != 0)
		return (n);
	if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) ||
	    PMC_AT_FUNCTION_EPILOGUE_RET(instr)) { 
		if (copyin((void *) sp, &pc, sizeof(pc)) != 0)
			return (n);
	} else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) {
		sp += sizeof(uintptr_t);
		if (copyin((void *) sp, &pc, sizeof(pc)) != 0)
			return (n);
	} else if (copyin((void *) r, &pc, sizeof(pc)) != 0 ||
	    copyin((void *) fp, &fp, sizeof(fp)) != 0)
		return (n);
	for (; n < nframes;) {
		if (pc == 0 || !PMC_IN_USERSPACE(pc))
			break;
		*cc++ = pc; n++;
		if (fp < oldfp)
			break;
		r = fp + sizeof(uintptr_t); 
		oldfp = fp;
		if (copyin((void *) r, &pc, sizeof(pc)) != 0 ||
		    copyin((void *) fp, &fp, sizeof(fp)) != 0)
			break;
	}
	return (n);
}
int pmc_save_user_callchain ( uintptr_t * cc , int nframes , struct trapframe * tf ) { int n ; uint32_t instr ; uintptr_t fp , oldfp , pc , r , sp ; KASSERT ( TRAPF_USERMODE ( tf ) , ( " " , __LINE__ , ( void * ) tf ) ) ; pc = PMC_TRAPFRAME_TO_PC ( tf ) ; oldfp = fp = PMC_TRAPFRAME_TO_FP ( tf ) ; sp = PMC_TRAPFRAME_TO_USER_SP ( tf ) ; * cc ++ = pc ; n = 1 ; r = fp + sizeof ( uintptr_t ) ; if ( ! PMC_IN_USERSPACE ( pc ) ) return ( n ) ; if ( copyin ( ( void * ) pc , & instr , sizeof ( instr ) ) != 0 ) return ( n ) ; if ( PMC_AT_FUNCTION_PROLOGUE_PUSH_BP ( instr ) || PMC_AT_FUNCTION_EPILOGUE_RET ( instr ) ) { if ( copyin ( ( void * ) sp , & pc , sizeof ( pc ) ) != 0 ) return ( n ) ; } else if ( PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP ( instr ) ) { sp += sizeof ( uintptr_t ) ; if ( copyin ( ( void * ) sp , & pc , sizeof ( pc ) ) != 0 ) return ( n ) ; } else if ( copyin ( ( void * ) r , & pc , sizeof ( pc ) ) != 0 || copyin ( ( void * ) fp , & fp , sizeof ( fp ) ) != 0 ) return ( n ) ; for ( ; n < nframes ; ) { if ( pc == 0 || ! PMC_IN_USERSPACE ( pc ) ) break ; * cc ++ = pc ; n ++ ; if ( fp < oldfp ) break ; r = fp + sizeof ( uintptr_t ) ; oldfp = fp ; if ( copyin ( ( void * ) r , & pc , sizeof ( pc ) ) != 0 || copyin ( ( void * ) fp , & fp , sizeof ( fp ) ) != 0 ) break ; } return ( n ) ; }
Attempt to walk a user call stack using a too-simple algorithm.
Attempt to walk a user call stack using a too - simple algorithm .
/* points to return address */ /* ret */ /* address of return address */