(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
(gdb) up 6 #6 0x0000000100000ed7 in main () at test.m:10 9 NSLog("Hello, world! x = %@", x);
这回不仅是函数名,连出错的那行代码也打印出来了。但是,我们还可以使用list(简写为l)命令,打印出更多信息:
ps: 如果需要回到栈列表。可以使用down命令。
(gdb) l 5 6 int main(int argc, char **argv) 7 { 8 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 9 int x = 42; 10 NSLog("Hello, world! x = %@", x); 11 [pool release]; 12 13 return 0; 14 }
(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 ?? ()
(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 8 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
debugger在在我们期望的地方停下了。现在我们使用next(简写n)命令单步调试程序,看看它到底是在哪一行崩溃的:
(gdb) n 9 int x = 42; (gdb) 10 NSLog(@"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。
(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'
(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
(gdb) b -[Class myMethod:] Breakpoint 5 at 0x7fff864f1404 (gdb) commands Type commands for when breakpoint 5 is hit, one per line. End with a line saying just "end". >bt >p parameter >continue >end
(gdb) run Starting program: /Users/mikeash/shell/a.out Reading symbols for shared libraries .+++........................ done ^C Program received signal SIGINT, Interrupt. 0x00007fff88c6ff8a in __semwait_signal () (gdb) bt #0 0x00007fff88c6ff8a in __semwait_signal () #1 0x00007fff88c6fe19 in nanosleep () #2 0x00007fff88cbcdf0 in sleep () #3 0x0000000100000ea7 in __main_block_invoke_1 (.block_descriptor=0x1000010a0, x=0) at test.m:12 #4 0x00007fff88cbbbc8 in _dispatch_apply2 () #5 0x00007fff88cb31e5 in dispatch_apply_f () #6 0x0000000100000e6a in main (argc=1, argv=0x7fff5fbff628) at test.m:11
(gdb) info threads 3 "com.apple.root.default-priorit" 0x00007fff88c6ff8a in __semwait_signal () 2 "com.apple.root.default-priorit" 0x00007fff88c6ff8a in __semwait_signal () * 1 "com.apple.root.default-priorit" 0x00007fff88c6ff8a in __semwait_signal ()
线程1前面有个星号,这表示它是现在活动中的线程。现在我们切换到线程2:
(gdb) thread 2 [Switching to thread 2 (process 4794), "com.apple.root.default-priority"] 0x00007fff88c6ff8a in __semwait_signal () (gdb) bt #0 0x00007fff88c6ff8a in __semwait_signal () #1 0x00007fff88c6fe19 in nanosleep () #2 0x00007fff88cbcdf0 in sleep () #3 0x0000000100000ea7 in __main_block_invoke_1 (.block_descriptor=0x1000010a0, x=1) at test.m:12 #4 0x00007fff88cbbbc8 in _dispatch_apply2 () #5 0x00007fff88c4f7f1 in _dispatch_worker_thread2 () #6 0x00007fff88c4f128 in _pthread_wqthread () #7 0x00007fff88c4efc5 in start_wqthread ()
现在我们输出了线程2的信息。然后时线程3……是不是觉得这种方法效率太低了?我们只有3个线程,但如果有300个呢?幸好,gdb提供了thread apply all backtrace命令(简写为t a a bt),用来列出所有线程的详细信息。
Thread 3 (process 4794):
#0 0x00007fff88c6ff8a in __semwait_signal ()
#1 0x00007fff88c6fe19 in nanosleep ()
#2 0x00007fff88cbcdf0 in sleep ()
#3 0x0000000100000ea7 in __main_block_invoke_1 (.block_descriptor=0x1000010a0, x=2) at test.m:12
#4 0x00007fff88cbbbc8 in _dispatch_apply2 ()
#5 0x00007fff88c4f7f1 in _dispatch_worker_thread2 ()
#6 0x00007fff88c4f128 in _pthread_wqthread ()
#7 0x00007fff88c4efc5 in start_wqthread ()
Thread 2 (process 4794):
#0 0x00007fff88c6ff8a in __semwait_signal ()
#1 0x00007fff88c6fe19 in nanosleep ()
#2 0x00007fff88cbcdf0 in sleep ()
#3 0x0000000100000ea7 in __main_block_invoke_1 (.block_descriptor=0x1000010a0, x=1) at test.m:12
#4 0x00007fff88cbbbc8 in _dispatch_apply2 ()
#5 0x00007fff88c4f7f1 in _dispatch_worker_thread2 ()
#6 0x00007fff88c4f128 in _pthread_wqthread ()
#7 0x00007fff88c4efc5 in start_wqthread ()
Thread 1 (process 4794):
#0 0x00007fff88c6ff8a in __semwait_signal ()
#1 0x00007fff88c6fe19 in nanosleep ()
#2 0x00007fff88cbcdf0 in sleep ()
#3 0x0000000100000ea7 in __main_block_invoke_1 (.block_descriptor=0x1000010a0, x=0) at test.m:12
#4 0x00007fff88cbbbc8 in _dispatch_apply2 ()
#5 0x00007fff88cb31e5 in dispatch_apply_f ()
#6 0x0000000100000e6a in main (argc=1, argv=0x7fff5fbff628) at test.m:11