/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*/
/*
* This file provides a general purpose mechanism
* for a user thread to walk its own call stack,
* calling a user-specified iterator function for each
* stack frame. Special handling is provided to indicate
* kernel-constructed signal handler frames.
*
*
* A signal handler frame is essentially a set of data pushed on to the user
* stack by the kernel prior to returning to the user program in one of the
* pre-defined signal handlers. The signal handler itself receives the signal
* number, an optional pointer to a siginfo_t, and a pointer to the interrupted
* ucontext as arguments.
*
* When performing a stack backtrace, we would like to
* detect these frames so that we can correctly return the interrupted program
* counter and frame pointer as a separate frame.
*
* The stack layout for a signal handler frame is as follows:
*
* +--------------+ - high +--------------+ -
* | struct fq | ^ addrs | siginfo_t | ^
* +--------------+ | ^ +--------------+ optional
* | gwindows_t | | | xregs data | v
* +--------------+ optional +--------------+ -
* | siginfo_t | | ucontext_t | ^
* +--------------+ | | +--------------+ |
* | xregs data | v v | ucontext_t * | |
* +--------------+ - low +--------------+
* | ucontext_t | ^ addrs | siginfo_t * | mandatory
* +--------------+ mandatory +--------------+
* | struct frame | v | int (signo) | |
* +--------------+ - <- %sp on resume +--------------+ |
* | struct frame | v
* +--------------+ - <- %esp on resume
* amd64 (64-bit)
* +--------------+ -
* | siginfo_t | ^
* +--------------+ optional
* | xregs data | v
* +--------------+ -
* | ucontext_t | ^
* +--------------+ |
* | siginfo_t * |
* +--------------+ mandatory
* | int (signo) |
* +--------------+ |
* | struct frame | v
* +--------------+ - <- %rsp on resume
*
* The bottom-most struct frame is actually constructed by the kernel by
* copying the previous stack frame, allowing naive backtrace code to simply
* skip over the interrupted frame. The copied frame is never really used,
* since it is presumed the signal handler wrapper function
* will explicitly setcontext(2) to the interrupted context if the user
* program's handler returns. If we detect a signal handler frame, we simply
* read the interrupted context structure from the stack, use its embedded
* gregs to construct the register set for the interrupted frame, and then
* continue our backtrace. Detecting the frame itself is easy according to
* the diagram ("oldcontext" represents any element in the uc_link chain):
*
* On SPARC v7 or v9:
* %fp + sizeof (struct frame) == oldcontext
*
* On i386:
* %ebp + sizeof (struct frame) + (3 words) == oldcontext
*
* On amd64:
* %rbp + sizeof (struct frame) + (2 words) == oldcontext
*
* Since we want to provide the signal number that generated a signal stack
* frame and on sparc this information isn't written to the stack by the kernel
* the way it's done on i386, we're forced to read the signo from the stack as
* one of the arguments to the signal handler. We use the thr_sighndlrinfo
* interface to find the correct frame.
*/
#include "lint.h"
#include <assert.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
#include <procfs.h>
#include <strings.h>
#include <signal.h>
#include <thread.h>
#include <ucontext.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <alloca.h>
#include <limits.h>
#include <stdlib.h>
#ifdef _LP64
#define _ELF64
#endif
#if defined(__sparc)
== (oldctx))
2 * sizeof (long) == (oldctx)) && \
3 * sizeof (int) == (oldctx)) && \
#else
#endif
/*
* die in the case of a stack smash
*/
static int
{
return (-1); /* misaligned */
return (-1);
/*
* handle stack bias on sparcv9
*/
if (newfp != 0)
newfp += STACK_BIAS;
return (0);
}
int
void *usrarg)
{
int fd;
int sig;
#if defined(__sparc)
int signo = 0;
#endif
/*
* snag frame point from ucontext... we'll see caller of
* getucontext since we'll start by working up the call
* stack by one
*/
/*
* Since we don't write signo to the stack on sparc, we need
* to extract signo from the stack frames.
* An awkward interface is provided for this purpose:
* thr_sighndlrinfo; this is documented in
* returns the PC of a special function (and its size) that
* will be present in the stack frame if a signal was
* delivered and will have the following signature
* __sighndlr(int sig, siginfo_t *si, ucontex_t *uc,
* void (*hndlr)())
* Since this function is written in assembler and doesn't
* perturb its registers, we can then read sig out of arg0
* when the saved pc is inside this function.
*/
#if defined(__sparc)
int special_size = 0;
#endif /* sparc */
return (-1);
sig = 0;
/*
* get value of saved fp and pc w/o crashing
*/
return (-1);
}
break;
/*
* note that the following checks to see if we've got a
* special signal stack frame present; this allows us to
* detect signals and pass that info to the user stack walker
*/
/*
* i386 and amd64 store signo on stack;
* simple to detect and use
*/
#endif
#if defined(__sparc)
/*
* In the case of threads, since there are multiple
* complex routines between kernel and user handler,
* we need to figure out where we can read signal from
* using thr_sighndlrinfo - which we've already done
* for this signal, since it appeared on the stack
* before the signal frame.... sigh.
*/
#endif
/*
* this is the special signal frame, so cons up
* the saved fp & pc to pass to user's function
*/
}
#if defined(__sparc)
/*
* lookahead code to find right spot to read signo from...
*/
(special_pc + special_size))
#endif
/*
* call user-supplied function and quit if non-zero return.
*/
break;
}
return (0);
}
/*
* async safe version of fprintf
*/
static void
{
}
/*
* print out stack frame info
*/
static int
{
if (signo) {
sigbuf[0] = '?';
sigbuf[1] = 0;
} else
return (0);
}
/*
* walk current thread stack, writing symbolic stack trace to specified fd
*/
int
{
ucontext_t u;
if (getcontext(&u) < 0)
return (-1);
}
/*
* Some routines for better opensource compatibility w/ glibc.
*/
typedef struct backtrace {
void **bt_buffer;
int bt_maxcount;
int bt_actcount;
} backtrace_t;
/* ARGSUSED */
static int
{
return (-1);
return (0);
}
/*
* dump stack trace up to length count into buffer
*/
int
{
ucontext_t u;
bt.bt_actcount = 0;
if (getcontext(&u) < 0)
return (0);
return (bt.bt_actcount);
}
/*
* format backtrace string
*/
int
{
RTLD_DL_SYMENT) == 0) {
}
/*
* we have containing symbol info
*/
pc));
} else {
/*
* no local symbol info
*/
pc));
}
}
/*
* This function returns the symbolic representation of stack trace; calls
* malloc so it is NOT async safe! A rather mis-designed and certainly misused
* interface.
*/
char **
{
char **ret_buffer;
char **ret;
int i;
/*
* tmp buffer to hold strings while finding all symbol names
*/
for (i = 0; i < size; i++) {
}
/*
* allocate total amount of storage required and copy strings
*/
return (NULL);
}
return (ret);
}
/*
* Write out symbolic stack trace in an async-safe way.
*/
void
{
int i;
int len;
for (i = 0; i < size; i++) {
sizeof (linebuffer) - 1);
if (len >= sizeof (linebuffer))
}
}