ATLAS Offline Software
Loading...
Searching...
No Matches
SealDebug.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
18
19
20#include "CxxUtils/SealCommon.h" // wlav
21#include "CxxUtils/SealDebug.h" // wlav
22#include "CxxUtils/SealSignal.h" // wlav
23#include "CxxUtils/UnwindBacktrace.h" // sss
25
26// wlav copied from SealBase/sysapi/DebugAids.h
27#include <cstring>
28# include <cctype>
29# include <cstdio>
30# include <cstdlib>
31# include <iostream>
32# include <iomanip>
33# include <sstream> // wlav
34# include <climits> // wlav
35
36# ifdef _WIN32
37# include <windows.h>
38# include <winnt.h>
39# include <imagehlp.h>
40//# include <io.h>
41# else
42# include <unistd.h>
43# include <sys/wait.h>
44# include <sys/resource.h> // fwinkl
45# if HAVE_BACKTRACE_SYMBOLS_FD // GNU
46# include <execinfo.h>
47# include <sys/uio.h>
48# include <cxxabi.h>
49# endif
50# if HAVE_DLADDR // Linux, Solaris
51# include <dlfcn.h>
52# endif
53# if HAVE_EXCEPTION_H
54 // This is yucky. KCC's <exception.h> that has nothing to do with the
55 // header we are looking for (it redirect to <exception>). This ugly
56 // workaround allows us to find the (IRIX) header we are looking for.
57# if defined __KCC && defined __sgi
58# include </usr/include/exception.h>
59# elif defined __sgi
60# include <exception.h>
61# endif
62# endif
63# if HAVE_EXCPT_H // IRIX
64# include <excpt.h>
65# undef try // Defined on SGI to structured exception handling goop
66# undef catch // Defined on SGI to structured exception handling goop
67# endif
68# if HAVE_RLD_INTERFACE_H // Tru64 (IRIX)
69# include <rld_interface.h>
70# endif
71# if HAVE_PDSC_H // Tru64
72# include <pdsc.h>
73# endif
74# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) // GCC 3.4+ C++ ABI
75# include <sys/uio.h>
76# endif
77# endif
78
79// Windows doesn't have this, so fake a suitable substitute
80# ifdef _WIN32
81# define STDERR_HANDLE GetStdHandle (STD_ERROR_HANDLE)
82# else
83# define STDERR_HANDLE STDERR_FILENO
84# endif
85
86// Define a suitable wrapper to write to system file descriptors.
87// This is needed because on Windows we are using HANDLEs, not the
88// compiler's crippled posixy interface.
89# ifdef _WIN32
90# define MYWRITE(fd,data,n) do { DWORD written; WriteFile(fd,data,n,\
91 &written,0); } while (0)
92# else
93# define MYWRITE(fd,data,n) write(fd,data,n)
94# endif
95
96// Helper to write literals
97# define MYWRITELIT(fd,str) MYWRITE(fd,str,sizeof(str)-1)
98
99//<<<<<< PUBLIC CONSTANTS >>>>>>
100//<<<<<< PUBLIC TYPES >>>>>>
101//<<<<<< PUBLIC VARIABLES >>>>>>
102
103#if HAVE_BACKTRACE_SYMBOLS_FD
106static const int MAX_BACKTRACE_DEPTH = 128;
107#endif
108
109
110#if HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR
111// sss
112#include <unistd.h>
113#include <errno.h>
114namespace {
115
116
117std::string addr2LinePath = "/usr/bin/eu-addr2line";
118
119
120struct ATLAS_NOT_THREAD_SAFE BacktraceInit
121{
122 BacktraceInit()
123 {
124 // backtrace() has a one-time initialization that uses malloc().
125 // so call it once now.
126 void* trace[1];
127 backtrace (trace, 1);
128
129 if (access (addr2LinePath.c_str(), F_OK) == 0) {
130 return;
131 }
132
133 // Search PATH for addr2line / eu-addr2line.
134 std::string path = getenv ("PATH");
135 while (!path.empty()) {
136 std::string::size_type pos = path.find (':');
137 std::string dir = path.substr (0, pos);
138 if (pos != std::string::npos) ++pos;
139 path.erase (0, pos);
140
141 {
142 std::string p1 = dir + "/eu-addr2line";
143 if (access (p1.c_str(), F_OK) == 0) {
144 addr2LinePath = std::move (p1);
145 break;
146 }
147 }
148
149 {
150 std::string p2 = dir + "/addr2line";
151 if (access (p2.c_str(), F_OK) == 0) {
152 addr2LinePath = std::move (p2);
153 break;
154 }
155 }
156 }
157 }
158};
159BacktraceInit backtraceInit;
160
161
162// This is like popen, except that it returns a fd rather
163// than a FILE*. The PID is returned in pid.
164// This is to avoid memory allocation.
165int stacktracePopenFD (const char* cmd, pid_t& child_pid)
166{
167 int stat;
168 int fds[2];
169
170 // The glibc popen() uses pipe2() here with O_CLOEXEC.
171 // pipe2() is linux-specific, though, so avoid it here.
172 stat = pipe (fds);
173 if (stat < 0) return stat;
174
175 int parent_end = fds[0];
176 int child_end = fds[1];
177
178#ifdef __linux__
179 // Use vfork rather than fork to avoid running pthread_atfork handlers.
180 // Openblas, for example, registers one unconditionally, but that can
181 // segfault if called with the program in a bad state.
182 // What we're doing here doesn't really comply with the restrictions
183 // in the vfork man page, which says that in the child after the vfork
184 // you can do only exec or _exit. This does in fact seem to work
185 // on linux, but put this within an ifdef.
186 child_pid = vfork();
187#else
188 child_pid = fork();
189#endif
190 if (child_pid == 0) {
191 int child_std_end = 1;
192 close (parent_end);
193 if (child_end != child_std_end) {
194 dup2 (child_end, child_std_end);
195 close (child_end);
196 }
197
198 /* POSIX.2: "popen() shall ensure that any streams from previous
199 popen() calls that remain open in the parent process are closed
200 in the new child process."
201
202 For our specific case here, we ignore this. */
203
204 execl ("/bin/sh", "sh", "-c", cmd, (char *) 0);
205 _exit (127);
206 }
207
208 close (child_end);
209 if (child_pid < 0) {
210 close (parent_end);
211 return child_pid;
212 }
213
214 return parent_end;
215}
216
217
218int stacktracePcloseFD (int fd, pid_t child_pid)
219{
220 int stat = close (fd);
221 if (stat < 0) return stat;
222
223 /* POSIX.2 Rationale: "Some historical implementations either block
224 or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
225 for the child process to terminate. Since this behavior is not
226 described in POSIX.2, such implementations are not conforming." */
227 pid_t wait_pid;
228 int wstatus;
229 do {
230 wait_pid = waitpid (child_pid, &wstatus, 0);
231 } while (wait_pid == -1 && errno == EINTR);
232
233 if (wait_pid == -1)
234 return -1;
235 return wstatus;
236}
237
238
239int stacktraceReadline (int fd, char* buf, int buflen)
240{
241 int len = 0;
242 while (len < buflen-1) {
243 int stat = read (fd, buf, 1);
244 if (stat < 0) return stat;
245 if (stat == 0) break;
246 if (*buf == '\n') break;
247 ++len;
248 ++buf;
249 }
250 *buf = '\0';
251 return len;
252}
253
254
255} // anonymous namespace
256// sss
257#endif
258
259
260namespace Athena { // wlav
261
262
264std::atomic<IOFD> DebugAids::s_stackTraceFd = IOFD_INVALID;
265
266
267#ifdef _WIN32
268// /** WIN32 function to grab the current PC address from the SEH context.
269// We need this to grab the exception context so we can walk the stack
270// in #Debug::stacktrace(). We use SEH (as compiler-independently as
271// we can) as only XP 64-bit has RtlGetContext() function. */
272// static LONG CALLBACK
273// GrabExceptionContext (PEXCEPTION_POINTERS info)
274// {
275// *((CONTEXT *) info->ExceptionRecord->ExceptionInformation[0])
276// = *info->ContextRecord;
277// return EXCEPTION_EXECUTE_HANDLER;
278// }
279
289bool
290GetLogicalAddress (PVOID addr, PTSTR name, DWORD length,
291 DWORD &section, DWORD &offset)
292{
293 MEMORY_BASIC_INFORMATION info;
294
295 if (! VirtualQuery (addr, &info, sizeof (info)))
296 return false;
297
298 DWORD module = (DWORD) info.AllocationBase;
299 if (! GetModuleFileName ((HMODULE) module, name, length))
300 return false;
301
302 PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER) module;
303 PIMAGE_NT_HEADERS ntheader
304 = (PIMAGE_NT_HEADERS) (module + dosheader->e_lfanew);
305 PIMAGE_SECTION_HEADER sect = IMAGE_FIRST_SECTION (ntheader);
306 DWORD rva = (DWORD) addr - module;
307
308 for (unsigned i = 0; i < ntheader->FileHeader.NumberOfSections; ++i,++sect)
309 {
310 DWORD sect_start = sect->VirtualAddress;
311 DWORD sect_end = sect_start + std::max (sect->SizeOfRawData,
312 sect->Misc.VirtualSize);
313
314 if ((rva >= sect_start) && (rva <= sect_end))
315 {
316 section = i+1;
317 offset = rva - sect_start;
318 return true;
319 }
320 }
321
322 assert (false);
323 return false;
324}
325#endif
326
332void DebugAids::stacktraceLine ATLAS_NOT_THREAD_SAFE (IOFD fd,
333 unsigned long addr)
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}
485
486
487#if !(HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR) && __GNUC__ >=4
488extern "C" {
489 typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
490 struct _Unwind_Context;
491 typedef enum
492 {
493 _URC_NO_REASON = 0,
494 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
495 _URC_FATAL_PHASE2_ERROR = 2,
496 _URC_FATAL_PHASE1_ERROR = 3,
497 _URC_NORMAL_STOP = 4,
498 _URC_END_OF_STACK = 5,
499 _URC_HANDLER_FOUND = 6,
500 _URC_INSTALL_CONTEXT = 7,
501 _URC_CONTINUE_UNWIND = 8
502 } _Unwind_Reason_Code;
503 typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
504 extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
505 extern _Unwind_Ptr _Unwind_GetIP (_Unwind_Context *);
506 extern _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
507}
508
515_Unwind_Reason_Code
516unwindWalkStack (_Unwind_Context *ctx, void *data)
517{
518 IOFD fd = *(IOFD *) data;
519 iovec bufs [5];
520 int nbufs = 0;
521 const int addrbuf_size = 5 + BitTraits<unsigned long>::HexDigits;
522 char addrbuf [addrbuf_size];
523 const int diffbuf_size = 10 + 2 * BitTraits<unsigned long>::HexDigits;
524 char diffbuf [diffbuf_size];
525 static const char trailer [] = "]\n";
526 unsigned long ip = _Unwind_GetIP (ctx);
527 unsigned long ir = _Unwind_GetRegionStart (ctx);
528
529# if HAVE_DLADDR
530 Dl_info info;
531 if (dladdr ((void *) ir, &info) && info.dli_fname && info.dli_fname[0])
532 {
533 const char *libname = info.dli_fname;
534 const char *symname = (info.dli_sname && info.dli_sname[0]
535 ? info.dli_sname : "?");
536 unsigned long symaddr = (unsigned long) info.dli_saddr;
537 bool gte = (ip >= symaddr);
538 unsigned long diff = (gte ? ip - symaddr : symaddr - ip);
539
540 bufs [nbufs].iov_base = addrbuf;
541 bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip);
542 ++nbufs;
543
544 bufs [nbufs].iov_base = (char *) symname; // discard const
545 bufs [nbufs].iov_len = strlen (symname);
546 ++nbufs;
547
548 bufs [nbufs].iov_base = diffbuf;
549 bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %s 0x%lx [",
550 gte ? "+" : "-", diff);
551 ++nbufs;
552
553 bufs [nbufs].iov_base = (char *) libname; // discard const
554 bufs [nbufs].iov_len = strlen (libname);
555 ++nbufs;
556
557 bufs [nbufs].iov_base = (char *) trailer; // discard const
558 bufs [nbufs].iov_len = 2;
559 ++nbufs;
560 }
561 else
562# endif // HAVE_DLADDR
563 {
564 bufs [nbufs].iov_base = addrbuf;
565 bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip);
566 ++nbufs;
567
568 bufs [nbufs].iov_base = diffbuf;
569 bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " <?%08lx> + 0x%lx\n",
570 ir, ip - ir);
571 ++nbufs;
572 }
573
574 writev (fd, bufs, nbufs);
575 return _URC_NO_REASON;
576}
577#endif // GCC 3.4+
578
579//<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>>
580
581// Change the path of the binary used for symbolization.
582void DebugAids::setStackTraceAddr2Line ATLAS_NOT_THREAD_SAFE (const char* path)
583{
584 addr2LinePath = path;
585}
586
587
588#if HAVE_U_STACK_TRACE
589// HP-UX stack walker (http://devresource.hp.com/STK/partner/unwind.pdf)
590extern "C" void U_STACK_TRACE (void);
591#endif
592
593#if HAVE_XL_TRBK
594// AIX stack walker (from xlf FORTRAN 90 runtime).
595extern "C" void xl__trbk (void);
596#endif
597
598//<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>>
599
606IOFD
607DebugAids::stacktraceFd (IOFD fd /* = IOFD_INVALID */)
608{
609 IOFD old = s_stackTraceFd;
610 if (fd == IOFD_INVALID) {
611 if (old == IOFD_INVALID) {
612 s_stackTraceFd.compare_exchange_strong (old, STDERR_HANDLE);
613 return s_stackTraceFd;
614 }
615 }
616 else {
617 s_stackTraceFd.compare_exchange_strong (old, fd);
618 }
619 return old;
620}
621
636void
637DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */)
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}
950
973void
975{
976#ifndef _WIN32
977 // FIXME: Forking vs. threads -- need to sort out what is safe.
978 // FIXME: Provide a resource limits interface so that core
979 // resource limits can be raised?
980
981 pid_t corepid;
982 int status;
983
984 ::unlink ("core");
985 if ((corepid = ::fork ()) == 0)
986 {
987 // In child: re-raise the signal, thus killing the process and
988 // producing a core dump. Make sure 1) the signal is not
989 // blocked so that we won't return to the caller, 2) we have a
990 // signal that is fatal, 3) the signal falls to its default
991 // handler to produce the dump.
992
993#ifdef SIGUSR1
994 // SIGUSR1 does not cause a core dump; use abort() instead
995 if (sig == SIGUSR1)
996 sig = SIGABRT; // Could be SIGIOT if SIGABRT is not defined
997#endif
998 Signal::handle (sig, (Signal::HandlerType) (void*)SIG_DFL);
999 Signal::block (sig, false);
1000 Signal::raise (sig);
1001
1002 // Yikes, this shouldn't happen. ASSERT isn't right here. If
1003 // raise() failed to deliver the signal, abort() is unlikely
1004 // to work any better, but try it anyway. Then make sure we
1005 // die so that we won't return to the caller from the child.
1006 abort ();
1007 // cppcheck-suppress unreachableCode
1008 _exit (255);
1009 }
1010 else if (corepid > 0) {
1011 pid_t wait_pid;
1012 do {
1013 wait_pid = ::waitpid (corepid, &status, 0);
1014 } while (wait_pid == -1 && errno == EINTR);
1015 }
1016#endif // !_WIN32
1017}
1018
1019
1029unsigned long
1031{
1032 struct rlimit core_limit;
1033 getrlimit(RLIMIT_CORE, &core_limit);
1034
1035 unsigned long old_limit = core_limit.rlim_cur;
1036 core_limit.rlim_cur = core_limit.rlim_max;
1037 if ( setrlimit(RLIMIT_CORE, &core_limit) == 0 ) {
1038 return core_limit.rlim_cur;
1039 }
1040 else {
1041 return old_limit;
1042 }
1043}
1044
1051{
1052 struct rlimit core_limit;
1053 core_limit.rlim_cur = 0;
1054 core_limit.rlim_max = 0;
1055 setrlimit(RLIMIT_CORE, &core_limit);
1056}
1057
1058
1059} // namespace Athena wlav
Hacked backtrace that can go past a bad stack frame.
double length(const pvec &v)
int32_t pid_t
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
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
Collecting a few shared bits and pieces from SEAL headers.
#define IOFD_INVALID
Invalid channel descriptor constant.
Definition SealCommon.h:20
int IOFD
Type the system uses for channel descriptors.
Definition SealCommon.h:27
This are the SEAL debug aids, adapted to build in Atlas, after the drop of that project.
#define MYWRITE(fd, data, n)
Definition SealDebug.h:44
#define STDERR_HANDLE
Definition SealDebug.h:34
This is the signal handler from SEAL, adapted to build in Atlas, after the drop of that project.
void section(const std::string &sec)
__attribute__((always_inline)) inline uint16_t TileCalibDrawerBase
Define macros for attributes used to control the static checker.
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
static IOFD stacktraceFd(IOFD fd=IOFD_INVALID)
Set and return the file descriptor for stack trace output.
static void coredump(int sig,...)
Drop a core dump and continue.
static std::atomic< IOFD > s_stackTraceFd
The default output file descriptor for stacktrace().
Definition SealDebug.h:88
static unsigned long enableCoreFiles()
Try to enable core dump files by raising the soft size limit to the hard limit.
static void disableCoreFiles()
Disable core dump files by setting the soft limit to 0.
static int raise(int sig)
Raise the signal number sig.
static void block(int sig, bool sense)
Block or unblock the signal number sig.
static HandlerType handle(int sig, HandlerType handler, const sigset_t *blockMask=0)
Install a new signal handler handler for signal number sig and returns the old handler.
void(* HandlerType)(int sig, siginfo_t *info, void *extra)
Signal handler type.
Definition SealSignal.h:196
#define MYWRITELIT(fd, str)
Definition exctrace.cxx:35
int ir
counter of the current depth
Definition fastadd.cxx:49
std::string depth
tag string for intendation
Definition fastadd.cxx:46
std::string base
Definition hcg.cxx:81
Some weak symbol referencing magic... These are declared in AthenaKernel/getMessageSvc....
StatusCode ROOTMessageFilterSvc::initialize ATLAS_NOT_THREAD_SAFE()
Return the file descriptor fataldump() uses for output.
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)