1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "config.h"
21
22 #ifdef HAVE_SIGNAL_H
23 # if !defined(_GNU_SOURCE)
24 # define _GNU_SOURCE /* required for getting at program counter */
25 # endif
26 # include <signal.h>
27 #endif
28
29 #ifdef HAVE_SYS_UCONTEXT_H
30 # if !defined(_GNU_SOURCE)
31 # define _GNU_SOURCE /* required for getting at program counter */
32 # endif
33 # include <sys/ucontext.h>
34 #endif
35
36 #ifdef HAVE_EXECINFO_H
37 # include <execinfo.h>
38 #endif
39
40 #include "common.h"
41 #include "log.h"
42
43 #include "fatal.h"
44
get_signal_name(int sig)45 const char *get_signal_name(int sig)
46 {
47 /* either strsignal() or sys_siglist[] could be used to */
48 /* get signal name, but these methods are not portable */
49
50 /* not all POSIX signals are available on all platforms, */
51 /* so we list only signals that we react to in our handlers */
52
53 switch (sig)
54 {
55 case SIGALRM: return "SIGALRM";
56 case SIGILL: return "SIGILL";
57 case SIGFPE: return "SIGFPE";
58 case SIGSEGV: return "SIGSEGV";
59 case SIGBUS: return "SIGBUS";
60 case SIGQUIT: return "SIGQUIT";
61 case SIGINT: return "SIGINT";
62 case SIGTERM: return "SIGTERM";
63 case SIGPIPE: return "SIGPIPE";
64 case SIGUSR1: return "SIGUSR1";
65 default: return "unknown";
66 }
67 }
68
69 #if defined(HAVE_SYS_UCONTEXT_H) && (defined(REG_EIP) || defined(REG_RIP))
70
get_register_name(int reg)71 static const char *get_register_name(int reg)
72 {
73 switch (reg)
74 {
75
76 /* i386 */
77
78 #ifdef REG_GS
79 case REG_GS: return "gs";
80 #endif
81 #ifdef REG_FS
82 case REG_FS: return "fs";
83 #endif
84 #ifdef REG_ES
85 case REG_ES: return "es";
86 #endif
87 #ifdef REG_DS
88 case REG_DS: return "ds";
89 #endif
90 #ifdef REG_EDI
91 case REG_EDI: return "edi";
92 #endif
93 #ifdef REG_ESI
94 case REG_ESI: return "esi";
95 #endif
96 #ifdef REG_EBP
97 case REG_EBP: return "ebp";
98 #endif
99 #ifdef REG_ESP
100 case REG_ESP: return "esp";
101 #endif
102 #ifdef REG_EBX
103 case REG_EBX: return "ebx";
104 #endif
105 #ifdef REG_EDX
106 case REG_EDX: return "edx";
107 #endif
108 #ifdef REG_ECX
109 case REG_ECX: return "ecx";
110 #endif
111 #ifdef REG_EAX
112 case REG_EAX: return "eax";
113 #endif
114 #ifdef REG_EIP
115 case REG_EIP: return "eip";
116 #endif
117 #ifdef REG_CS
118 case REG_CS: return "cs";
119 #endif
120 #ifdef REG_UESP
121 case REG_UESP: return "uesp";
122 #endif
123 #ifdef REG_SS
124 case REG_SS: return "ss";
125 #endif
126
127 /* x86_64 */
128
129 #ifdef REG_R8
130 case REG_R8: return "r8";
131 #endif
132 #ifdef REG_R9
133 case REG_R9: return "r9";
134 #endif
135 #ifdef REG_R10
136 case REG_R10: return "r10";
137 #endif
138 #ifdef REG_R11
139 case REG_R11: return "r11";
140 #endif
141 #ifdef REG_R12
142 case REG_R12: return "r12";
143 #endif
144 #ifdef REG_R13
145 case REG_R13: return "r13";
146 #endif
147 #ifdef REG_R14
148 case REG_R14: return "r14";
149 #endif
150 #ifdef REG_R15
151 case REG_R15: return "r15";
152 #endif
153 #ifdef REG_RDI
154 case REG_RDI: return "rdi";
155 #endif
156 #ifdef REG_RSI
157 case REG_RSI: return "rsi";
158 #endif
159 #ifdef REG_RBP
160 case REG_RBP: return "rbp";
161 #endif
162 #ifdef REG_RBX
163 case REG_RBX: return "rbx";
164 #endif
165 #ifdef REG_RDX
166 case REG_RDX: return "rdx";
167 #endif
168 #ifdef REG_RAX
169 case REG_RAX: return "rax";
170 #endif
171 #ifdef REG_RCX
172 case REG_RCX: return "rcx";
173 #endif
174 #ifdef REG_RSP
175 case REG_RSP: return "rsp";
176 #endif
177 #ifdef REG_RIP
178 case REG_RIP: return "rip";
179 #endif
180 #ifdef REG_CSGSFS
181 case REG_CSGSFS: return "csgsfs";
182 #endif
183 #ifdef REG_OLDMASK
184 case REG_OLDMASK: return "oldmask";
185 #endif
186 #ifdef REG_CR2
187 case REG_CR2: return "cr2";
188 #endif
189
190 /* i386 and x86_64 */
191
192 #ifdef REG_EFL
193 case REG_EFL: return "efl";
194 #endif
195 #ifdef REG_ERR
196 case REG_ERR: return "err";
197 #endif
198 #ifdef REG_TRAPNO
199 case REG_TRAPNO: return "trapno";
200 #endif
201
202 /* unknown */
203
204 default: return "unknown";
205 }
206 }
207
208 #endif /* defined(HAVE_SYS_UCONTEXT_H) && (defined(REG_EIP) || defined(REG_RIP)) */
209
zbx_backtrace(void)210 void zbx_backtrace(void)
211 {
212 # define ZBX_BACKTRACE_SIZE 60
213 #ifdef HAVE_EXECINFO_H
214 char **bcktrc_syms;
215 void *bcktrc[ZBX_BACKTRACE_SIZE];
216 int bcktrc_sz, i;
217
218 zabbix_log(LOG_LEVEL_CRIT, "=== Backtrace: ===");
219
220 bcktrc_sz = backtrace(bcktrc, ZBX_BACKTRACE_SIZE);
221 bcktrc_syms = backtrace_symbols(bcktrc, bcktrc_sz);
222
223 if (NULL == bcktrc_syms)
224 {
225 zabbix_log(LOG_LEVEL_CRIT, "error in backtrace_symbols(): %s", zbx_strerror(errno));
226
227 for (i = 0; i < bcktrc_sz; i++)
228 zabbix_log(LOG_LEVEL_CRIT, "%d: %p", bcktrc_sz - i - 1, bcktrc[i]);
229 }
230 else
231 {
232 for (i = 0; i < bcktrc_sz; i++)
233 zabbix_log(LOG_LEVEL_CRIT, "%d: %s", bcktrc_sz - i - 1, bcktrc_syms[i]);
234
235 zbx_free(bcktrc_syms);
236 }
237 #else
238 zabbix_log(LOG_LEVEL_CRIT, "backtrace is not available for this platform");
239 #endif /* HAVE_EXECINFO_H */
240 }
241
print_fatal_info(int sig,siginfo_t * siginfo,void * context)242 void print_fatal_info(int sig, siginfo_t *siginfo, void *context)
243 {
244 #ifdef HAVE_SYS_UCONTEXT_H
245
246 #if defined(REG_EIP) || defined(REG_RIP)
247 ucontext_t *uctx = (ucontext_t *)context;
248 #endif
249
250 /* look for GET_PC() macro in sigcontextinfo.h files */
251 /* of glibc if you wish to add more CPU architectures */
252
253 # if defined(REG_EIP) /* i386 */
254
255 # define ZBX_GET_REG(uctx, reg) (uctx)->uc_mcontext.gregs[reg]
256 # define ZBX_GET_PC(uctx) ZBX_GET_REG(uctx, REG_EIP)
257
258 # elif defined(REG_RIP) /* x86_64 */
259
260 # define ZBX_GET_REG(uctx, reg) (uctx)->uc_mcontext.gregs[reg]
261 # define ZBX_GET_PC(uctx) ZBX_GET_REG(uctx, REG_RIP)
262
263 # endif
264
265 #endif /* HAVE_SYS_UCONTEXT_H */
266 int i;
267 FILE *fd;
268
269 zabbix_log(LOG_LEVEL_CRIT, "====== Fatal information: ======");
270
271 #ifdef HAVE_SYS_UCONTEXT_H
272
273 #ifdef ZBX_GET_PC
274 zabbix_log(LOG_LEVEL_CRIT, "Program counter: %p", ZBX_GET_PC(uctx));
275 zabbix_log(LOG_LEVEL_CRIT, "=== Registers: ===");
276 for (i = 0; i < NGREG; i++)
277 zabbix_log(LOG_LEVEL_CRIT, "%-7s = %16lx = %20lu = %20ld", get_register_name(i),
278 ZBX_GET_REG(uctx, i), ZBX_GET_REG(uctx, i), ZBX_GET_REG(uctx, i));
279
280 #ifdef REG_EBP /* dump a bit of stack frame for i386 */
281 zabbix_log(LOG_LEVEL_CRIT, "=== Stack frame: ===");
282 for (i = 16; i >= 2; i--)
283 zabbix_log(LOG_LEVEL_CRIT, "+0x%02x(%%ebp) = ebp + %2d = %08x = %10u = %11d%s",
284 i * ZBX_PTR_SIZE, i * ZBX_PTR_SIZE,
285 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + i * ZBX_PTR_SIZE),
286 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + i * ZBX_PTR_SIZE),
287 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + i * ZBX_PTR_SIZE),
288 i == 2 ? " <--- call arguments" : "");
289 zabbix_log(LOG_LEVEL_CRIT, "+0x%02x(%%ebp) = ebp + %2d = %08x%28s<--- return address",
290 ZBX_PTR_SIZE, ZBX_PTR_SIZE,
291 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + ZBX_PTR_SIZE), "");
292 zabbix_log(LOG_LEVEL_CRIT, " (%%ebp) = ebp = %08x%28s<--- saved ebp value",
293 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP)), "");
294 for (i = 1; i <= 16; i++)
295 zabbix_log(LOG_LEVEL_CRIT, "-0x%02x(%%ebp) = ebp - %2d = %08x = %10u = %11d%s",
296 i * ZBX_PTR_SIZE, i * ZBX_PTR_SIZE,
297 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) - i * ZBX_PTR_SIZE),
298 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) - i * ZBX_PTR_SIZE),
299 *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) - i * ZBX_PTR_SIZE),
300 i == 1 ? " <--- local variables" : "");
301 #endif /* REG_EBP */
302
303 #else
304 zabbix_log(LOG_LEVEL_CRIT, "program counter not available for this architecture");
305 zabbix_log(LOG_LEVEL_CRIT, "=== Registers: ===");
306 zabbix_log(LOG_LEVEL_CRIT, "register dump not available for this architecture");
307 #endif /* ZBX_GET_PC */
308
309 #endif /* HAVE_SYS_UCONTEXT_H */
310
311 zbx_backtrace();
312
313 zabbix_log(LOG_LEVEL_CRIT, "=== Memory map: ===");
314
315 if (NULL != (fd = fopen("/proc/self/maps", "r")))
316 {
317 char line[1024];
318
319 while (NULL != fgets(line, sizeof(line), fd))
320 {
321 if (line[0] != '\0')
322 line[strlen(line) - 1] = '\0'; /* remove trailing '\n' */
323
324 zabbix_log(LOG_LEVEL_CRIT, "%s", line);
325 }
326
327 zbx_fclose(fd);
328 }
329 else
330 zabbix_log(LOG_LEVEL_CRIT, "memory map not available for this platform");
331
332 #ifdef ZBX_GET_PC
333 zabbix_log(LOG_LEVEL_CRIT, "================================");
334 zabbix_log(LOG_LEVEL_CRIT, "Please consider attaching a disassembly listing to your bug report.");
335 zabbix_log(LOG_LEVEL_CRIT, "This listing can be produced with, e.g., objdump -DSswx %s.", progname);
336 #endif
337
338 zabbix_log(LOG_LEVEL_CRIT, "================================");
339 }
340