Ubuntu下正确姿势使用GDB调试Android Native进程

前言

  对于Android Native进程大家是既爱又恨啊,爱的是它能为我们的Android世界带来别样的精彩,狠的是当它耍脾气奔溃或者是创造它的人不留神造歪了那后果可是天崩地裂而且还不能让人好好调试。除了常规手段debuggerd -b PID分析Native进程的traces信息或者待Crash后分析trace.txt日志外,也没有比较好的完善的调试手段。不,难道我们伟大的android世界就这么羸弱吗!当然不是它还有一个必杀技,可以通过gdb+gdbserver的经典组合来进行Android Native进程的调试。那么本篇的重任来了,我将和大伙一起探讨正确姿势使用GDB调试Android Native进程(主要介绍怎么开启GDB调试)。开干!

注意:本篇是以Android 8版本为基础进行讲解的。

一.前期知识储备

在正式开干前,让我们先磨磨刀,磨刀不误砍柴工吗!先把基础打牢固了,还怕啥牛鬼蛇神的给解决不了。

1.1 啥是GDB

这里不是经济频道说的不是GDP是GDB,GDB是GNU Project Debugger 的缩写,它也是很多开源软件的调试利器。它主要提供了如下几个功能点:

  • 启动程序,可以按照自定义的要求随心所欲的运行程序
  • 可让被调试的程序在所指定的断点处停住(断点可以是条件表达式)
  • 当程序被停住时,可以检查此时程序中所发生的事
  • 动态的改变程序的执行环境

最后盗用一张网上的GDB调试原理图,如下:

二.调试环境准备

前期知识已经储备OK了,那么得准备好调试幻境了。不然环境不好,就不能正确的使用姿势调试了。让我们一一准备。

2.1 准备好Ubuntu开发环境

  • 当前首先你得安装了Ubuntu的操作系统,这个至于是用虚拟机安装或是其它方式,就不是本篇的讨论重点了。我这边的Ubuntu版本的信息如下,可以看到我当期的ubuntu版本信息是14.04,这里不做过多的讲解。
xxx@ubuntu:~/.android$ cat /proc/version
Linux version 3.19.0-25-generic (buildd@lgw01-20) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015
xxx@ubuntu:~/.android$
  • 安装好Ubuntu操作系统后,必须取得Root权限,这个也不是本文的重点。

  • 调试的终端可以在Ubuntu下环境通过adb进行真机调试,如果读者有不清楚怎么连接的,可以参考如下博客Ubuntu下正确姿势使用adb调试真机保证教会为止。

2.2 Android源码和编译环境准备

这个Android源码不管读者是偷的也好,抢的也好反正只要能搞到就行。譬如下面就是我的Android 8的源码环境,这里我是使用SSH将远程服务器挂载到我的虚拟机里里面的,至于怎么通过SSH挂载远程服务器目录可以参见篇章Ubuntu下使用SSH挂载远程服务器目录,其中hgfs就是我将远程服务器挂载的目录,如下所示:

[SPRD] xxx@ubuntu:~/hgfs$ pwd
/home/xxx/hgfs
[SPRD] xxx@ubuntu:~/hgfs$ ls
XXXX                                          Code sections for review-XXX_20190708T1.docx  ntfs.txt          repo          ssd    vfat.txt
Code sections for review-xxx_20190708T1.docx  ~$de sections for review-XXX_20190708T1.docx      XxxxxManager.rar  sourceisight  Tools
[SPRD] xxx@ubuntu:~/hgfs$
[SPRD] xxx@ubuntu:~/hgfs$ cd ssd/
[SPRD] xxx@ubuntu:~/hgfs/ssd$ cd xxx/ap/idh.code/
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ ls
Android.bp  bootstrap.bash  compatibility  device                  frameworks  libcore          packages          prebuilts                     stack   toolchain
art         build           cts            docs                    hardware    libnativehelper  xxxdroid          readme.md                     system  tools
bionic      chipram         dalvik         dump-all-packages.info  imagefiles  Makefile         pdk               sdk                           tags    u-boot15
bootable    code            development    external                kernel      out              platform_testing  XXXX.txt  test    vendor
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$

构建Android编译环境
这里我已经在服务器端编译过一次Android源码了,所以Android源码已经编译完成了,这里我只是构建一下Android编译环境,具体操作步骤如下:

source build/envsetup.sh
lunch //根据实际情况选择
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=8.1.0
TARGET_PRODUCT=sl8541e_1h10_gofu_osll
TARGET_BUILD_VARIANT=userdebug
TARGET_BUILD_TYPE=release
TARGET_PLATFORM_VERSION=OPM1
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.19.0-25-generic-x86_64-with-Ubuntu-14.04-trusty
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=OPM2.171019.012
OUT_DIR=out
AUX_OS_VARIANT_LIST=
XXX_PRODUCT_BUILD=SPRD
============================================

2.3 获取终端调试权限

对于被调试的终端一定要获取如下的权限,否则就上天无门了,谁也救不了,具体需要的权限如下:

  • 对于被调试的终端一定要能被root,然后被remount,这个其中的道道就不介绍了,不是本文的重点,对于从事终端开发的一般都可以获取到。
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ adb root
adbd is already running as root
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ adb remount
remount succeeded
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ adb shell
XXX:/ #

  • 临时关闭SELinux,否则后续执行相关操作会报avc 错误。
XXX:/ # setenforce 0
XXX:/ # getenforce
Permissive
XXX:/ #

2.4 设置终端调试环境

通过adb 查看终端当前是否有gdbserver存在,一般情况下是不存在。这个也是终端厂商为了安全方便考虑故意裁剪的。

XXX:/system/bin # ls | gerp gdbserver
/system/bin/sh: gerp: not found
127|XXX:/system/bin #

不存在难道就搞不下去了,当然不是Android的妈咪谷歌已经为我们提前准备好了,我们可以到Android源码目录prebuilts或者Android编译生成out目录(这个目录谷歌内置了如果有用的工具)下面去搜索,这里需要根据终端是32位的还是64的具体情况确定使用那个。

[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ cd prebuilts/
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code/prebuilts$ find .  -name gdbserver
./misc/android-x86/gdbserver
./misc/android-x86/gdbserver/gdbserver
./misc/android-mips/gdbserver
./misc/android-mips/gdbserver/gdbserver
./misc/android-arm/gdbserver
./misc/android-arm/gdbserver/gdbserver
./gcc/linaro-x86/aarch64/gcc-linaro-4.8/gcc-linaro-4.8-2015.06-x86_64_aarch64-linux-gnu/bin/gdbserver
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code/prebuilts$ cd ..
c[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ cd out/
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code/out$ find .  -name gdbserver
./target/product/sl8541e_1h10_go/obj/EXECUTABLES/gdbserver_intermediates/gdbserver
./target/product/sl8541e_1h10_go/system/bin/gdbserver
[SPRD] xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code/out$


这里我们选用out目录下面的gbdserver,将其push到终端并修改权限,具体操作步骤如下所示:

xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ adb push  ./out/target/product/sl8541e_1h10_go/system/bin/gdbserver  /system/bin
782 KB/s (596484 bytes in 0.744s)
xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ adb shell "chmod 777 /system/bin/gdbserver"
xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$ adb shell "ls -l  /system/bin/gdbserver"
-rwxrwxrwx 1 root shell 596484 2020-01-17 01:45 /system/bin/gdbserver
xxx@ubuntu:~/hgfs/ssd/xxx/ap/idh.code$

三.正式开始调试

前面做了这么多的准备前戏,都是为了检验最后的姿势是否正式,不,应该是是否能正确调试。好了下面拉开我们的正式调试序幕。这里我们要调试的进程名字是xxx_xxx。

3.1 启动gdbserver并attach到想要调试的进程

在正式开始调试前,让我们看看gdbserver支持那些命令,在终端下输入gdbserver,可以看出支持如下的命令:

XXX:/ # gdbserver
Usage:  gdbserver [OPTIONS] COMM PROG [ARGS ...]gdbserver [OPTIONS] --attach COMM PIDgdbserver [OPTIONS] --multi COMMCOMM may either be a tty device (for serial debugging),
HOST:PORT to listen for a TCP connection, or '-' or 'stdio' to use
stdin/stdout of gdbserver.
PROG is the executable program.  ARGS are arguments passed to inferior.
PID is the process ID to attach to, when --attach is specified.Operating modes:--attach              Attach to running process PID.--multi               Start server without a specific program, andonly quit when explicitly commanded.--once                Exit after the first connection has closed.--help                Print this message and then exit.--version             Display version information and exit.Other options:--wrapper WRAPPER --  Run WRAPPER to start new programs.--disable-randomizationRun PROG with address space randomization disabled.--no-disable-randomizationDon't disable address space randomization whenstarting PROG.Debug options:--debug               Enable general debugging output.--debug-format=opt1[,opt2,...]Specify extra content in debugging output.Options:allnonetimestamp--remote-debug        Enable remote protocol debugging output.--disable-packet=opt1[,opt2,...]Disable support for RSP packets or features.Options:vCont, Tthread, qC, qfThreadInfo and threads (disable all threading packets).For more information, consult the GDB manual (available as on-line
info or a printed manual).
1|XXX:/ #

这里我们使用的是–attach参数来进行,下面来详细介绍一下具体调试应该执行的流程:

  • 查找需要被调试Native进程的PID号,可以使用如下命令查找。
XXX:/ # ps -A | grep  xxx_xxx
root          4027     1   19960   5096 poll_schedule_timeout a9a0c7d0 S xxx_xxx
XXX:/ # 
  • 通过gdbserver attach到我们需要调试的Native进程
XXX:/ # gdbserver :5050 --attach 4027
Attached; pid = 4027
Listening on port 5050


参数说明: 在tcp端口5050上监听xxx_xxx程序,其中客户端gdb只要也连上5050端口即可。
结果: 如上图就是attach成功了。

3.2 设置tcp转发端口

设置调试终端端口转发这里使用的是forward,Android官方解释如下:

  adb forward <local> <remote> - forward socket connectionsforward specs are one of: tcp:<port>localabstract:<unix domain socket name>localreserved:<unix domain socket name>localfilesystem:<unix domain socket name>dev:<character device name>jdwp:<process pid> (remote only)


将上面命令格式引入实际情况,如下:

adb forward tcp:5050 tcp:5050

参数说明: 表示通过adb映射tcp端口5050,命令中前面的是local的端口,后面的是remote的端口。
注意: 这里的端口必须和前面gdbserver设置的端口一致,否则后果吗就是姿势不对,导致gdb无法和gdbserver服务端通信。

3.3 在终端上启动gdb调试

失败的尝试,重要的说三次,三次
网上很多博客说可以使用gdbclient进行调试,不需要进行任何配置,我这边也尝试了一下,但是失败了,应该是Android O上面已经给废弃了,这里一笔带过给说说,具体操作步骤如下:

  • 构建Android编译环境,当然是source然后lunch
  • 然后执行下述命令,其中xxx_xxx是我们要调试的Native进程。

Android的妈咪谷歌已经为我们提供了gdb调试的客户端,我们可以在目录Android源码目录prebuilts下面进行搜索,如下:

这里我们使用红色框标记的gdb客户端进行调试,下面我们分步骤详细讲解。

3.3.1 启动gdb并连接到gbdserver

可以通过如下命令执行:

arm-eabi-gdb
target remote:5050  //这里填入你实际的端口


连接成功后,服务端提示如下:

3.3.2 设置监控的二进制文件

这里要监控的二进制文件是xxx_xxx,执行下述命令:

(gdb) file /home/xxx/hgfs/ssd/xxx/ap/idh.code/out/target/product/sl8541e_1h10_go/symbols/system/bin/xxx_xxx
A program is being debugged already.
Are you sure you want to change the file? (y or n) yLoad new symbol table from "/home/xxx/hgfs/ssd/xxx/ap/idh.code/out/target/product/sl8541e_1h10_go/symbols/system/bin/xxx_xxx"? (y or n) y
Reading symbols from /home/xxx/hgfs/ssd/xxx/ap/idh.code/out/target/product/sl8541e_1h10_go/symbols/system/bin/xxx_xxx...done.
(gdb)

3.3.3 Set sysroot路径

执行如下命令:

(gdb) set sysroot /home/xxx/hgfs/ssd/xxx/ap/idh.code/out/target/product/sl8541e_1h10_go/symbols
(gdb)

3.3.4 设置Android源码目录

执行如下命令:

(gdb) set dir /home/xxx/hgfs/ssd/xxx/ap/idh.code
(gdb)

3.3.4 设置gdb带符号表的so路径

执行如下命令:

(gdb) set solib-absolute-prefix  /home/xxx/hgfs/ssd/xxx/ap/idh.code/out/target/product/sl8541e_1h10_go/symbols
(gdb)

3.3.4 设置gdb的so搜索路径

执行如下命令:

(gdb) set solib-search-path /home/xxx/hgfs/ssd/xxx/ap/idh.code/out/target/product/sl8541e_1h10_go/symbols/system/lib/
(gdb)

3.4 开启终极调试

gdb调试支持的命令比较多,这里挑选几个:

3.4.1 gdb list查看源码

执行下述命令:

(gdb) list
206         system("iptables -P OUTPUT ACCEPT");
207         system("iptables -P INPUT ACCEPT");(gdb) list main.c:110//查看指定行数代码

3.4.2 gdb break设置断点

执行如下命令设置断点:

(gdb) break mian.c:100
No source file named mian.c.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (mian.c:100) pending.

3.4.3 gdb breakpoints显示断点信息

执行如下命令:

(gdb) info breakpoints 1
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   <PENDING>  mian.c:100
(gdb)


关于gdb命令的使用就介绍到这了,这个不是本文的重点,至于读者想解锁更多姿势那就只能百度gdb常用命令了(说实话我也就知道常用的那么一丢丢而已)。

结语

修行至此,恭喜读者你已经开启了Ubuntu下正确姿势使用GDB调试Android Native进程,行走于ubuntu江湖木有任何问题了。此时的你可以一剑走天下了,为师的必杀器已经倾囊相授了。各位江湖见。但是还有几个点需要注意:

  • 编译时请禁止编译优化选项,即添加-O0编译选项,否则会导致代码在调试时出现跳来跳去的可能,并且在打印变量值是出现
  • 在编译程序时需要添加-g编译选项以为程序添加gdb调试功能,否则你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址
LOCAL_CFLAGS += -g

写在最后

  各位读者看官朋友们,Ubuntu下正确姿势使用GDB调试Android Native进程已经全部完毕,希望能吸引你,激活发你的学习欲望和斗志,我也会在后续篇章中加上gdb命令的更多详细信息。在最后麻烦读者朋友们如果本篇对你有帮助,关注和点赞一下,当然如果有错误和不足的地方也可以拍砖。

Ubuntu下正确姿势使用GDB调试Android Native进程相关推荐

  1. Eclipse+CDT+GDB调试android NDK程序

    http://www.cnblogs.com/shadox/archive/2011/12/02/2272564.html Eclipse+CDT+GDB调试android NDK程序 Eclipse ...

  2. 使用 GDB 调试 Android 应用

    GNU 工程调试器(GDB)是一个常用的 Unix 调试器.本文详述使用 gdb 调试 Android 应用和进程的方法. 调试运行中的应用或进程 gdbclient 是源码库中的一个 shell 脚 ...

  3. Linux(Ubuntu)下C语言编译与调试

    Linux(Ubuntu)下C语言编译与调试 编译流程 gcc安装命令 sudo apt install build-essential vim/touch 创建源文件 vim打开编辑源文件(.c结尾 ...

  4. 如何调试Android Native Framework

    原文: https://zhuanlan.zhihu.com/p/24867284 如何调试Android Native Framework weishu 7 个月前 半年前写了一篇文章,介绍 如何调 ...

  5. ubuntu android 真机调试,Ubuntu下AndroidStudio的真机调试

    手机设置里面,开启开发者选项,然后再打开USB调试 (我的小米手机需要USB打开方式为文件传输) 查看手机端口id 终端输入命令 lsusb, 系统会列出所有的usb设备.例如: Bus 004 De ...

  6. Ubuntu和Mac使用gdbserver远程调试android源码

    一.gdbserver在android上远程调试进程 0.关闭Enforcing # adb shell setenforce 01.拷贝gdb和gdbserver文件 <1>PC端为Cl ...

  7. 使用GDB调试android模拟器

    使用android的模拟器可以调试应用,也可以调试C/C++代码库. 调试C/C++代码时,还可以使用GDB单步调试代码,跟linux上一样方便. 1. 准备android代码:从官网上下载代码,编译 ...

  8. Linux下gcc/g++编译器gdb调试器和makefile的使用

    文章目录 一.gcc的使用 gcc选项 二.gdb的使用 三.Linux项目自动化构建工具-make/Makefile 3.1 概念 3.2 使用 3.3 原理 一.gcc的使用 首先我们知道一个C/ ...

  9. ubuntu android 手机驱动,ubuntu 下正确安装android手机驱动

    1. 查看手机ID号. charlesxue@THSHIBA:~/setup/cocos2d-x/cocos2d-x-2.1.4/projects/simpleGame/proj.android/bi ...

最新文章

  1. 自己动手设计RESTful API
  2. getline简单例子
  3. ZOJ 3700 Ever Dream(模拟)
  4. 伦敦科学博物馆用百年智慧打造的一套探索书,拓展孩子的科学、数学和艺术思维...
  5. ANTLR –语义谓词
  6. raid5坏了一块盘怎么办_机械硬盘的坏道处理——屏蔽之
  7. 遍历所有点的最短路径matlab_运筹学实验8 最短路的求解
  8. ubuntu mysql环境变量配置_MySQL在Win10与Ubuntu下的安装与配置
  9. 科研福利!北京超算获AI Perf500总量份额第一,200元卡时免费领取
  10. 数学建模学习笔记(三十一)模糊评价法
  11. MySQL卸载不干净问题
  12. 【信息系统项目管理师】2018下半年系统集成项目管理工程师案例分析
  13. 什么是UL2809认证?
  14. 华为HCIP-DATACOM391-420(821)
  15. 《Python自然语言处理》——第1章 语言处理与Python 1.1 语言计算:文本和词汇...
  16. python 文本框不能放表情_用Python自动生成表情包,生活不易多才多艺!
  17. 如何在谷歌浏览器内设置http代理?
  18. 用IMAP4访问Exchange邮箱
  19. 某网页在线视频有声音无图像
  20. AOP--Filter使用,过滤器和拦截器的区别

热门文章

  1. 三角形中的正方形,三个问题
  2. 为何用户体验无法被设计,如何为用户体验设计
  3. 悦读 | 公布你的原则,读瑞.达利欧的《原则》
  4. 网络流量监控软件怎样实现
  5. RTTHREAD软件包目录
  6. iOS图片转成视频方法
  7. android hawk 保存map对象,Android Hawk数据库 github开源项目
  8. matlab小波神经网络,MATLAB 小波神经网络预测求助大神
  9. 球形FP-MAP的接收端迭代检测模型
  10. day2:牛客网 糖果俱乐部