Xcode GDB 命令list

此文下半部分为转载:但是这里有一些我自己使用技巧,结合下面的文章,我们会有更多的收获,在此感谢原创者。

   

---------------------

关于调试异常崩溃:

一般崩溃是由内存使用错误导致的,要么多了,要么少了。

用xcode的调试提示可以知道是什么原因导致的崩溃。

在xcode中product àedit scheme à diagnostics 将enable Zombie objects 和 Malloc Stack 选中, 如果是内存释放错误,则gdb会提示release dealloc object。

然后可以用断点缩小错误范围, 在可能出现错误的地方用单步调试, 当执行到有错误代码时, gdb会再次提示release dealloc object。

其实XCODE内嵌GDB,那个 lldb就是gdb!

-----------------------

http://blog.csdn.net/ch_soft/article/details/7005998

关于GDB

对于大多数Cocoa程序员来说,最常用的debugger莫过于Xcode自带的调试工具了。而实际上,它正是gdb的一个图形化包装。相对于gdb,图形化带来了很多便利,但同时也缺少了一些重要功能。而且在某些情况下,gdb反而更加方便。因此,学习gdb,了解一下幕后的实质,也是有必要的。

gdb可以通过终端运行,也可以在Xcode的控制台调用命令。本文将通过终端讲述一些gdb的基本命令和技巧。

首先,我们来看一个例子:

#import

int main(int argc, char **argv)
 {
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 NSLog(@"Hello, world!");
 [pool release];

return 0;
 }

糟糕,程序竟然exited normally了(==|||)。这可不行,我们得让他崩溃才行。所以我们给这个小程序添加一个bug:

int x = 42;
 NSLog("Hello, world! x = %@", x);
nice。这样一来程序就会漂亮地崩溃了:

(gdb) run

Starting program: /Users/mikeash/shell/a.out
 Reading symbols for shared libraries .++++....................... done

Program received signal EXC_BAD_ACCESS, Could not access memory.
 Reason: 13 at address: 0x0000000000000000
 0x00007fff84f1011c in objc_msgSend ()
 (gdb)

如果我们是在shell中直接运行的程序,在崩溃后就会回到shell。不过现在我们是通过gdb运行的,所以现在并没有跳出。gdb暂停了我们的程序,但依然使之驻留在内存中,让我们有机会做调试。

首先,我们想知道具体是哪里导致了程序崩溃。gdb已经通过刚才的输出告知了我们: 函数objc_msgSend就是祸之根源。但是这个信息并不足够,因为这个objc_msgSend是objc运行时库中的函数。我们并不知道它是怎么调用的。我们关注的是我们自己的代码。
要知道这一点,我们需要得到当前进程的函数调用栈的情况,以此回溯找到我们自己的方法。这时我们需要用到backtrace命令,一般简写为bt:

(gdb) bt
 #0 0x00007fff84f1011c in objc_msgSend ()
 #1 0x00007fff864ff30b in _CFStringAppendFormatAndArgumentsAux ()
 #2 0x00007fff864ff27d in _CFStringCreateWithFormatAndArgumentsAux ()
 #3 0x00007fff8657e9ef in _CFLogvEx ()
 #4 0x00007fff87beab3e in NSLogv ()
 #5 0x00007fff87beaad6 in NSLog ()
 #6 0x0000000100000ed7 in main () at test.m:10

现在我们可以看到,程序在test.m的第10行,调用NSLog方法时崩溃了。接下来我们想看一下这次调用的详细信息。这时我们要用到up命令。up命令可以在栈的各层之间跳转。本例中,我们的代码main是#6:

(gdb) up 6
 #6 0x0000000100000ed7 in main () at test.m:10
 9NSLog("Hello, world! x = %@", x);
这回不仅是函数名,连出错的那行代码也打印出来了。但是,我们还可以使用list(简写为l)命令,打印出更多信息:
ps: 如果需要回到栈列表。可以使用down命令。

(gdb) l
 5
 6int main(int argc, char **argv)
 7{
 8NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 9int x = 42;
 10NSLog("Hello, world! x = %@", x);
 11[pool release];
 12
 13return 0;
 14}

啊,整个代码都被列出来了。虽然我们用编辑器打开test.m文件然后找到第10行也可以打到同样效果,但显然没有上面的方法更有效率。(当然没有Xcode自带的那个快就是了)

好了,现在我们再来看看这个bug(虽然是我们自己弄出来的)。很明显,在格式化字符串前少加了一个@。我们改正它,并重新运行一遍程序:

(gdb) run
 Starting program: /Users/mikeash/shell/a.out
 Reading symbols for shared libraries .++++....................... done

Program received signal EXC_BAD_ACCESS, Could not access memory.
 Reason: KERN_INVALID_ADDRESS at address: 0x000000000000002a
 0x00007fff84f102b3 in objc_msgSend_fixup ()
 (gdb) bt
 #0 0x00007fff84f102b3 in objc_msgSend_fixup ()
 #1 0x0000000000000000 in ?? ()

啊咧,程序还是崩溃了。更杯具的是,栈信息没有显示出这个objc_msgSend_fixup方法是从哪里调用的。这样我们就没法用上面的方法找到目标代码了。这时,我们只好请出一个debugger最常用的功能:断点。

在gdb中,设置断点通过break命令实现。它可以简写为b。有两种方法可以确定断点的位置:传入一个已定义的符号,或是直接地通过一个file:line对设置位置。
现在让我们在main函数的开始处设置一个断点:

(gdb) b test.m:8
 Breakpoint 1 at 0x100000e8f: file test.m, line 8.

debugger给了我们一个回应,告诉我们断点设置成功了,而且这个断点的标号是1。断点的标号很有用,可以用来给断点排序&停用&启用&删除等。不过我们现在不需要理会,我们只是接着运行程序:

(gdb) run
 The program being debugged has been started already.
 Start it from the beginning? (y or n) y
 Starting program: /Users/mikeash/shell/a.out

Breakpoint 1, main (argc=1, argv=0x7fff5fbff628) at test.m:8
 8NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
debugger在在我们期望的地方停下了。现在我们使用next(简写n)命令单步调试程序,看看它到底是在哪一行崩溃的:

(gdb) n
 9int x = 42;
 (gdb)
 10NSLog(@"Hello, world! x = %@", x);
 (gdb)

Program received signal EXC_BAD_ACCESS, Could not access memory.
 Reason: KERN_INVALID_ADDRESS at address: 0x000000000000002a
 0x00007fff84f102b3 in objc_msgSend_fixup ()
值得注意的是,我只键入了一次n命令,随后直接敲了2次回车。这样做的原因是gdb把任何空输入当作最近一次输入命令的重复。所以这里相当于输入了3次n。

现在我们可以看到,崩溃之处依然是NSLog。原因嘛,当然是在格式化输出的地方用%@表示int型变量x了。我们仔细看一下输出信息:崩溃原因是错误地访问了0x000000000000002a这个地址。而2a的十进制表示正是42--我们为x赋的值。编译器把它当作地址了。

输出数值

一个很重要的调试方法是输出表达式和变量的值。在gdb中,这是通过print命令完成的。

(gdb) p x
 $1 = 42

在print命令后追加/format可以格式化输出。/format是一个gdb的格式化字符串,比较有用的格式化字符有 x:十进制数; c:字符; a:地址等。

(gdb) p/x x
 $2 = 0x2a

print-object方法(简写为po)用来输出obj-c中的对象。它的工作原理是,向被调用的对象发送名为debugDescription的消息。它和常见的description消息很像。

举例来说,让我们输出一下autorelease pool:

(gdb) po pool

这个命令不仅仅可以输出显式定义的对象,也可以输出表达式的结果。这次我们测试一下nsobject中debugDescription的方法签名:

返回值是对象的表达式可以用po命令输出结果,那么返回值是基本类型的方法又怎样呢?显然,它们是可以用p命令输出的。但是要小心,因为gdb并不能自动识别出返回值的类型。所以我们在输出前要显式地转换一下:

(gdb) p [NSObject instancesRespondToSelector: @selector(doesNotExist)]
 Unable to call function "objc_msgSend" at 0x7fff84f100f4: no return type information available.
 To call this function anyway, you can cast the return type explicitly (e.g. ‘print (float) fabs (3.0)‘)
 (gdb) p (char)[NSObject instancesRespondToSelector: @selector(doesNotExist)]
 $5 = 0 ‘00‘

你也许发现了,doesNotExist方法的返回值是BOOL,而我们做的转换却是char。这是因为gdb也不能识别那些用typedef定义的类型。不仅仅是你定义的,即使是Cocoa框架里定义的也不行。

你也许已经注意到,在用p进行输出的时侯,输出值前面会有一个类似"$1="的前缀。它们是gdb变量。它们可以在后面的表达式中使用,来指代它后面的值。在下面的例子里,我们开辟了一块内存,将其置零,然后释放。在这个过程中,我们使用了gdb变量,这样就不用一遍遍地复制粘贴地址了。

(gdb) p (int *)malloc(4)
 $6 = (int *) 0x100105ab0
 (gdb) p (void)bzero($6, 4)
 $7 = void
 (gdb) p *$6
 $8 = 0
 (gdb) p (void)free($6)
 $9 = void

我们也想把这个技巧用到对象上,但不幸的是po命令并不会把它的返回值存储到变量里。所以我们在得到一个新的对象时必须先使用p命令:

(gdb) p (void *)[[NSObject alloc] init]
 $10 = (void *) 0x100105950
 (gdb) po $10
 
 (gdb) p (long)[$10 retainCount]
 $11 = 1
 (gdb) p (void)[$10 release]
 $12 = void

检查内存

有些时候,仅仅输出一个数值还不能帮助我们查找出错误。我们需要一次性地打印出一整块内存来窥视全局。这时候我们就需要使用x命令。

x命令的格式是x/format address。其中address很简单,它通常是指向一块内存的表达式。但是format的语法就有点复杂了。它由三个部分组成:

第一个是要显示的块的数量;第二个是显示格式(如x代表16进制,d代表十进制,c代表字符);第三个是每个块的大小。值得注意的是第三部分,即块大小是用字符对应的。用b, h, w,g 分别表示1, 2, 4, 8 bytes。举例来说,用十六进制方式,打印从ptr开始的4个4-byte块应该这样写:

(gdb) x/4xw ptr

接下来举一个比较实际的例子。我们看一下NSObject类的内容:

(gdb) x/4xg (void *)[NSObject class]
 0x7fff70adb468 : 0x00007fff70adb4400x0000000000000000
 0x7fff70adb478 :0x0000000100105ac00x0000000100104ac0

接下来再看看一个NSObject实例的内容:

(gdb) x/1xg (void *)[NSObject new]
 0x100105ba0:0x00007fff70adb468

现在我们看到,在实例开头引用了类的地址。

设置变量

有时,查看数值程度的能力还是稍弱了一点,我们还想能够修改变量。这也很简单,只需要使用set命令:

(gdb) set x = 43

我们可以用任意表达式给一个变量赋值。比如说新创建一个对象然后赋值:

(gdb) set obj = (void *)[[NSObject alloc] init]

断点

我们可以在程序的某个位置设置断点,这样当程序运行到那里的时候就会暂停,而把控制权转移给调试器。就像之前提到的,我们用break命令来设置断点。下面详细地列出了如何设置断点的目标:

SymbolName: 为断点指定一个函数名。这样断点就会设置在该函数上。
file.c:1234: 把断点设置在指定文件的一行。
-[ClassName method:name:]: 把断点设置在objc的方法上。用+代表类方法。
*0xdeadbeef: 在内存的指定位置设置断点。这不是很常用,一般在没有源码的调试时使用。

断点可以用enable命令和disable命令来切换到使用和停用状态,也可以通过delete命令彻底删除。想要查看现有断点的话,使用info breakpoints命令(可以简写成info b,或是i b)。

另外,我们也可以用if命令,把断点升级成条件断点。顾名思义,条件断点只会在设定的条件成真时起作用。举例来说,下面的语句为MyMethod添加了一个条件断点,它只在参数等于5的时候有效:

(gdb) b -[Class myMethod:] if parameter == 5

最后,在断点上可以附加gdb命令。这样,当断点中断时,附带的命令会自动执行。附加命令使用commands breakpointnumber。这时gdb就会进入断点指令输入状态。

断点指令就是一个以end结尾的标准gdb指令序列。举个例子,我们想在每次NSLog被调用时输出栈信息:

(gdb) b NSLog
 Breakpoint 4 at 0x7fff87beaa62
 (gdb) commands
 Type commands for when breakpoint 4 is hit, one per line.
 End with a line saying just "end".
 >bt
 >end

  1. 命 令                        解释
  2. break NUM               在指定的行上设置断点。
  3. bt                      显 示所有的调用栈帧。该命令可用来显示函数的调用顺序。
  4. clear                   删 除设置在特定源文件、特定行上的断点。其用法为:clear FILENAME:NUM。
  5. continue                继续执行正在调试的程序。该命令用在程序 由于处理信号或断点而
  6. 导致停止运行 时。
  7. display EXPR            每次程序停止后显示表达式的值。表达式由程序定 义的变量组成。
  8. file FILE               装载指定的可执行文件进行调试。
  9. help NAME               显 示指定命令的帮助信息。
  10. info break              显 示当前断点清单,包括到达断点处的次数等。
  11. info files              显 示被调试文件的详细信息。
  12. info func               显示所有的函数名称。
  13. info local              显 示当函数中的局部变量信息。
  14. info prog               显示被调试程序的执行状 态。
  15. info var                显示所有的全局和静态变量名称。
  16. kill                    终 止正被调试的程序。
  17. list                    显示源代码段。
  18. make                    在 不退出 gdb 的情况下运行 make 工具。
  19. next                    在 不单步执行进入其他函数的情况下,向前执行一行源代码。
  20. print EXPR              显 示表达式 EXPR 的值。
  21. print- object            打印一个对象
  22. print (int) name      打印一个类型
  23. print- object [artist description]   调用一个函数
  24. set artist = @"test"    设置变量值
  25. whatis                      查 看变理的数据类型
时间: 2024-08-13 15:54:58

Xcode GDB 命令list的相关文章

Xcode 调试命令

XCode4.0以后,编译器换成了LLVM 编译器 2.0 与以前相比,更加强大:1.LLVM 编译器是下一带开源的编译技术.完全支持C, Objective-C, 和 C++.2.LLVM 速度比 GCC快两倍,建立的程序也会运行的更快. 因为它更好的利用现代的芯片的结构.3.LLVM和Xcode 4完全的整合在一起.包括关键字高亮,代码完整性等全都是由LLVM语法分析器来分析的. 这样可以在编辑的时候就可以很好的了解你的代码. 编译器进化之后,控制台调试命令前缀,也由原来的gdb更改成了ll

gdb命令1

今天学习的命令: 下断: b 函数名 b 文件名:函数名 b 文件名:行号 b +/-偏移                       //在当前行号前面或者后面的行号处下断 删除断点: delete breakpoint 断点号  //删除指定断点 delete breakpoint           //删除所有断点 显示所有断点: info b 运行: c C语言源码单步: n s 汇编语言单步: ni si 查看寄存器值: info r 查看变量值: p 变量名称 查看栈: (gdb)

C++常用GDB命令

目前项目使用的: find ./ -name "InfoCheckStat"   ps -ef|grep  workordercon   ps -ef|grep ctpclient export PROCESS_ID=1003 gdb   format workordergen  set args -y -t 3 -n 100000 -i F82 -s ext     export PROCESS_ID=1201 gdb   bussevent  set args  -a   (gdb

用gdb分析core文件及常见gdb命令操作示例

1.概述 在实际的软件开发项目中,程序出现问题是在所难免的.遥想本人参加工作之后首次遇到程序的情景,至今还历历在目.之前的经验告诉我,我们越是惊慌失措,问题就越是解决不了.我们要先让自己平静下来,然后再寻找解决程序问题的办法. 在Linux下做开发的朋友,想必都与core文件打过交道.当看到自己的程序运行之后出现core时,很多人都慌乱了,仿佛天快要塌下来一样.其实,我们大可不必如此,只要我们掌握了用gdb调试core文件的办法,依然可以很快定位程序问题,一举将bug消灭掉.有关Linux co

GDB命令行最基本操作

程序启动: A.冷启动 gdb program              e.g., gdb ./cs gdb –p pid                 e.g., gdb –p `pidof cs` gdb program core      e.g., gdb ./cs core.xxx B.热启动 (gdb) attach pid        e.g., (gdb) attach 2313 C.传入命令行参数 gdb program --args arglist (gdb) set

gdb系列之三 GDB命令

 假如缩写是无歧义的话,你可以将一个GDB命令缩写为开头的几个字母:你也可以用回车键来重复一些GDB命令.你也可以 用TAP键来让GDB补全一个命令的剩余部分(或者告诉你可供选择的命令,假如不止一个命令可选的话). 3.1 命令语法 一个GDB命令是单独的输入行.没有长度限制.命令由一个命令名开始,接着是提供给命令的参数.例如,命令step接收 一个代表步长的参数,就像"step 5″.你也可以用不带参数的step命令.某些命令不允许参数. GDB命令名总是在没有歧义的情况下允许截短.在某些

jLink(v8)GDB 命令总结

/** ****************************************************************************** * @author    Maoxiao Hu * @version   V1.0.0 * @date       Dec-2014 ****************************************************************************** * < COPYRIGHT 2014 IS

用GDB命令PO(print-object)打印UIView的视图层级

UIView有一个私有方法: recursiveDescription 这个方法可以显示出当前视图的详细层级,可以在代码中直接调用,也可以在GDB中调用,在GDB中调用时需要借助另一个GDB命令:print-object: recursiveDescription: 由于是私有方法,键入时不会有任何提示,注意不要输错. tips: 如果想知道print和print-object的区别,请使用help命令: 我们关心的是data的显示,所以: 这样一来,你就应该有了一些线索,如果想知道更详细的说明

常用 GDB 命令中文速览

转自:https://linux.cn/article-8900-1.html?utm_source=index&utm_medium=moremore 目录 break -- 在指定的行或函数处设置断点,缩写为 b info breakpoints -- 打印未删除的所有断点,观察点和捕获点的列表,缩写为 i b disable -- 禁用断点,缩写为 dis enable -- 启用断点 clear -- 清除指定行或函数处的断点 delete -- 删除断点,缩写为 d tbreak --