精华内容
下载资源
问答
  • Android下面打印进程函数调用堆栈(dump backtrace)的方法 转载农夫三拳_最后发布于2016-07-05 10:20:49阅读数 8346收藏 展开 1. 为什么要打印函数调用堆栈? 打印调用堆栈可以直接把问题发生时的函数调用关系打...

    Android下面打印进程函数调用堆栈(dump backtrace)的方法

    转载农夫三拳_ 最后发布于2016-07-05 10:20:49 阅读数 8346  收藏

    展开

    1. 为什么要打印函数调用堆栈?

    打印调用堆栈可以直接把问题发生时的函数调用关系打出来,非常有利于理解函数调用关系。比如函数A可能被B/C/D调用,如果只看代码,B/C/D谁调用A都有可能,如果打印出调用堆栈,直接就把谁调的打出来了。不仅如此,打印函数调用堆栈还有另一个好处。在Android代码里,函数命名很多雷同的,虚函数调用,几个类里的函数名相同等,即使用source insight工具看也未必容易看清函数调用关系。如果用了堆栈打印,很容易看到函数调用逻辑。

    那么一个问题来了,Android/kernel本身在发生问题(kernel panic, tombstone, …)时,都可以打出详细的堆栈信息,这里干嘛还要费劲研究打堆栈?答案是发生问题时的堆栈的确很详细,但这里研究的是不影响(准确说是基本不影响)系统运行的境况下,打印出某个情形下的堆栈信息,这个对源代码逻辑研究很有帮助。

    2. Linux Kernel

    Kernel里最简单,直接有几现成的函数可以使用:dump_stack() 这个函数打出当前堆栈和函数调用backtrace后接着运行WARN_ON(x) 这个函数跟dump_stack很像,它有个条件,如果条件满足了就把stack打出来。打印出来的结果都在kernel log里,一般dmesg命令就可以看到了

    3. Native C++

    Android在新版(至少5.0, 6.0)里加入了CallStack类,这个类可以打出当前的backtrace。用法很简单:
    1. 前面确保包含头文件 #include “utils/CallStack.h”;
    2. Android.mk的库依赖列表(LOCAL_SHARED_LIBRARIES)里包含libutils,一般都已经包含了;
    3. 然后在要打印堆栈处加入android::CallStack cs(“haha”);“haha”是在logcat输出的TAG,这里可以自己定义。
    如果上下文已经在android namespace里,”android::”前缀就不必加了。Native C++的输出log可以在logcat里看到。

    注意,在网上的一些文档里说要这么用:
    CallStack stack;
    stack.update();
    stack.dump();
    这样做已经不行了,在新版Android里编译不过。

    4. Native C

    Android对C的堆栈打印支持不太好。过去网上的文章一般是推荐libcorkscrew.so,并加入大段代码来unwind_backtrace。新版Android上libcorkscrew已经被拿掉了,网上的加载libcorkscrew库的方法自然就不能用了。一个简单方法是用C语言调C++的函数,对,就是extern “C”。先在项目里加入一个c++文件,比如callstack.cpp,里面是:

    #include
    extern "C" void dumping_callstack(void);
    void dumping_callstack(void)
    {
        android::CallStack cs("Jamie");
    }

    在项目里再加入一个c++的头文件,比如callstack.h,里面是:void dumping_callstack(void);在Android.mk里源文件列表LOCAL_SRC_FILES里加入callstack.cpp,确保libutils在依赖列表里。在native C里include callstack.h后直接调用dumping_callstack()就可以了。这个log也可以在logcat里看到。

    5. Java

    Java最简单,它的backtrace最详细,连文件名和行号都打出来了:Exception e = new Exception(“haha”); e.printStackTrace(); log在logcat里看以看到。还可以使用这种方式:Log.d(“haha”, Log.getStackTraceString(new Throwable()));

    展开全文
  • 这种方法打印出来的部分堆栈只有地址,没有符号名,可以调用addr2line命令,然后popen获取符号表,但这样太麻烦,容易出错; 进程崩溃并非经常出现,有部分堆栈用来辅助定位问题即可,可以大概知道哪部分代码有问题...

    示例代码:

    #include <signal.h>
    #include <execinfo.h>
    
    void signal_handler(int signo) {
        int nptrs;
        void *buffer[1024];
        char **strings;
        
        signal(signo, SIG_DFL);
    
        nptrs = backtrace(buffer, 1024);
        strings = backtrace_symbols(buffer, nptrs);
        if (strings == NULL) {
           perror("backtrace_symbols");
           exit(EXIT_FAILURE);
        }
    
        for (int i = 0; i < nptrs; i++) {
           printf("%s\n", strings[i]);
        }
    
        free(strings);
    }
    
    
    int main(int argc, char* argv[]) {
        signal(SIGSEGV, signal_handler);
        signal(SIGABRT, signal_handler);
        
        //doing......
        
        return 0;
    }
    

    个人观点:

    1. 信号处理函数的实现不能太复杂,防止信号处理函数里出现死循环,导致进程永远退不出来了,造成服务不可用;
    2. 这种方法打印出来的部分堆栈只有地址,没有符号名,可以调用addr2line命令,然后popen获取符号表,但这样太麻烦,容易出错;
    3. 进程崩溃并非经常出现,有部分堆栈用来辅助定位问题即可,可以大概知道哪部分代码有问题即可;
    展开全文
  • 比如说在xxx.c文件中的xxx()函数中打印 步骤: 一、在xxx.c所在的目录中增加一个文件夹,例如dump,然后在里面创建callstack.cpp和callstack.h。 二、在callstack.cpp中添加如下代码 #include <utils/Call...

    比如说在xxx.c文件中的xxx()函数中打印
    步骤:
    一、在xxx.c所在的目录中增加一个文件夹,例如dump,然后在里面创建callstack.cpp和callstack.h。

    二、在callstack.cpp中添加如下代码
    #include <utils/CallStack.h>
    extern “C” void dumping_callstack(void);

    void dumping_callstack(void)
    {
    android::CallStack cs(“oliver.he_dump_test”);
    }

    三、在callstack.h中添加如下代码
    void dumping_callstack(void);

    四、在xxx()函数中添加头文件
    #include “callstack.h”
    然后在xxx()函数中直接调用 dumping_callstack()

    五、修改Android.mk文件
    在相应位置增加一行代码:
    LOCAL_SRC_FILES += dump/callstack.cpp

    添加进我们需要的库文件:
    libutilscallstack或libutils
    在LOCAL_SHARED_LIBRARIES :=中添加
    具体添加的是哪个根据实际情况来判断。
    如果不知道到底是哪个,可以两个都试下,哪个可以就是哪个。

    展开全文
  • 进程在初始化时,堆栈里面保存了关于进程执行环境和命令行参数等信息。此外,还保存了动态链接器所需要的辅助信息数组。辅助信息的格式如下数组: typedef struct { uint32_t a_type; union { uint32_t a_val;...

    进程在初始化时,堆栈里面保存了关于进程执行环境和命令行参数等信息。此外,还保存了动态链接器所需要的辅助信息数组。辅助信息的格式如下数组:

    typedef struct 
    {
        uint32_t a_type;
        union
        {
            uint32_t a_val;
        }a_un;
    }Elf32_auxv_t;
    

    以下小程序可以堆栈的初始化信息:

    #include <stdio.h>
    #include <elf.h>
    
    /* typedef struct */
    /* { */
        /* uint32_t a_type; */
        /* union */
        /* { */
            /* uint32_t a_val; */
        /* }a_un; */
    /* }Elf32_auxv_t; */
    
    int main(int argc, char *argv[])
    {
        int *pInt = (int *)argv;  /* pInt 指向命令行参数数组 */
        int iIndex = 0;
        Elf32_auxv_t *pAux = NULL;
    
        /* pInt-1 向后偏移四个字节可以指向命令行参数个数 */
        printf("==========Argument count : %d===========\n", *(pInt-1));
    
        for (iIndex = 0; iIndex < *(pInt-1); iIndex++)
        {
            printf("Argument(%d) is : %s\n", iIndex, *(pInt + iIndex));
        }
        pInt += iIndex; /* 后面是环境变量数组 */
        pInt++;     /* 中间空出一个4字节0 */
    
        printf("=========Environment :============\n");
        while ( *pInt)
        {
            printf("%s\n",*pInt);
            pInt++;
        }
        pInt++;     /* 空出一个4字节0 */
    
        printf("==============Auxiliary Vertors : ============\n");
        pAux = (Elf32_auxv_t *)pInt; /* 在后面是辅助信息数组 */
        while(pAux->a_type != AT_NULL)
        {
            printf("Type: %2d Value : %x\n", pAux->a_type, pAux->a_un.a_val);
            pAux++;
        }
        /* 测试一下后面还有什么 */
        pInt = (int *)pAux;
        pInt++;
        iIndex = 0;
        printf("==========others :==========\n");
        while(NULL != *pInt)
        {
            printf("others(%d) is : %s\n", iIndex, *pInt);
            iIndex++;
        }
        
        
        return 0;
    }
    
    编译测试得到如下结果:



    展开全文
  • 1. 为什么要打印函数调用堆栈打印调用堆栈可以直接把问题发生时的函数调用关系打出来,非常有利于理解函数调用关系。比如函数A可能被B/C/D调用,如果只看代码,B/C/D谁调用A都有可能,如果打印出调用堆栈,直接...
  • PostgreSQL中使用pstack打印fork子进程所有线程堆栈信息 PostgreSQL数据库在并行查询中, 出现如下"stack depth limit exceeded"的错误, 因此想使用pstack来打印堆栈信息, 依次来排查错误. void check_stack_depth...
  • 日志中不打印异常堆栈

    千次阅读 2017-08-03 20:41:52
    前几天,我们线上的机器打印日志,我发现有些打印空指针的异常,没有具体的堆栈信息,正常而言,像空指针这种异常是一定会有异常的堆栈信息(有少量的这种情况,大多数像空指针有堆栈信息的打印)。而我这里想看看...
  • 使用pstack指令对进程堆栈进行跟踪

    千次阅读 2018-12-20 17:17:12
    pstack命令可显示每个进程的栈跟踪,pstack $pid即可,pstack命令须由$pid进程的属主或者root运行。 安装 RedHat公司发行的Linux操作系统(RHEL,CentOS等等)也提供了pstack工具,只要安装gdb: yum install gdb ...
  • [code="java"]D:\>jstack -l 6000[/code] 参数: -F 强制返回 -l 打印详细信息 -h 帮助信息 -help 帮助信息
  • 输入命令:jps -lvm :用于查看当前机器上运行的java进程 输入命令: jstack -l pid :jstack -l 6812 查看... no.dump 把堆栈信息打印到当前目录 转载于:https://www.cnblogs.com/liudongdong666666/p/8961101.html...
  • 上一篇文章《Impala查询卡顿分析案例》介绍了怎么对Impala进程打印线程堆栈,JVM部分直接用 jstack 比较直接,但 C++ 部分由于要使用 gdb 或 breakpad 工具,还需要编译源码,显得比较繁琐。本文直接演示如何在 CDH ...
  • 进程在运行过程中遇到逻辑错误, 比如除零, 空指针等等, 系统会触发一个软件中断. 这个中断会以信号的方式通知进程, 这些信号的默认处理方式是结束进程. 发生这种情况, 我们就认为进程崩溃了. 进程崩溃后, 我们会...
  • Android下面打印进程函数调用堆栈(dump backtrace)的方法  (2016-02-05 16:47:22) 转载▼ 标签:  android   堆栈   调试   backtrace   1. 为什么...
  • #include #include "debug_trace.h" #define TRACE_SIZE 1024 static void trace_print(int signal_type) { int trace_id = -1; void *buffer[100]; char **info = NULL;... trace_id = backtra
  • 打印堆栈信息

    千次阅读 2017-01-17 17:11:03
    因为项目原因,了解下如何打印程序的堆栈信息。 首先打开任务管理器,找到对应Java 进程的pid 然后 进入到Java jdk 的安装路进行,在bin目录有一个叫 jstack.exe 的程序。使用下面的命令 D:\Java\jdk1.8.0\bin>...
  • 有时候,我们跟踪某个函数的时候,不知道这个函数是哪个函数调用的,当然对代码比较熟悉的话,...2、在该函数添加打印堆栈的log,可以直接打印出调用关系。 Log.e("TAG", Log.getStackTraceString(new Exception...
  • diff --git a/device/fsl/sabresd_6dq/BoardConfig.mk b/device/fsl/sabresd_6dq/BoardConfig.mk index e490e440a..7251596ca 100755 --- a/device/fsl/sabresd_6dq/BoardConfig.mk +++ b/device/fsl/sabresd_6dq/B....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 558
精华内容 223
关键字:

打印进程堆栈