blob: e9280c9a7bf69876867e7d0d7ddcdcd570446426 [file] [log] [blame]
b.liubb590492024-06-13 16:42:08 +08001/*
2* mbtk_debug.c
3*
4* Generate application exception information.
5*
6*/
7/******************************************************************************
8
9 EDIT HISTORY FOR FILE
10
11 WHEN WHO WHAT,WHERE,WHY
12-------- -------- -------------------------------------------------------
132024/6/5 LiuBin Initial version
14
15******************************************************************************/
16#ifndef _GNU_SOURCE
17#define _GNU_SOURCE
18#endif
19#include <stdio.h>
20#include <dlfcn.h>
21#include <stdlib.h>
22#include <signal.h>
23#include <unistd.h>
24#include <string.h>
25#include <ucontext.h>
26#include <fcntl.h>
27#include <errno.h>
28#include <time.h>
29#include <sys/time.h>
30#include <stdarg.h>
31
32#include "mbtk_type.h"
33#include "mbtk_log.h"
34
35/* 纯C环境下,不定义宏NO_CPP_DEMANGLE */
36#if (!defined(__cplusplus)) && (!defined(NO_CPP_DEMANGLE))
37#define NO_CPP_DEMANGLE
38#endif
39
40#ifndef NO_CPP_DEMANGLE
41#include <cxxabi.h>
42#ifdef __cplusplus
43using __cxxabiv1::__cxa_demangle;
44#endif
45#endif
46
47#if (defined __x86_64__)
48#define REGFORMAT "%016lx"
49#elif (defined __i386__)
50#define REGFORMAT "%08x"
51#elif (defined __arm__)
52#define REGFORMAT "%lx"
53#endif
54
55#define MBTK_PROC_DUMP_DIR "persist.mbtk.dump_dir"
56#define MBTK_PROC_DUMP_FILE_DEF "/etc/mbtk/mbtk_dump.log"
57
58
59static char proc_name[100];
60static char proc_dump_name[100];
61static int proc_dump_fd = -1;
62
63#ifdef HAS_ULSLIB
64#include <uls/logger.h>
65#define sigsegv_outp(x) sigsegv_outp(, gx)
66#else
67//#define sigsegv_outp(x, ...) fprintf(stderr, x"\n", ##__VA_ARGS__)
68void sigsegv_outp(const char* format, ...)
69{
70 if(proc_dump_fd > 0) {
71 char buf[1024] = {0};
72 va_list ap;
73 int length = 0;
74
75 va_start(ap, format);
76 length = vsnprintf(buf, sizeof(buf), format, ap);
77 if (length < 0 || 0 == length) {
78 return;
79 }
80
81 char *tmp = buf + length - 1;
82 while(tmp >= buf && (*tmp == '\r' || *tmp == '\n')) {
83 *tmp-- = '\0';
84 }
85 tmp++;
86 *tmp = '\n';
87
88 write(proc_dump_fd, buf, strlen(buf));
89
90 va_end(ap);
91 }
92}
93#endif
94
95static void print_reg(ucontext_t *uc)
96{
97#if (defined __x86_64__) || (defined __i386__)
98 int i;
99 for (i = 0; i < NGREG; i++)
100 {
101 sigsegv_outp("reg[%02d]: 0x"REGFORMAT, i, uc->uc_mcontext.gregs[i]);
102 }
103#elif (defined __arm__)
104 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 0, uc->uc_mcontext.arm_r0);
105 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 1, uc->uc_mcontext.arm_r1);
106 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 2, uc->uc_mcontext.arm_r2);
107 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 3, uc->uc_mcontext.arm_r3);
108 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 4, uc->uc_mcontext.arm_r4);
109 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 5, uc->uc_mcontext.arm_r5);
110 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 6, uc->uc_mcontext.arm_r6);
111 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 7, uc->uc_mcontext.arm_r7);
112 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 8, uc->uc_mcontext.arm_r8);
113 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 9, uc->uc_mcontext.arm_r9);
114 sigsegv_outp("reg[%02d] = 0x"REGFORMAT, 10, uc->uc_mcontext.arm_r10);
115 sigsegv_outp("FP = 0x"REGFORMAT, uc->uc_mcontext.arm_fp);
116 sigsegv_outp("IP = 0x"REGFORMAT, uc->uc_mcontext.arm_ip);
117 sigsegv_outp("SP = 0x"REGFORMAT, uc->uc_mcontext.arm_sp);
118 sigsegv_outp("LR = 0x"REGFORMAT, uc->uc_mcontext.arm_lr);
119 sigsegv_outp("PC = 0x"REGFORMAT, uc->uc_mcontext.arm_pc);
120 sigsegv_outp("CPSR = 0x"REGFORMAT, uc->uc_mcontext.arm_cpsr);
121 sigsegv_outp("Fault Address = 0x"REGFORMAT, uc->uc_mcontext.fault_address);
122 sigsegv_outp("Trap no = 0x"REGFORMAT, uc->uc_mcontext.trap_no);
123 sigsegv_outp("Err Code = 0x"REGFORMAT, uc->uc_mcontext.error_code);
124 sigsegv_outp("Old Mask = 0x"REGFORMAT, uc->uc_mcontext.oldmask);
125#endif
126}
127
128static void print_call_link(ucontext_t *uc)
129{
130 int i = 0;
131 void **frame_pointer = (void **)NULL;
132 void *return_address = NULL;
133 Dl_info dl_info = { 0 };
134
135#if (defined __i386__)
136 frame_pointer = (void **)uc->uc_mcontext.gregs[REG_EBP];
137 return_address = (void *)uc->uc_mcontext.gregs[REG_EIP];
138#elif (defined __x86_64__)
139 frame_pointer = (void **)uc->uc_mcontext.gregs[REG_RBP];
140 return_address = (void *)uc->uc_mcontext.gregs[REG_RIP];
141#elif (defined __arm__)
142 /* sigcontext_t on ARM:
143 unsigned long trap_no;
144 unsigned long error_code;
145 unsigned long oldmask;
146 unsigned long arm_r0;
147 ...
148 unsigned long arm_r10;
149 unsigned long arm_fp;
150 unsigned long arm_ip;
151 unsigned long arm_sp;
152 unsigned long arm_lr;
153 unsigned long arm_pc;
154 unsigned long arm_cpsr;
155 unsigned long fault_address;
156 */
157 frame_pointer = (void **)uc->uc_mcontext.arm_fp;
158 return_address = (void *)uc->uc_mcontext.arm_pc;
159#endif
160
161 sigsegv_outp("\nStack trace:");
162 while (frame_pointer && return_address)
163 {
164 if (!dladdr(return_address, &dl_info)) break;
165 const char *sname = dl_info.dli_sname;
166#ifndef NO_CPP_DEMANGLE
167 int status;
168 char *tmp = __cxa_demangle(sname, NULL, 0, &status);
169 if (status == 0 && tmp)
170 {
171 sname = tmp;
172 }
173#endif
174 /* No: return address <sym-name + offset> (filename) */
175 sigsegv_outp("%02d: %p <%s + %lu> (%s)", ++i, return_address, sname,
176 (unsigned long)return_address - (unsigned long)dl_info.dli_saddr,
177 dl_info.dli_fname);
178#ifndef NO_CPP_DEMANGLE
179 if (tmp) free(tmp);
180#endif
181 if (dl_info.dli_sname && !strcmp(dl_info.dli_sname, "main"))
182 {
183 break;
184 }
185
186#if (defined __x86_64__) || (defined __i386__)
187 return_address = frame_pointer[1];
188 frame_pointer = frame_pointer[0];
189#elif (defined __arm__)
190 return_address = frame_pointer[-1];
191 frame_pointer = (void **)frame_pointer[-3];
192#endif
193 }
194 sigsegv_outp("Stack trace end.");
195}
196
197static void proc_maps_print() {
198 char file[64] = {0x00};
199 sprintf(file,"/proc/%d/maps", getpid());
200 FILE *fptr = fopen(file, "r");
201 char line[1024];
202 if(fptr)
203 {
204 memset(line, 0, sizeof(line));
205 while(fgets(line, sizeof(line), fptr)) {
206 // printf("Line : %s", line);
207 if(strstr(line, "libmbtk_") || strstr(line, "liblynq_") || strstr(line, "libql_")) {
208 sigsegv_outp("%s", line);
209 }
210 memset(line, 0, sizeof(line));
211 }
212
213 fclose(fptr);
214 }
215}
216
217static void sigsegv_handler(int signo, siginfo_t *info, void *context)
218{
219 printf("sigsegv_handler - %d\n", signo);
220 if (context)
221 {
222 struct timeval log_time;
223 char tmp[50] = {0};
224 gettimeofday(&log_time, NULL);
225 struct tm* tm_t = localtime(&(log_time.tv_sec));
226 strftime(tmp, 50, "%F %T", tm_t);
227 snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), ".%d", (int)(log_time.tv_usec / 1000));
228 sigsegv_outp("----------------------------%s----------------------------", tmp);
229
230 proc_maps_print();
231
232 ucontext_t *uc = (ucontext_t *)context;
233 char proc[100] = {0};
234 int fd = open("/proc/self/cmdline", O_RDONLY);
235 if(fd > 0)
236 {
237 if(read(fd, proc, sizeof(proc)) > 0) {
238 sigsegv_outp("Segmentation Fault:%s", proc);
239 } else {
240 sigsegv_outp("Segmentation Fault:%s", "Unknown");
241 }
242 close(fd);
243 } else {
244 sigsegv_outp("Segmentation Fault:%s", "Unknown");
245 }
246
247 sigsegv_outp("info.si_signo = %d", signo);
248 sigsegv_outp("info.si_errno = %d", info->si_errno);
249 sigsegv_outp("info.si_code = %d (%s)", info->si_code,
250 (info->si_code == SEGV_MAPERR) ? "SEGV_MAPERR" : "SEGV_ACCERR");
251 sigsegv_outp("info.si_addr = 0x%x(%p)\n", info->si_addr, info->si_addr);
252
253 print_reg(uc);
254 print_call_link(uc);
255
256 signal(signo, SIG_DFL);
257 raise(signo);
258
259 printf("Segmentation Fault, refer to the log file:%s\n", proc_dump_name);
260 }
261
262 exit(0);
263}
264
265#if 1
266#define BACKTRACE_SIZE 32
267void sigsegv_handler_with_thread(int signo) {
268 struct timeval log_time;
269 char tmp[50] = {0};
270 gettimeofday(&log_time, NULL);
271 struct tm* tm_t = localtime(&(log_time.tv_sec));
272 strftime(tmp, 50, "%F %T", tm_t);
273 snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), ".%d", (int)(log_time.tv_usec / 1000));
274 sigsegv_outp("----------------------------%s----------------------------", tmp);
275
276 proc_maps_print();
277
278 char proc[100] = {0};
279 int fd = open("/proc/self/cmdline", O_RDONLY);
280 if(fd > 0)
281 {
282 if(read(fd, proc, sizeof(proc)) > 0) {
283 sigsegv_outp("Segmentation Fault:%s", proc);
284 } else {
285 sigsegv_outp("Segmentation Fault:%s", "Unknown");
286 }
287 close(fd);
288 } else {
289 sigsegv_outp("Segmentation Fault:%s", "Unknown");
290 }
291
292 sigsegv_outp("info.si_signo = %d", signo);
293
294 int j, nptrs;
295 void *buffer[BACKTRACE_SIZE];
296 char **strings;
297 nptrs = backtrace(buffer, BACKTRACE_SIZE);
298 //printf("backtrace() returned %d addresses\n", nptrs);
299 strings = backtrace_symbols(buffer, nptrs);
300 if(strings == NULL){
301 //perror("backtrace_symbols");
302 exit(EXIT_FAILURE);
303 }
304
305 sigsegv_outp("\nStack trace:");
306 if(nptrs > 0) {
307 for (j = 0; j < nptrs; j++) {
308 sigsegv_outp("%02d: %s", j, strings[j]);
309 }
310 }
311 free(strings);
312 sigsegv_outp("Stack trace end.");
313
314 signal(signo, SIG_DFL);
315 raise(signo);
316
317 printf("Segmentation Fault, refer to the log file:%s\n", proc_dump_name);
318 exit(0);
319}
320#endif
321
322#define SETSIG(sa, sig, fun, flags) \
323 do { \
324 sa.sa_sigaction = fun; \
325 sa.sa_flags = flags; \
326 sigemptyset(&sa.sa_mask); \
327 sigaction(sig, &sa, NULL); \
328 } while(0)
329
330
b.liuced8dd02024-06-28 13:28:29 +0800331// arm-openwrt-linux-addr2line -e out/bin/mbtk_gnssd 0x12ca8
b.liubb590492024-06-13 16:42:08 +0800332void mbtk_debug_open(const char *log_file, bool thread_support)
333{
334 struct sigaction sa;
335
336#if 1
337 if(thread_support) {
338 SETSIG(sa, SIGSEGV, sigsegv_handler_with_thread, 0);
339 SETSIG(sa, SIGABRT, sigsegv_handler_with_thread, 0);
340 } else {
341 SETSIG(sa, SIGSEGV, sigsegv_handler, SA_SIGINFO);
342 SETSIG(sa, SIGABRT, sigsegv_handler, SA_SIGINFO);
343 }
344#else
345 SETSIG(sa, SIGSEGV, sigsegv_handler, SA_SIGINFO);
346#endif
347
348 memset(proc_name, 0, sizeof(proc_name));
349 memset(proc_dump_name, 0, sizeof(proc_dump_name));
350 int fd = open("/proc/self/cmdline", O_RDONLY);
351 if(fd > 0)
352 {
353 if(read(fd, proc_name, sizeof(proc_name)) <= 0) {
354 LOGE("Get PROC name fail.");
355 }
356 close(fd);
357 }
358
359 // Redirect stderr to log_file.
360 if(log_file) {
361 memcpy(proc_dump_name, log_file, strlen(log_file));
362 } else {
363 property_get(MBTK_PROC_DUMP_DIR, proc_dump_name, "");
364 if(strlen(proc_dump_name) > 0) {
365 snprintf(proc_dump_name + strlen(proc_dump_name),sizeof(proc_dump_name) - strlen(proc_dump_name), "/%s", proc_name);
366 } else {
367 memcpy(proc_dump_name, MBTK_PROC_DUMP_FILE_DEF, strlen(MBTK_PROC_DUMP_FILE_DEF));
368 }
369 }
370
371#if 0
372 if(freopen(proc_dump_name, "a", stderr) == NULL) {
373 LOGE("reopen stderr to %s fail.[%d]", proc_dump_name, errno);
374 }
375#else
376 proc_dump_fd = open(proc_dump_name, O_WRONLY | O_CREAT | O_APPEND, 0666);
377 if(proc_dump_fd < 0) {
378 LOGE("Open(%s) fail:%d.", proc_dump_name, errno);
379 }
380#endif
381}
382