#if defined(sun) && defined(_XOPEN_XPG3)
// ---------------------
// - SUN -
// ---------------------
// Written with the help of barts@Eng.Sun.COM (Bart Smaalders)
// This works on Solaris 2.4 and higher (sparc, x86 and PPC)
#include <ctype.h>
#define __EXTENSIONS__
#include <dlfcn.h>
#undef __EXTENSIONS__
#include <setjmp.h>
#include <sys/frame.h>
#include <demangle.h>
#include <string.h>
#if defined(sparc) || defined(__sparc)
#define FLUSHWIN() asm("ta 3");
#define FRAME_PTR_INDEX 1
#define SKIP_FRAMES 0
#endif
#if defined(i386) || defined(__i386) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__)
#define FLUSHWIN()
#define FRAME_PTR_INDEX 3
#define SKIP_FRAMES 1
#endif
#if defined(ppc) || defined(__ppc)
#define FLUSHWIN()
#define FRAME_PTR_INDEX 0
#define SKIP_FRAMES 2
#endif
static void erDumpCurrentLevel(std::ostream &strm,
const char *library,
const char *function,
unsigned long offset)
{
char dem[1024];
#if defined(_DEMANGLE_H)
// this is CC4.1
int s = cplus_demangle((char*)function,dem,1024);
#else // _DEMANGLE_H
// this is CC4.0.1
int s = demangle((char*)function,dem);
#endif // _DEMANGLE_H
if (s!=0) strcpy(dem,function);
strm << dem
<< " + 0x" << std::hex << offset << std::dec
<< " [";
const char *c = library;
while (isprint(*c)) {
strm << *c;
c++;
}
strm << "]\n" << std::flush;
}
void erDumpStack(std::ostream &strm,
unsigned int numberOfIgnoredLevels)
{
FLUSHWIN();
jmp_buf buf;
(void)setjmp(buf);
int *cast=(int*)buf;
struct frame *sp=(struct frame *)cast[FRAME_PTR_INDEX];
#if SKIP_FRAMES>0
for ( int i=0 ; i<SKIP_FRAMES && sp ; i++ ) sp=sp->fr_savfp;
#endif
int incr=0;
while ( sp && sp->fr_savpc ) {
incr++;
Dl_info info;
const char *function,*library;
if (dladdr((void*)sp->fr_savpc,&info)) {
function=info.dli_sname;
library=info.dli_fname;}
else {
function=library="?";}
unsigned long offset=sp->fr_savpc-(unsigned long)info.dli_saddr;
if (incr>numberOfIgnoredLevels) {
erDumpCurrentLevel(strm,library,function,offset);}
sp=sp->fr_savfp;}
}
#elif defined(sgi)
// ---------------------
// - SGI -
// ---------------------
#include <stdlib.h>
#include <stdio.h>
#include <sym.h>
#include <dem.h>
#include <setjmp.h>
// beginning of hack - see end(3C) man page
extern int _procedure_table[];
extern int _procedure_table_size[];
extern int _procedure_string_table[];
extern int _ftext[];
extern int _etext[];
// end of hack - see end(3C) man page
static struct runtime_pdr* find_runtime_pdr(unsigned long pc)
{
struct runtime_pdr *p;
unsigned int base,limit,mid;
base=0;
limit=(int)_procedure_table_size-1;
while (base<=limit) {
mid=(base+limit)/2;
p=((struct runtime_pdr*)_procedure_table)+mid;
if (pc<p->adr) {
limit=mid-1;}
else if (pc>=(p+1)->adr) {
base=mid+1;}
else {
return(p);};}
/*NOTREACHED*/
return(NULL);
}
static void erDumpCurrentLevel(std::ostream &strm,
const char *function,
unsigned long pc)
{
char dem[MAXDBUF];
(void)demangle(function,dem);
strm << dem << " pc=0x" << hex << pc << dec << '\n';
}
void erDumpStack(std::ostream &strm,
unsigned int numberOfIgnoredLevels)
{
jmp_buf jb;
struct runtime_pdr *p;
unsigned long pc; /* program counter */
char *sp; /* pointer stack */
setjmp(jb);
pc=jb[JB_PC];
sp=(char*)jb[JB_SP];
unsigned int incr=0;
while ((p=find_runtime_pdr(pc))!=NULL) {
incr++;
if (incr>numberOfIgnoredLevels) {
erDumpCurrentLevel(strm,(char*)_procedure_string_table+p->irpss,pc);}
sp+=p->frameoffset;
pc=((unsigned long *)sp)[p->regoffset>>2];
if ( pc<(unsigned long)_ftext || pc>=(unsigned long)_etext ) break;}
}
#elif defined(hpux)
// ---------------------
// - HP -
// ---------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dem.h>
#include <iomanip>
extern "C" void U_STACK_TRACE();
void erDumpStack(std::ostream &strm,
unsigned int numberOfIgnoredLevels)
{
// the undocumented routine U_STACK_TRACE dump the stack on stderr
// we patch it to dump in ostream
//
// SOME EXPLANATIONS:
// ------------------
// I use the fact that with POSIX, the file descriptor for a new open, dup,…
// will be the smallest available file descriptor. So, if we close the file
// descriptor 2 and open a FILE*, its file descriptor will be 2!
//
// We must keep a copy of errno in order to be able to restore it. Indeed, tmpfile
// and U_STACK_TRACE are modifying errno even if no failure happened.
const char *errorString="Cannot dump the stack\n";
const size_t buffer_size=1024;
int errno_copy=errno;
ostrstream oss;
/* flush stderr */
(void)fflush(stderr);
/* keep a copy of stderr */
int dup_stderr=dup(2);
if (dup_stderr==-1) {
errno=errno_copy;
strm << errorString;
return;}
/* close the initial stderr */
if (close(2)==-1) {
(void)close(dup_stderr);
errno=errno_copy;
strm << errorString;
return;}
/* redirect file descriptor 2 toward a temporary file */
FILE *tmp_file=tmpfile();
if (tmp_file==NULL) {
(void)dup(dup_stderr); // restore fd 2 toward stderr
(void)close(dup_stderr);
errno=errno_copy;
strm << errorString;
return;}
/* dump the stack */
U_STACK_TRACE();
/* copy the temporary file in the iostream */
rewind(tmp_file);
char buffer[buffer_size];
int incr=0;
while (fgets(buffer,buffer_size,tmp_file)) {
incr++;
if (incr>numberOfIgnoredLevels) {
int stack_depth;
long address,offset;
char function[buffer_size],library[buffer_size];
if (sscanf(buffer,"(%d) 0x%lx %s + 0x%lx [%s]",
&stack_depth,&address,&function,&offset,&library)!=5) {
// cannot parse the line -> we copy it like it is
oss << buffer;}
else {
// unmangle the name
char dem[MAXDBUF];
(void)demangle(function,dem);
oss << "(" << stack_depth << ") "
<< "0x" << hex << address << dec
<< " "
<< dem
<< " + "
<< "0x" << hex << offset << dec
<< " "
<< "[" << library << "]"
<< '\n';};};}
/* destroy the temporay file */
(void)fclose(tmp_file);
/* redirect file descriptior 2 toward stderr */
(void)dup(dup_stderr);
/* close the copy */
(void)close(dup_stderr);
// On HP, the end-of-string character is not put at the end of ostrstreams.
oss << '\0';
/* Do the stack dump on the stream */
strm << oss.str();
delete [] oss.str();
errno=errno_copy;
}
#elif defined(linux)
// ---------------------
// - Linux -
// ---------------------
#include <execinfo.h>
#include <stdlib.h>
void erDumpStack(std::ostream &strm,
unsigned int numberOfIgnoredLevels)
{
void *array[128];
size_t size = backtrace(array,sizeof(array)/sizeof(array[0]));
char **strings = backtrace_symbols(array, size);
for (size_t i = numberOfIgnoredLevels; i < size; i++) strm << strings[i] << "\n";
free(strings);
}
#else
// -----------------------------------
// - other architecture -
// -----------------------------------
void erDumpStack(std::ostream &strm,
unsigned int)
{
strm << "Sorry! Do not know how to dump the stack on this architecture\n" << flush;
}
#endif
|