Anda di halaman 1dari 4

1

Debugging with GDB - XCode iPhone Adventures Debugging with GDB - XCode iPhone Adventures Episode 1: The tale of the broken traffic light
This article assumes the reader already knows their way around the XCode development environment, and knows how to get to the GDB command window while debugging their iPhone app.

ISSUE:
A deadlock occurred in an iPhone app, causing its buttons to become unresponsive. One button was responsible for starting a routine, and the other was responsible for stopping the routine. The routine enters some critical sections of code, and is guarded using mutex and condition variables. One rare occasion, when the stars align just right, a deadlock would occur in the app when trying to stop the routine.

DEBUGGING:
Looking at XCode's UI Debugger, it only listed the main UI thread: Thread 1 (thread 10755): #0 0x31d47158 in mach_msg_trap () #1 0x31d49ee0 in mach_msg () #2 0x30254554 in CFRunLoopRunSpecific () #3 0x3025416a in CFRunLoopRunInMode () #4 0x320452a4 in GSEventRunModal () #5 0x308f037c in -[UIApplication _run] () #6 0x308eea94 in UIApplicationMain () #7 0x000023cc in main (argc=3, argv=0x2ffff4cc) main.m:14 I'm sure there's a way to list all threads easily using XCode's UI; however, being used to WinDBG, GDB's command line interface was more familiar - so I decided to navigate using the GDB command window. To list a stacktrace for a specific thread: thread apply <thread number> backtrace Example: (gdb) thread apply 1 backtrace Thread 1 (thread 10755): #0 0x31d47158 in mach_msg_trap () #1 0x31d49ee0 in mach_msg () #2 0x30254554 in CFRunLoopRunSpecific () #3 0x3025416a in CFRunLoopRunInMode () #4 0x320452a4 in GSEventRunModal () #5 0x308f037c in -[UIApplication _run] () #6 0x308eea94 in UIApplicationMain () #7 0x000023cc in main (argc=3, argv=0x2ffff4cc) main.m:14 To list all threads for an overview: (gdb) info threads

Debugging with GDB - XCode iPhone Adventures


8 thread 12803 (Thread 0x632b: user=0.000000 system=0.000000 cpu=0 sleep_time=0) 0x31dd6510 in __semwait_signal () 7 thread 12547 (Thread 0x5c23: user=0.000000 system=0.000000 cpu=0 sleep_time=0) 0x31d47158 in mach_msg_trap () 6 thread 12291 (Thread 0x6b1f: user=1.610000 system=1.610000 cpu=0 sleep_time=0) 0x31dd6510 in __semwait_signal () 5 thread 12035 (Thread 0x5e03: user=0.000000 system=0.000000 cpu=0 sleep_time=0) 0x31d47158 in mach_msg_trap () 4 thread 11779 (Thread 0x590b: user=0.050000 system=0.050000 cpu=0 sleep_time=0) 0x31d6b0e0 in select$DARWIN_EXTSN () 3 thread 11267 (Thread 0x1103: user=0.000000 system=0.000000 cpu=0 sleep_time=0) 0x31d47158 in mach_msg_trap () * 1 thread 10755 (Thread 0x0207: user=31.900000 system=31.900000 cpu=0 sleep_time=0) 0x31d47158 in mach_msg_trap () The * appears to identify the current thread context (need to verify) Another way to dump stack for current thread: (gdb) bt #0 0x31d47158 #1 0x31d49ee0 #2 0x30254554 #3 0x3025416a #4 0x320452a4 #5 0x308f037c #6 0x308eea94 #7 0x000023cc in in in in in in in in mach_msg_trap () mach_msg () CFRunLoopRunSpecific () CFRunLoopRunInMode () GSEventRunModal () -[UIApplication _run] () UIApplicationMain () main (argc=3, argv=0x2ffff4cc) main.m:14

To dump stack for all threads: (gdb) thread apply all backtrace Thread 8 (thread 12803): #0 0x31dd6510 in __semwait_signal () #1 0x31d49760 in nanosleep () #2 0x31d496e2 in usleep () #3 0x0000d706 in ButtonHandler (this=0x846c00, pThread=0x139800) at xxxxxxxx.h:xxx #4 0x0000a89a in -[DemoClassVIEW ButtonHandler] (self=0x11a330, _cmd=0x2935c) #5 0x30554068 in -[NSThread main] () #6 0x305023f8 in __NSThread__main__ () #7 0x31d705a8 in _pthread_body () #8 0x00000000 in ?? () Thread 7 (thread 12547): #0 0x31d47158 in mach_msg_trap () #1 0x31d49ee0 in mach_msg () ... #8 0x00000000 in ?? () Thread 6 (thread 12291): #0 0x31dd6510 in __semwait_signal () #1 0x31d782d0 in _pthread_cond_wait () #2 0x31d77a94 in pthread_cond_wait ()

Thread placed in wait state

Debugging with GDB - XCode iPhone Adventures


... #22 #23 #24 #25

0x30554068 0x305023f8 0x31d705a8 0x00000000

in in in in

-[NSThread main] () __NSThread__main__ () _pthread_body () ?? ()

Thread 5 (thread 12035): #0 0x31d47158 in mach_msg_trap () #1 0x31d49ee0 in mach_msg () #2 0x30254554 in CFRunLoopRunSpecific () #3 0x3020d25e in CFRunLoopRun () #4 0x334531ec in DecodeNotificationThread::ThreadMain () #5 0x3348d1b8 in CAPThread::Entry () #6 0x31d705a8 in _pthread_body () #7 0x00000000 in ?? () Thread 4 (thread 11779): #0 0x31d6b0e0 in select$DARWIN_EXTSN () #1 0x3021dd24 in __CFSocketManager () #2 0x31d705a8 in _pthread_body () #3 0x00000000 in ?? () Thread 3 (thread 11267): #0 0x31d47158 in mach_msg_trap () #1 0x31d49ee0 in mach_msg () #2 0x30254554 in CFRunLoopRunSpecific () #3 0x3025416a in CFRunLoopRunInMode () #4 0x3588dbd0 in RunWebThread () #5 0x31d705a8 in _pthread_body () #6 0x00000000 in ?? () Thread 1 (thread 10755): #0 0x31d47158 in mach_msg_trap () #1 0x31d49ee0 in mach_msg () #2 0x30254554 in CFRunLoopRunSpecific () #3 0x3025416a in CFRunLoopRunInMode () #4 0x320452a4 in GSEventRunModal () #5 0x308f037c in -[UIApplication _run] () #6 0x308eea94 in UIApplicationMain () #7 0x000023cc in main (argc=3, argv=0x2ffff4cc) main.m:14 To protect the innocent, I had to snip some of the frames off a few threads - but the point is still achieved. We see that thread # 6 os waiting on a condition variable, and we see that thread # 8 is waiting on a call to usleep(). It makes sense for the call to usleep() to wait... but the other thread (#6) seems to be waiting for a condition to be signaled. Looking at the code around the wait (pseudo code shown below): void SomeFunc() { pthread_mutex_lock(&mutex); printf("Waiting on some event to be signaled!\n"); pthread_cond_wait(&cond, &mutex); pthread_mutex_unlock(&mutex);

Debugging with GDB - XCode iPhone Adventures


} So what is happening to the thread which is supposed to set this event? void SomeOtherFunc() { pthread_mutex_lock(&mutex); pthread_cond_signal(&cond); Never gets called! pthread_mutex_unlock(&mutex); } Investigating the source code some more, found that this condition is signaled by a callback function. In this specific case, the mechanism responsible for the callback was already terminated - therefore the callback would never get fired. Hence why the thread is stuck in a wait state and the other thread is in a constant sleep, because it polls the thread in a wait state to ensure that it exited! Takeaways: To display a stacktrace of the current thread: backtrace OR bt To list all threads for an overview: info threads To display a stacktrace for all threads: thread apply all bt To display a stacktrace for a specific thread: Thread apply <thread number> bt Thank you GDB! ;) Until next time! KappA

Anda mungkin juga menyukai