一.基础知识-编译,链接,装载
基础的程序怎么来的,怎么到内存运行的,参考如下:
[](https://blog.csdn.net/TaylorPotter/article/details/103778980
二.NativeCrash原理
Native 程序是指可以直接运行在操作系统上,并且处理器直接执行机器码的程序,比如 “/system/bin” “/system/lib” 目录下的文件,这些应用程序都是由GCC(c/c++)编译生成,这些程序的崩溃统称为Native Exception,比如空指针,非法指针,程序跑飞,内存踩坏等。
Native Crash都是进程收到信号引起的.
2.1 信号的来源:
盗图如上,一个进程收到信号可以是系统发送的也可以是另一个级别的进程发送的
但都需要经过内核,相当于内核需截获信号,预处理或善后操作:
信号注册和发送详细过程如下:
- 信号发送或信号注册的信息保存在目标进程的进程控制块中;
- 在进程返回用户态之前会检查进程的控制块signal的位图信息,需要处理的信号需要找到制定的处理函数指针去处理
- signal处理处理函数可以在目标进程中自定义,内核有默认处理信号的操作;
- 目标进程的signal处理函数处理完后会继续交给内核继续处理,内核做该进程的信号处理善后操作.
2.2 信号处理函数
绝大多数的用户空间进程的入口是linker,在linux中即ld动态链接器.为什么这么说?
如果该程序需要动态链接共享库,可执行文件装载进内存后第一次进入用户态当前cpu占寄存器上的指令地址是动态链接器的入口,需要先调用动态链接器解释可执行文件执行,需要首先链接加载共享库.
在android上,动态连接器即是linker,在linux上动态链接器即是ld动态连接器
如果该程序是一个静态链接的可执行文件,则在该可执行文件加载入内存后,第一次进入用户态时当前cpu占寄存器上的指令地址是该可执行文件的Entry point address.
当然大多数可可执行文件需要动态链接,比如一个libc就太多可执行文件需要用到.
2.3 Native程序注册信号过程
2.3.1 Native进程装载运行过程:
1.如图,大部分动态链接的可执行文件,进入用户空间入口是linker,linux上是ld动态链接器,android上是linker,
图中.interp section中即是可执行文件中保存动态链接器的地址,返回给startThread,在返回用户空间时pc指针指的就是动态链接器的入口地址.
2.如果是静态链接的可执行程序,入口即是可执行文件中指定的程序入口地址
3.大部分动态链接的可执行文件不包含动态链接的共享库,在装载到内存后发现依赖的so不在物理内存中便会去通过linker试图加载so至物理内存然后映射到虚拟地址空间,通过重定位已获取so的虚拟地址,以供程序使用.
4.从图中可以看出,在一个程序的main方法之前还跑了一些其他的方法,其中.init区函数是程序员可控的,比如写了一个全局的变量赋值为 new 一个对象,此时这个对象的初始化方法在.init区,会在main方法前执行.
2.3.2 Native程序注册信号简单过程:
文末附详细过程.
2.4 App进程注册信号过程
2.4.1 应用进程启动过程
2.4.2 zygote fork app process简单过程
从native角度来看,app进程都是可执行文件app_process的进程映像
2.4.3 App进程注册信号简单过程
文末附详细过程
2.5 Native Crash后处理过程
图中应该还需画出,当目标进程处理完信号(主要是日志的dump操作)之后内核还会对该信号进行善后处理,如释放进程资源,进程退出等.
debuggerd的主要操作过程:
文末附详细过程.
三.Debug材料及工具使用
https://blog.csdn.net/TaylorPotter/article/details/103785967
四.附录-代码详细过程:
1. linker初始化详细过程
2. native进程启动及信号注册详细流程
3. App进程启动及信号注册处理详细过程:
4. Native Crash处理详细流程: