GDB调试

来源:互联网 发布:免费手机电视软件 编辑:程序博客网 时间:2024/05/29 12:28
概要
    coredump是linux原生的概念,目前有很多工具可以支持coredump调试。其中gdb/trace32都可以支持。
    coredump包含进程空间的内存,如果在加上含有调试信息的lib/程序,那么可以还原出当时异常的场景,这时你可以查看寄存器内容,调用栈,变量和内存等等。这对分析问题非常有帮助。
    下面我们会一一介绍gdb和trace32如何调试coredump。
1. gdb (GNU debugger)
(1). 概述
    GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具
    官网: 
http://www.gnu.org/software/gdb/ (可以下载到工具和文档)
(2). 功能
    启动或连接程序,可以按照你的自定义的要求随心所欲的运行程序。
    可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)。
    当程序被停住时,可以检查此时你的程序中所发生的事。
    动态的改变你程序的执行环境。
(3). 调试方法
    在线调试(需要在eng build版本)
        1. 可以用gdb直接启动一个程序调试。
        2. 对一个已经运行的程序用gdb attach调试。
    离线调试(借助coredump)
        就是本章节的重点。
(4). 工具来源
    Android NDK: 
http://developer.android.com/sdk/ndk/index.html
    在ndk安装目录下的toolchains/arm-linux-androideabit-$version/prebuilts/linux-x86/bin/arm-linux-androideabi-gdb
    另外还可以从codebase里找到,在alps/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-$version/bin/arm-linux-androideabi-gdb
    【注意】不要使用PC预装的gdb,android有对gdb做修改。
2. 离线调试
    gdb离线调试coredump,一定要有这个程序的symbols文件才行。你可以这样启动gdb:
        arm-linux-androideabi-gdb <program> PROCESS_COREDUMP
    gdb有一些启动参数可以配置:
        -symbols <file>或-s <file>: 从指定文件中读取符号表。
        -se file: 从指定文件中读取符号表信息,并把他用在可执行文件中。
        -core <file>或-c <file>: 调试时core dump的core文件。
        -directory <directory>或-d <directory>: 加入一个源文件的搜索路径。默认搜索路径是环境变量中PATH所定义的路径。
    当然了,简单使用gdb的话,直接arm-linux-androideabi-gdb即可启动,然后在里面输入对应的命令。
    进入gdb之后,会有类似shell的窗口,你可以输入任何gdb的命令,gdb的调试就是在这样的窗口上进行的。下一章节我们会介绍gdb常用的几个命令。
3. 命令
    gdb的命令可以使用help命令来查看,如下所示
        命令有很多,gdb把之分成许多个种类。help命令只是例出gdb的命令种类,如果要看种类中的命令,可以使用help <class>命令,如:help breakpoints,查看设置断点的所有命令。也可以直接help <command>来查看命令的帮助。
    在gdb中输入命令时,可以不用打全命令,只用打命令的前几个字符就可以了,当然命令的前几个字符应该要标志着一个唯一的命令,在Linux下,你可以敲击两次TAB键来补齐命令的全称,如果有重复的,那么gdb会把其例出来。
    以下列出常用命令(更多的命令请查看gdb官网的用户手册):
命令
缩写
描述
backtrace
bt
Prints a stack trace
display
Displays the value of an expression every time execution stops
finish
Runs to the end of the function and displays return values of that function
jump
Jumps to an address and continues the execution there
list
l
Lists the next 10 lines
next
n
Steps to the next machine language instruction
print
p
Prints the value of an expression
run
r
Runs the current program from the start
set
Changes the value of a variable

(1). 查看栈信息
    当程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。
    backtrace或bt <n>
        无n: 打印当前的函数调用栈的所有信息。
        n是一个正整数: 只打印栈顶上n层的栈信息。
        n是一个负整数: 只打印栈底下|n|层的栈信息。
    frame <n>或f <n> (n是一个从0开始的整数,是栈中的层编号)
        如果你要查看某一层的信息,你需要在切换当前的栈,一般来说,程序停止时,最顶层的栈就是当前栈。
    up <n>或down <n>
        向栈的上面/下面移动n层,可以不打n,表示向上/下移动一层。
    info frame或info f
        打印出更为详细的当前栈层的信息(目前的函数是由什么样的程序语言写成的、函数参数地址及值、局部变量的地址等等)。
    info args
        打印出当前函数的参数名及其值。
    info locals
        打印出当前函数中所有局部变量及其值。
(2). 查看源程序
    显示源代码list或l,list后面可以跟以下参数:
        <linenum> 行号。
        <+offset> 当前行号的正偏移量。
        <-offset> 当前行号的负偏移量。
        <filename:linenum> 哪个文件的哪一行。
        <function> 函数名。
        <filename:function> 哪个文件中的哪个函数。
        <*address> 程序运行时的语句在内存中的地址。
    指定源文件的路径:
        directory <dirname ... >或dir <dirname ... >
            加一个源文件路径到当前路径的前面,如有多个路径,UNIX下你可以使用":",Windows下你可以使用";"。
        directory
            清除所有的自定义的源文件搜索路径信息。
        show directories
            显示定义了的源文件搜索路径。
(3). 查看变量
    在你调试程序时,当程序被停住时,你可以使用print(p)命令查看变量
    print [/<f>] <expr>
        <expr>是表达式,是你所调试的程序的语言的表达式(GDB可以调试多种编程语言)。
            可以是当前程序运行中的const常量、变量、函数等(不能用宏)。
            有几种操作符,它们可以用在任何一种语言中。
                :: 指定一个在文件或是一个函数中的变量,比如'file'::variable,function::variable。
                {<type>} <addr> 表示一个指向内存地址<addr>的类型为type的一个对象。
            如果你的程序编译时开启了优化选项,那么在用GDB调试被优化过的程序时,可能会发生某些变量不能访问,或是取值错误码的情况。
                gcc可以加-gstabs解决此问题。
        <f>是输出的格式
            x 按十六进制格式显示变量。
            d 按十进制格式显示变量。
            u 按十六进制格式显示无符号整型。
            o 按八进制格式显示变量。
            t 按二进制格式显示变量。
            c 按字符格式显示变量。
            f 按浮点数格式显示变量。
(4). 查看内存
    examine(x)命令查看内存: x/<n/f/u> <addr>
        n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
        f 表示显示的格式。如果地址所指的是字符串,那么格式可以是s,如果指令地址,那么格式可以是I。
        u 表示从当前地址往后请求的字节数,如果不指定的话,默认是4个bytes。也可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。
(5). 查看寄存器和线程
    info registers [<regname ...>]或info reg [<regname …>]
        查看寄存器的情况(除了浮点寄存器)。
        <regname ...>查看所指定的寄存器的情况。
        同样可以使用print命令来访问寄存器的情况,只需要在寄存器名字前加一个$符号就可以:p $sp
    info all-registers
        查看所有寄存器的情况(包括浮点寄存器)。
    info thread
        查看所有thread。
    thread <threadnum>
        切换到某个thread。
4. 例子
    以某个app为例子,发生了NE,产生了db。先用GAT解开db,拿到PROCESS_COREDUMP,放到/home/db/
    假设:
        gdb路径:/home/alps/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-gdb。
        symbols路径:/home/alps/out/target/product/$proj/symbols。
    开始启动gdb,app对应的程序为system/bin/app_process:
        cd /home/db/
        /home/alps/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-gdb /home/alps/out/target/product/$proj/symbols/system/bin/app_process PROCESS_COREDUMP
    这样就进入gdb的命令行了,下面需要设置symbols搜索路径,设置后gdb会自动加载所需的lib库:
        set solib-absolute-prefix /home/alps/out/target/product/$proj/symbols
        set solib-search-path /home/alps/out/target/product/$proj/symbols/system/lib
    到这里就完成了gdb的启动和加载,之后就可以自由使用各种命令分析NE了,比如bt,info registers等。更多使用gdb的命令或技巧请多查看官方文档或网络上有关gdb的技术分享。
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 经常脱发严重不长头发怎么办 产后3年一直脱发怎么办 生完宝宝头发掉怎么办 生完小孩掉好多头发怎么办 脱发头发掉的厉害怎么办 宝宝四个月妈妈掉头发怎么办 产后四个月掉头发怎么办 洗头时严重掉发怎么办 头发老是掉得到处都是怎么办 短发洗完头头发向外外怎么办 20岁掉头发厉害怎么办 20岁老掉头发怎么办 20岁有点掉头发怎么办 20岁开始掉头发怎么办 20岁掉头发严重怎么办 20岁脱发很严重怎么办 手的纹路很深怎么办 20岁白头发很多怎么办 一天掉40根头发怎么办 烫完头发掉头皮怎么办 接发遗留的胶水怎么办 头发又干又卷怎么办 每天掉很多头发怎么办掉头发 植过发15天手抓植发区了怎么办 洗头梳头老掉头发怎么办 掉头发特别特别严重怎么办 哺乳期掉头发特别严重怎么办 最近掉头发特别严重怎么办 近掉头发特别严重怎么办 50多岁脱发严重怎么办 2岁宝宝掉发严重怎么办 生孩子后掉头发严重怎么办 有16岁孩孑教吾听怎么办 生完孩子后脱发怎么办 学生掉头发很厉害怎么办 35岁开始掉头发怎么办 高三学生玩手机怎么办 高三学生不学习怎么办 17岁经常掉头发怎么办 出汗后头皮很痒怎么办 头发老是掉怎么办会不会长出来