#include <mach/mach_types.h>
#include <machine/machine_routines.h>
#include <kern/thread.h>
#include <chud/chud_xnu.h>
#include <kperf/buffer.h>
#include <kperf/context.h>
#include <kperf/callstack.h>
#include <kperf/ast.h>
static void
callstack_sample( struct callstack *cs,
struct kperf_context *context,
uint32_t is_user )
{
kern_return_t kr;
mach_msg_type_number_t nframes;
uint32_t code;
if( is_user )
code = PERF_CS_USAMPLE;
else
code = PERF_CS_KSAMPLE;
BUF_INFO1( code, (uintptr_t)context->cur_thread );
cs->flags = 0;
if( !is_user )
{
cs->flags |= CALLSTACK_KERNEL;
#ifdef __LP64__
cs->flags |= CALLSTACK_64BIT;
#endif
}
else
{
}
nframes = MAX_CALLSTACK_FRAMES;
kr = chudxnu_thread_get_callstack64_kperf( context->cur_thread,
cs->frames,
&nframes,
is_user );
if( kr == KERN_SUCCESS )
{
cs->flags |= CALLSTACK_VALID;
cs->nframes = nframes;
}
else if( kr == KERN_RESOURCE_SHORTAGE )
{
cs->flags |= CALLSTACK_TRUNCATED;
cs->flags |= CALLSTACK_VALID;
cs->nframes = nframes;
}
else
{
BUF_INFO2(PERF_CS_ERROR, ERR_GETSTACK, kr);
cs->nframes = 0;
}
if( cs->nframes >= MAX_CALLSTACK_FRAMES )
{
BUF_INFO1(PERF_CS_ERROR, ERR_FRAMES);
cs->nframes = 0;
}
}
void
kperf_kcallstack_sample( struct callstack *cs, struct kperf_context *context )
{
callstack_sample( cs, context, 0 );
}
void
kperf_ucallstack_sample( struct callstack *cs, struct kperf_context *context )
{
callstack_sample( cs, context, 1 );
}
static void
callstack_log( struct callstack *cs, uint32_t hcode, uint32_t dcode )
{
unsigned int i, j, n, of = 4;
BUF_DATA2( hcode, cs->flags, cs->nframes );
n = cs->nframes / 4;
of = cs->nframes % 4;
if( of != 0 )
n++;
for( i = 0; i < n; i++ )
{
#define SCRUB_FRAME(x) (((x)<cs->nframes)?cs->frames[x]:0)
j = i * 4;
BUF_DATA ( dcode,
SCRUB_FRAME(j+0),
SCRUB_FRAME(j+1),
SCRUB_FRAME(j+2),
SCRUB_FRAME(j+3) );
#undef SCRUB_FRAME
}
}
void
kperf_kcallstack_log( struct callstack *cs )
{
callstack_log( cs, PERF_CS_KHDR, PERF_CS_KDATA );
}
void
kperf_ucallstack_log( struct callstack *cs )
{
callstack_log( cs, PERF_CS_UHDR, PERF_CS_UDATA );
}
int
kperf_ucallstack_pend( struct kperf_context * context )
{
return kperf_ast_pend( context->cur_thread, T_AST_CALLSTACK,
T_AST_CALLSTACK );
}