一种“特殊”的调试手段
2008-10-22 10:49
204 查看
在考文档:http://yuanma.org/data/2008/0610/article_3064.htm
原文的目的是用来解决Oops时没有相应的vmlinux在手的办法。传说是Linus的喜好。我尝试把它扩展到其他程序中。在Oops中会看到:Code: 6b c0 e8 2e 7e f6 ff e8 d1 16 f2 ff b8 01 00 00 00 e8 aa 1c f4 ff 89 d8 83 c4 10 5b 5d c3 90 90 90 55 89 e5 53 83 ec 0c 8b 48 04 <8b> 11 39 c2 74 18 89 54 24 08 89 44 24 04 c7 04 24 be 32 6b c0
这东东有点作用,只要你写:
const char array[] = "/xnn/xnn/xnn...";
int main(int argc, char *argv[])
{
printf("%p/n", array);
*(int *)0 = 0;
}
其中const char array[]的值用上面的那堆code代替即可。然后gcc -g -o 编译出程序,用gdb执行:(gdb) r
Starting program: /home/arc/hello
0x80484e0
Program received signal SIGSEGV, Segmentation fault.
然后反编译:(gdb) disassemble 0x80484e0
Dump of assembler code for function array:
0x080484e0 <array+0>: imul $0xffffffe8,%eax,%eax
0x080484e3 <array+3>: jle,pn 0x80484dc <__dso_handle+20>
0x080484e6 <array+6>: ljmp *<internal disassembler error>
0x080484e8 <array+8>: rcll (%esi)
0x080484ea <array+10>: repnz (bad)
0x080484ec <array+12>: mov $0x1,%eax
0x080484f1 <array+17>: call 0x7f8a1a0
0x080484f6 <array+22>: mov %ebx,%eax
0x080484f8 <array+24>: add $0x10,%esp
0x080484fb <array+27>: pop %ebx
0x080484fc <array+28>: pop %ebp
0x080484fd <array+29>: ret
0x080484fe <array+30>: nop
0x080484ff <array+31>: nop
0x08048500 <array+32>: nop
0x08048501 <array+33>: push %ebp
0x08048502 <array+34>: mov %esp,%ebp
0x08048504 <array+36>: push %ebx
0x08048505 <array+37>: sub $0xc,%esp
0x08048508 <array+40>: mov 0x4(%eax),%ecx
0x0804850b <array+43>: mov (%ecx),%edx
0x0804850d <array+45>: cmp %eax,%edx
0x0804850f <array+47>: je 0x8048529
0x08048511 <array+49>: mov %edx,0x8(%esp)
0x08048515 <array+53>: mov %eax,0x4(%esp)
0x08048519 <array+57>: movl $0xc06b32be,(%esp)
0x08048520 <array+64>: add %ah,0xa70
End of assembler dump.
这样就可以看到<8b>的位置,即array[43]对应的是move (%ecx), %edx,根据AT&T汇编程序的写法,可以知道问题出现在%ecx指向的地址有问题。
然后我把这个问题应用到jni的crash中去。
首先看crash log的开头,这里已经有很重要的信息:
## An unexpected error has been detected by Java Runtime Environment:## SIGSEGV (0xb) at pc=0x6fd1dba5, pid=29450, tid=3086605200## Java VM: Java HotSpot(TM) Server VM (1.6.0_03-b05 mixed mode)# Problematic frame:# C [libdb_java-4.2.so+0x15ba5] Java_com_sleepycat_db_db_1javaJNI_initDbEnvRef0+0x25## If you would like to submit a bug report, please visit:# http://java.sun.com/webapps/bugreport/crash.jsp 注意pc值。
找到code:Instructions: (pc=0x6fd1dba5)0x6fd1db95: 8b 45 18 89 75 f0 89 0c 24 89 44 24 04 ff 52 540x6fd1dba5: 89 86 e8 00 00 00 89 74 24 04 89 34 24 ff 96 50
注意寄存器数据:Registers:EAX=0x707db9d8, EBX=0x71122a80, ECX=0x00000000, EDX=0x00000ffcESP=0xb7f9ce30, EBP=0xb7f9ce48, ESI=0x00000000, EDI=0x091a3800EIP=0x6fd1dba5, CR2=0x000000e8, EFLAGS=0x00010246
查看callstack:Stack: [0xb7f4d000,0xb7f9e000), sp=0xb7f9ce30, free space=319kNative frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)C [libdb_java-4.2.so+0x15ba5] Java_com_sleepycat_db_db_1javaJNI_initDbEnvRef0+0x25j com.sleepycat.db.db_javaJNI.initDbEnvRef0(JLjava/lang/Object;)Ljava/lang/Object;+0j com.sleepycat.db.db_java.initDbEnvRef0(Lcom/sleepycat/db/DbEnv;Ljava/lang/Object;)Ljava/lang/Object;+5j com.sleepycat.db.DbEnv.initialize()V+3j com.sleepycat.db.DbEnv.<init>(I)V+10
然后写个小程序,把code输入,然后反汇编:(gdb) disassemble 0x8048500Dump of assembler code for function array:0x08048500 <array+0>: mov 0x18(%ebp),%eax0x08048503 <array+3>: mov %esi,0xfffffff0(%ebp)0x08048506 <array+6>: mov %ecx,(%esp)0x08048509 <array+9>: mov %eax,0x4(%esp)0x0804850d <array+13>: call *0x54(%edx)0x08048510 <array+16>: mov %eax,0xe8(%esi)0x08048516 <array+22>: mov %esi,0x4(%esp)0x0804851a <array+26>: mov %esi,(%esp)0x0804851d <array+29>: call *0x70250050(%esi)
出问题的应该是这句:0x08048510 <array+16>: mov %eax,0xe8(%esi)
根据AT&T汇编的特点,应该是%esi + 0xe8这个位置非法。现在%esi的值为0,不用想都知道这个位置非法了。然后查看源代码:
找到com.sleepycat.db.db_javaJNI.initDbEnvRef0(JLjava/lang/Object;)Ljava/lang/Object;+0
JNIEXPORT jobject JNICALL Java_com_sleepycat_db_db_1javaJNI_initDbEnvRef0( JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg2) { DB_ENV *self = *(DB_ENV **)&jarg1; COMPQUIET(jcls, NULL);
DB_ENV_INTERNAL(self) = (void *)(*jenv)->NewGlobalRef(jenv, jarg2); --> (1) self->set_errpfx(self, (const char*)self); --> (2) return (jobject)DB_ENV_INTERNAL(self);}
问题不在(1)不在(2)了
到此为止前没有解决问题,毕竟我不是专门弄berkeley db的,只好goo一下了,找了个patch,现在正在测试。。。
原文的目的是用来解决Oops时没有相应的vmlinux在手的办法。传说是Linus的喜好。我尝试把它扩展到其他程序中。在Oops中会看到:Code: 6b c0 e8 2e 7e f6 ff e8 d1 16 f2 ff b8 01 00 00 00 e8 aa 1c f4 ff 89 d8 83 c4 10 5b 5d c3 90 90 90 55 89 e5 53 83 ec 0c 8b 48 04 <8b> 11 39 c2 74 18 89 54 24 08 89 44 24 04 c7 04 24 be 32 6b c0
这东东有点作用,只要你写:
const char array[] = "/xnn/xnn/xnn...";
int main(int argc, char *argv[])
{
printf("%p/n", array);
*(int *)0 = 0;
}
其中const char array[]的值用上面的那堆code代替即可。然后gcc -g -o 编译出程序,用gdb执行:(gdb) r
Starting program: /home/arc/hello
0x80484e0
Program received signal SIGSEGV, Segmentation fault.
然后反编译:(gdb) disassemble 0x80484e0
Dump of assembler code for function array:
0x080484e0 <array+0>: imul $0xffffffe8,%eax,%eax
0x080484e3 <array+3>: jle,pn 0x80484dc <__dso_handle+20>
0x080484e6 <array+6>: ljmp *<internal disassembler error>
0x080484e8 <array+8>: rcll (%esi)
0x080484ea <array+10>: repnz (bad)
0x080484ec <array+12>: mov $0x1,%eax
0x080484f1 <array+17>: call 0x7f8a1a0
0x080484f6 <array+22>: mov %ebx,%eax
0x080484f8 <array+24>: add $0x10,%esp
0x080484fb <array+27>: pop %ebx
0x080484fc <array+28>: pop %ebp
0x080484fd <array+29>: ret
0x080484fe <array+30>: nop
0x080484ff <array+31>: nop
0x08048500 <array+32>: nop
0x08048501 <array+33>: push %ebp
0x08048502 <array+34>: mov %esp,%ebp
0x08048504 <array+36>: push %ebx
0x08048505 <array+37>: sub $0xc,%esp
0x08048508 <array+40>: mov 0x4(%eax),%ecx
0x0804850b <array+43>: mov (%ecx),%edx
0x0804850d <array+45>: cmp %eax,%edx
0x0804850f <array+47>: je 0x8048529
0x08048511 <array+49>: mov %edx,0x8(%esp)
0x08048515 <array+53>: mov %eax,0x4(%esp)
0x08048519 <array+57>: movl $0xc06b32be,(%esp)
0x08048520 <array+64>: add %ah,0xa70
End of assembler dump.
这样就可以看到<8b>的位置,即array[43]对应的是move (%ecx), %edx,根据AT&T汇编程序的写法,可以知道问题出现在%ecx指向的地址有问题。
然后我把这个问题应用到jni的crash中去。
首先看crash log的开头,这里已经有很重要的信息:
## An unexpected error has been detected by Java Runtime Environment:## SIGSEGV (0xb) at pc=0x6fd1dba5, pid=29450, tid=3086605200## Java VM: Java HotSpot(TM) Server VM (1.6.0_03-b05 mixed mode)# Problematic frame:# C [libdb_java-4.2.so+0x15ba5] Java_com_sleepycat_db_db_1javaJNI_initDbEnvRef0+0x25## If you would like to submit a bug report, please visit:# http://java.sun.com/webapps/bugreport/crash.jsp 注意pc值。
找到code:Instructions: (pc=0x6fd1dba5)0x6fd1db95: 8b 45 18 89 75 f0 89 0c 24 89 44 24 04 ff 52 540x6fd1dba5: 89 86 e8 00 00 00 89 74 24 04 89 34 24 ff 96 50
注意寄存器数据:Registers:EAX=0x707db9d8, EBX=0x71122a80, ECX=0x00000000, EDX=0x00000ffcESP=0xb7f9ce30, EBP=0xb7f9ce48, ESI=0x00000000, EDI=0x091a3800EIP=0x6fd1dba5, CR2=0x000000e8, EFLAGS=0x00010246
查看callstack:Stack: [0xb7f4d000,0xb7f9e000), sp=0xb7f9ce30, free space=319kNative frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)C [libdb_java-4.2.so+0x15ba5] Java_com_sleepycat_db_db_1javaJNI_initDbEnvRef0+0x25j com.sleepycat.db.db_javaJNI.initDbEnvRef0(JLjava/lang/Object;)Ljava/lang/Object;+0j com.sleepycat.db.db_java.initDbEnvRef0(Lcom/sleepycat/db/DbEnv;Ljava/lang/Object;)Ljava/lang/Object;+5j com.sleepycat.db.DbEnv.initialize()V+3j com.sleepycat.db.DbEnv.<init>(I)V+10
然后写个小程序,把code输入,然后反汇编:(gdb) disassemble 0x8048500Dump of assembler code for function array:0x08048500 <array+0>: mov 0x18(%ebp),%eax0x08048503 <array+3>: mov %esi,0xfffffff0(%ebp)0x08048506 <array+6>: mov %ecx,(%esp)0x08048509 <array+9>: mov %eax,0x4(%esp)0x0804850d <array+13>: call *0x54(%edx)0x08048510 <array+16>: mov %eax,0xe8(%esi)0x08048516 <array+22>: mov %esi,0x4(%esp)0x0804851a <array+26>: mov %esi,(%esp)0x0804851d <array+29>: call *0x70250050(%esi)
出问题的应该是这句:0x08048510 <array+16>: mov %eax,0xe8(%esi)
根据AT&T汇编的特点,应该是%esi + 0xe8这个位置非法。现在%esi的值为0,不用想都知道这个位置非法了。然后查看源代码:
找到com.sleepycat.db.db_javaJNI.initDbEnvRef0(JLjava/lang/Object;)Ljava/lang/Object;+0
JNIEXPORT jobject JNICALL Java_com_sleepycat_db_db_1javaJNI_initDbEnvRef0( JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg2) { DB_ENV *self = *(DB_ENV **)&jarg1; COMPQUIET(jcls, NULL);
DB_ENV_INTERNAL(self) = (void *)(*jenv)->NewGlobalRef(jenv, jarg2); --> (1) self->set_errpfx(self, (const char*)self); --> (2) return (jobject)DB_ENV_INTERNAL(self);}
问题不在(1)不在(2)了
到此为止前没有解决问题,毕竟我不是专门弄berkeley db的,只好goo一下了,找了个patch,现在正在测试。。。
相关文章推荐
- CE 调试遇到保护的一种解决办法
- 平面和圆环面的一种特殊交线: Villarceau circles
- 构造了一种难解的非线性一阶常微分方程,边值特殊;但可用非常规方法求解
- C语言调试手段:锁定错误的实现方法
- 网站-常用调试手段
- 写代码同时应注意的几个代码调试手段
- .NET下一种简单的调试诊断方法
- .NET下一种简单的调试诊断方法(2)
- Silverlight 雷达图和一种特殊泡泡画法
- 能人文章: 嵌入式调试手段
- 使用Carbide进行调试时免除重新启动模拟器的一种方法(转)
- 前端调试的那些手段
- VS调试时断点不被命中(breakpoint will not correctly be hit)问题的一种原因
- Android debug调试之特殊情况下的调试
- 解决多进程ptrace反调试保护的一种方法
- 一种基于TLS的高级反调试技术
- 单片机一种简便的printf调试方案。
- thinkphp调试手段
- C++ 基础调试手段
- 一种特殊的滋味