1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "backtrace.h"
6
7#include <qlogging.h>
8#include <QCoreApplication>
9
10#include <csignal>
11#include <execinfo.h>
12#include <cxxabi.h>
13#include <dlfcn.h>
14#include <sstream>
15
16#define TOSTRING(s) #s
17
18DPF_BEGIN_NAMESPACE
19namespace backtrace {
20
21/*!
22 * \brief demangle ABI-mandated entry point in the
23 * C++ runtime library for demangling
24 * \param value backtrace string
25 * \return demangled value
26 */
27std::string demangle(void *value)
28{
29 if (!value)
30 return "";
31
32 std::ostringstream ostream;
33 ostream.imbue(std::locale::classic());
34 ostream << value << " : ";
35 Dl_info info = {nullptr, nullptr, nullptr, nullptr};
36 if (dladdr(value, &info) == 0) {
37 ostream << "???";
38 } else {
39 if (info.dli_sname) {
40 int status = 0;
41 char *demangledName = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
42 if (demangledName) {
43 ostream << demangledName;
44 free(demangledName);
45 } else {
46 ostream << info.dli_sname;
47 }
48 } else {
49 ostream << "???";
50 }
51
52 long offset = reinterpret_cast<char *>(value) - reinterpret_cast<char *>(info.dli_saddr);
53 ostream << std::hex << " + 0x" << offset ;
54
55 if (info.dli_fname)
56 ostream << " @ " << info.dli_fname;
57 }
58 return ostream.str();
59}
60
61/*!
62 * \brief logStackInfo
63 * \param signal kernel expection signal
64 */
65[[noreturn]] void logStackInfo(int signal)
66{
67 const int bufSize = 100;
68 void *buffer[bufSize] = {nullptr};
69 int numLine = ::backtrace(buffer, bufSize);
70
71 std::string strSig;
72 switch (signal) {
73 case SIGINT: /* Interactive attention signal. */
74 strSig = TOSTRING(SIGINT);
75 break;
76 case SIGILL: /* Illegal instruction. */
77 strSig = TOSTRING(SIGILL);
78 break;
79 case SIGABRT: /* Abnormal termination. */
80 strSig = TOSTRING(SIGABRT);
81 break;
82 case SIGFPE: /* Erroneous arithmetic operation. */
83 strSig = TOSTRING(SIGFPE);
84 break;
85 case SIGSEGV: /* Invalid access to storage. */
86 strSig = TOSTRING(SIGSEGV);
87 break;
88 case SIGTERM: /* Termination request. */
89 strSig = TOSTRING(SIGTERM);
90 break;
91 default:
92 char szTmpBuf[bufSize] = {0};
93 sprintf(szTmpBuf, "No register signal: %d", signal);
94 strSig = szTmpBuf;
95 break;
96 };
97 QString head,end;
98 head = QString("****************** %0 crashed backtrace ******************")
99 .arg(qApp->applicationName());
100 qCritical("%s", head.toStdString().data());
101 qCritical("* signal:%s numLine:%d", strSig.data(), numLine);
102 for (int i = 1; i < numLine; ++i) {
103 std::string stackInfo = demangle(buffer[i]);
104 qCritical("* %d> %s", i, stackInfo.data());
105 }
106 for(int index = head.size(); index > 0; index --) {
107 end += "*";
108 }
109 qCritical("%s", end.toStdString().data());
110 exit(EXIT_FAILURE);
111}
112
113/*!
114 * \brief regSignal
115 * register sig signal handler.
116 * \param sig
117 */
118void regSignal(int sig)
119{
120 signal(sig, logStackInfo);
121}
122
123/*!
124 * \brief initbacktrace
125 * Register signal handler.
126 */
127void initbacktrace()
128{
129 regSignal(SIGINT); /* Interactive attention signal. */
130 regSignal(SIGILL); /* Illegal instruction. */
131 regSignal(SIGABRT); /* Abnormal termination. */
132 regSignal(SIGFPE); /* Erroneous arithmetic operation. */
133 regSignal(SIGSEGV); /* Invalid access to storage. */
134 regSignal(SIGTERM); /* Termination request. */
135}
136}
137DPF_END_NAMESPACE
138