#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