ATLAS Offline Software
SealDebug.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 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 
345  if (dladdr ((void*)addr, &info) && info.dli_fname && info.dli_fname[0])
346  {
347  const char *libname = info.dli_fname;
348 
349  unsigned long symaddr = (unsigned long) info.dli_saddr;
350  bool gte = (addr >= symaddr);
351  unsigned long diff = (gte ? addr - symaddr : symaddr - addr);
352 
353  // RS start
354  int length = 0;
355 
356  const int relbuf_size = 7 + BitTraits<unsigned long>::HexDigits;
357  char relbuf [relbuf_size];
358 
359  // difference of two pointers
360  unsigned long libaddr = (unsigned long) info.dli_fbase;
361  unsigned long relative_address = (addr >= libaddr) ? addr - libaddr : libaddr - addr;
362  // ELF executables are usually not relocatable, and on 64-bit platforms
363  // are usually loaded starting at 0x400000. In that case, we should _not_
364  // subtract the base address. But clang15 by default appears to produce
365  // position-independent executables (PIE) by default. In that case,
366  // we do need to subtract the offset.
367  // I'm not sure how to reliably tell the difference short of parsing
368  // the object headers. For now, just assume that something
369  // that doesn't have .so in the name and is loaded at 0x400000
370  // is not relocatable. This is not really portable, though.
371  if (strstr (info.dli_fname, ".so") == 0 && libaddr == 0x400000)
372  relative_address = addr;
373 
374  // need popen for addr2line ...
375  int pfd;
376  pid_t child_pid;
377  const char* symname = dembuf;
378  size_t demlen = 0;
379 
380  // did we find valid entry ?
381  size_t len = strlen(info.dli_fname);
382  if ( len > 0 && len + 80 < LINE_MAX)
383  {
384  if (getenv ("LD_PRELOAD"))
385  unsetenv ("LD_PRELOAD");
386 
387  if ( addr2LinePath == "/usr/bin/eu-addr2line" )
388  {
389  snprintf (line, LINE_MAX, "%s -f -e %s %p | /usr/bin/c++filt | /usr/bin/tr \\\\012 \\\\040 ",
390  addr2LinePath.c_str(),
391  info.dli_fname,
392  (void*)relative_address);
393  }
394  else
395  {
396  snprintf (line, LINE_MAX, "%s -f -C -e %s %p",
397  addr2LinePath.c_str(),
398  info.dli_fname,
399  (void*)relative_address);
400  }
401 
402  pfd = stacktracePopenFD( line, child_pid );
403 
404  length = 1;
405  line[0] = ' ';
406 
407  // did we succeed to open the pipe?
408  if ( pfd >= 0 )
409  {
410  demlen = stacktraceReadline (pfd, dembuf, sizeof(dembuf));
411 
412  length = stacktraceReadline (pfd, line+1, sizeof(line)-1);
413  if (length >= 0) ++length;
414 
415  int stat = stacktracePcloseFD (pfd, child_pid);
416 
417  // don't print anything, if nothing is found
418  if ( stat || line[1] == '?' || length < 0)
419  {
420  line[1] = '\0';
421  length = 0;
422  }
423 
424  if ( stat || demlen <= 0 || dembuf[0] == '?') {
425  symname = info.dli_sname;
426  if (!symname) symname = "???";
427  demlen = strlen (symname);
428  }
429 
430  }
431  }
432  // RS end
433 
434  bufs [nbufs].iov_base = addrbuf;
435  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr);
436  ++nbufs;
437 
438  bufs [nbufs].iov_base = (void *) symname; // discard const
439  bufs [nbufs].iov_len = demlen;
440  ++nbufs;
441 
442  // RS start
443  bufs [nbufs].iov_base = line;
444  bufs [nbufs].iov_len = length;
445  ++nbufs;
446  // RS end
447 
448  bufs [nbufs].iov_base = diffbuf;
449  bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %c 0x%lx [",
450  gte ? '+' : '-', diff);
451  ++nbufs;
452 
453  bufs [nbufs].iov_base = (void *) libname; // discard const
454  bufs [nbufs].iov_len = strlen (libname);
455  ++nbufs;
456 
457  // RS start
458  bufs [nbufs].iov_base = relbuf;
459  bufs [nbufs].iov_len = snprintf( relbuf, relbuf_size, " D[%p]", (void*)relative_address );
460  ++nbufs;
461  // RS end
462 
463  bufs [nbufs].iov_base = (void *) trailer; // discard const
464  bufs [nbufs].iov_len = 2;
465  ++nbufs;
466 
467  }
468  else
469 #endif
470  {
471  bufs [nbufs].iov_base = addrbuf;
472  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", addr);
473  ++nbufs;
474 
475  bufs [nbufs].iov_base = (void *) "<unknown function>\n"; //no const
476  bufs [nbufs].iov_len = 19;
477  ++nbufs;
478  }
479 
480  writev (fd, bufs, nbufs);
481 }
482 
483 
484 #if !(HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR) && __GNUC__ >=4
485 extern "C" {
486  typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
487  struct _Unwind_Context;
488  typedef enum
489  {
490  _URC_NO_REASON = 0,
491  _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
492  _URC_FATAL_PHASE2_ERROR = 2,
493  _URC_FATAL_PHASE1_ERROR = 3,
494  _URC_NORMAL_STOP = 4,
495  _URC_END_OF_STACK = 5,
496  _URC_HANDLER_FOUND = 6,
497  _URC_INSTALL_CONTEXT = 7,
498  _URC_CONTINUE_UNWIND = 8
499  } _Unwind_Reason_Code;
500  typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
501  extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
502  extern _Unwind_Ptr _Unwind_GetIP (_Unwind_Context *);
503  extern _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
504 }
505 
512 _Unwind_Reason_Code
513 unwindWalkStack (_Unwind_Context *ctx, void *data)
514 {
515  IOFD fd = *(IOFD *) data;
516  iovec bufs [5];
517  int nbufs = 0;
518  const int addrbuf_size = 5 + BitTraits<unsigned long>::HexDigits;
519  char addrbuf [addrbuf_size];
520  const int diffbuf_size = 10 + 2 * BitTraits<unsigned long>::HexDigits;
521  char diffbuf [diffbuf_size];
522  static const char trailer [] = "]\n";
523  unsigned long ip = _Unwind_GetIP (ctx);
524  unsigned long ir = _Unwind_GetRegionStart (ctx);
525 
526 # if HAVE_DLADDR
527  Dl_info info;
528  if (dladdr ((void *) ir, &info) && info.dli_fname && info.dli_fname[0])
529  {
530  const char *libname = info.dli_fname;
531  const char *symname = (info.dli_sname && info.dli_sname[0]
532  ? info.dli_sname : "?");
533  unsigned long symaddr = (unsigned long) info.dli_saddr;
534  bool gte = (ip >= symaddr);
535  unsigned long diff = (gte ? ip - symaddr : symaddr - ip);
536 
537  bufs [nbufs].iov_base = addrbuf;
538  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip);
539  ++nbufs;
540 
541  bufs [nbufs].iov_base = (char *) symname; // discard const
542  bufs [nbufs].iov_len = strlen (symname);
543  ++nbufs;
544 
545  bufs [nbufs].iov_base = diffbuf;
546  bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " %s 0x%lx [",
547  gte ? "+" : "-", diff);
548  ++nbufs;
549 
550  bufs [nbufs].iov_base = (char *) libname; // discard const
551  bufs [nbufs].iov_len = strlen (libname);
552  ++nbufs;
553 
554  bufs [nbufs].iov_base = (char *) trailer; // discard const
555  bufs [nbufs].iov_len = 2;
556  ++nbufs;
557  }
558  else
559 # endif // HAVE_DLADDR
560  {
561  bufs [nbufs].iov_base = addrbuf;
562  bufs [nbufs].iov_len = snprintf (addrbuf, addrbuf_size, " 0x%08lx ", ip);
563  ++nbufs;
564 
565  bufs [nbufs].iov_base = diffbuf;
566  bufs [nbufs].iov_len = snprintf (diffbuf, diffbuf_size, " <?%08lx> + 0x%lx\n",
567  ir, ip - ir);
568  ++nbufs;
569  }
570 
571  writev (fd, bufs, nbufs);
572  return _URC_NO_REASON;
573 }
574 #endif // GCC 3.4+
575 
576 //<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>>
577 
578 // Change the path of the binary used for symbolization.
579 void DebugAids::setStackTraceAddr2Line ATLAS_NOT_THREAD_SAFE (const char* path)
580 {
581  addr2LinePath = path;
582 }
583 
584 
585 #if HAVE_U_STACK_TRACE
586 // HP-UX stack walker (http://devresource.hp.com/STK/partner/unwind.pdf)
587 extern "C" void U_STACK_TRACE (void);
588 #endif
589 
590 #if HAVE_XL_TRBK
591 // AIX stack walker (from xlf FORTRAN 90 runtime).
592 extern "C" void xl__trbk (void);
593 #endif
594 
595 //<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>>
596 
603 IOFD
604 DebugAids::stacktraceFd (IOFD fd /* = IOFD_INVALID */)
605 {
607  if (fd == IOFD_INVALID) {
608  if (old == IOFD_INVALID) {
609  s_stackTraceFd.compare_exchange_strong (old, STDERR_HANDLE);
610  return s_stackTraceFd;
611  }
612  }
613  else {
614  s_stackTraceFd.compare_exchange_strong (old, fd);
615  }
616  return old;
617 }
618 
633 void
634 DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */)
635 {
636  if (fd == IOFD_INVALID)
637  fd = stacktraceFd();
638 
639  std::cerr.flush ();
640  fflush (stderr);
641 
642 #ifdef _WIN32
643  // FIXME: Autoload all these functions so users don't need to
644  // link in imagehlp.dll.
645  if (! SymInitialize (GetCurrentProcess (), NULL, TRUE))
646  {
647  MYWRITELIT (fd, ("failed to dump stack trace:"
648  " cannot get symbolic information\n"));
649  return;
650  }
651 
652  union SYMBUFFER {
653  IMAGEHLP_SYMBOL sym;
654  BYTE buffer [ sizeof (IMAGEHLP_SYMBOL) + 512 ];
655  };
656 
657  unsigned level = 0;
658  CONTEXT context;
659  STACKFRAME frame;
660  SYMBUFFER symbol;
661  IMAGEHLP_MODULE module;
662  char modulename [MAX_PATH];
663  DWORD section;
664  DWORD offset;
665  const int buf_size = 2*40+6; // ample for two 128+ bit numbers
666  char buf [buf_size];
667  // DWORD exceptargs [] = { (DWORD) &context };
668 
669  // FIXME: XP 64-bit adds: RtlCaptureContext (&context);
670  // This is documented to *not* work, but apparently it does.
671  context.ContextFlags = CONTEXT_FULL;
672  if (! GetThreadContext (GetCurrentThread (), &context))
673  return;
674 
675  // LPTOP_LEVEL_EXCEPTION_FILTER oldseh
676  // = SetUnhandledExceptionFilter (&GrabExceptionContext);
677  // RaiseException (0, 0, 1, exceptargs);
678  // SetUnhandledExceptionFilter (oldseh);
679 
680  memset (&module, 0, sizeof (module));
681  memset (&frame, 0, sizeof (frame));
682 
683  module.SizeOfStruct = sizeof (module);
684 
685  frame.AddrPC.Offset = context.Eip;
686  frame.AddrPC.Mode = AddrModeFlat;
687  frame.AddrStack.Offset = context.Esp;
688  frame.AddrStack.Mode = AddrModeFlat;
689  frame.AddrFrame.Offset = context.Ebp;
690  frame.AddrFrame.Mode = AddrModeFlat;
691 
692  while (true)
693  {
694  if (! StackWalk (IMAGE_FILE_MACHINE_I386,
695  GetCurrentProcess (),
696  GetCurrentThread (),
697  &frame,
698  &context,
699  NULL,
700  SymFunctionTableAccess,
701  SymGetModuleBase,
702  NULL)
703  || frame.AddrFrame.Offset == 0)
704  break;
705 
706  // FIXME: Throw away everything above stacktrace? Keep looping
707  // below until the name includes something we understand?
708 
709  // Print stack frame too? If we know how many arguments there
710  // are (from demangling function name -- see below, could count
711  // commas), args are: *((ULONG *)frame.AddrFrame.Offset+2+ARG).
712  MYWRITE (fd, buf, snprintf (buf, buf_size, "(%2u) 0x%08lx 0x%08lx ",
713  level, frame.AddrPC.Offset,
714  frame.AddrFrame.Offset));
715 
716  memset (&symbol, 0, sizeof (symbol));
717  symbol.sym.SizeOfStruct = sizeof (symbol);
718  symbol.sym.MaxNameLength = sizeof (symbol) - sizeof (symbol.sym);
719 
720  offset = 0;
721  if (SymGetSymFromAddr (GetCurrentProcess (), frame.AddrPC.Offset,
722  &offset, &symbol.sym))
723  {
724  // FIXME: Demangle name with:
725  // UnDecorateSymbolName (name, undecname, sizeof (undecname),
726  // UNDNAME_COMPLETE
727  // | UNDNAME_NO_THISTYPE
728  // | UNDNAME_NO_SPECIAL_SYMS
729  // | UNDNAME_NO_MEMBER_TYPE
730  // | UNDNAME_NO_MS_KEYWORDS
731  // | UNDNAME_NO_ACCESS_SPECIFIERS);
732  MYWRITE (fd, symbol.sym.Name, STDC::strlen (symbol.sym.Name));
733  MYWRITE (fd, buf, snprintf (buf, buf_size, " + %lx", offset));
734 
735  if (SymGetModuleInfo (GetCurrentProcess(), frame.AddrPC.Offset,
736  &module))
737  {
738  MYWRITELIT (fd, " [");
739  MYWRITE (fd, module.ImageName,
740  STDC::strlen (module.ImageName));
741  MYWRITELIT (fd, "]");
742  }
743  }
744  else
745  {
746  GetLogicalAddress ((PVOID) frame.AddrPC.Offset,
747  modulename, sizeof (modulename),
748  section, offset);
749  MYWRITE (fd, buf, snprintf (buf, buf_size, "%04lx:%08lx [", section, offset));
750  MYWRITE (fd, modulename, STDC::strlen (modulename));
751  MYWRITELIT (fd, "]");
752  }
753  MYWRITELIT (fd, "\n");
754  ++level;
755  }
756  SymCleanup (GetCurrentProcess ());
757 
758 #elif (HAVE_U_STACK_TRACE || HAVE_XL_TRBK) // hp-ux, aix
759  // FIXME: deal with inability to duplicate the file handle
760  int stderrfd = dup (STDERR_FILENO);
761  if (stderrfd == -1)
762  return;
763 
764  int newfd = dup2 (fd, STDERR_FILENO);
765  if (newfd == -1)
766  {
767  close (stderrfd);
768  return;
769  }
770 
771 # if HAVE_U_STACK_TRACE // hp-ux
772  U_STACK_TRACE ();
773 # elif HAVE_XL_TRBK // aix
774  xl__trbk ();
775 # else
776 # error "oops, you shouldn't have gotten here!"
777 # endif
778 
779  fflush (stderr);
780  dup2 (stderrfd, STDERR_FILENO);
781  close (newfd);
782 #elif HAVE_LINUX_UNWIND_BACKTRACE
783  CxxUtils::backtraceByUnwind (stacktraceLine, fd);
784 
785 #elif HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR // linux
786  // we could have used backtrace_symbols_fd, except its output
787  // format is pretty bad, so recode that here :-(
788  void *trace [MAX_BACKTRACE_DEPTH];
789  int depth = backtrace (trace, MAX_BACKTRACE_DEPTH);
790 
791  for (int n = 0; n < depth; ++n/*, nbufs = 0*/)
792  {
793  unsigned long addr = (unsigned long) trace [n];
794  stacktraceLine (fd, addr);
795  }
796 
797 #elif HAVE_EXCPT_H && HAVE_PDSC_H && HAVE_RLD_INTERFACE_H // tru64
798  // Tru64 stack walk. Uses the exception handling library and the
799  // run-time linker's core functions (loader(5)). FIXME: Tru64
800  // should have _RLD_DLADDR like IRIX below. Verify and update.
801 
802  const int buffer_size = 100 + BitTraits<unsigned long>::HexDigits * 2 + 11;
803  char buffer [buffer_size];
804  sigcontext context;
805  int rc = 0;
806 
807  exc_capture_context (&context);
808  while (!rc && context.sc_pc)
809  {
810  // FIXME: Elf32?
811  pdsc_crd *func, *base, *crd
812  = exc_remote_lookup_function_entry(0, 0, context.sc_pc, 0, &func, &base);
813  Elf32_Addr addr = PDSC_CRD_BEGIN_ADDRESS(base, func);
814  // const char *name = _rld_address_to_name(addr);
815  const char *name = "<unknown function>";
816  snprintf (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n",
817  context.sc_pc, name, context.sc_pc - addr);
818  write (fd, buffer, STDC::strlen(buffer));
819  rc = exc_virtual_unwind(0, &context);
820  }
821 
822 #elif HAVE_EXCEPTION_H && defined __sgi // irix
823  // IRIX stack walk -- like Tru64 but with a little different names.
824  // NB: The guard above is to protect against unrelated <exception.h>
825  // provided by some compilers (e.g. KCC 4.0f).
826  // NB: libexc.h has trace_back_stack and trace_back_stack_and_print
827  // but their output isn't pretty and nowhere as complete as ours.
828  char buffer [340];
829  sigcontext context;
830 
831  exc_setjmp (&context);
832  while (context.sc_pc >= 4)
833  {
834  // Do two lookups, one using exception handling tables and
835  // another using _RLD_DLADDR, and use the one with a smaller
836  // offset. For signal handlers we seem to get things wrong:
837  // _sigtramp's exception range is huge while based on Dl_info
838  // the offset is small -- but both supposedly describe the
839  // same thing. Go figure.
840  char *name = 0;
841  const char *libname = 0;
842  const char *symname = 0;
843  Elf32_Addr offset = ~0L;
844 
845  // Do the exception/dwarf lookup
846  Elf32_Addr pc = context.sc_pc;
847  Dwarf_Fde fde = find_fde_name (&pc, &name);
848  Dwarf_Addr low_pc = context.sc_pc;
849  Dwarf_Unsigned udummy;
850  Dwarf_Signed sdummy;
851  Dwarf_Ptr pdummy;
852  Dwarf_Off odummy;
853  Dwarf_Error err;
854 
855  symname = name;
856 
857  // Determine offset using exception descriptor range information.
858  if (dwarf_get_fde_range (fde, &low_pc, &udummy, &pdummy, &udummy,
859  &odummy, &sdummy, &odummy, &err) == DW_DLV_OK)
860  offset = context.sc_pc - low_pc;
861 
862  // Now do a dladdr() lookup. If the found symbol has the same
863  // address, trust the more accurate offset from dladdr();
864  // ignore the looked up mangled symbol name and prefer the
865  // demangled name produced by find_fde_name(). If we find a
866  // smaller offset, trust the dynamic symbol as well. Always
867  // trust the library name even if we can't match it with an
868  // exact symbol.
869  Elf32_Addr addr = context.sc_pc;
870  Dl_info info;
871 
872  if (_rld_new_interface (_RLD_DLADDR, addr, &info))
873  {
874  if (info.dli_fname && info.dli_fname [0])
875  libname = info.dli_fname;
876 
877  Elf32_Addr symaddr = (Elf32_Addr) info.dli_saddr;
878  if (symaddr == low_pc)
879  offset = addr - symaddr;
880  else if (info.dli_sname
881  && info.dli_sname [0]
882  && addr - symaddr < offset)
883  {
884  offset = addr - symaddr;
885  symname = info.dli_sname;
886  }
887  }
888 
889  // Print out the result
890  if (libname && symname)
891  write (fd, buffer, snprintf
892  (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx [%.200s]\n",
893  addr, symname, offset, libname));
894  else if (symname)
895  write (fd, buffer, snprintf
896  (buffer, buffer_size, " 0x%012lx %.100s + 0x%lx\n",
897  addr, symname, offset));
898  else
899  write (fd, buffer, snprintf
900  (buffer, buffer_size, " 0x%012lx <unknown function>\n", addr));
901 
902  // Free name from find_fde_name().
903  free (name);
904 
905  // Check for termination. exc_unwind() sets context.sc_pc to
906  // 0 or an error (< 4). However it seems we can't unwind
907  // through signal stack frames though this is not mentioned in
908  // the docs; it seems that for those we need to check for
909  // changed pc after find_fde_name(). That seems to indicate
910  // end of the post-signal stack frame. (FIXME: Figure out how
911  // to unwind through signal stack frame, e.g. perhaps using
912  // sigcontext_t's old pc? Or perhaps we can keep on going
913  // down without doing the symbol lookup?)
914  if (pc != context.sc_pc)
915  break;
916 
917  exc_unwind (&context, fde);
918  }
919 
920 #elif defined PROG_PSTACK // solaris
921 # ifdef PROG_CXXFILT
922 # define CXXFILTER " | " PROG_CXXFILT
923 # else
924 # define CXXFILTER
925 # endif
926  // 64 should more than plenty for a space and a pid.
927  const int buffer_size = sizeof(PROG_PSTACK) + 1 + BitTraits<unsigned long>::Digits
928  + 3 + sizeof(PROG_CXXFILT) + BitTraits<int>::Digits + 1;
929  char buffer [buffer_size];
930  snprintf (buffer, buffer_size, "%s %lu%s 1>&%d", PROG_PSTACK, (unsigned long) getpid (),
931  "" CXXFILTER, fd);
932  system (buffer);
933 # undef CXXFILTER
934 
935 #elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
936  // FIXME: Check for _Unwind*, compilers other than GCC support this API
937  _Unwind_Backtrace (unwindWalkStack, &fd);
938 #endif
939 
940  // FIXME: mpatrol has some generic unix unwind code.
941  // FIXME: from unix faq: ask debugger to dump stack trace
942  // with something like:
943  // - gdb: echo "thread apply all where\nwhere\ndetach" | gdb $prog $pid
944  // - dbx: echo "where\ndetach" | dbx -a $program_path $pid
945  // - dbx (aix): echo "where\ndetach" | dbx -p $program_path $pid
946 }
947 
970 void
972 {
973 #ifndef _WIN32
974  // FIXME: Forking vs. threads -- need to sort out what is safe.
975  // FIXME: Provide a resource limits interface so that core
976  // resource limits can be raised?
977 
978  pid_t corepid;
979  int status;
980 
981  ::unlink ("core");
982  if ((corepid = ::fork ()) == 0)
983  {
984  // In child: re-raise the signal, thus killing the process and
985  // producing a core dump. Make sure 1) the signal is not
986  // blocked so that we won't return to the caller, 2) we have a
987  // signal that is fatal, 3) the signal falls to its default
988  // handler to produce the dump.
989 
990 #ifdef SIGUSR1
991  // SIGUSR1 does not cause a core dump; use abort() instead
992  if (sig == SIGUSR1)
993  sig = SIGABRT; // Could be SIGIOT if SIGABRT is not defined
994 #endif
995  Signal::handle (sig, (Signal::HandlerType) (void*)SIG_DFL);
996  Signal::block (sig, false);
997  Signal::raise (sig);
998 
999  // Yikes, this shouldn't happen. ASSERT isn't right here. If
1000  // raise() failed to deliver the signal, abort() is unlikely
1001  // to work any better, but try it anyway. Then make sure we
1002  // die so that we won't return to the caller from the child.
1003  abort ();
1004  // cppcheck-suppress unreachableCode
1005  _exit (255);
1006  }
1007  else if (corepid > 0) {
1008  pid_t wait_pid;
1009  do {
1010  wait_pid = ::waitpid (corepid, &status, 0);
1011  } while (wait_pid == -1 && errno == EINTR);
1012  }
1013 #endif // !_WIN32
1014 }
1015 
1016 
1026 unsigned long
1028 {
1029  struct rlimit core_limit;
1030  getrlimit(RLIMIT_CORE, &core_limit);
1031 
1032  unsigned long old_limit = core_limit.rlim_cur;
1033  core_limit.rlim_cur = core_limit.rlim_max;
1034  if ( setrlimit(RLIMIT_CORE, &core_limit) == 0 ) {
1035  return core_limit.rlim_cur;
1036  }
1037  else {
1038  return old_limit;
1039  }
1040 }
1041 
1048 {
1049  struct rlimit core_limit;
1050  core_limit.rlim_cur = 0;
1051  setrlimit(RLIMIT_CORE, &core_limit);
1052 }
1053 
1054 
1055 } // 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:634
checkFileSG.line
line
Definition: checkFileSG.py:75
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:126
max
#define max(a, b)
Definition: cfImp.cxx:41
Athena::DebugAids::coredump
static void coredump(int sig,...)
Drop a core dump and continue.
Definition: SealDebug.cxx:971
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.
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:134
PlotCalibFromCool.modulename
modulename
Definition: PlotCalibFromCool.py:81
createCoolChannelIdFile.buffer
buffer
Definition: createCoolChannelIdFile.py:12
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:193
lumiFormat.i
int i
Definition: lumiFormat.py:92
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:215
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
python.Constants.TRUE
bool TRUE
for job options legacy (TODO: get rid of these!) ----------------------—
Definition: Control/AthenaCommon/python/Constants.py:22
Athena::DebugAids::stacktraceFd
static IOFD stacktraceFd(IOFD fd=IOFD_INVALID)
Set and return the file descriptor for stack trace output.
Definition: SealDebug.cxx:604
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:195
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:1027
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:569
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:1047
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