coredump介绍
coredump是什么?
coredump一般我们说是核心转储,就是在进程异常时的一个快照,保存了异常时的内存、寄存器、堆栈等数据。这些数据存储成一个文件,而且是一个ELF文件格式,可通过readelf读取查看。
为何需要coredump?
在android系统上,一般程序在native或者art中异常后会在data/tombstones下生成对应的tombstone文件,这个文件一般已经包含了很多native程序的重要信息,结合symbol,我们会对异常原因有个初步判断,而且一般的简单问题可以有个初步分析结论。但对于较难的问题,仅有tombstone不足以判断异常原因,尤其是需要查看一些较多分支,对象地址数据没有在tombstone中输出时,我们就需要更多的寄存器和内存信息。这就需要抓起coredump来分析。
如何抓取coredump?
1,设置要抓取进程的rlimit
#define RLIM_INFINITY 0x7fffffffUL
......
221 rl.rlim_cur = RLIM_INFINITY;
222 rl.rlim_max = RLIM_INFINITY;
223 if (setrlimit(RLIMIT_CORE, &rl) < 0) {//异常打印
}
上面即设置core文件大小不限。
在android中,不同平台调用时机有区别,以某平台调用时机为例,在zygote fork进程时执行,其时序如下:
//frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
487static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
488 jint debug_flags, jobjectArray javaRlimits,
489 jlong permittedCapabilities, jlong effectiveCapabilities,
490 jint mount_external,
491 jstring java_se_info, jstring java_se_name,
492 bool is_system_server, jintArray fdsToClose,
493 jintArray fdsToIgnore,
494 jstring instructionSet, jstring dataDir) {
......
529 pid_t pid = fork();
531 if (pid == 0) {
......//这里执行java方法
669 env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
670 is_system_server, instructionSet);
671 if (env->ExceptionCheck()) {
672 RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
673 }
674 } else if (pid > 0) {
.....
}// gCallPostForkChildHooks对应的Java方法如下
832int register_com_android_internal_os_Zygote(JNIEnv* env) {
833 gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName));
834 gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
835 "(IZLjava/lang/String;)V");callPostForkChildHookspostForkChild(×××)nativePostForkChild(); //JniZygoteHooks_nativePostForkChild(); //native方法EnableDebugFeaturesEnableDebugger()setrlimit()
2,设置coredump存储路径和core文件名称
mkdir /data/core 0777 root root
write /proc/sys/kernel/core_pattern "data/core/%E.%p.%e"
即创建一个放置core的路径,且具有读写权限,然后设置了文件的名称,若不设置,则名称为core,可以用cat 查看,路径在可执行程序路径下。
对应某q公司,则设置了一个属性,persist.debug.trace,当其为1时,出发init执行上述两条命令:
device/q**/common/rootdir/etc/init.***.rcon property:persist.debug.trace=1mkdir /data/core 0777 root rootwrite /proc/sys/kernel/core_pattern "data/core/%E.%p.%e"
关于core文件名称的格式意义如下:
%p 出Core进程的PID
%u 出Core进程的UID
%s 造成Core的signal号
%t 出Core的时间,从1970-01-0100:00:00开始的秒数
%e 出core进程对应的可执行文件名
3,然后等待触发native crash
补充:
对于抓取fulldump话,需要增加一个步骤:adb shell echo 0x27 > /proc/pid/coredump_filter,进程重启需要重新执行
1278 snprintf(path,sizeof(path),"/proc/%d/coredump_filter",pid);
......
1283 if (is_full) {
1284 write(fd, "39", 2); /*0x27
1285 } else {
1286 write(fd, "35", 2); /*0x23
1287 }
这一步如果动态或者监控的话,可以通过hook执行。以某android厂商为例,hook了android的debuggerd进程的syscall,然后在发现进程正要处理的是SYS_tgkill信号时,就增加一个方法调用,之后在执行正常的syscall。
160extern "C" long hook_syscall(long number, ...) {
......
165 if (SYS_tgkill == number) {
166 int pid = va_arg(ap,int);
167 int tid = va_arg(ap,int);
168 int signal = va_arg(ap,int);
169 ****_native_debug_process(pid,tid);
170 ret = syscall(SYS_tgkill, pid, tid, signal);//先在context初始化时hook了pthread_setname_np,在hook_pthread_setname_np执行时设置了syscall的hook函数hook_syscall180extern "C" int hook_pthread_setname_np(pthread_t thread, const char* name) {
181 MILOGI("hook hook_pthread_setname_np name=%s", name);
182#if defined(__LP64__)
183 const char* sigsendersname = "debuggerd64:sig";
184#else
185 const char* sigsendersname = "debuggerd:sig";
186#endif
187 if (!strcmp(name,sigsendersname)) {
188 SoInfo si;
189 if (si.replace("syscall",(const uintptr_t)&hook_syscall)) {
android上有可能存在selinux的权限问题,可以将se关闭(adb shell setenforce 0),重启后需要重新关闭se。
对于已经启动的进程,rlimit不好更改,目前只能gdb attach到目标进程更改。
如何使用coredump?
coredump一般通过gdb调试,同时需要准备对应版本的symbol文件一起调试。
1,启动gdb
./prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-gdb(gdb路径)
或者prebuilts/gdb/linux-x86/bin/gdb
2,加载coredump
core-file coredump_file(coredump文件)
file
3. 设置symbol路径,即当前栈中用的可执行文件的symbol位置
file ~/symbols/out/target/product/项目名称/symbols/system/bin/app_process32 (一般app的话,是app_process,注意32位和64位的区别)
set solib-search-path symbols/system/lib/
4. 然后通过gdb命令查看,几个常用命令如下:
bt:查看对应当前线程栈
set arm force-mode thumb:汇编按照thumb命令解析
info r:查看当前帧寄存器
info thread:列出进程的所有线程
t num:切换到num线程
f num:切换到num帧
disassemble 0x9d73320c-0x30,+0x32:反汇编一段地址
x /10x 0x9d7331fc:按16进制,读取10个指定地址内存
p *(android::JavaBBinder*)0x8bb5c500:把指定地址按照指定数据类型解析数据;
set print pretty on:设置良好的阅读模式
directory ~/disk/androidO/:指定源码路径
其他命令不再列出
如何查看是否已开启coredump?
:/ # ulimit -a
-t: time(cpu-seconds) unlimited
-f: file(blocks) unlimited
-c: coredump(blocks) 0 //coredump大小为0,即关闭,可以通过ulimit -c size或者ulimit -c unlimited来指定size大小或者不限制大小
-d: data(KiB) unlimited
-s: stack(KiB) 8192
-l: lockedmem(KiB) 65536
-n: nofiles(descriptors) 32768
-p: processes 21499
-i: sigpending 21499
-q: msgqueue(bytes) 819200
-e: maxnice 40
-r: maxrtprio 0
-m: resident-set(KiB) unlimited
-v: address-space(KiB) unlimited
补充一篇不错的类似文章:https://blog.csdn.net/tenfyguo/article/details/8159176
coredump介绍相关推荐
- coredump介绍和使用
目录 1 什么是coredump 2 如何开启coredump功能 2.1 设置core文件的大小的方法: 2.2 设置core文件的路径 3 出现coredump的几种情况 3.1 内存访问越界 3 ...
- Linux 下Coredump分析与配置
查看全文 http://www.taodudu.cc/news/show-5652543.html 相关文章: coredump配置.产生原理.分析及示例 segmentation fault 常见原 ...
- 万变不离其宗——程序动态分析(gdb)
万剑归宗是无名的招数,但是它却道出一个道理.不管剑招多么花哨,多么厉害,最终还是需要回归正宗与朴实.程序也是一样,不管代码如何实现,不论语言如何,技巧如何,最终也是要能够被正确,有效,可靠的运行 ...
- android coredump,coredump功能介绍
[coredump简介] blog.csdn.net/tenfyguo/article/details/8159176 [如何打开coredump功能] 1.打开kernel编译开关 @kernel/ ...
- Linux调试——gdb调试器的简单使用调试coredump文件
文章目录 一.背景 二.gdb的指令与使用 1.gdb的基本指令. 2.gdb指令的简单使用 1.进入gdb模式 2.实例说明 三.调试coredump文件 前提:本质上是在调试程序崩溃之后的内存镜像 ...
- Linux 系统服务管理器(初始化系统/init system) -- systemd 及命令 systemctl 的详细介绍
文章目录 一.系统服务管理器 systemd (一)systemd 的特性 (二)systemd 与 传统 init 系统的区别 (三)systemd 的目录和文件 (四)systemd 的 Unit ...
- Linux下coredump调试3:补录
本篇文章记录在coredump调试过程中记录的其它事项. 一般地,调试的方式多种多样,不可能将其一网打尽.就笔者而言,一般喜欢用print大法,分段注解法,版本回退法,等等.实在无招,则用coredu ...
- Linux下coredump调试1:使用
李迟按: 调试是程序员的一项基本能力,经历过大大小小的实战,随着见识的增长,只要用心留意并做总结,相信调试的能力会越来越好.写程序不可能没有bug,只是bug容易不容易被发现,bug的危害大不大.笔者 ...
- coredump gdb 调试_CRASH安装和调试
一.Crash?当linux系统内核发生崩溃的时候,可以通过KEXEC+KDUMP等方式收集内核崩溃之前的内存,生成一个转储elf文件vmcore或者其他dump形式.内核开发者通过分析该elf du ...
最新文章
- redis-3.0.2集群部署
- ubuntu java开发环境搭建(jdk+tomcat+eclipse)
- easyUI tree 多选框设置是否级联选中
- as2的Key.isDown方法在as3的代替
- 6.4 SQL Server 加密
- python基础(set)补充
- oracle 循环块,Oracle语句块PL/SQL循环判断
- MySQL 5.5/5.6——概述 MySQL 客户端程序
- Snort 中文手册
- [生存志] 第14节 历代大事件概览 西汉
- WPF打开子窗口给父窗口添加蒙版效果
- 【年薪百万之IT界大神成长之路零】年薪百万之IT界大神成长之路
- 以下11條小建議,幫助你們的異地戀一直保持活力
- STM32软件模拟IIC---读写驱动AT24Cxx
- 利用Python进行数据分析 学习笔记
- R语言中的线性判别分析
- Android 12 Watchdog(4) Trace生成过程
- linux切换用户时释放资源,linux 切换用户报Resource temporarily unavailable
- Android与iOS在DES加密算法上的统一
- 横向评测常见的优秀国外5个域名注册商