美文网首页
C 报错打印调用栈

C 报错打印调用栈

作者: wjundong | 来源:发表于2022-09-06 17:59 被阅读0次


#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <string.h>

void error_write(const char *filename, const char *string)
{
    if(!string) return ;

    int len = strlen(string);

    FILE *fp = fopen(filename, "a+");
    if(fp)
    {
        fwrite(string, 1, len, fp);
        fwrite("\n", 1, 1, fp);
        fclose(fp);
    }
}


#define LOG_ERROR_WRITE(info) error_write("log.txt", info)

#define ENABLE_DEBUG 1

#if ENABLE_DEBUG == 1
#define MY_DEBUG_ASSERT(expr, msg, value)               \
        do {                                            \
            if(!(expr)) {                               \
                print_trace();                          \
                while(1);                               \
            }                                           \
    } while(0)

#else
#define MY_DEBUG_ASSERT(expr, msg, value)
#endif /* #if ENABLE_DEBUG == 1 */

#define MY_ASSERT_IS_NULL(p) (p) != NULL

#define MY_ASSERT_NULL(p) MY_DEBUG_ASSERT(MY_ASSERT_IS_NULL(p), " NULL Value 0x%lx\n", p)

void crashHandler(int signal)
{
    void *bt[20];
    int btSize = 20;
    char **btStrings;
 
    switch (signal)
    {
    case SIGINT:
        printf("SIGINT  Interactive attention signal.  \n");
        break;
    case SIGILL:
        printf("SIGILL  Illegal instruction.  \n");
        break;
    case SIGABRT:
        printf("SIGABRT  Abnormal termination.  \n");
        break;
    case SIGFPE:
        printf("SIGFPE  Erroneous arithmetic operation.  \n");
        break;
    case SIGSEGV:
        printf("SIGSEGV  Invalid access to storage.  \n");
        break;
    case SIGTERM:
        printf("SIGTERM  Termination request.  \n");
        break;
    case SIGHUP:
        printf("SIGHUP  Hangup.  \n");
        break;
    case SIGQUIT:
        printf("SIGQUIT  Quit.  \n");
        break;
    case SIGTRAP:
        printf("SIGTRAP  Trace/breakpoint trap.  \n");
        break;
    case SIGKILL:
        printf("SIGKILL  Killed.  \n");
        break;
    case SIGBUS:
        printf("SIGBUS  Bus error.  \n");
        break;
    case SIGSYS:
        printf("SIGSYS  Bad system call.  \n");
        break;
    case SIGPIPE:
        printf("SIGPIPE  Broken pipe.  \n");
        break;
    case SIGALRM:
        printf("SIGALRM  Alarm clock.  \n");
        break;
    case SIGURG:
        printf("SIGURG  Urgent data is available at a socket.  \n");
        break;
    case SIGSTOP:
        printf("SIGSTOP  Stop, unblockable.  \n");
        break;
    case SIGTSTP:
        printf("SIGTSTP  Keyboard stop.  \n");
        break;
    case SIGCONT:
        printf("SIGCONT  Continue.  \n");
        break;
    case SIGCHLD:
        printf("SIGCHLD  Child terminated or stopped.  \n");
        break;
    case SIGTTIN:
        printf("SIGTTIN  Background read from control terminal.  \n");
        break;
    case SIGTTOU:
        printf("SIGTTOU  Background write to control terminal.  \n");
        break;
    case SIGPOLL:
        printf("SIGPOLL  Pollable event occurred (System V).  \n");
        break;
    case SIGXCPU:
        printf("SIGXCPU  CPU time limit exceeded.  \n");
        break;
    case SIGXFSZ:
        printf("SIGXFSZ  File size limit exceeded.  \n");
        break;
    case SIGVTALRM:
        printf("SIGVTALRM  Virtual timer expired.  \n");
        break;
    case SIGPROF:
        printf("SIGPROF  Profiling timer expired.  \n");
        break;
    case SIGUSR1:
        printf("SIGUSR1  User-defined signal 1.  \n");
        break;
    case SIGUSR2:
        printf("SIGUSR2  User-defined signal 2.  \n");
        break;
    case SIGWINCH:
        printf("SIGWINCH  Window size change (4.3 BSD, Sun).  \n");
        break;
 
    default:
        printf("unkown signal:%d\n", signal);
        break;
    }
 
    btSize = backtrace(bt, btSize);
    btStrings = backtrace_symbols(bt, btSize);
    for (int i = 0; i < btSize; i++)
    {
        // printf("%s\n", btStrings[i]);
        LOG_ERROR_WRITE(btStrings[i]);
    }
    exit(signal);
}


/* Obtain a backtrace and print it to stdout. */
void print_trace(void)
{
    void *array[10];
    size_t size;
    char **strings;
    size_t i;

    size = backtrace(array, 10);
    strings = backtrace_symbols(array, size);

    printf("Obtained %zd stack frames.\n", size);

    for (i = 0; i < size; i++)
    {   
        // printf("%s\n", strings[i]);
        LOG_ERROR_WRITE(strings[i]);
    }
        

    free(strings);
}

/* A dummy function to make the backtrace more interesting. */
void dummy_function(void)
{
    print_trace();
}

void testCrash()
{
    int *a = 0;
    int aa = *a;
    printf("%d\n", aa);
}




int main(void)
{
    int *p = NULL;

    signal(SIGSEGV, &crashHandler);

    testCrash();
    
    // MY_ASSERT_NULL(p);
    
    // dummy_function();
    return 0;
}

相关文章

  • C 报错打印调用栈

  • Xcode(C/C++)打印调用栈信息

    本文档记录Xcode打印调用栈信息的配置,辅助调试复杂C/C++代码。 1、输出调用栈信息 具体功能由由如下函数实...

  • java 打印 调用栈

  • frida 打印调用栈

    智姐姐的打印堆栈的脚本特别好用: console.log(Java.use("android.util.Log")...

  • 【Java】打印调用栈

    第一种方式,使用 Exception: 第二种方式,使用 Thread.getStackTrace():

  • C语言10- C语言与汇编

    20:C语言与汇编 20.1:调用约定之汇编 x86调用约定: cdecl:参数从右往左依次入栈,调用者栈平衡(C...

  • 打印代码中的调用层级(调用栈)

    获取方法调用栈,场景:比如你想让不同的人调用这个方法,给的参数不同,可以通过调用栈拦截修改。场景:打印日志上传到云...

  • NSLog(@"测试%@",10) 做了什么?

    准备工作 如果正常打印不请求调用流程是很难看到具体调用栈的,那就先让它crash,然后再去查看调用栈。 我们知道%...

  • [转载]C语言函数调用栈

    原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...

  • 逆向思维

    1. 利用异常栈信息输出调用栈 在Java中插入这样的代码,可以打印当前方法的调用栈;同理也可以在安卓的smali...

网友评论

      本文标题:C 报错打印调用栈

      本文链接:https://www.haomeiwen.com/subject/hpwgnrtx.html