基本概念(4)——调试器

一个非常好的参考资料《100个gdb技巧》
https://wizardforcel.gitbooks.io/100-gdb-tips/content/

gdb与lldb不同点对比
https://lldb.llvm.org/use/map.html

运行lldb

lldb main.out
或者直接lldb,进入后 使用file main.out指定要调试的文件
注意:运行之前要clang++ -g,一定要有-g参数才能用lldb调试。
另一种执行:lldb main.out example1 假设可执行程序名为 main.out,参数为 example1
q\quit 离开lldb

tab键

支持tab键联想,输入br然后按下tab就会联想出breakpoint
然后再次按下tab会联想出子命令:

(lldb) breakpoint 
Available completions:
clear
command
delete
disable
enable
list
modify
name
read
set
write
(lldb) breakpoint 

help

查看帮助,支持help b查看b命令的帮助:

_regexp-break <filename>:<linenum>
              main.c:12             // Break at line 12 of main.c
_regexp-break <linenum>
              12                    // Break at line 12 of current file
_regexp-break 0x<address>
              0x1234000             // Break at address 0x1234000
_regexp-break <name>
              main                  // Break in 'main' after the prologue
_regexp-break &<name>
              &main                 // Break at first instruction in 'main'
_regexp-break <module>`<name>
              libc.so`malloc        // Break in 'malloc' from 'libc.so'
_regexp-break /<source-regex>/
              /break here/          // Break on source lines in current file
                                    // containing text 'break here'.
'b' is an abbreviation for '_regexp-break'
help breakpoint list //查看breakpoint list的帮助

执行程序

run/r

给定程序参数

run <args>的方式gdb或者lldb都支持,或者用简写:r <args>,但是这种方式每次run都需要给定被调试程序的参数

想要每次run的时候不用这么麻烦,可以在启动gdb/lldb的时候给定参数,种类gdb和lldb有些区别
gdb:
gdb --args ***.exe <args>
lldb:
lldb -- ***.exe <args>

也可以启动gdb/lldb之后给定参数:
gdb:
set args <args>
lldb:
settings set -- target.run-args "--framework" "100" "--comm" "tcp" "-p" "35900" "-t" "0" "--run"

breakporint 断点

help breakpoint 查看命令
_regexp-break <filename>:<linenum>
              main.c:12             // Break at line 12 of main.c main.c文件的12行

_regexp-break <linenum>
              12                    // Break at line 12 of current file当前文件12行

_regexp-break 0x<address>
              0x1234000             // Break at address 0x1234000  地址断点

_regexp-break <name>
              main                  // Break in 'main' after the prologue   

_regexp-break &<name>
              &main                 // Break at first instruction in 'main'

_regexp-break <module>`<name>
              libc.so`malloc        // Break in 'malloc' from 'libc.so'

_regexp-break /<source-regex>/
              /break here/          // Break on source lines in current file
                                    // containing text 'break here'.

'b' is an abbreviation for '_regexp-break'

删除断点

l/list

查看当前文件代码

看某个函数的代码:直接输入某个函数的名字即可

(lldb) help list
 List relevant source code using one of several shorthand formats.  Expects 'raw' input (see 'help raw-input'.)

Syntax: 
_regexp-list <file>:<line>   // List around specific file/line
_regexp-list <line>          // List current file around specified line
_regexp-list <function-name> // List specified function
_regexp-list 0x<address>     // List around specified address
_regexp-list -[<count>]      // List previous <count> lines
_regexp-list                 // List subsequent lines

如果程序编译的时候是由很多文件组成的,那么就可以使用list 文件名 看其他文件的代码, 以后再执行 list 3 的时候,看的就是你前面设置的文件名的第三行。

c 、n、 s、 finsh

c/continue,继续执行
n/next,单步调试
s/step,进入一个函数
finsh,执行完当前函数

查看变量、跳帧查看变量

使用po或p,po一般用来输出指针指向的那个对象,p一般用来输出基础变量。普通数组两者都可用

(lldb) po result_array

查看所有帧(bt)

(lldb) bt
函数调用栈由连续的栈帧组成。每个栈帧记录一个函数调用的信息,这些信息包括函数参数,函数变量,函数运行地址。
    当程序启动后,栈中只有一个帧,这个帧就是main函数的帧。我们把这个帧叫做初始化帧或者叫做最外层帧。每当一
个函数被调用,一个新帧将被建立,每当一个函数返回时,函数帧将被剔除。如果函数是个递归函数,栈中将有很多帧是
记录同一个函数的。但前执行的函数的帧被称作最深帧,这个帧是现存栈中最近被创建的帧。
    在程序内部,函数栈帧用函数的地址来标记。一个帧由一定字节的内存组成,每个字节都有自己的地址 。每种类型的计
算机有个约定,用一个特殊字节的地址存放函数帧的地址。通常函数帧的地址存放在一个称作帧指针的寄存器中--$fp.
    gdb 为所有存活的栈帧分配一个数字编号,最深帧的编号是0,被它调用的内个帧的编号就是1。这些编号子程序中是不
存在的,只不过时调试的时候被gdb用的。
    关于函数帧的两个指令:
    frame args
    移动到args指定的栈帧中去,并打印选中的栈的信息。args可以时帧编号或者时帧的地址。如果没有args,则打印当前帧的信息。
    select-frame args
    移动到指定的帧中去,不打印信息。

跳帧(frame select)

(lldb) frame select 1

查看当前帧中所有变量的值(frame variable)

(lldb) frame variable

查看内存

格式x /nfu
x 是检查的意思(examine)
n 表示要显示的内存单元的个数,比如:20
f 表示显示方式, 可取如下值:

x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。

u表示一个地址单元的长度:

b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节

gdb插件

https://github.com/cyrus-and/gdb-dashboard
只在linux下正常使用,mingw等都没过,下图是wsl2

posted @ 2021-01-22 16:15  feipeng8848  阅读(328)  评论(0编辑  收藏  举报