What is dynamic debugging?

Dynamic debugging is to view parameters, return values, function call flow, and so on, through a series of ways, such as breaking points, printing, and so on, while our program is running. Dynamic debugging is needed not only in iOS open, but also in any language development process

How does Xcode debug dynamically?

Xcode compiler and debugger

  • Xcode originally used the GCC compiler developed by GUN, but since Xcode5 it has used its own LLVM compiler. Check out GCC and LLVM for an introduction
  • The Xcode debugger was originally a GDB debugger developed using GUN, and has since been replaced with a self-developed LLDB debugger. You can check out the introduction of GDB and LLDB.

Xcode debugs the App process

  • The first thing that comes with Xcode is a tool called == debugServer ==, Stored in the/Applications/Xcode. App/Contents/Developer/Platforms/iPhoneOS platform/De ViceSupport / 9.1 / DeveloperDiskImage. DMG/usr/bin/debugserver directory, when we use the Xcode run our program on the iPhone, Xcode will install = = debugserver = = to our iPhone, specific installation path is/Developer/usr/bin/debugserver
  • After Xcode is connected to the mobile phone, it transmits instructions to the == debugServer == on iPhone through its own ==LLDB== compiler. After receiving the instructions, the debugServer == will run the instructions into the App. App executes the command and returns the result as == debugServer ==, and then == DebugServer == will feed the information back to ==LLDB==, and finally ==LLDB== will print the information to Xcode.
  • However, Xcode is very limited because it can only debug apps installed through Xcod

How to dynamically debug any App without Xcode?

You can use terminals instead of Xcode to dynamically debug your App

The DebugServer environment is set up

Method 1. Use LDID for signature

  • Under the access to the iPhone/Developer/usr/bin/debugserver directory debugserver tools, copied to the Mac
  • Since the == debugServer == installed by Xcode does not have enough permissions, it can only debug the App installed by Xocde, so we need to add more permissions to the == DebugServer ==.
  • Run the ldiD-e command to export the permission information of the == debugServer ==
ldid -e debugserver > debugserver.entitlements
Copy the code
  • Add the following two permissions in debugServer. entitlements
    • get-task-allow
    • task_for_pid-allow

  • Re-sign the == debugServer == using LDID
ldid -Sdebugserver.entitlements debugserver
Copy the code
  • == debugServer == == == == == == == == == == == == == == == == ==
chmod +x /usr/bin/debugserver
Copy the code

Method 2. Use CoDesign to sign the DEBUgServer

# View basic permission information
codesign -d --entitlements - debugserver

# signature permission
codesign -f -s - --entitlements debugserver.entitlements debugserver

# can also be shortened to
codesign -fs - --entitlements debugserver.entitlements debugserver
Copy the code

Let the DebugServer attach to a process

Debugserver *: indicates the port number-aprocessCopy the code

*: Port number: indicates that a port on the iPhone is used to start the debugServer service (note: do not use the reserved port number) -a process: specifies the process ID or process name

Start the App using the DebugServer

Debugserver -x Auto *: port number App executable file pathCopy the code

Start LLDB on the Mac and remotely connect to the DEBUgServer on the iPhone

In previous studies, we know that the IP address of iPhone can be used to connect the mobile phone, but it is necessary to ensure that the mobile phone and the computer are under the same wifi, and data transmission in this way is very slow. Therefore, the common practice is to connect the iPhone via USB, map a port on the iPhone to a port on the Mac, and then communicate with the port on the Mac

debugserver attaching

  • Map iPhone 10089 with the following command
python ./usbmuxd/tcprelay.py -t 22:10088 9999:10089
Copy the code

Port 10089 here can be defined arbitrarily, as long as the reserved port number is not used. Port 10088 is mapped to port 22 for SSH communication with iPhone

  • After the mapping is successful, start the == debugServer == service using port 9999. Let == DebugServer == attach to Tencent Video App process as follows:
debugserver *:9999 -a live4iphone
Copy the code
  • If the following effect appears, == DebugServer == has been successfully attached to Tencent Video App

Start LLDB on the Mac and remotely connect to the debugServer service on the iPhone

  • Start LLDB on a Mac
➜  ~ lldb
(lldb)
Copy the code
  • Connect to the Mac through port 10089 == debugServer == service
process connect connect://localhost:10089
Copy the code

  • Since the program is in the breakpoint state by default after connecting to the == debugServer == service, use the LLDB c command to continue the program
(lldb) c
Process 635 resuming
Copy the code

Common LLDB commands

The basic format of LLDB instructions

 <command> [<subcommand> [<subcommand>...]] <action> [-options [option- value]] [argument [argument...]]
Copy the code

Corresponds to the

Command subcommand Command Operation Command option Command parametersCopy the code

For example, to set a breakpoint on the test function:

breakpoint set -n test
Copy the code

The help command

The help directive can help us quickly find out how to use the LLDB directive

help breakpoint
help breakpoint set
Copy the code

Expression — instructions

The expression directive is used to execute an expression

Expression of self. The backgroundColor = [UIColor redColor] / / or expression -- self. The backgroundColor = [UIColor redColor]Copy the code
  • Expression, expression — is equivalent to the print, p, call instructions

  • Expression -O – is the same as the Po command

Expression — indicates the end of command options. It indicates that all command options are set. If no command options are available, — can be omitted. If expression is followed by a command option, — cannot be omitted.

thread backtrace

The ==thread backtrace== directive prints the stack information for the thread. The effect is the same as that of ==bt==.

(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame # 0: 0x0000000102d4d61d TestFont`-[ViewController touchesBegan:withEvent:](self=0x00007fd2f86066d0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000036d4ab0) at ViewController.m:26
    frame #1: 0x0000000106f6f8e8 UIKitCore`forwardTouchMethod + 353. (lldb) bt * thread#1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame # 0: 0x0000000102d4d61d TestFont`-[ViewController touchesBegan:withEvent:](self=0x00007fd2f86066d0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000036d4ab0) at ViewController.m:26
    frame #1: 0x0000000106f6f8e8 UIKitCore`forwardTouchMethod + 353.Copy the code

thread return []

Let the function return a value, not execute the following code. If the function returns a value, follow it with the return value. If the function does not return a value, simply use Thread return

frame variable []

Prints the variable of the current stack frame

Thread related instruction

The following instructions are shown from left to right: full name of instruction, abbreviation of instruction, and minimalist instruction

  • Thread continue, continue, c: Let the program skip the breakpoint and continue running
  • Thread step-over, next, n: Run in a single step, executing sub-functions as a whole in one step
  • Thread step-in, step, s: Runs in a single step and enters a sub-function when it encounters a sub-function
  • Thread step-out, finish: Executes all code of the current function and returns to the previous function
  • Thread step-inst-over, Nexti, ni
  • Thread step-inst, STEPI, and SI

Si and NI are similar to s and N instructions, but S and N are at the source level, while SI and NI are at the assembly level. Each line of OC code consists of one or more assembly instructions. S and N instructions represent the step by step execution of each line of OC code, while SI and NI represent the step by step execution of assembly instructions.

Breakpoint related instructions

breakpoint set

To set breakpoints

  • Breakpoint set -a Function address
  • Breakpoint set -n Specifies the function name
    • breakpoint set -n test
    • breakpoint set -n touchesBegan:withEvent:
    • breakpoint set -n “-[ViewController touchesBegan:withEvent:]”
  • Breakpoint set -r Regular expression

Following the regular expression, breakpoints are added to all matched methods

  • Breakpoint set -s breakpoint set -n Breakpoint sets the breakpoint for the specified function in the specified dynamic library

breakpoint list

Lists all breakpoints, with each breakpoint individually numbered

Breakpoint Disable Indicates the breakpoint number

Disable breakpoints

Breakpoint Enable Indicates the breakpoint number

Enable the breakpoint

Breakpoint delete Indicates the breakpoint number

Remove breakpoints

Breakpoint Command add Breakpoint number

The breakpoint with the specified breakpoint number is preconfigured with commands to execute. When the breakpoint is triggered, the preconfigured commands are executed in sequence

Breakpoint Command List Breakpoint number

View all preset commands for a breakpoint number

Breakpoint Command delete Number of a breakpoint

Deletes all default commands for breakpoints specified by number

Memory breakpoint Watchpoint

A breakpoint is triggered when data in memory changes

Watchpoint set variable

Sets a memory breakpoint on a specified variable. It is triggered when the value of the variable changes

watchpoint set variable self->_age
Copy the code

Note: Self.age cannot be used here

Watchpoint set expression Memory address

Set a breakpoint on a specified memory address, as watchpoint set variable does

watchpoint list

List all memory breakpoints

Watchpoint Disable Breakpoint number

Disabling memory breakpoints

Watchpoint enable Number of a breakpoint

Enabling memory breakpoints

Watchpoint delete Breakpoint number

Delete memory breakpoints

Watchpoint Command add Breakpoint number

A memory breakpoint with a specified breakpoint number is preconfigured with commands to be executed. When a memory breakpoint is triggered, the preconfigured commands are executed in sequence

Watchpoint Command List Breakpoint number

View all preset commands for a specified memory breakpoint

Watchpoint Command delete Number of a breakpoint

Deletes all default commands for the specified number of memory breakpoints

Image module query instruction

image lookup

Module query instruction

  • Image lookup -t type Searches for information of a certain type

  • Image lookup -a Memory address Locate the memory address in the module

  • Image lookup -n Symbol or function name Finds the location of a symbol or function

image list

Lists all loaded modules

  • Image list -o -f Displays the offset address and full path of the module

LLDB tip

  • Each time you press Enter, the previous command is automatically executed
  • Abbreviations can be used for most instructions
(lldb) breakpoint list
(lldb) br li
(lldb) br l

(lldb) breakpoint set -n test
(lldb) br s -n test
Copy the code