Common iOS debugging methods: LLDB commands

Common iOS debugging methods: LLDB commands

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:

  1. < 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.

  1. (lldb) help help
  2. Show a list of all debugger commands, or give details about a specific
  3. command.
  4.  
  5. Syntax: help [ < cmd-name > ]
  6.  
  7. Command Options Usage:
  8. help [-ahu] [ < cmd-name > [ < cmd-name > [...]]]
  9.  
  10. -a ( --hide-aliases )
  11. Hide aliases in the command list.
  12.  
  13. -h ( --show-hidden-commands )
  14. Include commands prefixed with an underscore.
  15.  
  16. -u ( --hide-user-commands )
  17. Hide user-defined commands from the list.
  18.       
  19. This command takes options and free-form arguments. If your arguments
  20. resemble option specifiers (ie, they start with a - or --), you must use
  21. ' -- ' between the end of the command options and the beginning of the
  22. 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:

  1. //! Output the value of count
  2. (lldb) expression count
  3. (NSUInteger) $ 0 = 10  
  4.  
  5. //! Execute the string concatenation method
  6. (lldb) expression [string stringByAppendingString:@"732"]
  7. (__NSCFString *) $ 1 = 0x00006000006ac870 @"QiShare732"
  8.  
  9. //! Change the color of the view
  10. (lldb) expression self.view.backgroundColor = [UIColor redColor]
  11. (UICachedDeviceRGBColor *) $ 2 = 0x0000600001d74780  
  12. (lldb) expression [CATransaction flush]
  13. //! < 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:

  1. (lldb) expression -- self.view
  2. (UIView *) $ 4 = 0x00007f8ca8401690  
  3.  
  4. (lldb) e self.view
  5. (UIView *) $ 5 = 0x00007f8ca8401690  
  6.  
  7. (lldb) p self.view
  8. (UIView *) $ 6 = 0x00007f8ca8401690  
  9.  
  10. (lldb) po self.view
  11. < UIView: 0x7f8ca8401690; frame = ( 0 0; 375 812); autoresize = W +H; layer = < CALayer: 0x6000008a1dc0 >>  
  12.  
  13. (lldb) call self.view
  14. (UIView *) $ 8 = 0x00007f8ca8401690  

In addition, developers can follow the print/ The syntax for the print command specifies the print format:

  1. p/x //! < Print integer in hexadecimal
  2. p/d //! < Print an integer in signed decimal
  3. p/u //! < Print integer in unsigned decimal
  4. p/o //! < Print integer in octal
  5. p/t //! < Print integer in binary
  6. p/a //! < Print address in hexadecimal
  7. p/c //! < Print character constant
  8. p/f //! < Print floating point number
  9. p/s //! < print string
  10. 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:

  1. (lldb) p count
  2. (NSUInteger) $ 0 = 10  
  3.  
  4. (lldb) p/t count
  5. (NSUInteger) $ 1 = 0b000000000000000000000000000000000000000000000000000000000001010  
  6.  
  7. (lldb) p/o count
  8. (NSUInteger) $ 2 = 012  
  9.  
  10. (lldb) p/x count
  11. (NSUInteger) $ 3 = 0x000000000000000a  
  12.  
  13. (lldb) p/x string
  14. (__NSCFConstantString *) $ 4 = 0x000000010416a0b8 @"QiShare"
  15.  
  16. (lldb) p/c string
  17. (__NSCFConstantString *) $ 5 = \xb8\xa0\x16\x04\x01\0\0\0 @"QiShare"
  18.  
  19. (lldb) p/s string
  20. (__NSCFConstantString *) $ 6 = @"QiShare"
  21.  
  22. (lldb) p/a string
  23. (__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:

  1. (lldb) thread list
  2. Process 4031 stopped
  3. * 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
  4. thread #2: tid = 0x25d2f , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  5. thread #3: tid = 0x25d30 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  6. thread #4: tid = 0x25d31 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  7. thread #5: tid = 0x25d32 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  8. thread #6: tid = 0x25d33 , 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
  9. 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:

  1. (lldb) thread backtrace
  2. * thread #1, queue = 'com.apple.main-thread' , stop reason = breakpoint 2.1
  3. frame #0: 0x0000000104cc2705 libobjc.A.dylib`objc_exception_throw
  4. frame #1: 0x00000001056704ec CoreFoundation`_CFThrowFormattedException + 194
  5. frame #2: 0x00000001057a6b00 CoreFoundation`-[__NSArrayI objectAtIndexedSubscript:] + 96
  6. * frame #3: 0x00000001043a1df7 QiDebugDemo`-[QiConsoleViewController testLLDBCommands]( self = 0x00007fadc7c50400 , _cmd = "testLLDBCommands" ) at QiConsoleViewController.m:33
  7. frame #4: 0x00000001043a1d5a QiDebugDemo`-[QiConsoleViewController viewDidLoad]( self = 0x00007fadc7c50400 , _cmd = "viewDidLoad" ) at QiConsoleViewController.m:26
  8. ...
  9. frame #18: 0x00000001056830be CoreFoundation`__CFRunLoopDoObservers + 430
  10. frame #19: 0x0000000105683751 CoreFoundation`__CFRunLoopRun + 1537
  11. frame #20: 0x0000000105682e11 CoreFoundation`CFRunLoopRunSpecific + 625
  12. frame #21: 0x000000010ddd51dd GraphicsServices`GSEventRunModal + 62
  13. frame #22: 0x000000010a1db81d UIKitCore`UIApplicationMain + 140
  14. frame #23: 0x00000001043a2450 QiDebugDemo`main( argc = 1 , argv = 0x00007ffeeb85df90 ) at main.m:7
  15. 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:

  1. (lldb) thread return string
  2. (lldb) continue
  3. 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:

  1. //! View all breakpoints
  2. (lldb) breakpoint list
  3.  
  4. //! Set breakpoints for viewDidAppear: in all classes
  5. (lldb) breakpoint set -n viewDidAppear:
  6.  
  7. //! Set a breakpoint for the testLLDBCommands method in the QiConsoleViewController.m file
  8. (lldb) breakpoint set -f QiConsoleViewController.m -n testLLDBCommands
  9.  
  10. //! Set a breakpoint for line 32 in the QiConsoleViewController.m file
  11. (lldb) breakpoint set -f QiConsoleViewController.m -l 32
  12.  
  13. //! Set a conditional breakpoint for the handleString: method, with the condition string != nil
  14. (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:

  1. (lldb) watchpoint set variable string
  2. Watchpoint created: Watchpoint 1: addr = 0x7ffeef497360   size = 8   state = enabled   type = w  
  3. declare @ '/Users/huangxianshuai/Desktop/Products/QiShare/QiDebugDemo/QiDebugDemo/QiConsoleViewController.m:33'
  4. watchpoint spec = 'string'  
  5. new value: 0x00000001007670b8
  6.  
  7. (lldb) next
  8.  
  9. Watchpoint 1 hit:
  10. old value: 0x00000001007670b8
  11. new value: 0x0000000100767138
  12.  
  13. (lldb) image lookup -a 0x00000001007670b8
  14. Address: QiDebugDemo[0x00000001000040b8] (QiDebugDemo.__DATA.__cfstring + 32)
  15. Summary: @"QiShare"
  16. (lldb) image lookup -a 0x0000000100767138
  17. Address: QiDebugDemo[0x0000000100004138] (QiDebugDemo.__DATA.__cfstring + 160)
  18. 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

<<:  A revolutionary breakthrough in Android performance? A detailed explanation of the technical principles of Huawei's Ark Compiler

>>:  A brief history of mobile phone "color change"

Recommend

How much reference value does Durex’s copywriting have for you?

A friend came to complain, saying that his boss a...

Why doesn’t anyone drink “pig milk”? Is it because it tastes bad?

Milk and dairy products are rich in nutrients, an...

The Mystery of the Pleiades Star Cluster: The Pleiades Nebula

Author | Wang Siliang Review | Zheng Chengzhuo Ed...

Genetically modified organisms: Things related to human development

As human beings study life phenomena more and mor...

Decoding the consumer psychology used by Pinduoduo in its promotions

You know exactly what to do to succeed, and then ...

How about opening an account with Baidu Advertising?

Now there are still a lot of businesses who see t...

For WeChat, micro-business is both a treasure and a locust

Wechat merchants should be thankful that they hav...

"Individual Youth" has grown up and AutoNavi has launched a new "Voice" strategy

In this era, personalization has gradually become...