In the process of iOS project development, static analysis (Analyze), breakpoints (BreakPoint) and console (Console) are often used for code debugging. This article introduces the "LLDB command" of Xcode's common debugging method. This article is contributed by the QiShare team of 360 Qiwutuan. [[263601]] Related reading: - 《Common iOS debugging methods: static analysis》
- 《Common iOS debugging methods: breakpoint debugging》
1. Introduction LLDB is a new generation of high-performance debugger. It is built as a set of reusable components that make heavy use of existing libraries in the larger LLVM project, such as the Clang expression parser and the LLVM disassembler. LLDB is the default debugger for Xcode on Mac OS X and supports debugging C, Objective-C, and C++ on the desktop and on iOS devices and simulators. All code in the LLDB project is provided under the standard LLVM License, an open source "BSD-style" license. 2. Help The LLDB command format is as follows: - < command name > < command action > [-option [option value]] [parameter 1 [parameter 2...]]
The parts of the LLDB command are separated by spaces. If the parameters contain spaces, they need to be enclosed in double quotes. If the parameters contain double quotes or backslashes, they need to be escaped with backslashes. LLDB commands have many functions, and it is not easy to memorize them all, nor is it necessary. Developers can use the help command to view the usage of related commands, and even view the usage of the help command. - (lldb) help help
- Show a list of all debugger commands, or give details about a specific
- command.
-
- Syntax: help [ < cmd-name > ]
-
- Command Options Usage:
- help [-ahu] [ < cmd-name > [ < cmd-name > [...]]]
-
- -a ( --hide-aliases )
- Hide aliases in the command list.
-
- -h ( --show-hidden-commands )
- Include commands prefixed with an underscore.
-
- -u ( --hide-user-commands )
- Hide user-defined commands from the list.
-
- This command takes options and free-form arguments. If your arguments
- resemble option specifiers (ie, they start with a - or --), you must use
- ' -- ' between the end of the command options and the beginning of the
- arguments.
3. Execution In LLDB, the execution command expression is the most basic command, abbreviated as expr or e, and the syntax is: expression -- , which is used to execute an expression and output the result returned by the expression. The following is an example: - //! Output the value of count
- (lldb) expression count
- (NSUInteger) $ 0 = 10
-
- //! Execute the string concatenation method
- (lldb) expression [string stringByAppendingString:@"732"]
- (__NSCFString *) $ 1 = 0x00006000006ac870 @"QiShare732"
-
- //! Change the color of the view
- (lldb) expression self.view.backgroundColor = [UIColor redColor]
- (UICachedDeviceRGBColor *) $ 2 = 0x0000600001d74780
- (lldb) expression [CATransaction flush]
- //! < Because the breakpoint will terminate the UI thread, executing the [CATransaction flush] command can render the modified interface
4. Print The print command is the most commonly used command, abbreviated as pri or p, and the syntax is: print , which is used to print variables or expressions. From help print, you will find that print is actually an abbreviation for the expression -- command: 'print' is an abbreviation for 'expression --', where -- marks the end of options and the beginning of parameters. The commonly used expression abbreviation commands include po and call. Po stands for print object, which is used to print an object, and call is used to call a method. The following are examples: - (lldb) expression -- self.view
- (UIView *) $ 4 = 0x00007f8ca8401690
-
- (lldb) e self.view
- (UIView *) $ 5 = 0x00007f8ca8401690
-
- (lldb) p self.view
- (UIView *) $ 6 = 0x00007f8ca8401690
-
- (lldb) po self.view
- < UIView: 0x7f8ca8401690; frame = ( 0 0; 375 812); autoresize = W +H; layer = < CALayer: 0x6000008a1dc0 >>
-
- (lldb) call self.view
- (UIView *) $ 8 = 0x00007f8ca8401690
In addition, developers can follow the print/ The syntax for the print command specifies the print format: - p/x //! < Print integer in hexadecimal
- p/d //! < Print an integer in signed decimal
- p/u //! < Print integer in unsigned decimal
- p/o //! < Print integer in octal
- p/t //! < Print integer in binary
- p/a //! < Print address in hexadecimal
- p/c //! < Print character constant
- p/f //! < Print floating point number
- p/s //! < print string
- p/r //! < Formatted printing
p/x //!< Print integer in hexadecimal p/d //!< Print integer in signed decimal p/u //!< Print integer in unsigned decimal p/o //!< Print integer in octal p/t //!< Print integer in binary p/a //!< Print address in hexadecimal p/c //!< Print character constant p/f //!< Print floating point number p/s //!< Print string p/r //!< Formatted printing Here is an example: - (lldb) p count
- (NSUInteger) $ 0 = 10
-
- (lldb) p/t count
- (NSUInteger) $ 1 = 0b000000000000000000000000000000000000000000000000000000000001010
-
- (lldb) p/o count
- (NSUInteger) $ 2 = 012
-
- (lldb) p/x count
- (NSUInteger) $ 3 = 0x000000000000000a
-
- (lldb) p/x string
- (__NSCFConstantString *) $ 4 = 0x000000010416a0b8 @"QiShare"
-
- (lldb) p/c string
- (__NSCFConstantString *) $ 5 = \xb8\xa0\x16\x04\x01\0\0\0 @"QiShare"
-
- (lldb) p/s string
- (__NSCFConstantString *) $ 6 = @"QiShare"
-
- (lldb) p/a string
- (__NSCFConstantString *) $ 7 = 0x000000010416a0b8 @"QiShare" @"QiShare"
5. Threads Thread is a thread-related command, the syntax is thread [ ], which can accept different optional parameters to achieve rich functions. Among them, thread list, thread backtrace and thread return are more commonly used. Developers can use the thread list command to view all current threads. The example is as follows: - (lldb) thread list
- Process 4031 stopped
- * thread #1: tid = 0x25cac , 0x0000000104167e23 QiDebugDemo`-[QiConsoleViewController testLLDBCommands]( self = 0x00007f850df0bbf0 , _cmd = "testLLDBCommands" ) at QiConsoleViewController.m:34, queue = 'com.apple.main-thread' , stop reason = breakpoint 4.1
- thread #2: tid = 0x25d2f , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
- thread #3: tid = 0x25d30 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
- thread #4: tid = 0x25d31 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
- thread #5: tid = 0x25d32 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
- thread #6: tid = 0x25d33 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
- thread #7: tid = 0x25d3e , 0x00000001079f520a libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'
The thread backtrace command allows developers to easily view thread stack information, abbreviated as bt. For example, when a program crashes, developers can view the stack call list. The example is as follows: - (lldb) thread backtrace
- * thread #1, queue = 'com.apple.main-thread' , stop reason = breakpoint 2.1
- frame #0: 0x0000000104cc2705 libobjc.A.dylib`objc_exception_throw
- frame #1: 0x00000001056704ec CoreFoundation`_CFThrowFormattedException + 194
- frame #2: 0x00000001057a6b00 CoreFoundation`-[__NSArrayI objectAtIndexedSubscript:] + 96
- * frame #3: 0x00000001043a1df7 QiDebugDemo`-[QiConsoleViewController testLLDBCommands]( self = 0x00007fadc7c50400 , _cmd = "testLLDBCommands" ) at QiConsoleViewController.m:33
- frame #4: 0x00000001043a1d5a QiDebugDemo`-[QiConsoleViewController viewDidLoad]( self = 0x00007fadc7c50400 , _cmd = "viewDidLoad" ) at QiConsoleViewController.m:26
- ...
- frame #18: 0x00000001056830be CoreFoundation`__CFRunLoopDoObservers + 430
- frame #19: 0x0000000105683751 CoreFoundation`__CFRunLoopRun + 1537
- frame #20: 0x0000000105682e11 CoreFoundation`CFRunLoopRunSpecific + 625
- frame #21: 0x000000010ddd51dd GraphicsServices`GSEventRunModal + 62
- frame #22: 0x000000010a1db81d UIKitCore`UIApplicationMain + 140
- frame #23: 0x00000001043a2450 QiDebugDemo`main( argc = 1 , argv = 0x00007ffeeb85df90 ) at main.m:7
- frame #24: 0x0000000107858575 libdyld.dylib`start + 1
During debugging, developers can use the thread return command to terminate a method and return a desired value. The following is an example: - (lldb) thread return string
- (lldb) continue
- 2019-02-27 17:22:47.323225+0800 QiDebugDemo[5071:222700] resultString: Qi_Share
6. Breakpoints The author introduced the usage of breakpoints in the article iOS debugging method: breakpoints. In fact, visual breakpoints can be implemented using LLDB syntax. For example, 1, 2, 3, 4, and 5 in the figure below can all be expressed using LLDB commands. - Enable/disable breakpoints
- Continue program execution (continue)
- Execute the next step (next)
- Enter method (step)
- Jump out of the method (finish)
In breakpoint related operations, because Xcode has integrated a visual breakpoint operation tool, the breakpoint command is not often used. However, the breakpoint command has very powerful functions, and the syntax is: breakpoint [ ], the main command examples are as follows: - //! View all breakpoints
- (lldb) breakpoint list
-
- //! Set breakpoints for viewDidAppear: in all classes
- (lldb) breakpoint set -n viewDidAppear:
-
- //! Set a breakpoint for the testLLDBCommands method in the QiConsoleViewController.m file
- (lldb) breakpoint set -f QiConsoleViewController.m -n testLLDBCommands
-
- //! Set a breakpoint for line 32 in the QiConsoleViewController.m file
- (lldb) breakpoint set -f QiConsoleViewController.m -l 32
-
- //! Set a conditional breakpoint for the handleString: method, with the condition string != nil
- (lldb) breakpoint set - handleString: -c string != nil
7. Observation Point Compared to breakpoint, which is a breakpoint that takes effect on a method, watchpoint is a breakpoint that takes effect on an address. Watchpoint is similar to the working principle of KVO. When it observes that something in the attribute address has changed, it interrupts the program. Its syntax is: watchpoint [ ]. Examples of its application scenarios are as follows: - (lldb) watchpoint set variable string
- Watchpoint created: Watchpoint 1: addr = 0x7ffeef497360 size = 8 state = enabled type = w
- declare @ '/Users/huangxianshuai/Desktop/Products/QiShare/QiDebugDemo/QiDebugDemo/QiConsoleViewController.m:33'
- watchpoint spec = 'string'
- new value: 0x00000001007670b8
-
- (lldb) next
-
- Watchpoint 1 hit:
- old value: 0x00000001007670b8
- new value: 0x0000000100767138
-
- (lldb) image lookup -a 0x00000001007670b8
- Address: QiDebugDemo[0x00000001000040b8] (QiDebugDemo.__DATA.__cfstring + 32)
- Summary: @"QiShare"
- (lldb) image lookup -a 0x0000000100767138
- Address: QiDebugDemo[0x0000000100004138] (QiDebugDemo.__DATA.__cfstring + 160)
- Summary: @"huang"
image lookup -a is the abbreviation of image lookup -address, which can be used to view the content of the parameter address. 8. Conclusion This article only lists some LLDB commands that the author usually uses, which can indeed improve debugging efficiency. More LLDB commands can be obtained from the LLDB Homepage (http://lldb.llvm.org/) or other online resources. [This article is an original article from 51CTO columnist 360 Technology, WeChat public account "360 Technology (id: qihoo_tech)"] Click here to read more articles by this author |