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