TombStone文件如何生成

开发者在分析系统稳定性的时候通常需要知道进程发生异常时的调用栈来分析问题,确认发生异常时进程正在做什么。这样才能根据进程所处场景或者调用栈、寄存器信息分析异常发生的原因。而在Android中,当Native进程发生崩溃时,会在/data/tombstones/目录下生成tombstones_xxx的文件,里面记录了某一个进程在发生崩溃时候的所有信息,包括调用栈、寄存器信息等等。这极大的有助于开发者来定位问题,本篇文章来分析下TombStone文件到底是如何生成的。

首先我们要知道,Native进程发生崩溃的时候,是因为接收到了Kernel发送的异常信号。这些信号是如何发送给当前进程呢?在Android平台上Native进程通过fork创建,然后由exec族的函数将elf文件替换原本的程序段,加载对应的程序指令,接着用通过linker32或者linker64去加载动态共享库,例如libc.so等等。而在Android平台中,linker会注册异常信号到kernel,然后通过回调函数来处理异常信号,在回调的过程就生成了TombStone文件,接下来看一下注册和回调的过程。

首先用objdump对linker64可执行程序进行反汇编,通过readelf找到elf文件执行的入口地址0x4cbb0,然后在反汇编中找到对应的地址就找到了对应的入口函数(类似于main函数),linker中__dl__start就是入口函数。

aarch64-linux-android-readelf -h  linker64
ELF Header:
  ...
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x4cbb0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          1440120 (bytes into file)
  ...

000000000004cbb0 <__dl__start>:
   4cbb0:   910003e0    mov x0, sp
   4cbb4:   9400cc07    bl  7fbd0 <__dl__linker_init>
   4cbb8:   d61f0000    br  x0
   4cbbc:   00000000    .inst   0x00000000 ; undefined

由于Android.bp中默认添加了前缀"_dl",prefix_symbols: “_dl”,所以入口地址就是_start。此处是用汇编写的,主要就跳转到__linker_init去执行。

android/bionic/linker/arch/arm64/begin.S
#include <private/bionic_asm.h>

ENTRY(_start)
  // Force unwinds to end in this function.
  .cfi_undefined x30

  mov x0, sp
  bl __linker_init

  /* linker init returns the _entry address in the main image */
  br x0
END(_start)

extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   
     ...
     return __linker_init_post_relocation(args, tmp_linker_so);
}

static ElfW(Addr) __attribute__((noinline))
__linker_init_post_relocation(KernelArgumentBlock& args, soinfo& tmp_linker_so) {
   

  ...
  sonext = solist = solinker = get_libdl_info(kLinkerPath, tmp_linker_so);
  g_default_namespace.add_soinfo(solinker);
  init_link_map_head(*solinker, kLinkerPath);

  ElfW(Addr) start_address = linker_main(args, exe_to_load);

  INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));

  // Return the address that the calling assembly stub should jump to.
  return start_address;
}

从代码逻辑来看,最后返回的是起始地址,接下来调用linker_main,函数中初始化了系统属性,并且调用debuggerd_init,并且传入了一个callback,但是此处并不是处理异常信号的回调。异常信号的注册是在debuggerd_init中。其中设置了接受异常信号的回调函数debuggerd_signal_handler以及要接收哪些异常信号。

static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load) <
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值