1 /*  $Id: ncbi_stack_libbackward.cpp 567764 2018-07-24 12:05:33Z ivanov $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors:  Anton Perkov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 #include <ncbiconf.h>
32 
33 #if defined(HAVE_LIBDW)
34 #  define BACKWARD_HAS_DW 1
35 #elif defined(HAVE_LIBUNWIND)
36 #  define BACKWARD_HAS_UNWIND 1
37 #endif
38 
39 #include <backward.hpp>
40 #if defined(HAVE_CXA_DEMANGLE)
41 #  include <cxxabi.h>
42 #endif
43 #include <stdio.h>
44 
45 BEGIN_NCBI_SCOPE
46 
47 #define CAN_HONOR_SIGNAL_HANDLING_CONFIGURATION 1
48 
49 #if defined(USE_LIBBACKWARD_SIG_HANDLING)
50 #  define TRACE_SIGNALS_BY_DEFAULT true
51 #else
52 #  define TRACE_SIGNALS_BY_DEFAULT false
53 #endif
54 
55 NCBI_PARAM_DECL(bool, Debug, Trace_Fatal_Signals);
56 NCBI_PARAM_DEF_EX(bool, Debug, Trace_Fatal_Signals, TRACE_SIGNALS_BY_DEFAULT,
57                   0, DEBUG_TRACE_FATAL_SIGNALS);
58 typedef NCBI_PARAM_TYPE(Debug, Trace_Fatal_Signals) TTraceFatalSignals;
59 
60 unique_ptr<backward::SignalHandling> s_SignalHandler;
61 
62 
63 // Call this function to get a backtrace.
64 class CStackTraceImpl
65 {
66 public:
67     CStackTraceImpl(void);
68     ~CStackTraceImpl(void);
69 
70     void Expand(CStackTrace::TStack& stack);
71     static void s_HonorSignalHandlingConfiguration(void);
72 
73 private:
74     typedef backward::StackTrace TStack;
75 
76     TStack m_Stack;
77 };
78 
79 
CStackTraceImpl(void)80 CStackTraceImpl::CStackTraceImpl(void)
81 {
82     m_Stack.load_here();
83 }
84 
85 
~CStackTraceImpl(void)86 CStackTraceImpl::~CStackTraceImpl(void)
87 {
88 }
89 
90 
Expand(CStackTrace::TStack & stack)91 void CStackTraceImpl::Expand(CStackTrace::TStack& stack)
92 {
93     backward::TraceResolver resolver;
94     resolver.load_stacktrace(m_Stack);
95     for (size_t trace_idx = 0; trace_idx < m_Stack.size(); ++trace_idx) {
96         CStackTrace::SStackFrameInfo info;
97         const backward::ResolvedTrace& trace
98             = resolver.resolve(m_Stack[trace_idx]);
99         info.module = trace.object_filename;
100         info.addr = trace.addr;
101 
102         if (!trace.source.filename.size()) {
103             /*os << "   Object \""
104                << trace.object_filename
105                << ", at "
106                << trace.addr
107                << ", in "
108                << trace.object_function
109                << "\n";*/
110         }
111 
112         for (size_t inliner_idx = 0; inliner_idx < trace.inliners.size(); ++inliner_idx) {
113             const backward::ResolvedTrace::SourceLoc& inliner_loc = trace.inliners[inliner_idx];
114             CStackTrace::SStackFrameInfo info2;
115             info2.file = inliner_loc.filename;
116             info2.line = inliner_loc.line;
117             info2.func = inliner_loc.function;
118             stack.push_back(move(info2));
119         }
120 
121         if (trace.source.filename.size()) {
122             info.file = trace.source.filename;
123             info.line = trace.source.line;
124             //info.func = trace.source.function;
125             info.func = trace.object_function;
126             info.addr = trace.addr;
127         }
128         stack.push_back(move(info));
129     }
130 }
131 
s_HonorSignalHandlingConfiguration(void)132 void CStackTraceImpl::s_HonorSignalHandlingConfiguration(void)
133 {
134     if (TTraceFatalSignals::GetDefault()) {
135         s_SignalHandler.reset(new backward::SignalHandling);
136     }
137 }
138 
139 END_NCBI_SCOPE
140