为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

iOS Debugging Magic

2011-11-02 23页 pdf 387KB 22阅读

用户头像

is_698409

暂无简介

举报
iOS Debugging Magic 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 1 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Technical Note TN2239 iOS Debugging Magic iOS contains a number of 'secret' debugging facilities, including environment var...
iOS Debugging Magic
19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 1 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Technical Note TN2239 iOS Debugging Magic iOS contains a number of 'secret' debugging facilities, including environment variables, preferences, routines callable from GDB, and so on. This technote describes these facilities. If you're developing for iOS, you should look through this list to see if you're missing out on something that will make your life easier. Introduction Basics Enabling Debugging Facilities Seeing Debug Output Some Assembly Required ARM Intel 32-Bit Architecture Gotchas Controlled Crash Instruments CrashReporter BSD Memory Allocator Standard C++ Library Dynamic Linker (dyld) Core Services Core Foundation Application Services Core Animation Cocoa and Cocoa Touch Objective-C Foundation UIKit Networking Power Push Notifications iPhone Simulator Document Revision History Introduction All Apple systems include debugging facilities added by Apple engineering teams to help develop and debug specific subsystems. Many of these facilities remain in released system software and you can use them to debug your code. This technote describes some of the more broadly useful ones. In cases where a debugging facility is documented in another place, there's a short overview of the facility and a link to the existing documentation. Important: This is not an exhaustive list: not all debugging facilities are, or will be, documented. Many of the details covered in this technote vary from platform to platform and release to release. As such, you may encounter minor variations between platforms, and on older or newer systems. Known significant variations are called out in the text. This technote was written with reference to iOS 4.1. 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 2 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Warning: The debugging facilities described in this technote are unsupported. Apple reserves the right to change or eliminate each facility as dictated by the evolution of the OS; this has happened in the past, and is very likely to happen again in the future. These facilities are for debugging only: you must not ship a product that relies on the existence or functionality of the facilities described in this technote. In addition to this technical issue of binary compatibility, keep in mind that iOS applications must comply with various legal agreements and the App Store Review Guidelines. Note: If you also develop for Mac OS X, you may want to read Technical Note TN2124, 'Mac OS X Debugging Magic'. This technote covers advanced debugging techniques. If you're just getting started, you should consult the following material: GDB is the system's primary debugging tool. For a full description of GDB, see Debugging with GDB. Xcode is Apple's integrated development environment (IDE). It includes a sophisticated graphical debugger, implemented as a wrapper around GDB. For more information about Xcode, see the "Tools & Languages" section of the Apple developer Reference Library. This technote does not cover performance debugging. If you're trying to debug a performance problem, the best place to start is the Getting Started with Performance document. Back to Top Basics The later sections of this technote describe the debugging facilities in detail. Many of these facilities use similar techniques to enable and disable the facility, and to see its output. This section describes these common techniques. Enabling Debugging Facilities Some debugging facilities are enabled by default. However, most facilities must be enabled using one of the techniques described in the following sections. Environment Variables In many cases you can enable a debugging facility by setting a particular environment variable. You can do this using the executable inspector in Xcode. Figure 1 shows an example of this. Figure 1: Setting environment variables in Xcode 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 3 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Preferences Some debugging facilities are enabled by setting a special preference. You can set such a debugging preference by configuring a command line argument in Xcode. Figure 2 shows how this is done. Figure 2: Setting command line arguments in Xcode 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 4 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Callable Routines Many system frameworks include routines that print debugging information to stderr. These routines may be specifically designed to be callable from within GDB, or they may just be existing API routines that are useful while debugging. Listing 1 shows an example of how to call a debugging routine from GDB; specifically, it calls CFBundleGetAllBundles to get a list of all the bundles loaded in the application, and then prints that list by calling the CFShow routine. Listing 1: Calling a debugging routine from GDB (gdb) call (void)CFShow((void *)CFBundleGetAllBundles()) {type = mutable-small, count = 59, values = ( 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 5 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html 0 : CFBundle 0x100234d00 … […] 12 : CFBundle 0x100237790 … […] 23 : CFBundle 0x100194eb0 … […] )} Note: When calling a routine like this, GDB must know the routine's return type (because some return types can affect the way in which parameters are passed). If you're calling a routine without debug symbols, you have to tell GDB the return type by adding a cast. For example, Listing 1 casts the return type of CFBundleGetAllBundles to (void *) and the return type of CFShow to (void). Similarly, if you call a routine with non-standard parameters, you may need to cast your arguments to ensure that GDB passes them correctly. If you don't see the output from the routine, you may need to look at the console log, as described in the Seeing Debug Output section. Important: If you use this technique for your own code, be warned that it doesn't always work for routines that are declared static. The compiler's interprocedural optimizations may cause a static routine to deviate from the standard function call ABI. In that case, it can't be reliably called by GDB. In practice, this only affects Intel 32-bit code, as used by the iPhone Simulator. Configuration Profiles Some iOS subsystems have debugging facilities that can be enabled by installing a special configuration profile. For an example of this, see Push Notifications. You install such a configuration profile in the usual way: put it on a web server, and then download it using Safari on the device attach it to an email, mail it to an account accessible from the device, and then run Mail and open the configuration profile attachment You can learn more about configuration profiles by reading the various documents accessible from iPhone in Business site. Seeing Debug Output Programs that generate debug output generally do so using one of following mechanisms: NSLog printing to stderr system log NSLog is a high-level API for logging which is used extensively by Objective-C code. The exact behaviour of NSLog is surprisingly complex, and has changed significantly over time, making it beyond the scope of this document. However, it's sufficient to know that NSLog prints to stderr, or logs to the system log, or both. So, if you understand those two mechanisms, you can see anything logged via NSLog. Printing to stderr is one of the most commonly used output mechanisms. Given this topic's importance, it is covered in depth in the next section. The easiest way to view the system log is in the Console tab in Xcode's Organizer window. If you're working with users who don't want to install Xcode, they can view the system log using the iPhone Configuration Utility. 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 6 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Console Output Many programs, and indeed many system frameworks, print debugging messages to stderr. The destination for this output is ultimately controlled by the program: it can redirect stderr to whatever destination it chooses. However, in most cases a program does not redirect stderr, so the output goes to the default destination inherited by the program from its launch environment. This is typically one of the following: If you launch a GUI application as it would be launched by a normal user, the system redirects any messages printed on stderr to the system log. You can view these messages using the techniques described earlier. If you run a program from within Xcode, you can see its stderr output in Xcode's debugger Console window (choose the Console menu item from the Run menu to see this window). Attaching to a running program (using Xcode's Attach to Process menu, or the attach command in GDB) does not automatically connect the program's stderr to your GDB window. You can do this from within GDB using the trick described in the "Seeing stdout and stderr After Attaching" section of Technical Note TN2030, 'GDB for MacsBug Veterans'. Back to Top Some Assembly Required While it's very unusual to write a significant amount of code in assembly language these days, it's still useful to have a basic understanding of that dark art. This is particularly true when you're debugging, especially when you're debugging crashes that occur in libraries or frameworks for which you don't have the source code. This section covers some of the most basic techniques necessary to debug programs at the assembly level. Specifically, it describes how to set breakpoints, access parameters, and access the return address on all supported architectures. Where the difference is significant the assembly-level examples in this technote are from an armv7 binary running on an iPhone 3GS. However, in most cases the difference is not significant and the example might be from a variety of different architectures, perhaps even from the Mac. It's very easy to adapt such examples to other architectures. The most significant differences are: accessing parameters getting the return address And these are exactly the items covered by the following architecture-specific sections. Important: The following architecture-specific sections contain rules of thumb. If the routine has any non- standard parameters, or a non-standard function result, these rules of thumb do not apply, and you should consult the documentation for the details. In this context, standard parameters are integers (that fit in a single register), enumerations, and pointers (including pointers to arrays and pointers to functions). Non-standard parameters are floating point numbers, vectors, structures, integers bigger than a register, and any parameter after the last fixed parameter of a routine that takes a variable number of arguments. For a detailed description of the calling conventions for all iOS devices, see iOS ABI Function Call Guide. The Intel 32-bit architecture used by the iPhone Simulator is described in the Mac OS X ABI Function Call Guide. Before you read the following sections, it's critical that you understand one GDB subtlety. Because GDB is, at heart, a source-level debugger, when you set a breakpoint on a routine, GDB does not set the breakpoint on the first instruction of the routine; rather, it sets the breakpoint at the first instruction after the routine's prologue. From a source-level debugging point of view this make perfect sense. In a source-level debugger you never want to step through the routine's prologue. However, when doing assembly-level debugging, it's easier to access parameters before the prologue runs. That's because the location of the parameters at the first instruction of a routine is determined by the function call ABI, but the prologue is allowed to shuffle things around at its discretion. Moreover, each prologue can do this in a slightly different way. So the only way 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 7 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html to access parameters after the prologue has executed is to disassemble the prologue and work out where everything went. This is typically, but not always, quite easy, but it's still extra work. The best way to tell GDB to set a breakpoint at the first instruction of a routine is to prefix the routine name with a "*". Listing 2 shows an example of this. Listing 2: Before and after the prologue (gdb) b CFStringCreateWithFormat Breakpoint 1 at 0x34427ff8 (gdb) info break Num Type Disp Enb Address What 1 breakpoint keep n 0x34427ff8 -- The breakpoint is not at the first instruction. -- Disassembling the routine shows that GDB has skipped the prologue. (gdb) x/5i CFStringCreateWithFormat 0x34427ff0 : push {r2, r3} 0x34427ff2 : push {r7, lr} 0x34427ff4 : add r7, sp, #0 0x34427ff6 : sub sp, #4 0x34427ff8 : add r3, sp, #12 -- So we use a "*" prefix to disable GDB's 'smarts'. (gdb) b *CFStringCreateWithFormat Breakpoint 2 at 0x34427ff0 (gdb) info break Num Type Disp Enb Address What 1 breakpoint keep n 0x34427ff8 2 breakpoint keep n 0x34427ff0 Important: Because iOS has no way to run programs from the command line, iOS-specific listings, like Listing 2, are taken from Xcode's Console window. And because the Console window does not support the '#' character for comments, comments are denoted by a leading '--'. If you try to replicate these examples yourself, you must not enter these lines into the Console window. In contrast, some other listings in this document were created on Mac OS X, and thus use traditional GDB comments. Finally, if you're looking for information about specific instructions, be aware that the Help menu in Shark (included in the Xcode developer tools) has an instruction set reference for ARM, Intel and PowerPC architectures. ARM In ARM programs the first four parameters are passed in registers. The return address is in register LR. Table 1 shows how to access these values from GDB when you've stopped at the first instruction of the function. Table 1: Accessing parameters on ARM What GDB Syntax return address $lr first parameter $r0 second parameter $r1 third parameter $r2 fourth parameter $r3 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 8 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html On return from a function the result is in register R0 ($r0). Because parameters are passed in registers, there's no straightforward way to access parameters after the prologue. Listing 3 shows an example of how to use this information to access parameters in GDB. Listing 3: Parameters on ARM -- We have to start the program from Xcode. Before we do that, we go to -- Xcode's Breakpoints window and set a symbolic breakpoint on -- CFStringCreateWithFormat. GNU gdb 6.3.50-20050815 […] -- We've stopped after the prologue. (gdb) p/a $pc $1 = 0x34427ff8 -- Let's see what the prologue has done to the registers -- holding our parameters. (gdb) x/5i $pc-8 0x34427ff0 : push {r2, r3} 0x34427ff2 : push {r7, lr} 0x34427ff4 : add r7, sp, #0 0x34427ff6 : sub sp, #4 0x34427ff8 : add r3, sp, #12 -- Hey, the prologue hasn't modified R0..R3, so we're OK. -- -- first parameter is "alloc" (gdb) p/a $r0 $2 = 0x3e801d60 <__kCFAllocatorSystemDefault> -- second parameter is "formatOptions" (gdb) p/a $r1 $3 = 0x0 -- third parameter is "format" (gdb) call (void)CFShow($r2) managed/%@/%@ -- It turns out the prologue has left LR intact as well. -- So we can get our return address. -- -- IMPORTANT: Bit zero of the return address indicates that it lies -- in a Thumb routine. So when using a return address in LR or on -- the stack, always mask off bit zero. (gdb) p/a $lr & 0xfffffffe $4 = 0x34427e18 <__CFXPreferencesGetManagedSourceForBundleIDAndUser+48> -- Now clear the breakpoint and set a new one before the prologue. (gdb) del 1 (gdb) b *CFStringCreateWithFormat Breakpoint 2 at 0x34427ff0 (gdb) c Continuing. Breakpoint 2, 0x34427ff0 in CFStringCreateWithFormat () -- We're at the first instruction. The parameters are guaranteed -- to be in the right registers. (gdb) p/a $pc $5 = 0x34427ff0 -- first parameter is "alloc" (gdb) p/a $r0 $6 = 0x3e801d60 <__kCFAllocatorSystemDefault> -- second parameter is "formatOptions" (gdb) p/a $r1 $7 = 0x0 -- third parameter is "format" (gdb) call (void)CFShow($r2) %@/%@.plist -- return address is in LR; again, we mask off bit zero (gdb) p/a $lr & 0xfffffffe $8 = 0x34427e7c <__CFXPreferencesGetManagedSourceForBundleIDAndUser+148> (gdb) b *0x34427e7c Breakpoint 3 at 0x34427e7c -- Delete the other breakpoint to avoid thread-based confusion. (gdb) del 2 -- Continue to the return address. (gdb) c Continuing. 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 9 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Breakpoint 3, 0x34427e7c in __CFXPreferencesGetManagedSourceForBundleIDAndUser () -- function result (gdb) p/a $r0 $9 = 0x1062d0 (gdb) call (void)CFShow($r0) mobile/.GlobalPreferences.plist Intel 32-Bit The Intel 32-bit architecture is used in the iPhone Simulator. In 32-bit Intel programs, parameters are passed on the stack. At the first instruction of a routine the top word of the stack contains the return address, the next word contains the first (leftmost) parameter, the next word contains the second parameter, and so on. Table 2 shows how to access these values from GDB. Table 2: Accessing parameters on Intel 32-bit What GDB Syntax return address *(int*)$esp first parameter *(int*)($esp+4) second parameter *(int*)($esp+8) ... and so on After the routine's prologue you can access parameters relative to the frame pointer (register EBP). Table 3 shows the syntax. Table 3: Accessing parameters after the prologue What GDB Syntax previous frame *(int*)$ebp return address *(int*)($ebp+4) first parameter *(int*)($ebp+8) second parameter *(int*)($ebp+12) ... and so on On return from a function the result is in register EAX ($eax). Listing 4 shows an example of how to use this information to access parameters in GDB. Listing 4: Parameters on Intel 32-Bit $ # Use the -arch i386 argument to GDB to get it to run the $ # 32-bit Intel binary. $ gdb -arch i386 /Applications/TextEdit.app GNU gdb 6.3.50-20050815 (Apple version gdb-1346) […] (gdb) fb CFStringCreateWithFormat 19/6/11 5:00 PMTechnical Note TN2239: Technical Note TN2239 Page 10 of 23http://developer.apple.com/library/ios/technotes/tn2239/_index.html Breakpoint 1 at 0x31ec6d6 (gdb) r Starting program: /Applications/TextEdit.app/Contents/MacOS/TextEdit Reading symbols for shared libraries […] Breakpoint 1, 0x940e36d6 in CFStringCreateWithFormat () (gdb) # We've stopped after the prologue. (gdb) p/a $pc $1 = 0x940e36d6 (gdb) # However, for 32-bit Intel we don't need to inspect (gdb) # the prologue because the parameters are on the stack. (gdb) # We can access them relative to EBP. (gdb) # (gdb) # first parameter is "alloc" (gdb) p/a *(int*
/
本文档为【iOS Debugging Magic】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索