ARM应用程序调试

ARM应用程序调试
一、使用strace命令来跟踪系统调用(涉及哪些open,read函数)
1.编译:
Tar xjf strace-4.5.15.tar.bz2
Cd strace-4.5.15
Patch -p1 < ../strace-fix-arm-bad-syscall.patch
./configure --host=arm-linux CC=arm-linux-gcc
Make
Cp strace /root
2.使用:
Strace -o log.txt 命令
得到程序执行调用的系统调用函数


二、使用gdb调试
    Pc机上运行gdb,arm板子运行gdbserver,gdb发送命令给gdbserver控制它,gdbserver发送命令给板子上待调试的子进程。
1.编译:gdb
Tar xjf gdb-7.4.tat.bz2
Cd gdb-7.4
./configure --target=arm-linux
Make
Mkdir tmp
Make install prefix=$PWD/tmp
2.编译gdbserver
Cd gdb/gdbserver
./configure --host=arm-linux
Make
出现未定义错误,到交叉编译链中寻找。
Cp  gdbserver  /arm_fs/bin复制到arm文件系统bin目录下
3.编译要调试的应用,编译时加上-g选项
4.使用:
(1)开发板
Gdbserver 192.168.1.17:2345 ./程序  (ip地址为开发板地址,端口随意写)
(2)在pc上
使用自己变编译出的arm-linux-gdb
Arm-linux-gdb ./程序
Target remote 192.168.1.17:2345
(3)Gdb命令
L:list显示源码
Break:break main在main函数打断点
Break test_debug.c:31在31行打断点
C:continue
Step:单步执行,会跟踪进入一个函数
Next:单步,不会进入函数
Print ¥:打印某变量值
Bt:函数调用关系
Quit:退出


5.另一种方法:
    让程序在开发板上直接运行,当它发生错误时,令它产生core dump文件,然后使用gdb根据core dump文件找到发生错误的地方
开发板:
(1)ulimit -c unlimited
(2)执行应用程序:./test_debug
程序执行出错会在当前目录产生core dump文件
(3)Cp core复制到上位机
(4)Pc:Arm-linux-gdb  ./test_debug ./core


三、配置内核输出应用程序的段错误信息
1.定义:
Arch/arm/mm/fault.c
函数__do_user_fault()
(1)配置内核CONFIG_DEBUG_USER
(2)Uboot:set bootargs user_debug=0xff
(3)操作:
Make menuconfig
Location:
 ->Kernel hacking
  ->Verbose user fault message


->Device Drivers
 ->Memory Technology Device (MTD) support (MTD)
  ->UBI - Unsorted block images
   ->Enable UBI (MTD_UBI)
    ->UBI debugging(MTD_UBI_DEBUG) 
(4)Uboot:set bootargs (原来的参数保留) user_debug=0xff
2.执行APP:./test_debug
出错信息:
a = 0x12
pgd = c04c8000
[00000000] *pgd=33d08031, *pte=00000000, *ppte=00000000


Pid: 772, comm:           test_debug
CPU: 0    Not tainted  (2.6.22.6 #1)
PC is at 0x84ac
LR is at 0x84d0
pc : [<000084ac>]    lr : [<000084d0>]    psr: 60000010
sp : bed9fe40  ip : bed9fe54  fp : bed9fe50
r10: 4013365c  r9 : 00000000  r8 : 00008514
r7 : 00000001  r6 : 000085cc  r5 : 00008568  r4 : bed9fec4
r3 : 00000012  r2 : 00000000  r1 : 00001000  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode USER_32  Segment user
Control: c000717f  Table: 304c8000  DAC: 00000015


(1)反汇编APP
Arm-linux-objdump -D test_debug > test_debug.dis
00008490<C>
...
84ac: e5823000 str r3, [r2] //r3=0x12,r2=0
查找出错PC位置0x84ac确定出错函数位置,将r3 : 00000012  存到r2 : 00000000出错


3.另一种修改内核打印栈信息
在内核函数__do_user_fault中
Unsigned long ret;
Unsigned long val;
Int i = 0;
Printk(“Stack: \n”);
While(i < 1024)
{
If(copy_from_user(&val, (const void __user *)(regs->ARM_sp + i*4), 4))
    Break;
Printk(“%08x ”, val);
If(i % 8 == 0)
    Printk(“\n”);
}
Printk(“\n End of Stack\n”);
使用新内核启动
执行程序:./test_debug
出错信息:
对于动态链接的test_debug
Stack: 
00000000 becd3e64 becd3e54 000084d0 000084a0 00000000 becd3e78 becd3e68 
C's sp                     return addr       B's sp


000084f0 000084c4 00000000 becd3e98 becd3e7c 00008554 000084e4 00000000 
ret addr          A's sp                     ret addr          main's sp


00000012 becd3ec4 00000001 00000000 becd3e9c 40034f14 00008524 00000000 
                                             ret addr          caller's sp
                                             对于动态链接,已经退出的程序不好确定动态库的地址


00000000 0000839c 00000000 00000000 4001d594 000083c4 000085cc 4000c02c 
静态连接的程序信息
对于静态链接的test_debug
PC is at 0x81e0
LR is at 0x8204
pc : [<000081e0>]    lr : [<00008204>]    psr: 60000010
sp : be93dc60  ip : be93dc74  fp : be93dc70
r10: 000085f4  r9 : 00008248  r8 : be93deb4
r7 : 00000001  r6 : 00000000  r5 : be93dd3e  r4 : 00000000
r3 : 00000012  r2 : 00000000  r1 : 00001000  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode USER_32  Segment user


Stack: 
00000000 be93dc84 be93dc74 00008204 000081d4 00000000 be93dc98 be93dc88 
C'sp                       ret addr          B'sp 


00008224 000081f8 00000000 be93dcb8 be93dc9c 00008288 00008218 00000000 
ret addr          A'sp                       ret addr          main'sp


00000012 be93deb4 00000001 00000000 be93dcbc 000084ac 00008258 756e694c 
                                             ret addr          __libc_start_main'sp


00000078 00000000 00000000 00000000 00000000 00000000 00000000 00000000


四、自制系统调用、编写进程查看器
1.自制系统调用hello函数
(1)写一个应用函数,仿flibc
Swi #val
(2)内核中,仿sys_write
仿照sys_XXX写一个函数放入数组
(3)内核修改文件:
linux/arch/arm/kernel/calls.S文件添加调用函数CALL(sys_hello)
Syscalls.h文件添加函数头文件asmlinkage void sys_hello(const char __user * buf, int count);
linux/fs/read_write.c文件添加函数实现
asmlinkage void sys_hello(const char __user * buf, int count)
{
char ker_buf[100];
if (buf)
{
copy_from_user(ker_buf, buf, (count < 100) ? count : 100);
ker_buf[99] = '\0';
printk("sys_hello: %s\n", ker_buf);
}
}
(4)应用层调用:
//#if defined(__thumb__) || defined(__ARM_EABI__)
//#define __NR_SYSCALL_BASE 0
//#else
#define __NR_SYSCALL_BASE 0x900000
//#endif


void hello(char *buf, int count)
{
/* swi */
asm ("mov r0, %0\n"   /* save the argment in r0 */
    "mov r1, %1\n"   /* save the argment in r0 */
"swi %2\n"   /* do the system call */
:
: "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE + 352)
: "r0", "r1");
}


int main(int argc, char **argv)
{
printf("in app, call hello\n");
hello("www.100ask.net", 15);
return 0;
}


2.利用自制的系统调用打断点
(1)修改应用程序的可执行文件,替换“某个位置”的代码为swi val。需要先看反汇编确定机器码
(2)执行程序
(3)进入sys_hello,在sys_hello中打印信息
(4)执行原来的指令,返回。


五、编写输入模拟器
1. 产品要经过测试才能发布,一般都是人工操作,比如手机触摸屏、遥控器
2. 操作过程中发现错误,要再次复现,找到规律,修改程序
3. 能否在驱动程序里把所有的操作记录下来,存为文件
   当出错时,可以通过文件里的数据来"复现"输入
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值