Mac环境下gdb调试Android ndk代码

Android从4.4开始,强制打开了SELinux,其规则是不允许一个进程attach到一个非自己的子进程或兄弟进程上进行调试的,哪怕这个进程是以root用户启动的也不行。想要知道当前SELinux的工作模式,可以在adb shell下键入getenforce命令,例如:

xxx:/ # getenforce
Enforcing

这是在我运行Android 8.0系统的Google 模拟器上运行的结果,可以看出,其已经默认打开了强制(Enforcing)模式。所以,要想调试成功,必须要关闭SELinux的强制模式,可以通过下面的命令来关闭:

xxx:/ # echo 0 > /sys/fs/selinux/enforce

注意,这条命令必须用root用户来运行。下面看看运行后的结果:

xxx:/ # getenforce
Permissive

可以看出,SELinux的模式已经从强制变成了允许(Permissive)。

一.查看你的应用进程号:
xxx:/$ adb shell ps | grep com.xxx.xxx
u0_a66       25862  1565 1484556  89372 SyS_epoll_wait aae55ac4 S com.xxx.xxx

可以看到我的应用进程号是25862

二.在pc段准备好资源:

将下列文件存放到pc指定路径下,如/desktop/gdb/workspace/test

  • /system/bin/app_process:这个资源在模拟器里可以找到
  • /system/bin/linker:这个资源在模拟器里可以找到
  • /system/lib/libc.so:这个资源在模拟器里可以找到
  • libxxx.so:你应用的debug的动态库,你需要在cflag和cxxflag中加入参数"-g"来保留调试信息
三.启动gdbserver attach到应用进程:
xxx:/$ adb shell
xxx:/ # gdbserver remote:1234 --attach 25862
四.映射端口:
xxx:/$ adb forward tcp:1234 tcp:1234

其中前面的是local的端口,后面的是remote的端口

五.启动GDB:
  • 在命令行中输入:

    xxx:/$ gdb
    
  • 设置可执行文件路径:

    (gdb) file /desktop/gdb/workspace/test/app_process
    
  • 设置动态库文件路径:

    (gdb) set solib-absolute-prefix /desktop/gdb/workspace/test
    (gdb) set solib-search-path /desktop/gdb/workspace/test
    
  • 连接到gdbserver:

    (gdb) target remote :1234
    

至此,就可以使用gdb调试程序了。

gdb命令说明

gdb中,输入命令时,可以不用打全命令,只用打命令的前几个字符就可以了,当然,命令的前几个字符应该要标志着一个唯一的命令,在Linux下,你可以敲击两次TAB键来补齐命令的全称,如果有重复的,那么gdb会把其例出来。

  • 显示gdb命令帮助信息:

    • help:显示gdb命令种类
    • help subcommand:显示subcommand的帮助信息
    • apropos word:搜索与word相关的命令
  • 设置断点:

    • b(break):在函数或某一行处设置断点 如果只记得部分函的前缀,可以这样:(gdb) b make_ <按TAB键>。
    • break filename:linenum:在源文件filename的linenum行处停住
    • break filename:function :在源文件filename的function函数的入口处停住
    • break *address:在程序运行的内存地址处停住 break break命令没有参数时,指在下一条指令处停住
      -break … If …:在条件成立时程序停住
    • break thread threadnum:定义在线程threadnum上的断点,如breakBootAnimation.cpp:364 thread 28 if bartab > lim
  • 设置观察点

    • watch expr:设置观察点,当表达式expr的值变化时,程序停住
    • rwatch expr:设置观察点,当表达式expr的值被读时,程序停住
    • awatch expr:设置观察点,当表达式expr的值被读或写时,程序停住
  • 设置捕捉点:

    • catch:设置被调试程序捕捉点,当event发生时,程序停住
    • catch catch [args]:捕捉一个C++捕捉到的异常
    • catch throw [args]:捕捉一个C++抛出的异常
    • catch syscall [args]:捕捉系统调用
  • 维护被调试程序断点:

    • condition N COND:修改断点号为N的停止条件为COND
    • ignore N COUNT:忽略断点号为N的停止条件COUNT次
    • clear [linenum|funname|*]:清除指定的行或函数断点
    • d(delete) [breakpoints][range]:清除指定的断点
    • disable [breakpoints] [range…]:禁用指定的断点
    • enable [breakpoints] [range…]:启用指定的断点
  • 为停止点设定运行命令:

    commands N  调试程序在断点号为N的断点处停止后,执行命令 
    执行命令 
    end
    
  • 显示被调试程序的信息:

    • info subcommand:显示被调试程序的某些信息,可用help info查看子命令。如:
    • info breakpoints [n]:显示所有断点(或断点n)信息
    • info watchpoints [n]:显示所有观察点(或观察点n)信息
    • info program:查看被调试程序的执行状态
    • info args:打印出当前函数的参数名及其值
    • info locals:打印出当前函数中所有局部变量及其值
    • info display:查看display设置的自动显示的信息
    • info frame:查看栈帧信息,包括程序语言
  • 运行及查看被调试信息:

    • r(run):运行被调试程序
    • c(continue):从断点出开始继续执行直到结束或下一个断点
    • s(step):单步跟踪,如果有函数调用,他会进入该函数。进入函数的前提是此函数被编译有debug信息
    • n(next):单步跟踪,如果有函数调用,他不会进入该函数
    • p(print):打印表达式的值,可以查看全局变量(所有文件可见)、静态全局变量(当前文件可见)、局部变量(当前Scope可见)
    • p file::var:查看文件file中的变量var
    • p func::var:查看函数file中的变量var
    • p start@len:查看一段连续的内存空间的值,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度,如:
      int array = (int ) malloc (len * sizeof (int));
    • p *array@len
    • p/format expr:按指定的格式显示表达式expr(format:x, d, f, c, u, o, t, a)
    • display[/fmt] expr:程序停下来后就会显示expr的值
    • undisplay/delete displaynum/disable displaynum/enable displaynum
    • bt:查看当前函数调用堆栈信息
    • f(frame):查看当前栈层信息,包括栈的层编号、当前的函数名、函数参数值、函数所在文件及行号和函数执行到的语句
    • finish:运行程序,直到当前函数完成返回
    • u(until):运行程序直到退出循环体
  • 显示源代码:

    • l(list):列出具体的函数或代码行
    • list:显示当前行后面的源程序
    • list -:显示当前行前面的源程序
    • list +:显示当前行后面的源程序
    • list linenum:显示程序第linenum行的周围的源程序
    • list file:filenum:显示文件file中的filenum行
    • list file:func:显示文件file中的函数func
    • list funcname:显示函数名为function的函数的源程序,如list android::BootAnimation::movie
  • 搜索源代码:

    • forward-search reg:利用正则表达式前向搜索源码
    • search reg:利用正则表达式前向搜索源码
    • reverse-search reg:利用正则表达式在全部源码中进行搜索
  • 设置被调试程序参数/gdb配置:

    • set subcommand:设置gdb环境变量,可以使用help set查看set子命令。如:
    • set args:设置被调试程序运行参数
    • set directories:设置源文件搜索路径,多个使用“:”分割
    • set solib-search-path:设置符号表搜索路径
    • set environment varname [=value]:设置环境变量。如:set env USER=llj
    • set listsize num:设置一次显示源代码的行数
    • set step-mode on:打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。这个参数有很利于查看机器码
    • set print address on:打开地址输出, 当程序显示函数信息时,GDB会显出函数的参数地址
    • set print array on:打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔
    • set print elements num:设置显示数组元素的最大个数
    • set print null-stop on/off:如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示
    • set print pretty on/off:打开后gdb显示结构体时会比较漂亮
    • set print sevenbit-strings:设置字符显示,是否按“/nnn”的格式显示
    • set print union on/off:设置显示结构体时,是否显式其内的联合体数据
    • show subcommand:显示调试器的信息,使用help show查看子命令。如:
    • show environment [varname]:查看环境变量
    • show listsize:显示当前listsize的设置
    • show directories:显示定义了的源文件搜索路径
    • show language:查看gdb当前的语言环境
  • 其他:

    • q(quit):退出gdb
    • handle:处理信号
    • disas:查看汇编指令
  • 调整程序线路:

    一旦使用GDB挂上被调试程序,当程序运行起来后,你可以根据自己的调试思路来动态地在GDB中更改当前被调试程序的运行线路或是其变量的值,这个强大的功能能够让你更好的调试你的程序,比如,你可以在程序的一次运行中走遍程序的所有分支。

    修改变量的值 
    print x = 4       C/C++语法,把变量x的值修改为4 
    set var width=10       用gdb命令将参数width值修改为10
    跳转执行 
    jump +num       当前运行点向下偏移num行开始执行 
    jump linenum       从当前调试文件的linenum行开始执行 
    jump file:linenum       从file的linenum行开始执行
    产生信号量 
    singal SIGNAL       发送信号SINGAL给被调试程序
    强制函数返回 
    return       强制函数返回,忽略未执行的语句 
    return result       强制函数返回结果result,忽略未执行的语句
    强制调用函数 
    call func       调用当前程序中的函数 
    print func       调用当前程序中的函数
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值