ATLAS Offline Software
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 
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
104 
106 static 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>
114 namespace {
115 
116 
117 std::string addr2LinePath = "/usr/bin/eu-addr2line";
118 
119 
120 struct 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 };
159 BacktraceInit 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.
165 int 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 
218 int 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 
239 int 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 
260 namespace Athena { // wlav
261 
262 
264 std::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 
289 bool
290 GetLogicalAddress (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 
332 void 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
488 extern "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
516 unwindWalkStack (_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.
582 void 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)
590 extern "C" void U_STACK_TRACE (void);
591 #endif
592 
593 #if HAVE_XL_TRBK
594 // AIX stack walker (from xlf FORTRAN 90 runtime).
595 extern "C" void xl__trbk (void);
596 #endif
597 
598 //<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>>
599 
606 IOFD
607 DebugAids::stacktraceFd (IOFD fd /* = IOFD_INVALID */)
608 {
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 
636 void
637 DebugAids::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 
973 void
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 
1029 unsigned 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
read
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)
Definition: openCoraCool.cxx:569
pid_t
int32_t pid_t
Definition: FPGATrackSimTypes.h:19
base
std::string base
Definition: hcg.cxx:78
Athena::Signal::raise
static int raise(int sig)
Raise the signal number sig.
Definition: SealSignal.cxx:377
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
Athena::ATLAS_NOT_THREAD_SAFE
void DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE(IOFD fd)
Produce a stack trace.
Definition: SealDebug.cxx:637
egammaParameters::depth
@ depth
pointing depth of the shower as calculated in egammaqgcld
Definition: egammaParamDefs.h:276
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:128
Athena::DebugAids::coredump
static void coredump(int sig,...)
Drop a core dump and continue.
Definition: SealDebug.cxx:974
jet::ExtendedBool::TRUE
@ TRUE
Definition: UncertaintyEnum.h:234
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
rerun_display.cmd
string cmd
Definition: rerun_display.py:67
SealDebug.h
This are the SEAL debug aids, adapted to build in Atlas, after the drop of that project.
TRTCalib_cfilter.p1
p1
Definition: TRTCalib_cfilter.py:130
mc.diff
diff
Definition: mc.SFGenPy8_MuMu_DD.py:14
SealCommon.h
Collecting a few shared bits and pieces from SEAL headers.
get_generator_info.stderr
stderr
Definition: get_generator_info.py:40
Athena::BitTraits::HexDigits
@ HexDigits
Definition: SealDebug.h:67
UnwindBacktrace.h
Hacked backtrace that can go past a bad stack frame.
dq_defect_bulk_create_defects.line
line
Definition: dq_defect_bulk_create_defects.py:27
python.iconfTool.models.loaders.level
level
Definition: loaders.py:20
python.PyAthena.module
module
Definition: PyAthena.py:131
TRTCalib_cfilter.p2
p2
Definition: TRTCalib_cfilter.py:131
PlotCalibFromCool.modulename
modulename
Definition: PlotCalibFromCool.py:81
createCoolChannelIdFile.buffer
buffer
Definition: createCoolChannelIdFile.py:11
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:183
lumiFormat.i
int i
Definition: lumiFormat.py:85
SealSignal.h
This is the signal handler from SEAL, adapted to build in Atlas, after the drop of that project.
Athena
Some weak symbol referencing magic...
Definition: AthLegacySequence.h:21
beamspotman.n
n
Definition: beamspotman.py:729
IOFD
int IOFD
Type the system uses for channel descriptors.
Definition: SealCommon.h:27
python.ByteStreamConfig.write
def write
Definition: Event/ByteStreamCnvSvc/python/ByteStreamConfig.py:248
python.BuildSignatureFlags.sig
sig
Definition: BuildSignatureFlags.py:221
Athena::Signal::HandlerType
void(* HandlerType)(int sig, siginfo_t *info, void *extra)
Signal handler type.
Definition: SealSignal.h:196
find_tgc_unfilled_channelids.ip
ip
Definition: find_tgc_unfilled_channelids.py:3
Athena::DebugAids::stacktraceFd
static IOFD stacktraceFd(IOFD fd=IOFD_INVALID)
Set and return the file descriptor for stack trace output.
Definition: SealDebug.cxx:607
Athena::ATLAS_NOT_THREAD_SAFE
StatusCode ROOTMessageFilterSvc::initialize ATLAS_NOT_THREAD_SAFE()
Return the file descriptor #fataldump() uses for output.
Definition: ROOTMessageFilterSvc.cxx:103
beamspotman.stat
stat
Definition: beamspotman.py:264
python.dummyaccess.access
def access(filename, mode)
Definition: dummyaccess.py:18
beamspotman.dir
string dir
Definition: beamspotman.py:621
ReadFromCoolCompare.fd
fd
Definition: ReadFromCoolCompare.py:196
Athena::BitTraits
Describe the bit features of an integral type T.
Definition: SealDebug.h:55
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
IOFD_INVALID
#define IOFD_INVALID
Invalid channel descriptor constant.
Definition: SealCommon.h:20
Athena::Signal::block
static void block(int sig, bool sense)
Block or unblock the signal number sig.
Definition: SealSignal.cxx:338
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:16
STDERR_HANDLE
#define STDERR_HANDLE
Definition: SealDebug.cxx:83
ir
int ir
counter of the current depth
Definition: fastadd.cxx:49
__attribute__
__attribute__((always_inline)) inline uint16_t TileCalibDrawerBase
Definition: TileCalibDrawerBase.h:190
windows.h
Athena::DebugAids::enableCoreFiles
static unsigned long enableCoreFiles()
Try to enable core dump files by raising the soft size limit to the hard limit.
Definition: SealDebug.cxx:1030
SCT_ConditionsAlgorithms::CoveritySafe::getenv
std::string getenv(const std::string &variableName)
get an environment variable
Definition: SCT_ConditionsUtilities.cxx:17
CSV_InDetExporter.old
old
Definition: CSV_InDetExporter.py:145
MYWRITE
#define MYWRITE(fd, data, n)
Definition: SealDebug.cxx:93
Athena::Signal::handle
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.
Definition: SealSignal.cxx:277
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:567
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
merge.status
status
Definition: merge.py:16
section
void section(const std::string &sec)
Definition: TestTriggerMenuAccess.cxx:22
MYWRITELIT
#define MYWRITELIT(fd, str)
Definition: SealDebug.cxx:97
checker_macros.h
Define macros for attributes used to control the static checker.
Athena::DebugAids::disableCoreFiles
static void disableCoreFiles()
Disable core dump files by setting the soft limit to 0.
Definition: SealDebug.cxx:1050
check_log.backtrace
backtrace
Definition: check_log.py:58
length
double length(const pvec &v)
Definition: FPGATrackSimLLPDoubletHoughTransformTool.cxx:26
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
Athena::DebugAids::s_stackTraceFd
static std::atomic< IOFD > s_stackTraceFd
The default output file descriptor for #stacktrace().
Definition: SealDebug.h:88
python.SystemOfUnits.pc
float pc
Definition: SystemOfUnits.py:114
python.SystemOfUnits.L
float L
Definition: SystemOfUnits.py:92