Example #1
0
/*ARGSUSED*/
void
dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
    uint32_t *ignored)
{
	int	depth;
#if !defined(HAVE_STACKTRACE_OPS)
	/***********************************************/
	/*   This  is  a basic stack walker - we dont  */
	/*   care  about  omit-frame-pointer,  and we  */
	/*   can  have  false positives. We also dont  */
	/*   handle  exception  stacks properly - but  */
	/*   this  is  for  older  kernels, where the  */
	/*   kernel  wont  help  us,  so they may not  */
	/*   have exception stacks anyhow.	       */
	/***********************************************/

	cpu_core_t	*this_cpu = cpu_get_this();
	struct pt_regs *regs = this_cpu->cpuc_regs;
	uintptr_t *sp = (uintptr_t *) &regs->r_rsp;
	uintptr_t *spend;
	
	if (regs == NULL)
		sp = (uintptr_t *) &depth;

	spend = sp + THREAD_SIZE / sizeof(uintptr_t);

	for (depth = 0; depth < pcstack_limit && sp < spend; ) {
		if (sp && is_kernel_text((unsigned long) *sp)) {
			pcstack[depth++] = *sp;
		}
		sp++;
	}
#else

	dmutex_enter(&dtrace_stack_mutex);
	g_depth = 0;
	g_pcstack = pcstack;
	g_pcstack_limit = pcstack_limit;

#if FUNC_DUMP_TRACE_ARGS == 6
	dump_trace(NULL, NULL, NULL, 0, &print_trace_ops, NULL);
#else
	dump_trace(NULL, NULL, NULL, &print_trace_ops, NULL);
#endif
	depth = g_depth;
	dmutex_exit(&dtrace_stack_mutex);
#endif

	while (depth < pcstack_limit)
		pcstack[depth++] = (pc_t) NULL;
}
Example #2
0
/*ARGSUSED*/
void
dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
                  uint32_t *ignored)
{
    int	depth;
#if !defined(HAVE_STACKTRACE_OPS)
    int	lim;
    /***********************************************/
    /*   This  is  a basic stack walker - we dont  */
    /*   care  about  omit-frame-pointer,  and we  */
    /*   can  have  false positives. We also dont  */
    /*   handle  exception  stacks properly - but  */
    /*   this  is  for  older  kernels, where the  */
    /*   kernel  wont  help  us,  so they may not  */
    /*   have exception stacks anyhow.	       */
    /***********************************************/

    /***********************************************/
    /*   20121125 Lets use this always - it avoid  */
    /*   kernel  specific  issues in the official  */
    /*   stack  walker and will give us a vehicle  */
    /*   later  for adding reliable vs guess-work  */
    /*   stack entries.			       */
    /***********************************************/
    cpu_core_t	*this_cpu = cpu_get_this();
    struct pt_regs *regs = this_cpu->cpuc_regs;
    struct thread_info *context;
    uintptr_t *sp;
    uintptr_t *spend;

    /***********************************************/
    /*   For   syscalls,  we  will  have  a  null  */
    /*   cpuc_regs,  since  we dont intercept the  */
    /*   trap,   but   instead  intercept  the  C  */
    /*   syscall function.			       */
    /***********************************************/
    if (regs == NULL)
        sp = (uintptr_t *) &depth;
    else
        sp = (uintptr_t *) regs->r_rsp;

    /***********************************************/
    /*   Daisy  chain the interrupt and any other  */
    /*   stacks.  Limit  ourselves in case of bad  */
    /*   corruptions.			       */
    /***********************************************/
    DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
    depth = 0;
    for (lim = 0; lim < 3 && depth < pcstack_limit; lim++) {
        int	ndepth = depth;
        uintptr_t *prev_esp;

        context = (struct thread_info *) ((unsigned long) sp & (~(THREAD_SIZE - 1)));
        spend = (uintptr_t *) ((unsigned long) sp | (THREAD_SIZE - 1));
        for ( ; depth < pcstack_limit && sp < spend; sp++) {
            if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
                goto end_stack;
            if (*sp && is_kernel_text((unsigned long) *sp)) {
                pcstack[depth++] = *sp;
            }
        }
        if (depth >= pcstack_limit || ndepth == depth)
            break;

        prev_esp = (uintptr_t *) ((char *) context + sizeof(struct thread_info));
        if ((sp = prev_esp) == NULL)
            break;
        /***********************************************/
        /*   Special signal to mark the IRQ stack.     */
        /***********************************************/
        if (depth < pcstack_limit) {
            pcstack[depth++] = 1;
        }
    }
end_stack:
    DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
    DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_FAULT);
#else

    /***********************************************/
    /*   I'm  a  little tired of the kernel dying  */
    /*   in  the  callback, so lets avoid relying  */
    /*   on the kernel stack walker.	       */
    /***********************************************/
    dmutex_enter(&dtrace_stack_mutex);
    g_depth = 0;
    g_pcstack = pcstack;
    g_pcstack_limit = pcstack_limit;

#if FUNC_DUMP_TRACE_ARGS == 6
    dump_trace(NULL, NULL, NULL, 0, &print_trace_ops, NULL);
#else
    dump_trace(NULL, NULL, NULL, &print_trace_ops, NULL);
#endif
    depth = g_depth;
    dmutex_exit(&dtrace_stack_mutex);
#endif

    while (depth < pcstack_limit)
        pcstack[depth++] = (pc_t) NULL;
}