Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  std::string p1 = dir + "/eu-addr2line";
142  if (access (p1.c_str(), F_OK) == 0) {
143  addr2LinePath = p1;
144  break;
145  }
146 
147  std::string p2 = dir + "/addr2line";
148  if (access (p2.c_str(), F_OK) == 0) {
149  addr2LinePath = p2;
150  break;
151  }
152  }
153  }
154 };
155 BacktraceInit backtraceInit;
156 
157 
158 // This is like popen, except that it returns a fd rather
159 // than a FILE*. The PID is returned in pid.
160 // This is to avoid memory allocation.
161 int stacktracePopenFD (const char* cmd, pid_t& child_pid)
162 {
163  int stat;
164  int fds[2];
165 
166  // The glibc popen() uses pipe2() here with O_CLOEXEC.
167  // pipe2() is linux-specific, though, so avoid it here.
168  stat = pipe (fds);
169  if (stat < 0) return stat;
170 
171  int parent_end = fds[0];
172  int child_end = fds[1];
173 
174 #ifdef __linux__
175  // Use vfork rather than fork to avoid running pthread_atfork handlers.
176  // Openblas, for example, registers one unconditionally, but that can
177  // segfault if called with the program in a bad state.
178  // What we're doing here doesn't really comply with the restrictions
179  // in the vfork man page, which says that in the child after the vfork
180  // you can do only exec or _exit. This does in fact seem to work
181  // on linux, but put this within an ifdef.
182  child_pid = vfork();
183 #else
184  child_pid = fork();
185 #endif
186  if (child_pid == 0) {
187  int child_std_end = 1;
188  close (parent_end);
189  if (child_end != child_std_end) {
190  dup2 (child_end, child_std_end);
191  close (child_end);
192  }
193 
194  /* POSIX.2: "popen() shall ensure that any streams from previous
195  popen() calls that remain open in the parent process are closed
196  in the new child process."
197 
198  For our specific case here, we ignore this. */
199 
200  execl ("/bin/sh", "sh", "-c", cmd, (char *) 0);
201  _exit (127);
202  }
203 
204  close (child_end);
205  if (child_pid < 0) {
206  close (parent_end);
207  return child_pid;
208  }
209 
210  return parent_end;
211 }
212 
213 
214 int stacktracePcloseFD (int fd, pid_t child_pid)
215 {
216  int stat = close (fd);
217  if (stat < 0) return stat;
218 
219  /* POSIX.2 Rationale: "Some historical implementations either block
220  or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
221  for the child process to terminate. Since this behavior is not
222  described in POSIX.2, such implementations are not conforming." */
223  pid_t wait_pid;
224  int wstatus;
225  do {
226  wait_pid = waitpid (child_pid, &wstatus, 0);
227  } while (wait_pid == -1 && errno == EINTR);
228 
229  if (wait_pid == -1)
230  return -1;
231  return wstatus;
232 }
233 
234 
235 int stacktraceReadline (int fd, char* buf, int buflen)
236 {
237  int len = 0;
238  while (len < buflen-1) {
239  int stat = read (fd, buf, 1);
240  if (stat < 0) return stat;
241  if (stat == 0) break;
242  if (*buf == '\n') break;
243  ++len;
244  ++buf;
245  }
246  *buf = '\0';
247  return len;
248 }
249 
250 
251 } // anonymous namespace
252 // sss
253 #endif
254 
255 
256 namespace Athena { // wlav
257 
258 
260 std::atomic<IOFD> DebugAids::s_stackTraceFd = IOFD_INVALID;
261 
262 
263 #ifdef _WIN32
264 // /** WIN32 function to grab the current PC address from the SEH context.
265 // We need this to grab the exception context so we can walk the stack
266 // in #Debug::stacktrace(). We use SEH (as compiler-independently as
267 // we can) as only XP 64-bit has RtlGetContext() function. */
268 // static LONG CALLBACK
269 // GrabExceptionContext (PEXCEPTION_POINTERS info)
270 // {
271 // *((CONTEXT *) info->ExceptionRecord->ExceptionInformation[0])
272 // = *info->ContextRecord;
273 // return EXCEPTION_EXECUTE_HANDLER;
274 // }
275 
285 bool
286 GetLogicalAddress (PVOID addr, PTSTR name, DWORD length,
287  DWORD &section, DWORD &offset)
288 {
289  MEMORY_BASIC_INFORMATION info;
290 
291  if (! VirtualQuery (addr, &info, sizeof (info)))
292  return false;
293 
294  DWORD module = (DWORD) info.AllocationBase;
295  if (! GetModuleFileName ((HMODULE) module, name, length))
296  return false;
297 
298  PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER) module;
299  PIMAGE_NT_HEADERS ntheader
300  = (PIMAGE_NT_HEADERS) (module + dosheader->e_lfanew);
301  PIMAGE_SECTION_HEADER sect = IMAGE_FIRST_SECTION (ntheader);
302  DWORD rva = (DWORD) addr - module;
303 
304  for (unsigned i = 0; i < ntheader->FileHeader.NumberOfSections; ++i,++sect)
305  {
306  DWORD sect_start = sect->VirtualAddress;
307  DWORD sect_end = sect_start + std::max (sect->SizeOfRawData,
308  sect->Misc.VirtualSize);
309 
310  if ((rva >= sect_start) && (rva <= sect_end))
311  {
312  section = i+1;
313  offset = rva - sect_start;
314  return true;
315  }
316  }
317 
318  assert (false);
319  return false;
320 }
321 #endif
322 
328 void DebugAids::stacktraceLine ATLAS_NOT_THREAD_SAFE (IOFD fd,
329  unsigned long addr)
330 {
331  iovec bufs [7];
332  int nbufs = 0;
333  const int addrbuf_size = 5 + BitTraits<unsigned long>::HexDigits;
334  char addrbuf [addrbuf_size];
335 
336 #if HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR
337  const int diffbuf_size = 15 + BitTraits<unsigned long>::HexDigits;
338  char diffbuf [diffbuf_size];
339  static const char trailer [] = "]\n";
340  Dl_info info;
341 
342  char dembuf[ LINE_MAX ];
343  char line[ LINE_MAX ];
344  const int relbuf_size = 7 + BitTraits<unsigned long>::HexDigits;
345  char relbuf [relbuf_size];
346 
347  if (dladdr ((void*)addr, &info) && info.dli_fname && info.dli_fname[0])
348  {
349  const char *libname = info.dli_fname;
350 
351  unsigned long symaddr = (unsigned long) info.dli_saddr;
352  bool gte = (addr >= symaddr);
353  unsigned long diff = (gte ? addr - symaddr : symaddr - addr);
354 
355  // RS start
356  int length = 0;
357 
358  // difference of two pointers
359  unsigned long libaddr = (unsigned long) info.dli_fbase;
360  unsigned long relative_address = (addr >= libaddr) ? addr - libaddr : libaddr - addr;
361  // ELF executables are usually not relocatable, and on 64-bit platforms
362  // are usually loaded starting at 0x400000. In that case, we should _not_
363  // subtract the base address. But clang15 by default appears to produce
364  // position-independent executables (PIE) by default. In that case,
365  // we do need to subtract the offset.
366  // I'm not sure how to reliably tell the difference short of parsing
367  // the object headers. For now, just assume that something
368  // that doesn't have .so in the name and is loaded at 0x400000
369  // is not relocatable. This is not really portable, though.
370  if (strstr (info.dli_fname, ".so") == 0 && libaddr == 0x400000)
371  relative_address = addr;
372 
373  // need popen for addr2line ...
374  int pfd;
375  pid_t child_pid;
376  const char* symname = dembuf;
377  size_t demlen = 0;
378 
379  // did we find valid entry ?
380  size_t len = strlen(info.dli_fname);
381  if ( len > 0 && len + 80 < LINE_MAX)
382  {
383  if (getenv ("LD_PRELOAD"))
384  unsetenv ("LD_PRELOAD");
385 
386  if ( addr2LinePath == "/usr/bin/eu-addr2line" )
387  {
388  snprintf (line, LINE_MAX, "%s -f -e %s %p | /usr/bin/c++filt | /usr/bin/tr \\\\012 \\\\040 ",
389  addr2LinePath.c_str(),
390  info.dli_fname,
391  (void*)relative_address);
392  }
393  else
394  {
395  snprintf (line, LINE_MAX, "%s -f -C -e %s %p",
396  addr2LinePath.c_str(),
397  info.dli_fname,
398  (void*)relative_address);
399  }
400 
401  pfd = stacktracePopenFD( line, child_pid );
402 
403  length = 1;
404  line[0] = ' ';
405 
406  // did we succeed to open the pipe?
407  if ( pfd >= 0 )
408  {
409  demlen = stacktraceReadline (pfd, dembuf, sizeof(dembuf));
410 
411  length = stacktraceReadline (pfd, line+1, sizeof(line)-1);
412  if (length >= 0) ++length;
413 
414  int stat = stacktracePcloseFD (pfd, child_pid);
415 
416  // don't print anything, if nothing is found
417  if ( stat || line[1] == '?' || length < 0)
418  {
419  line[1] = '\0';
420  length = 0;
421  }
422 
423  if ( stat || demlen <= 0 || dembuf[0] == '?') {
424  symname = info.dli_sname;
425  if (!symname) symname = "???";
426  demlen = strlen (symname);
427  }
428 
429  }
430  }
431  // RS end
432 
433  bufs [nbufs].iov_base = addrbuf;
434  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr);
435  ++nbufs;
436 
437  bufs [nbufs].iov_base = (void *) symname; // discard const
438  bufs [nbufs].iov_len = demlen;
439  ++nbufs;
440 
441  // RS start
442  bufs [nbufs].iov_base = line;
443  bufs [nbufs].iov_len = length;
444  ++nbufs;
445  // RS end
446 
447  bufs [nbufs].iov_base = diffbuf;
448  bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %c 0x%lx [",
449  gte ? '+' : '-', diff);
450  ++nbufs;
451 
452  bufs [nbufs].iov_base = (void *) libname; // discard const
453  bufs [nbufs].iov_len = strlen (libname);
454  ++nbufs;
455 
456  // RS start
457  bufs [nbufs].iov_base = relbuf;
458  bufs [nbufs].iov_len = snprintf( relbuf, relbuf_size, " D[%p]", (void*)relative_address );
459  ++nbufs;
460  // RS end
461 
462  bufs [nbufs].iov_base = (void *) trailer; // discard const
463  bufs [nbufs].iov_len = 2;
464  ++nbufs;
465 
466  }
467  else
468 #endif
469  {
470  bufs [nbufs].iov_base = addrbuf;
471  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr);
472  ++nbufs;
473 
474  bufs [nbufs].iov_base = (void *) "<unknown function>\n"; //no const
475  bufs [nbufs].iov_len = 19;
476  ++nbufs;
477  }
478 
479  writev (fd, bufs, nbufs);
480 }
481 
482 
483 #if !(HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR) && __GNUC__ >=4
484 extern "C" {
485  typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
486  struct _Unwind_Context;
487  typedef enum
488  {
489  _URC_NO_REASON = 0,
490  _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
491  _URC_FATAL_PHASE2_ERROR = 2,
492  _URC_FATAL_PHASE1_ERROR = 3,
493  _URC_NORMAL_STOP = 4,
494  _URC_END_OF_STACK = 5,
495  _URC_HANDLER_FOUND = 6,
496  _URC_INSTALL_CONTEXT = 7,
497  _URC_CONTINUE_UNWIND = 8
498  } _Unwind_Reason_Code;
499  typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
500  extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
501  extern _Unwind_Ptr _Unwind_GetIP (_Unwind_Context *);
502  extern _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
503 }
504 
511 _Unwind_Reason_Code
512 unwindWalkStack (_Unwind_Context *ctx, void *data)
513 {
514  IOFD fd = *(IOFD *) data;
515  iovec bufs [5];
516  int nbufs = 0;
517  const int addrbuf_size = 5 + BitTraits<unsigned long>::HexDigits;
518  char addrbuf [addrbuf_size];
519  const int diffbuf_size = 10 + 2 * BitTraits<unsigned long>::HexDigits;
520  char diffbuf [diffbuf_size];
521  static const char trailer [] = "]\n";
522  unsigned long ip = _Unwind_GetIP (ctx);
523  unsigned long ir = _Unwind_GetRegionStart (ctx);
524 
525 # if HAVE_DLADDR
526  Dl_info info;
527  if (dladdr ((void *) ir, &info) && info.dli_fname && info.dli_fname[0])
528  {
529  const char *libname = info.dli_fname;
530  const char *symname = (info.dli_sname && info.dli_sname[0]
531  ? info.dli_sname : "?");
532  unsigned long symaddr = (unsigned long) info.dli_saddr;
533  bool gte = (ip >= symaddr);
534  unsigned long diff = (gte ? ip - symaddr : symaddr - ip);
535 
536  bufs [nbufs].iov_base = addrbuf;
537  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip);
538  ++nbufs;
539 
540  bufs [nbufs].iov_base = (char *) symname; // discard const
541  bufs [nbufs].iov_len = strlen (symname);
542  ++nbufs;
543 
544  bufs [nbufs].iov_base = diffbuf;
545  bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %s 0x%lx [",
546  gte ? "+" : "-", diff);
547  ++nbufs;
548 
549  bufs [nbufs].iov_base = (char *) libname; // discard const
550  bufs [nbufs].iov_len = strlen (libname);
551  ++nbufs;
552 
553  bufs [nbufs].iov_base = (char *) trailer; // discard const
554  bufs [nbufs].iov_len = 2;
555  ++nbufs;
556  }
557  else
558 # endif // HAVE_DLADDR
559  {
560  bufs [nbufs].iov_base = addrbuf;
561  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip);
562  ++nbufs;
563 
564  bufs [nbufs].iov_base = diffbuf;
565  bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " <?%08lx> + 0x%lx\n",
566  ir, ip - ir);
567  ++nbufs;
568  }
569 
570  writev (fd, bufs, nbufs);
571  return _URC_NO_REASON;
572 }
573 #endif // GCC 3.4+
574 
575 //<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>>
576 
577 // Change the path of the binary used for symbolization.
578 void DebugAids::setStackTraceAddr2Line ATLAS_NOT_THREAD_SAFE (const char* path)
579 {
580  addr2LinePath = path;
581 }
582 
583 
584 #if HAVE_U_STACK_TRACE
585 // HP-UX stack walker (http://devresource.hp.com/STK/partner/unwind.pdf)
586 extern "C" void U_STACK_TRACE (void);
587 #endif
588 
589 #if HAVE_XL_TRBK
590 // AIX stack walker (from xlf FORTRAN 90 runtime).
591 extern "C" void xl__trbk (void);
592 #endif
593 
594 //<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>>
595 
602 IOFD
603 DebugAids::stacktraceFd (IOFD fd /* = IOFD_INVALID */)
604 {
606  if (fd == IOFD_INVALID) {
607  if (old == IOFD_INVALID) {
608  s_stackTraceFd.compare_exchange_strong (old, STDERR_HANDLE);
609  return s_stackTraceFd;
610  }
611  }
612  else {
613  s_stackTraceFd.compare_exchange_strong (old, fd);
614  }
615  return old;
616 }
617 
632 void
633 DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */)
634 {
635  if (fd == IOFD_INVALID)
636  fd = stacktraceFd();
637 
638  std::cerr.flush ();
639  fflush (stderr);
640 
641 #ifdef _WIN32
642  // FIXME: Autoload all these functions so users don't need to
643  // link in imagehlp.dll.
644  if (! SymInitialize (GetCurrentProcess (), NULL, TRUE))
645  {
646  MYWRITELIT (fd, ("failed to dump stack trace:"
647  " cannot get symbolic information\n"));
648  return;
649  }
650 
651  union SYMBUFFER {
652  IMAGEHLP_SYMBOL sym;
653  BYTE buffer [ sizeof (IMAGEHLP_SYMBOL) + 512 ];
654  };
655 
656  unsigned level = 0;
657  CONTEXT context;
658  STACKFRAME frame;
659  SYMBUFFER symbol;
660  IMAGEHLP_MODULE module;
661  char modulename [MAX_PATH];
662  DWORD section;
663  DWORD offset;
664  const int buf_size = 2*40+6; // ample for two 128+ bit numbers
665  char buf [buf_size];
666  // DWORD exceptargs [] = { (DWORD) &context };
667 
668  // FIXME: XP 64-bit adds: RtlCaptureContext (&context);
669  // This is documented to *not* work, but apparently it does.
670  context.ContextFlags = CONTEXT_FULL;
671  if (! GetThreadContext (GetCurrentThread (), &context))
672  return;
673 
674  // LPTOP_LEVEL_EXCEPTION_FILTER oldseh
675  // = SetUnhandledExceptionFilter (&GrabExceptionContext);
676  // RaiseException (0, 0, 1, exceptargs);
677  // SetUnhandledExceptionFilter (oldseh);
678 
679  memset (&module, 0, sizeof (module));
680  memset (&frame, 0, sizeof (frame));
681 
682  module.SizeOfStruct = sizeof (module);
683 
684  frame.AddrPC.Offset = context.Eip;
685  frame.AddrPC.Mode = AddrModeFlat;
686  frame.AddrStack.Offset = context.Esp;
687  frame.AddrStack.Mode = AddrModeFlat;
688  frame.AddrFrame.Offset = context.Ebp;
689  frame.AddrFrame.Mode = AddrModeFlat;
690 
691  while (true)
692  {
693  if (! StackWalk (IMAGE_FILE_MACHINE_I386,
694  GetCurrentProcess (),
695  GetCurrentThread (),
696  &frame,
697  &context,
698  NULL,
699  SymFunctionTableAccess,
700  SymGetModuleBase,
701  NULL)
702  || frame.AddrFrame.Offset == 0)
703  break;
704 
705  // FIXME: Throw away everything above stacktrace? Keep looping
706  // below until the name includes something we understand?
707 
708  // Print stack frame too? If we know how many arguments there
709  // are (from demangling function name -- see below, could count
710  // commas), args are: *((ULONG *)frame.AddrFrame.Offset+2+ARG).
711  MYWRITE (fd, buf, snprintf (buf, buf_size, "(%2u) 0x%08lx 0x%08lx ",
712  level, frame.AddrPC.Offset,
713  frame.AddrFrame.Offset));
714 
715  memset (&symbol, 0, sizeof (symbol));
716  symbol.sym.SizeOfStruct = sizeof (symbol);
717  symbol.sym.MaxNameLength = sizeof (symbol) - sizeof (symbol.sym);
718 
719  offset = 0;
720  if (SymGetSymFromAddr (GetCurrentProcess (), frame.AddrPC.Offset,
721  &offset, &symbol.sym))
722  {
723  // FIXME: Demangle name with:
724  // UnDecorateSymbolName (name, undecname, sizeof (undecname),
725  // UNDNAME_COMPLETE
726  // | UNDNAME_NO_THISTYPE
727  // | UNDNAME_NO_SPECIAL_SYMS
728  // | UNDNAME_NO_MEMBER_TYPE
729  // | UNDNAME_NO_MS_KEYWORDS
730  // | UNDNAME_NO_ACCESS_SPECIFIERS);
731  MYWRITE (fd, symbol.sym.Name, STDC::strlen (symbol.sym.Name));
732  MYWRITE (fd, buf, snprintf (buf, buf_size, " + %lx", offset));
733 
734  if (SymGetModuleInfo (GetCurrentProcess(), frame.AddrPC.Offset,
735  &module))
736  {
737  MYWRITELIT (fd, " [");
738  MYWRITE (fd, module.ImageName,
739  STDC::strlen (module.ImageName));
740  MYWRITELIT (fd, "]");
741  }
742  }
743  else
744  {
745  GetLogicalAddress ((PVOID) frame.AddrPC.Offset,
746  modulename, sizeof (modulename),
747  section, offset);
748  MYWRITE (fd, buf, snprintf (buf, buf_size, "%04lx:%08lx [", section, offset));
749  MYWRITE (fd, modulename, STDC::strlen (modulename));
750  MYWRITELIT (fd, "]");
751  }
752  MYWRITELIT (fd, "\n");
753  ++level;
754  }
755  SymCleanup (GetCurrentProcess ());
756 
757 #elif (HAVE_U_STACK_TRACE || HAVE_XL_TRBK) // hp-ux, aix
758  // FIXME: deal with inability to duplicate the file handle
759  int stderrfd = dup (STDERR_FILENO);
760  if (stderrfd == -1)
761  return;
762 
763  int newfd = dup2 (fd, STDERR_FILENO);
764  if (newfd == -1)
765  {
766  close (stderrfd);
767  return;
768  }
769 
770 # if HAVE_U_STACK_TRACE // hp-ux
771  U_STACK_TRACE ();
772 # elif HAVE_XL_TRBK // aix
773  xl__trbk ();
774 # else
775 # error "oops, you shouldn't have gotten here!"
776 # endif
777 
778  fflush (stderr);
779  dup2 (stderrfd, STDERR_FILENO);
780  close (newfd);
781 #elif HAVE_LINUX_UNWIND_BACKTRACE
782  CxxUtils::backtraceByUnwind (stacktraceLine, fd);
783 
784 #elif HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR // linux
785  // we could have used backtrace_symbols_fd, except its output
786  // format is pretty bad, so recode that here :-(
787  void *trace [MAX_BACKTRACE_DEPTH];
788  int depth = backtrace (trace, MAX_BACKTRACE_DEPTH);
789 
790  for (int n = 0; n < depth; ++n/*, nbufs = 0*/)
791  {
792  unsigned long addr = (unsigned long) trace [n];
793  stacktraceLine (fd, addr);
794  }
795 
796 #elif HAVE_EXCPT_H && HAVE_PDSC_H && HAVE_RLD_INTERFACE_H // tru64
797  // Tru64 stack walk. Uses the exception handling library and the
798  // run-time linker's core functions (loader(5)). FIXME: Tru64
799  // should have _RLD_DLADDR like IRIX below. Verify and update.
800 
801  const int buffer_size = 100 + BitTraits<unsigned long>::HexDigits * 2 + 11;
802  char buffer [buffer_size];
803  sigcontext context;
804  int rc = 0;
805 
806  exc_capture_context (&context);
807  while (!rc && context.sc_pc)
808  {
809  // FIXME: Elf32?
810  pdsc_crd *func, *base, *crd
811  = exc_remote_lookup_function_entry(0, 0, context.sc_pc, 0, &func, &base);
812  Elf32_Addr addr = PDSC_CRD_BEGIN_ADDRESS(base, func);
813  // const char *name = _rld_address_to_name(addr);
814  const char *name = "<unknown function>";
815  snprintf (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n",
816  context.sc_pc, name, context.sc_pc - addr);
817  write (fd, buffer, STDC::strlen(buffer));
818  rc = exc_virtual_unwind(0, &context);
819  }
820 
821 #elif HAVE_EXCEPTION_H && defined __sgi // irix
822  // IRIX stack walk -- like Tru64 but with a little different names.
823  // NB: The guard above is to protect against unrelated <exception.h>
824  // provided by some compilers (e.g. KCC 4.0f).
825  // NB: libexc.h has trace_back_stack and trace_back_stack_and_print
826  // but their output isn't pretty and nowhere as complete as ours.
827  char buffer [340];
828  sigcontext context;
829 
830  exc_setjmp (&context);
831  while (context.sc_pc >= 4)
832  {
833  // Do two lookups, one using exception handling tables and
834  // another using _RLD_DLADDR, and use the one with a smaller
835  // offset. For signal handlers we seem to get things wrong:
836  // _sigtramp's exception range is huge while based on Dl_info
837  // the offset is small -- but both supposedly describe the
838  // same thing. Go figure.
839  char *name = 0;
840  const char *libname = 0;
841  const char *symname = 0;
842  Elf32_Addr offset = ~0L;
843 
844  // Do the exception/dwarf lookup
845  Elf32_Addr pc = context.sc_pc;
846  Dwarf_Fde fde = find_fde_name (&pc, &name);
847  Dwarf_Addr low_pc = context.sc_pc;
848  Dwarf_Unsigned udummy;
849  Dwarf_Signed sdummy;
850  Dwarf_Ptr pdummy;
851  Dwarf_Off odummy;
852  Dwarf_Error err;
853 
854  symname = name;
855 
856  // Determine offset using exception descriptor range information.
857  if (dwarf_get_fde_range (fde, &low_pc, &udummy, &pdummy, &udummy,
858  &odummy, &sdummy, &odummy, &err) == DW_DLV_OK)
859  offset = context.sc_pc - low_pc;
860 
861  // Now do a dladdr() lookup. If the found symbol has the same
862  // address, trust the more accurate offset from dladdr();
863  // ignore the looked up mangled symbol name and prefer the
864  // demangled name produced by find_fde_name(). If we find a
865  // smaller offset, trust the dynamic symbol as well. Always
866  // trust the library name even if we can't match it with an
867  // exact symbol.
868  Elf32_Addr addr = context.sc_pc;
869  Dl_info info;
870 
871  if (_rld_new_interface (_RLD_DLADDR, addr, &info))
872  {
873  if (info.dli_fname && info.dli_fname [0])
874  libname = info.dli_fname;
875 
876  Elf32_Addr symaddr = (Elf32_Addr) info.dli_saddr;
877  if (symaddr == low_pc)
878  offset = addr - symaddr;
879  else if (info.dli_sname
880  && info.dli_sname [0]
881  && addr - symaddr < offset)
882  {
883  offset = addr - symaddr;
884  symname = info.dli_sname;
885  }
886  }
887 
888  // Print out the result
889  if (libname && symname)
890  write (fd, buffer, snprintf
891  (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx [%.200s]\n",
892  addr, symname, offset, libname));
893  else if (symname)
894  write (fd, buffer, snprintf
895  (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n",
896  addr, symname, offset));
897  else
898  write (fd, buffer, snprintf
899  (buffer, buffer_size, " 0x%012lx <unknown function>\n", addr));
900 
901  // Free name from find_fde_name().
902  free (name);
903 
904  // Check for termination. exc_unwind() sets context.sc_pc to
905  // 0 or an error (< 4). However it seems we can't unwind
906  // through signal stack frames though this is not mentioned in
907  // the docs; it seems that for those we need to check for
908  // changed pc after find_fde_name(). That seems to indicate
909  // end of the post-signal stack frame. (FIXME: Figure out how
910  // to unwind through signal stack frame, e.g. perhaps using
911  // sigcontext_t's old pc? Or perhaps we can keep on going
912  // down without doing the symbol lookup?)
913  if (pc != context.sc_pc)
914  break;
915 
916  exc_unwind (&context, fde);
917  }
918 
919 #elif defined PROG_PSTACK // solaris
920 # ifdef PROG_CXXFILT
921 # define CXXFILTER " | " PROG_CXXFILT
922 # else
923 # define CXXFILTER
924 # endif
925  // 64 should more than plenty for a space and a pid.
926  const int buffer_size = sizeof(PROG_PSTACK) + 1 + BitTraits<unsigned long>::Digits
927  + 3 + sizeof(PROG_CXXFILT) + BitTraits<int>::Digits + 1;
928  char buffer [buffer_size];
929  snprintf (buffer, buffer_size, "%s %lu%s 1>&%d", PROG_PSTACK, (unsigned long) getpid (),
930  "" CXXFILTER, fd);
931  system (buffer);
932 # undef CXXFILTER
933 
934 #elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
935  // FIXME: Check for _Unwind*, compilers other than GCC support this API
936  _Unwind_Backtrace (unwindWalkStack, &fd);
937 #endif
938 
939  // FIXME: mpatrol has some generic unix unwind code.
940  // FIXME: from unix faq: ask debugger to dump stack trace
941  // with something like:
942  // - gdb: echo "thread apply all where\nwhere\ndetach" | gdb $prog $pid
943  // - dbx: echo "where\ndetach" | dbx -a $program_path $pid
944  // - dbx (aix): echo "where\ndetach" | dbx -p $program_path $pid
945 }
946 
969 void
971 {
972 #ifndef _WIN32
973  // FIXME: Forking vs. threads -- need to sort out what is safe.
974  // FIXME: Provide a resource limits interface so that core
975  // resource limits can be raised?
976 
977  pid_t corepid;
978  int status;
979 
980  ::unlink ("core");
981  if ((corepid = ::fork ()) == 0)
982  {
983  // In child: re-raise the signal, thus killing the process and
984  // producing a core dump. Make sure 1) the signal is not
985  // blocked so that we won't return to the caller, 2) we have a
986  // signal that is fatal, 3) the signal falls to its default
987  // handler to produce the dump.
988 
989 #ifdef SIGUSR1
990  // SIGUSR1 does not cause a core dump; use abort() instead
991  if (sig == SIGUSR1)
992  sig = SIGABRT; // Could be SIGIOT if SIGABRT is not defined
993 #endif
994  Signal::handle (sig, (Signal::HandlerType) (void*)SIG_DFL);
995  Signal::block (sig, false);
996  Signal::raise (sig);
997 
998  // Yikes, this shouldn't happen. ASSERT isn't right here. If
999  // raise() failed to deliver the signal, abort() is unlikely
1000  // to work any better, but try it anyway. Then make sure we
1001  // die so that we won't return to the caller from the child.
1002  abort ();
1003  // cppcheck-suppress unreachableCode
1004  _exit (255);
1005  }
1006  else if (corepid > 0) {
1007  pid_t wait_pid;
1008  do {
1009  wait_pid = ::waitpid (corepid, &status, 0);
1010  } while (wait_pid == -1 && errno == EINTR);
1011  }
1012 #endif // !_WIN32
1013 }
1014 
1015 
1025 unsigned long
1027 {
1028  struct rlimit core_limit;
1029  getrlimit(RLIMIT_CORE, &core_limit);
1030 
1031  unsigned long old_limit = core_limit.rlim_cur;
1032  core_limit.rlim_cur = core_limit.rlim_max;
1033  if ( setrlimit(RLIMIT_CORE, &core_limit) == 0 ) {
1034  return core_limit.rlim_cur;
1035  }
1036  else {
1037  return old_limit;
1038  }
1039 }
1040 
1047 {
1048  struct rlimit core_limit;
1049  core_limit.rlim_cur = 0;
1050  setrlimit(RLIMIT_CORE, &core_limit);
1051 }
1052 
1053 
1054 } // namespace Athena wlav
grepfile.info
info
Definition: grepfile.py:38
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:633
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
collListGuids.line
string line
Definition: collListGuids.py:77
Athena::DebugAids::coredump
static void coredump(int sig,...)
Drop a core dump and continue.
Definition: SealDebug.cxx:970
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.
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:12
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:182
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:731
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:219
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:603
beamspotman.stat
stat
Definition: beamspotman.py:266
python.dummyaccess.access
def access(filename, mode)
Definition: dummyaccess.py:18
beamspotman.dir
string dir
Definition: beamspotman.py:623
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:18
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:1026
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:17
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:1046
check_log.backtrace
backtrace
Definition: check_log.py:58
length
double length(const pvec &v)
Definition: FPGATrackSimLLPDoubletHoughTransformTool.cxx:26
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:99
Athena::ATLAS_NOT_THREAD_SAFE
void DebugAids::stacktraceLine ATLAS_NOT_THREAD_SAFE(IOFD fd, unsigned long addr)
Write out stack trace line to FD.
Definition: SealDebug.cxx:328