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