当前位置: 首页 > 工具软件 > Android Core > 使用案例 >

Android 抓取 core dump

施刚毅
2023-12-01

简单介绍下 coredump抓取方法,该方法适用于Android 5.0之后的 Root版本。

1.设置 debug 属性

adb shell setprop persist.debug.trace 1

设置这个属性的作用:

1.创建存放 core文件的目录 /data/core,配置 core_pattern

# corefile limit
on property:persist.debug.trace=1
    mkdir /data/core 0777 root root
    write /proc/sys/kernel/core_pattern "/data/core/%E.%p.%e"

2.在 zygote 新 fork出一个进程后,给这个进程设置 rlimit 为 RLIM_INFINITY

【注意】如果这个属性是在当前进程 fork 出来之后设置的,则不能起到设置当前进程的 rlimit的作用,因为:

--------------------------------------------------------------------------------------------
ForkAndSpecializeCommon()
   if(pid == 0) {
→ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags, is_system_server, instructionSet);
→ callPostForkChildHooks
→ VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
→ nativePostForkChild(token, debugFlags, isSystemServer, instructionSet);
→ EnableDebugFeatures(debug_flags);
→ EnableDebugger();
     if ( persist.debug.trace == 1) {
→ setrlimit(RLIMIT_CORE, &rl)
     }
    }
--------------------------------------------------------------------------------------------

从这个调用过程可以看到,一个 APP进程的 Rlimit 是在进程刚刚 fork 出来时设置的,根据 persist.debug.trace==1 来设置 rlimit 的;

如果错过了这个时机,是没有其他机会设置 rlimit的;【问题1】如果错过了这个时机怎么办,比如定屏的手机,想让 system_server coredump,而在定屏之前没有设置这个属性 ?这个在第 5部分说明。

【注】这个属性是 persist 的,设置一次后,即便重启也不需要重设了。

2.关闭 selinux

adb shell setenforce 0

关闭 selinux功能,从而不会因为 SE权限问题导致的 dump core 失败;

【注】每次重启手机,都需要重新关闭一次。

3.设置 coredump 类型

coredump类型,是由进程的 /proc/pid/coredump_filter 标志位决定的。

full   dump: /*0x27 MMF_DUMP_ANON_PRIVATE|MMF_DUMP_ANON_SHARED|MMF_DUMP_MAPPED_PRIVATE|MMF_DUMP_HUGETLB_PRIVATE*/
normal dump: /*0x23 MMF_DUMP_ANON_PRIVATE|MMF_DUMP_ANON_SHARED|MMF_DUMP_HUGETLB_PRIVATE*/
进程默认的 filter是 0x23,所以如果是一般的 dump core就能满足需求,则不需要这一步;

而如果需要 full dump,则需要设置:

adb shell echo 0x27 > /proc/pid/coredump_filter

它们的区别是:MMF_DUMP_MAPPED_PRIVATE

【注】如果需要 full dump,进程重启后需要重新设置,因为默认启动后是 0x23

对于一个 APP进程,如果不能很好的把握其启动时机,以及 FC的时机 { 比如app一启动就 Crash,比如 CTS测试过程中 FC },而又要抓其 fulldump,

那么可以给对应的 zygote/ zygote64 进程设置 coredump_filter,因为APP进程从 zygote fork出来会继承其 coredump_filter,也能达到目的;

4.触发 core dump

如果你的进程在特定步骤下就会 Native Crash,则触发这个路径即可。

一般情况下,我们使用发送信号的方式触发 coredump:

adb shell kill -6 pid

即,给 pid发送一个  ABORT信号,使之 abort;

这样 core file 就会生成在  /data/core/ 目录下了,同样 /data/tombstones/ 目录下有对应的 tombstone文件

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

【注】一般情况下,我们遇到的问题都是偶现的,有一个现场不容易,所以在有一定把握前,不要轻易的发送使进程挂掉的信号,先做如下检查,输出符合时再发送信号:

    1. @1:~$ adb shell getprop | grep persist.debug.trace
      [persist.debug.trace]: [1]
    2. @1:~$ adb shell getenforce
      Permissive
    3. @1:~$ adb shell cat /proc/1310/coredump_filter
      00000023

      如果需求是 fulldump,则应显示 00000027
    4. @1:~$ adb shell cat /proc/1310/limits | grep "core file"
      Max core file size unlimited unlimited bytes

    5. @1:~$ adb shell cat /proc/sys/kernel/core_pattern
      /data/core/%E.%p.%e

    当上面这些条件都满足时,再触发 core dump就会比较保险了。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

5.给已经存在的进程设置 rlimit

第2部分的问题,在这里回答,

【问题1】如果错过了这个时机怎么办,比如定屏的手机,想让 system_server coredump,而在定屏之前没有设置这个属性 ?

对于这种情况,我们可以使用 GDB attach 上 system_server进程,调用 setrlimit 函数来给当前进程设置 rlimit。

其实,在能够 attach的情况下,已经不需要 core dump了,不过,在调试完成后,做个 coredump可以把现场长久的保留下来。

设置方式:

  1. attach 上想要修改的进程
  2. 在 GDB中调用 setrlimit 函数

gdb attach方法,网上都有,这里就不展开了。主要介绍下 GDB中 调用函数的方法:

调用函数的关键在于参数的构造:

1.我们可以使用当前线程栈上还未使用的空间上构造参数, $sp - 0x1000 可以用来构造参数,使用之前先查看原来的值(如果你想还原栈的话)

2.参数的赋值使用 set 命令

3.函数的调用使用 call 命令

【注】一般Art线程的 stack size >= 1MB + 8k + 8k,实际查看的size是: 1036 K,最后 8K 不可用。所以上边使用当前栈帧 $sp - 0x1000 (4k),一般情况下,都应该还在线程的栈上;

(gdb) p /x $sp
$1 = 0x7fc2519240
(gdb) x /6x 0x7fc2518240
0x7fc2518240:   0xc25192d0  0x0000007f  0xacb70a8c  0x00000071
0x7fc2518250:   0xa1ce18c7  0xb398b292
(gdb) p * ((rlimit*)0x7fc2518240)
$3 = {
  rlim_cur = 548720972496,
  rlim_max = 488228981388
}
(gdb) set ((rlimit*)0x7fc2518240)->rlim_cur=10
(gdb) set ((rlimit*)0x7fc2518240)->rlim_max=20
(gdb) p * ((rlimit*)0x7fc2518240)
$4 = {
  rlim_cur = 10,
  rlim_max = 20
}
(gdb) call setrlimit(4, 0x7fc2518240)
$5 = 0

可以看到调用 setrlimit 函数的返回值是 0;

# cat /proc/24656/limits | grep core                                                                                                                                                        
Limit                     Soft Limit           Hard Limit           Units   
Max core file size        10                   20                   bytes   

在函数调用完成后当前进程的 rlimit 已经成功设置为 10 和 20;我们的真实情况应该是设置这两个值都是 -1;

6. setcoredump 工具

要开启 coredump,像上面那样要设置的项还是过多,不够方便。所以我们集成了这些设置到一个工具: setcoredump

使用该工具,执行一条命令即可达到开启 coredump功能的能力:


test:/ # setcoredump                                                                                                                                                                      
 
setcoredump: should have an option value as bellow:
 
Usage:
    setcoredump -h: show this help message.
    setcoredump -f: enable full dump on this device.
    setcoredump -n: enable normal dump on this device.
    setcoredump -p [pid] : enable normal dump for one process [pid].
    setcoredump -f -p [pid]: enable full dump for one process [pid].
 
core file directory: /data/core/
具体使用方式,在 help msg 中已有说明,工具是在 Android5.0 环境下编译的;

【工具下载】:setcoredump

【运行要求】:Android 5.0 ~ 8.1 的 root 版本,亲测都可以使用;




 类似资料: