ATLAS Offline Software
Loading...
Searching...
No Matches
SealDebug.cxx File Reference
#include "CxxUtils/SealCommon.h"
#include "CxxUtils/SealDebug.h"
#include "CxxUtils/SealSignal.h"
#include "CxxUtils/UnwindBacktrace.h"
#include "CxxUtils/checker_macros.h"
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <climits>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/resource.h>

Go to the source code of this file.

Macros

#define STDERR_HANDLE   STDERR_FILENO
#define MYWRITE(fd, data, n)
#define MYWRITELIT(fd, str)

Functions

void DebugAids::stacktraceLine ATLAS_NOT_THREAD_SAFE (IOFD fd, unsigned long addr)
 Write out stack trace line to FD.
void DebugAids::setStackTraceAddr2Line ATLAS_NOT_THREAD_SAFE (const char *path)
void DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd)
 Produce a stack trace.

Macro Definition Documentation

◆ MYWRITE

#define MYWRITE ( fd,
data,
n )
Value:
write(fd,data,n)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11

◆ MYWRITELIT

#define MYWRITELIT ( fd,
str )
Value:
MYWRITE(fd,str,sizeof(str)-1)
#define MYWRITE(fd, data, n)

◆ STDERR_HANDLE

#define STDERR_HANDLE   STDERR_FILENO

Function Documentation

◆ ATLAS_NOT_THREAD_SAFE() [1/3]

void DebugAids::setStackTraceAddr2Line ATLAS_NOT_THREAD_SAFE ( const char * path)

Definition at line 582 of file SealDebug.cxx.

583{
584 addr2LinePath = path;
585}
path
python interpreter configuration --------------------------------------—
Definition athena.py:130

◆ ATLAS_NOT_THREAD_SAFE() [2/3]

void DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE ( IOFD fd)

Produce a stack trace.

Prints the current stack trace to file descriptor fd or if the default invalid descriptor, the currently registered stack trace descriptor as registered with #stacktraceFd(). Avoids unnecessary memory allocation so it should be safe to call this function even in dire situations. On some systems the implementation always outputs to the standard error and has no means for redirection. On these systems an attempt is made to redirect standard error momentarily elsewhere and then redirect standard error to the desired file descriptor, invoke the output, and redirect standard error back to its original location. If the redirection fails or the system has no stack tracing support, no stack trace is produced.

Definition at line 637 of file SealDebug.cxx.

638{
639 if (fd == IOFD_INVALID)
640 fd = stacktraceFd();
641
642 std::cerr.flush ();
643 fflush (stderr);
644
645#ifdef _WIN32
646 // FIXME: Autoload all these functions so users don't need to
647 // link in imagehlp.dll.
648 if (! SymInitialize (GetCurrentProcess (), NULL, TRUE))
649 {
650 MYWRITELIT (fd, ("failed to dump stack trace:"
651 " cannot get symbolic information\n"));
652 return;
653 }
654
655 union SYMBUFFER {
656 IMAGEHLP_SYMBOL sym;
657 BYTE buffer [ sizeof (IMAGEHLP_SYMBOL) + 512 ];
658 };
659
660 unsigned level = 0;
661 CONTEXT context;
662 STACKFRAME frame;
663 SYMBUFFER symbol;
664 IMAGEHLP_MODULE module;
665 char modulename [MAX_PATH];
666 DWORD section;
667 DWORD offset;
668 const int buf_size = 2*40+6; // ample for two 128+ bit numbers
669 char buf [buf_size];
670 // DWORD exceptargs [] = { (DWORD) &context };
671
672 // FIXME: XP 64-bit adds: RtlCaptureContext (&context);
673 // This is documented to *not* work, but apparently it does.
674 context.ContextFlags = CONTEXT_FULL;
675 if (! GetThreadContext (GetCurrentThread (), &context))
676 return;
677
678 // LPTOP_LEVEL_EXCEPTION_FILTER oldseh
679 // = SetUnhandledExceptionFilter (&GrabExceptionContext);
680 // RaiseException (0, 0, 1, exceptargs);
681 // SetUnhandledExceptionFilter (oldseh);
682
683 memset (&module, 0, sizeof (module));
684 memset (&frame, 0, sizeof (frame));
685
686 module.SizeOfStruct = sizeof (module);
687
688 frame.AddrPC.Offset = context.Eip;
689 frame.AddrPC.Mode = AddrModeFlat;
690 frame.AddrStack.Offset = context.Esp;
691 frame.AddrStack.Mode = AddrModeFlat;
692 frame.AddrFrame.Offset = context.Ebp;
693 frame.AddrFrame.Mode = AddrModeFlat;
694
695 while (true)
696 {
697 if (! StackWalk (IMAGE_FILE_MACHINE_I386,
698 GetCurrentProcess (),
699 GetCurrentThread (),
700 &frame,
701 &context,
702 NULL,
703 SymFunctionTableAccess,
704 SymGetModuleBase,
705 NULL)
706 || frame.AddrFrame.Offset == 0)
707 break;
708
709 // FIXME: Throw away everything above stacktrace? Keep looping
710 // below until the name includes something we understand?
711
712 // Print stack frame too? If we know how many arguments there
713 // are (from demangling function name -- see below, could count
714 // commas), args are: *((ULONG *)frame.AddrFrame.Offset+2+ARG).
715 MYWRITE (fd, buf, snprintf (buf, buf_size, "(%2u) 0x%08lx 0x%08lx ",
716 level, frame.AddrPC.Offset,
717 frame.AddrFrame.Offset));
718
719 memset (&symbol, 0, sizeof (symbol));
720 symbol.sym.SizeOfStruct = sizeof (symbol);
721 symbol.sym.MaxNameLength = sizeof (symbol) - sizeof (symbol.sym);
722
723 offset = 0;
724 if (SymGetSymFromAddr (GetCurrentProcess (), frame.AddrPC.Offset,
725 &offset, &symbol.sym))
726 {
727 // FIXME: Demangle name with:
728 // UnDecorateSymbolName (name, undecname, sizeof (undecname),
729 // UNDNAME_COMPLETE
730 // | UNDNAME_NO_THISTYPE
731 // | UNDNAME_NO_SPECIAL_SYMS
732 // | UNDNAME_NO_MEMBER_TYPE
733 // | UNDNAME_NO_MS_KEYWORDS
734 // | UNDNAME_NO_ACCESS_SPECIFIERS);
735 MYWRITE (fd, symbol.sym.Name, STDC::strlen (symbol.sym.Name));
736 MYWRITE (fd, buf, snprintf (buf, buf_size, " + %lx", offset));
737
738 if (SymGetModuleInfo (GetCurrentProcess(), frame.AddrPC.Offset,
739 &module))
740 {
741 MYWRITELIT (fd, " [");
742 MYWRITE (fd, module.ImageName,
743 STDC::strlen (module.ImageName));
744 MYWRITELIT (fd, "]");
745 }
746 }
747 else
748 {
749 GetLogicalAddress ((PVOID) frame.AddrPC.Offset,
750 modulename, sizeof (modulename),
751 section, offset);
752 MYWRITE (fd, buf, snprintf (buf, buf_size, "%04lx:%08lx [", section, offset));
753 MYWRITE (fd, modulename, STDC::strlen (modulename));
754 MYWRITELIT (fd, "]");
755 }
756 MYWRITELIT (fd, "\n");
757 ++level;
758 }
759 SymCleanup (GetCurrentProcess ());
760
761#elif (HAVE_U_STACK_TRACE || HAVE_XL_TRBK) // hp-ux, aix
762 // FIXME: deal with inability to duplicate the file handle
763 int stderrfd = dup (STDERR_FILENO);
764 if (stderrfd == -1)
765 return;
766
767 int newfd = dup2 (fd, STDERR_FILENO);
768 if (newfd == -1)
769 {
770 close (stderrfd);
771 return;
772 }
773
774# if HAVE_U_STACK_TRACE // hp-ux
775 U_STACK_TRACE ();
776# elif HAVE_XL_TRBK // aix
777 xl__trbk ();
778# else
779# error "oops, you shouldn't have gotten here!"
780# endif
781
782 fflush (stderr);
783 dup2 (stderrfd, STDERR_FILENO);
784 close (newfd);
785#elif HAVE_LINUX_UNWIND_BACKTRACE
786 CxxUtils::backtraceByUnwind (stacktraceLine, fd);
787
788#elif HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR // linux
789 // we could have used backtrace_symbols_fd, except its output
790 // format is pretty bad, so recode that here :-(
791 void *trace [MAX_BACKTRACE_DEPTH];
792 int depth = backtrace (trace, MAX_BACKTRACE_DEPTH);
793
794 for (int n = 0; n < depth; ++n/*, nbufs = 0*/)
795 {
796 unsigned long addr = (unsigned long) trace [n];
797 stacktraceLine (fd, addr);
798 }
799
800#elif HAVE_EXCPT_H && HAVE_PDSC_H && HAVE_RLD_INTERFACE_H // tru64
801 // Tru64 stack walk. Uses the exception handling library and the
802 // run-time linker's core functions (loader(5)). FIXME: Tru64
803 // should have _RLD_DLADDR like IRIX below. Verify and update.
804
805 const int buffer_size = 100 + BitTraits<unsigned long>::HexDigits * 2 + 11;
806 char buffer [buffer_size];
807 sigcontext context;
808 int rc = 0;
809
810 exc_capture_context (&context);
811 while (!rc && context.sc_pc)
812 {
813 // FIXME: Elf32?
814 pdsc_crd *func, *base, *crd
815 = exc_remote_lookup_function_entry(0, 0, context.sc_pc, 0, &func, &base);
816 Elf32_Addr addr = PDSC_CRD_BEGIN_ADDRESS(base, func);
817 // const char *name = _rld_address_to_name(addr);
818 const char *name = "<unknown function>";
819 snprintf (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n",
820 context.sc_pc, name, context.sc_pc - addr);
821 write (fd, buffer, STDC::strlen(buffer));
822 rc = exc_virtual_unwind(0, &context);
823 }
824
825#elif HAVE_EXCEPTION_H && defined __sgi // irix
826 // IRIX stack walk -- like Tru64 but with a little different names.
827 // NB: The guard above is to protect against unrelated <exception.h>
828 // provided by some compilers (e.g. KCC 4.0f).
829 // NB: libexc.h has trace_back_stack and trace_back_stack_and_print
830 // but their output isn't pretty and nowhere as complete as ours.
831 char buffer [340];
832 sigcontext context;
833
834 exc_setjmp (&context);
835 while (context.sc_pc >= 4)
836 {
837 // Do two lookups, one using exception handling tables and
838 // another using _RLD_DLADDR, and use the one with a smaller
839 // offset. For signal handlers we seem to get things wrong:
840 // _sigtramp's exception range is huge while based on Dl_info
841 // the offset is small -- but both supposedly describe the
842 // same thing. Go figure.
843 char *name = 0;
844 const char *libname = 0;
845 const char *symname = 0;
846 Elf32_Addr offset = ~0L;
847
848 // Do the exception/dwarf lookup
849 Elf32_Addr pc = context.sc_pc;
850 Dwarf_Fde fde = find_fde_name (&pc, &name);
851 Dwarf_Addr low_pc = context.sc_pc;
852 Dwarf_Unsigned udummy;
853 Dwarf_Signed sdummy;
854 Dwarf_Ptr pdummy;
855 Dwarf_Off odummy;
856 Dwarf_Error err;
857
858 symname = name;
859
860 // Determine offset using exception descriptor range information.
861 if (dwarf_get_fde_range (fde, &low_pc, &udummy, &pdummy, &udummy,
862 &odummy, &sdummy, &odummy, &err) == DW_DLV_OK)
863 offset = context.sc_pc - low_pc;
864
865 // Now do a dladdr() lookup. If the found symbol has the same
866 // address, trust the more accurate offset from dladdr();
867 // ignore the looked up mangled symbol name and prefer the
868 // demangled name produced by find_fde_name(). If we find a
869 // smaller offset, trust the dynamic symbol as well. Always
870 // trust the library name even if we can't match it with an
871 // exact symbol.
872 Elf32_Addr addr = context.sc_pc;
873 Dl_info info;
874
875 if (_rld_new_interface (_RLD_DLADDR, addr, &info))
876 {
877 if (info.dli_fname && info.dli_fname [0])
878 libname = info.dli_fname;
879
880 Elf32_Addr symaddr = (Elf32_Addr) info.dli_saddr;
881 if (symaddr == low_pc)
882 offset = addr - symaddr;
883 else if (info.dli_sname
884 && info.dli_sname [0]
885 && addr - symaddr < offset)
886 {
887 offset = addr - symaddr;
888 symname = info.dli_sname;
889 }
890 }
891
892 // Print out the result
893 if (libname && symname)
894 write (fd, buffer, snprintf
895 (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx [%.200s]\n",
896 addr, symname, offset, libname));
897 else if (symname)
898 write (fd, buffer, snprintf
899 (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n",
900 addr, symname, offset));
901 else
902 write (fd, buffer, snprintf
903 (buffer, buffer_size, " 0x%012lx <unknown function>\n", addr));
904
905 // Free name from find_fde_name().
906 free (name);
907
908 // Check for termination. exc_unwind() sets context.sc_pc to
909 // 0 or an error (< 4). However it seems we can't unwind
910 // through signal stack frames though this is not mentioned in
911 // the docs; it seems that for those we need to check for
912 // changed pc after find_fde_name(). That seems to indicate
913 // end of the post-signal stack frame. (FIXME: Figure out how
914 // to unwind through signal stack frame, e.g. perhaps using
915 // sigcontext_t's old pc? Or perhaps we can keep on going
916 // down without doing the symbol lookup?)
917 if (pc != context.sc_pc)
918 break;
919
920 exc_unwind (&context, fde);
921 }
922
923#elif defined PROG_PSTACK // solaris
924# ifdef PROG_CXXFILT
925# define CXXFILTER " | " PROG_CXXFILT
926# else
927# define CXXFILTER
928# endif
929 // 64 should more than plenty for a space and a pid.
930 const int buffer_size = sizeof(PROG_PSTACK) + 1 + BitTraits<unsigned long>::Digits
931 + 3 + sizeof(PROG_CXXFILT) + BitTraits<int>::Digits + 1;
932 char buffer [buffer_size];
933 snprintf (buffer, buffer_size, "%s %lu%s 1>&%d", PROG_PSTACK, (unsigned long) getpid (),
934 "" CXXFILTER, fd);
935 system (buffer);
936# undef CXXFILTER
937
938#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
939 // FIXME: Check for _Unwind*, compilers other than GCC support this API
940 _Unwind_Backtrace (unwindWalkStack, &fd);
941#endif
942
943 // FIXME: mpatrol has some generic unix unwind code.
944 // FIXME: from unix faq: ask debugger to dump stack trace
945 // with something like:
946 // - gdb: echo "thread apply all where\nwhere\ndetach" | gdb $prog $pid
947 // - dbx: echo "where\ndetach" | dbx -a $program_path $pid
948 // - dbx (aix): echo "where\ndetach" | dbx -p $program_path $pid
949}
static Double_t rc
#define IOFD_INVALID
Invalid channel descriptor constant.
Definition SealCommon.h:20
#define MYWRITE(fd, data, n)
#define MYWRITELIT(fd, str)
void section(const std::string &sec)
std::string depth
tag string for intendation
Definition fastadd.cxx:46
std::string base
Definition hcg.cxx:83
void free(pointer p)
Free an element.
list backtrace
Definition check_log.py:58

◆ ATLAS_NOT_THREAD_SAFE() [3/3]

void DebugAids::stacktraceLine ATLAS_NOT_THREAD_SAFE ( IOFD fd,
unsigned long addr )

Write out stack trace line to FD.

IP is the instruction pointer. (sss)

Definition at line 332 of file SealDebug.cxx.

334{
335 iovec bufs [7];
336 int nbufs = 0;
337 const int addrbuf_size = 5 + BitTraits<unsigned long>::HexDigits;
338 char addrbuf [addrbuf_size];
339
340#if HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR
341 const int diffbuf_size = 15 + BitTraits<unsigned long>::HexDigits;
342 char diffbuf [diffbuf_size];
343 static const char trailer [] = "]\n";
344 Dl_info info;
345
346 char dembuf[ LINE_MAX ];
347 char line[ LINE_MAX ];
348 const int relbuf_size = 7 + BitTraits<unsigned long>::HexDigits;
349 char relbuf [relbuf_size];
350
351 if (dladdr ((void*)addr, &info) && info.dli_fname && info.dli_fname[0])
352 {
353 const char *libname = info.dli_fname;
354
355 unsigned long symaddr = (unsigned long) info.dli_saddr;
356 bool gte = (addr >= symaddr);
357 unsigned long diff = (gte ? addr - symaddr : symaddr - addr);
358
359 // RS start
360 int length = 0;
361
362 // difference of two pointers
363 unsigned long libaddr = (unsigned long) info.dli_fbase;
364 unsigned long relative_address = (addr >= libaddr) ? addr - libaddr : libaddr - addr;
365 // ELF executables are usually not relocatable, and on 64-bit platforms
366 // are usually loaded starting at 0x400000. In that case, we should _not_
367 // subtract the base address. But clang15 by default appears to produce
368 // position-independent executables (PIE) by default. In that case,
369 // we do need to subtract the offset.
370 // I'm not sure how to reliably tell the difference short of parsing
371 // the object headers. For now, just assume that something
372 // that doesn't have .so in the name and is loaded at 0x400000
373 // is not relocatable. This is not really portable, though.
374 if (strstr (info.dli_fname, ".so") == 0 && libaddr == 0x400000)
375 relative_address = addr;
376
377 // need popen for addr2line ...
378 int pfd;
379 pid_t child_pid;
380 const char* symname = dembuf;
381 size_t demlen = 0;
382
383 // did we find valid entry ?
384 size_t len = strlen(info.dli_fname);
385 if ( len > 0 && len + 80 < LINE_MAX)
386 {
387 if (getenv ("LD_PRELOAD"))
388 unsetenv ("LD_PRELOAD");
389
390 if ( addr2LinePath == "/usr/bin/eu-addr2line" )
391 {
392 snprintf (line, LINE_MAX, "%s -f -e %s %p | /usr/bin/c++filt | /usr/bin/tr \\\\012 \\\\040 ",
393 addr2LinePath.c_str(),
394 info.dli_fname,
395 (void*)relative_address);
396 }
397 else
398 {
399 snprintf (line, LINE_MAX, "%s -f -C -e %s %p",
400 addr2LinePath.c_str(),
401 info.dli_fname,
402 (void*)relative_address);
403 }
404
405 pfd = stacktracePopenFD( line, child_pid );
406
407 length = 1;
408 line[0] = ' ';
409
410 // did we succeed to open the pipe?
411 if ( pfd >= 0 )
412 {
413 demlen = stacktraceReadline (pfd, dembuf, sizeof(dembuf));
414
415 length = stacktraceReadline (pfd, line+1, sizeof(line)-1);
416 if (length >= 0) ++length;
417
418 int stat = stacktracePcloseFD (pfd, child_pid);
419
420 // don't print anything, if nothing is found
421 if ( stat || line[1] == '?' || length < 0)
422 {
423 line[1] = '\0';
424 length = 0;
425 }
426
427 if ( stat || demlen <= 0 || dembuf[0] == '?') {
428 symname = info.dli_sname;
429 if (!symname) symname = "???";
430 demlen = strlen (symname);
431 }
432
433 }
434 }
435 // RS end
436
437 bufs [nbufs].iov_base = addrbuf;
438 bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr);
439 ++nbufs;
440
441 bufs [nbufs].iov_base = (void *) symname; // discard const
442 bufs [nbufs].iov_len = demlen;
443 ++nbufs;
444
445 // RS start
446 bufs [nbufs].iov_base = line;
447 bufs [nbufs].iov_len = length;
448 ++nbufs;
449 // RS end
450
451 bufs [nbufs].iov_base = diffbuf;
452 bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %c 0x%lx [",
453 gte ? '+' : '-', diff);
454 ++nbufs;
455
456 bufs [nbufs].iov_base = (void *) libname; // discard const
457 bufs [nbufs].iov_len = strlen (libname);
458 ++nbufs;
459
460 // RS start
461 bufs [nbufs].iov_base = relbuf;
462 bufs [nbufs].iov_len = snprintf( relbuf, relbuf_size, " D[%p]", (void*)relative_address );
463 ++nbufs;
464 // RS end
465
466 bufs [nbufs].iov_base = (void *) trailer; // discard const
467 bufs [nbufs].iov_len = 2;
468 ++nbufs;
469
470 }
471 else
472#endif
473 {
474 bufs [nbufs].iov_base = addrbuf;
475 bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr);
476 ++nbufs;
477
478 bufs [nbufs].iov_base = (void *) "<unknown function>\n"; //no const
479 bufs [nbufs].iov_len = 19;
480 ++nbufs;
481 }
482
483 writev (fd, bufs, nbufs);
484}
double length(const pvec &v)
int32_t pid_t
void diff(const Jet &rJet1, const Jet &rJet2, std::map< std::string, double > varDiff)
Difference between jets - Non-Class function required by trigger.
Definition Jet.cxx:631