strace与gdb调试方法

linux下调试技巧

这几天一直在找关于介绍linux下调试工具与调试方法的书,然后找到了《hack and debug》,这本书介绍特别多的工具对linux程序进行调试。对于驱动开发特别有用,最开始作者一直认为驱动调试与应用程序调试不一样,但是研究研究strace和gdb联合调试后,发现如果驱动程序出现Bug,调试它的测试程序时,会找到这个有bug的驱动接口。
当然这本书写作时间比较早,linux更新又快,所以有些指令使用方法有些变动。


strace

  1. 有bug的程序

/*
 * 内核调试使用 strace
 *
 */

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    //int fd;
    //printf("we want to open a file\n");
    int fd;
    // bug:吴权限访问/etc/gshadow
    fd = fopen("/etc/gshadow","r");
    //printf("we want to open a file\n");
    if(fd == NULL){
        printf("Error!\n");
        //return EXIT_SUCCESS;
    }

    return EXIT_SUCCESS;
}
  • 程序说明
    在无权限的时候访问/etc目录下的文件节点,肯定会出错。但是对于普通的驱动测试程序,无法预知程序在哪出错,当然可以加判断和大量的prinf来打印程序信息,但是这样麻烦。因此需要使用strace先跟踪程序运行,找到出现问题的API和运行地址,然后使用gdb深入到驱动程序(主要目的),当然使用gdb深入到驱动程序是作者的理解,需要实战一下才知道可不可行。

    1. strace ./st1
      跟踪当前目录下的st1程序,打印出数据:

execve(“./st1”, [“./st1”], [/* 79 vars */]) = 0
brk(NULL) = 0x73f000
access(“/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4aa58df000
access(“/etc/ld.so.preload”, R_OK) = -1 ENOENT (No such file or directory)
open(“/etc/ld.so.cache”, O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=195135, …}) = 0
mmap(NULL, 195135, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4aa58af000
close(3) = 0
access(“/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)
open(“/lib/x86_64-linux-gnu/libc.so.6”, O_RDONLY|O_CLOEXEC) = 3
read(3, “\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0”…, 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1868984, …}) = 0
mmap(NULL, 3971488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4aa52f2000
mprotect(0x7f4aa54b2000, 2097152, PROT_NONE) = 0
mmap(0x7f4aa56b2000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7f4aa56b2000
mmap(0x7f4aa56b8000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f4aa56b8000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4aa58ae000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4aa58ad000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4aa58ac000
arch_prctl(ARCH_SET_FS, 0x7f4aa58ad700) = 0
mprotect(0x7f4aa56b2000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ) = 0
mprotect(0x7f4aa58e1000, 4096, PROT_READ) = 0
munmap(0x7f4aa58af000, 195135) = 0
brk(NULL) = 0x73f000
brk(0x760000) = 0x760000
open(“/etc/gshadow”, O_RDONLY) = -1 EACCES (Permission denied)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), …}) = 0
write(1, “Error!\n”, 7Error!
) = 7
nanosleep({3, 0}, 0x7ffe8901d6b0) = 0

  • 说明
    打印的确够多的,其实就是显示出st1程序在加载、运行过程中,调用系统接口或者库函数的顺序,发现:

open(“/etc/gshadow”, O_RDONLY) = -1 EACCES (Permission denied)

问题找到了,还可以知道运行这一行的地址。

  1. strace -i ./st1
    带地址打印上面的信息。截一段打印:

[00007f365cfd0010] open(“/etc/gshadow”, O_RDONLY) = -1 EACCES (Permission denied)
[00007f365cfcfc04] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), …}) = 0
[00007f365cfd0290] write(1, “Error!\n”, 7Error!
) = 7
[00007f365cfa52f0] nanosleep({3, 0}, 0x7ffed49a3c70) = 0

strace联合gdb

在上面strace使用过程中,得到了程序出问题的地址0x00007f365cfd0010

  • gcc -g -o st1 st1.c
    重新编译st1.c,加上-g选项(带上调试信息),否则在使用gdb会出现没有debug symbol。
  • gcc st1
    这个指令运行gcc,但是调试没有开始
  • start
    最开始有一个自动断点在main函数第一个调用上,输入start后停在main函数第一个调用上。

  • b *0x00007f365cfd0010
    在0x00007f365cfd0010设置一个断点,然后可以使用s或者c,这里不对其他gdb指令说明。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值