Add mbtk dump and

Change-Id: I510bbfa20d954d4212cbb7710337de029cfc95e1
diff --git a/mbtk/libmbtk_lib/Makefile b/mbtk/libmbtk_lib/Makefile
index 5e46530..efa293c 100755
--- a/mbtk/libmbtk_lib/Makefile
+++ b/mbtk/libmbtk_lib/Makefile
@@ -8,7 +8,7 @@
 
 LIB_DIR +=
 
-LIBS += -llog -lubus -lubox -luci -lprop2uci -lrilutil -lblobmsg_json
+LIBS += -llog -lubus -lubox -luci -lprop2uci -lrilutil -lblobmsg_json -ldl
 
 CFLAGS += -shared -Wl,-shared,-Bsymbolic
 
@@ -48,6 +48,10 @@
 	src/mbtk_device_info.c \
 	src/mbtk_version.c
 
+ifeq ($(MBTK_DUMP_SUPPORT), y)
+LOCAL_SRC_FILES += src/mbtk_debug.c
+endif
+
 OBJS = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(LOCAL_SRC_FILES)))
 $(info OBJS = $(OBJS))
 
diff --git a/mbtk/libmbtk_lib/src/mbtk_debug.c b/mbtk/libmbtk_lib/src/mbtk_debug.c
new file mode 100755
index 0000000..84e13e0
--- /dev/null
+++ b/mbtk/libmbtk_lib/src/mbtk_debug.c
@@ -0,0 +1,381 @@
+/*
+*    mbtk_debug.c
+*
+*    Generate application exception information.
+*
+*/
+/******************************************************************************
+
+                          EDIT HISTORY FOR FILE
+
+  WHEN        WHO       WHAT,WHERE,WHY
+--------    --------    -------------------------------------------------------
+2024/6/5     LiuBin      Initial version
+
+******************************************************************************/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <ucontext.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdarg.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+
+/* 纯C环境下,不定义宏NO_CPP_DEMANGLE */
+#if (!defined(__cplusplus)) && (!defined(NO_CPP_DEMANGLE))
+#define NO_CPP_DEMANGLE
+#endif
+
+#ifndef NO_CPP_DEMANGLE
+#include <cxxabi.h>
+#ifdef __cplusplus
+using __cxxabiv1::__cxa_demangle;
+#endif
+#endif
+
+#if (defined __x86_64__)
+#define REGFORMAT   "%016lx"
+#elif (defined __i386__)
+#define REGFORMAT   "%08x"
+#elif (defined __arm__)
+#define REGFORMAT   "%lx"
+#endif
+
+#define MBTK_PROC_DUMP_DIR           "persist.mbtk.dump_dir"
+#define MBTK_PROC_DUMP_FILE_DEF      "/etc/mbtk/mbtk_dump.log"
+
+
+static char proc_name[100];
+static char proc_dump_name[100];
+static int proc_dump_fd = -1;
+
+#ifdef HAS_ULSLIB
+#include <uls/logger.h>
+#define sigsegv_outp(x) sigsegv_outp(, gx)
+#else
+//#define sigsegv_outp(x, ...)    fprintf(stderr, x"\n", ##__VA_ARGS__)
+void sigsegv_outp(const char* format, ...)
+{
+    if(proc_dump_fd > 0) {
+        char buf[1024] = {0};
+        va_list ap;
+        int length = 0;
+
+        va_start(ap, format);
+        length = vsnprintf(buf, sizeof(buf), format, ap);
+        if (length < 0 || 0 == length) {
+            return;
+        }
+
+        char *tmp = buf + length - 1;
+        while(tmp >= buf && (*tmp == '\r' || *tmp == '\n')) {
+            *tmp-- = '\0';
+        }
+        tmp++;
+        *tmp = '\n';
+
+        write(proc_dump_fd, buf, strlen(buf));
+
+        va_end(ap);
+    }
+}
+#endif
+
+static void print_reg(ucontext_t *uc)
+{
+#if (defined __x86_64__) || (defined __i386__)
+    int i;
+    for (i = 0; i < NGREG; i++)
+    {
+        sigsegv_outp("reg[%02d]: 0x"REGFORMAT, i, uc->uc_mcontext.gregs[i]);
+    }
+#elif (defined __arm__)
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 0, uc->uc_mcontext.arm_r0);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 1, uc->uc_mcontext.arm_r1);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 2, uc->uc_mcontext.arm_r2);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 3, uc->uc_mcontext.arm_r3);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 4, uc->uc_mcontext.arm_r4);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 5, uc->uc_mcontext.arm_r5);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 6, uc->uc_mcontext.arm_r6);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 7, uc->uc_mcontext.arm_r7);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 8, uc->uc_mcontext.arm_r8);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 9, uc->uc_mcontext.arm_r9);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 10, uc->uc_mcontext.arm_r10);
+    sigsegv_outp("FP		= 0x"REGFORMAT, uc->uc_mcontext.arm_fp);
+    sigsegv_outp("IP		= 0x"REGFORMAT, uc->uc_mcontext.arm_ip);
+    sigsegv_outp("SP		= 0x"REGFORMAT, uc->uc_mcontext.arm_sp);
+    sigsegv_outp("LR		= 0x"REGFORMAT, uc->uc_mcontext.arm_lr);
+    sigsegv_outp("PC		= 0x"REGFORMAT, uc->uc_mcontext.arm_pc);
+    sigsegv_outp("CPSR		= 0x"REGFORMAT, uc->uc_mcontext.arm_cpsr);
+    sigsegv_outp("Fault Address	= 0x"REGFORMAT, uc->uc_mcontext.fault_address);
+    sigsegv_outp("Trap no		= 0x"REGFORMAT, uc->uc_mcontext.trap_no);
+    sigsegv_outp("Err Code	= 0x"REGFORMAT, uc->uc_mcontext.error_code);
+    sigsegv_outp("Old Mask	= 0x"REGFORMAT, uc->uc_mcontext.oldmask);
+#endif
+}
+
+static void print_call_link(ucontext_t *uc)
+{
+    int i = 0;
+    void **frame_pointer = (void **)NULL;
+    void *return_address = NULL;
+    Dl_info dl_info = { 0 };
+
+#if (defined __i386__)
+    frame_pointer = (void **)uc->uc_mcontext.gregs[REG_EBP];
+    return_address = (void *)uc->uc_mcontext.gregs[REG_EIP];
+#elif (defined __x86_64__)
+    frame_pointer = (void **)uc->uc_mcontext.gregs[REG_RBP];
+    return_address = (void *)uc->uc_mcontext.gregs[REG_RIP];
+#elif (defined __arm__)
+    /* sigcontext_t on ARM:
+            unsigned long trap_no;
+            unsigned long error_code;
+            unsigned long oldmask;
+            unsigned long arm_r0;
+            ...
+            unsigned long arm_r10;
+            unsigned long arm_fp;
+            unsigned long arm_ip;
+            unsigned long arm_sp;
+            unsigned long arm_lr;
+            unsigned long arm_pc;
+            unsigned long arm_cpsr;
+            unsigned long fault_address;
+    */
+    frame_pointer = (void **)uc->uc_mcontext.arm_fp;
+    return_address = (void *)uc->uc_mcontext.arm_pc;
+#endif
+
+    sigsegv_outp("\nStack trace:");
+    while (frame_pointer && return_address)
+    {
+        if (!dladdr(return_address, &dl_info))  break;
+        const char *sname = dl_info.dli_sname;
+#ifndef NO_CPP_DEMANGLE
+        int status;
+        char *tmp = __cxa_demangle(sname, NULL, 0, &status);
+        if (status == 0 && tmp)
+        {
+            sname = tmp;
+        }
+#endif
+        /* No: return address <sym-name + offset> (filename) */
+        sigsegv_outp("%02d: %p <%s + %lu> (%s)", ++i, return_address, sname,
+                     (unsigned long)return_address - (unsigned long)dl_info.dli_saddr,
+                     dl_info.dli_fname);
+#ifndef NO_CPP_DEMANGLE
+        if (tmp)    free(tmp);
+#endif
+        if (dl_info.dli_sname && !strcmp(dl_info.dli_sname, "main"))
+        {
+            break;
+        }
+
+#if (defined __x86_64__) || (defined __i386__)
+        return_address = frame_pointer[1];
+        frame_pointer = frame_pointer[0];
+#elif (defined __arm__)
+        return_address = frame_pointer[-1];
+        frame_pointer = (void **)frame_pointer[-3];
+#endif
+    }
+    sigsegv_outp("Stack trace end.");
+}
+
+static void proc_maps_print() {
+    char file[64] = {0x00};
+    sprintf(file,"/proc/%d/maps", getpid());
+    FILE *fptr = fopen(file, "r");
+    char line[1024];
+    if(fptr)
+    {
+        memset(line, 0, sizeof(line));
+        while(fgets(line, sizeof(line), fptr)) {
+            // printf("Line : %s", line);
+            if(strstr(line, "libmbtk_") || strstr(line, "liblynq_") || strstr(line, "libql_")) {
+                sigsegv_outp("%s", line);
+            }
+            memset(line, 0, sizeof(line));
+        }
+
+        fclose(fptr);
+    }
+}
+
+static void sigsegv_handler(int signo, siginfo_t *info, void *context)
+{
+    printf("sigsegv_handler - %d\n", signo);
+    if (context)
+    {
+        struct timeval log_time;
+        char tmp[50] = {0};
+        gettimeofday(&log_time, NULL);
+        struct tm* tm_t = localtime(&(log_time.tv_sec));
+        strftime(tmp, 50, "%F %T", tm_t);
+        snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), ".%d", (int)(log_time.tv_usec / 1000));
+        sigsegv_outp("----------------------------%s----------------------------", tmp);
+
+        proc_maps_print();
+
+        ucontext_t *uc = (ucontext_t *)context;
+        char proc[100] = {0};
+        int fd = open("/proc/self/cmdline", O_RDONLY);
+        if(fd > 0)
+        {
+            if(read(fd, proc, sizeof(proc)) > 0) {
+                sigsegv_outp("Segmentation Fault:%s", proc);
+            } else {
+                sigsegv_outp("Segmentation Fault:%s", "Unknown");
+            }
+            close(fd);
+        } else {
+            sigsegv_outp("Segmentation Fault:%s", "Unknown");
+        }
+
+        sigsegv_outp("info.si_signo = %d", signo);
+        sigsegv_outp("info.si_errno = %d", info->si_errno);
+        sigsegv_outp("info.si_code  = %d (%s)", info->si_code,
+                     (info->si_code == SEGV_MAPERR) ? "SEGV_MAPERR" : "SEGV_ACCERR");
+        sigsegv_outp("info.si_addr  = 0x%x(%p)\n", info->si_addr, info->si_addr);
+
+        print_reg(uc);
+        print_call_link(uc);
+
+        signal(signo, SIG_DFL);
+        raise(signo);
+
+        printf("Segmentation Fault, refer to the log file:%s\n", proc_dump_name);
+    }
+
+    exit(0);
+}
+
+#if 1
+#define BACKTRACE_SIZE 32
+void sigsegv_handler_with_thread(int signo) {
+    struct timeval log_time;
+    char tmp[50] = {0};
+    gettimeofday(&log_time, NULL);
+    struct tm* tm_t = localtime(&(log_time.tv_sec));
+    strftime(tmp, 50, "%F %T", tm_t);
+    snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), ".%d", (int)(log_time.tv_usec / 1000));
+    sigsegv_outp("----------------------------%s----------------------------", tmp);
+
+    proc_maps_print();
+
+    char proc[100] = {0};
+    int fd = open("/proc/self/cmdline", O_RDONLY);
+    if(fd > 0)
+    {
+        if(read(fd, proc, sizeof(proc)) > 0) {
+            sigsegv_outp("Segmentation Fault:%s", proc);
+        } else {
+            sigsegv_outp("Segmentation Fault:%s", "Unknown");
+        }
+        close(fd);
+    } else {
+        sigsegv_outp("Segmentation Fault:%s", "Unknown");
+    }
+
+    sigsegv_outp("info.si_signo = %d", signo);
+
+    int j, nptrs;
+    void *buffer[BACKTRACE_SIZE];
+    char **strings;
+    nptrs = backtrace(buffer, BACKTRACE_SIZE);
+    //printf("backtrace() returned %d addresses\n", nptrs);
+    strings = backtrace_symbols(buffer, nptrs);
+    if(strings == NULL){
+        //perror("backtrace_symbols");
+        exit(EXIT_FAILURE);
+    }
+
+    sigsegv_outp("\nStack trace:");
+    if(nptrs > 0) {
+        for (j = 0; j < nptrs; j++) {
+            sigsegv_outp("%02d: %s", j, strings[j]);
+        }
+    }
+    free(strings);
+    sigsegv_outp("Stack trace end.");
+
+    signal(signo, SIG_DFL);
+    raise(signo);
+
+    printf("Segmentation Fault, refer to the log file:%s\n", proc_dump_name);
+    exit(0);
+}
+#endif
+
+#define SETSIG(sa, sig, fun, flags)     \
+        do {                            \
+            sa.sa_sigaction = fun;      \
+            sa.sa_flags = flags;        \
+            sigemptyset(&sa.sa_mask);   \
+            sigaction(sig, &sa, NULL);  \
+        } while(0)
+
+
+void mbtk_debug_open(const char *log_file, bool thread_support)
+{
+    struct sigaction sa;
+
+#if 1
+    if(thread_support) {
+        SETSIG(sa, SIGSEGV, sigsegv_handler_with_thread, 0);
+        SETSIG(sa, SIGABRT, sigsegv_handler_with_thread, 0);
+    } else {
+        SETSIG(sa, SIGSEGV, sigsegv_handler, SA_SIGINFO);
+        SETSIG(sa, SIGABRT, sigsegv_handler, SA_SIGINFO);
+    }
+#else
+    SETSIG(sa, SIGSEGV, sigsegv_handler, SA_SIGINFO);
+#endif
+
+    memset(proc_name, 0, sizeof(proc_name));
+    memset(proc_dump_name, 0, sizeof(proc_dump_name));
+    int fd = open("/proc/self/cmdline", O_RDONLY);
+    if(fd > 0)
+    {
+        if(read(fd, proc_name, sizeof(proc_name)) <= 0) {
+            LOGE("Get PROC name fail.");
+        }
+        close(fd);
+    }
+
+    // Redirect stderr to log_file.
+    if(log_file) {
+        memcpy(proc_dump_name, log_file, strlen(log_file));
+    } else {
+        property_get(MBTK_PROC_DUMP_DIR, proc_dump_name, "");
+        if(strlen(proc_dump_name) > 0) {
+            snprintf(proc_dump_name + strlen(proc_dump_name),sizeof(proc_dump_name) - strlen(proc_dump_name), "/%s", proc_name);
+        } else {
+            memcpy(proc_dump_name, MBTK_PROC_DUMP_FILE_DEF, strlen(MBTK_PROC_DUMP_FILE_DEF));
+        }
+    }
+
+#if 0
+    if(freopen(proc_dump_name, "a", stderr) == NULL) {
+        LOGE("reopen stderr to %s fail.[%d]", proc_dump_name, errno);
+    }
+#else
+    proc_dump_fd = open(proc_dump_name, O_WRONLY | O_CREAT | O_APPEND, 0666);
+    if(proc_dump_fd < 0) {
+        LOGE("Open(%s) fail:%d.", proc_dump_name, errno);
+    }
+#endif
+}
+
diff --git a/mbtk/libmbtk_lib/src/mbtk_version.c b/mbtk/libmbtk_lib/src/mbtk_version.c
index cbc2e68..bc2499e 100755
--- a/mbtk/libmbtk_lib/src/mbtk_version.c
+++ b/mbtk/libmbtk_lib/src/mbtk_version.c
@@ -76,6 +76,15 @@
 #endif
             break;
         }
+        case MBTK_BUILD_DEF_MBTK_DUMP_SUPPORT:
+        {
+            strcpy(name, STR_GET(MBTK_BUILD_DEF_MBTK_DUMP_SUPPORT));
+#ifdef MBTK_DUMP_SUPPORT
+            strcpy(value, "Y");
+#else
+            strcpy(value, "N");
+#endif
+        }
         default:
         {
             strcpy(name, "Unknown");