We often use Xcode breakpoints in our daily development. This powerful feature solves 99% of our development problems, but our breakpoints are only a small part of the LLDB.

1. What is LLDB?

LLDB is the short for Low Lever Debug, which is a built-in debugging tool provided by XCode for developers. Together with LLVM compiler, it exists in the console at the bottom of the main window and can bring us richer debugging functions of process control and data detection.

2. LLDB command line breakpoint setting (forward development)

Create a new project, write the following code, give an OC method breakpoint, this is our usual Xcode interface breakpoint, so let’s try to use the console LLDB under.

1. Break the function

Breakpoint set -n test1 Tells us a few things:

  • Breakpoint 2: This breakpoint is the second breakpoint
  • Where LLDB debug test1 + 11 at viewController. m:23:5: tells us where the break point is
  • address = 0x000000010fb07ecb: Address of the breakpoint
(lldb) breakpoint set -n test1
Breakpoint 2: where= LLDB debug 'test1 + 11 at ViewController.m:23:5, address = 0x000000010fb07ecb
(lldb) 
Copy the code

2. Give the method a breakpoint

The last one was a breakpoint for the function. Now we are going to break the OC method. Create three UI Buttons on the interface and add click methods.

LLDB input: breakpoint set -n “[ViewController onWeChatClicked:]” -n “[ViewController onQQClicked:]” -n “[ViewController onSinaClicked:]”

Breakpoint 1: 3 Locations Breakpoint 1: added at 3 locations

Then enter breakpoint list in LLDB to display the details of breakpoint. Then enter C to pass the breakpoint. Click the button to try and find the same function as the interface.

(lldb) breakpoint set -n "[ViewController onWeChatClicked:]" -n "[ViewController onQQClicked:]" -n "[ViewController onSinaClicked:]"
Breakpoint 1: 3 locations.
(lldb) breakpoint list
Current breakpoints:
1: names = {'[ViewController onWeChatClicked:]'.'[ViewController onWeChatClicked:]'.'[ViewController onQQClicked:]'.'[ViewController onQQClicked:]'.'[ViewController onSinaClicked:]'.'[ViewController onSinaClicked:]'}, locations = 1, resolved = 1, hit count = 0where= LLDB debug '-[ViewController onWeChatClicked:] + 43 at ViewController.m:22, address = 0x0000000102FF0DAB, resolved, Hit count = 0where= LLDB debug '-[ViewController onQQClicked:] + 43 at viewController. m:27:5, address = 0x0000000102FF0DFB, resolved, Hit count = 0where= LLDB debug '-[ViewController onSinaClicked:] + 43 at viewController. m:31:5, address = 0x0000000102ff0e4b, resolved, hit count = 0 (lldb) cCopy the code

3. Disable breakpoints

Since breakpoints are now directly accessed through LLDB, breakpoints cannot be disabled, deleted, and so on. Now we need to use the LLDB instructions to do this.

LLDB input: breakpoint disable 1, which means to disable all breakpoints of the first set. After testing, we found that all breakpoints of the last 3 click events failed.

The breakpoint is not in effect.

4. Enable breakpoints

Then we enable breakpoints again, LLDB: breakpoint enable 1 to enable the first set of breakpoints.

(lldb) breakpoint enable 1
1 breakpoints enabled.
(lldb) breakpoint list
Current breakpoints:
1: names = {'[ViewController onWeChatClicked:]'.'[ViewController onWeChatClicked:]'.'[ViewController onQQClicked:]'.'[ViewController onQQClicked:]'.'[ViewController onSinaClicked:]'.'[ViewController onSinaClicked:]'}, locations = 1, resolved = 1, hit count = 1where= LLDB debug '-[ViewController onWeChatClicked:] + 43 at ViewController.m:22, address = 0x0000000102FF0DAB, resolved, Hit count = 1where= LLDB debug '-[ViewController onQQClicked:] + 43 at viewController. m:27:5, address = 0x0000000102FF0DFB, resolved, Hit count = 1where= LLDB debug '-[ViewController onSinaClicked:] + 43 at viewController. m:31:5, address = 0x0000000102ff0e4b, resolved, hit count = 1 (lldb)Copy the code

5. Disable a breakpoint

Breakpoint disable 1.1 = breakpoint disable 1.1 = breakpoint disable 1.1 = breakpoint disable 1.1 = breakpoint disable 1.1 = breakpoint disable 1.1 = breakpoint disable 1.1

6. View interface breakpoint LLDB

Breakpoints above and below the interface can also be seen on the LLDB using breakpoint List.

7. Delete breakpoints

Breakpoints have been added and, of course, they need to be able to be deleted.

LLDB breakpoint delete 1.1, press Enter, but 0 breakpoints deleted is displayed on the console. 1 Breakpoint Locations Disabled.

Breakpoint 1.1 is disabled because you can delete only one breakpoint in a breakpoint group. Even if you run the breakpoint delete command on a breakpoint in a breakpoint group, the LLDB will disable only that breakpoint.

Delete 1 breakpoints delete 1 breakpoints delete 1 breakpoints delete 1 0 breakpoint locations Disabled., 1 breakpoint is deleted, and 0 breakpoints are disabled.

LLDB Run the breakpoint delete command to delete all breakpoints.

(lldb) breakpoint delete
About to delete all breakpoints, do you want to dothat? : [Y/n] y All breakpoints removed. (2 breakpoints) (lldb)Copy the code

View other LLDB directives

To view other commands, type: help on LLDB.

For example, “help Breakpoint” is to view all breakpoint commands.

9. Set a breakpoint for a method

(void)touch began :(NSSet

*)touches withEvent:(UIEvent *)event; Set breakpoints.

Breakpoint set — Selector touchesBegan:withEvent:, press Enter. Group 4 breakpoints, 94 in total.

When I click on the screen, it’s clear that this is not the method that I just did in the project, because in UIKit, almost any control that can be manipulated has a gesture, so the current break point goes into the system method.

Viewcontroller.m -(void)touchesBegan:(NSSet

*)touches withEvent:(UIEvent *)event;

Breakpoint set –file ViewController.m — Selector touchesBegan:withEvent:, and press Enter to show that our breakpoint is set.

(lldb) breakpoint set  --file ViewController.m --selector  touchesBegan:withEvent:
Breakpoint 8: where= LLDB debug '-[ViewController touchesBegan:withEvent:] + 77 at ViewController.m:40:5, address = 0x0000000102ff0edD (LLDB)Copy the code

Set breakpoints for all methods that contain a string

Now you need to break a method that contains Clicked:.

Breakpoint set -r Clicked:, press Enter

In addition to the methods that contain Clicked: in our current viewController.m file, some system methods have broken points as well.

Of course, we can also specify the file to set a breakpoint. Breakpoint set –file viewController. m -r Clicked:

11, short for breakpoint setting

B -f ViewController. M -r Clicked: equal to breakpoint set –file ViewController. M -r Clicked: equal to breakpoint set –file ViewController.

  • bbreakpoint set
  • -f:--file
  • -n:--name

Breakpoint list breakpoint disable break li break dis Break li break dis

3, LLDB some instructions of the meaning and advanced use method

We often get the value of an object by typing “p XXX” or “Po XXX” in the LLDB during Xcode debugging. So what does p or Po mean?

LLDB Enter help p and help Po to view the following information:

  • pexpressionThe shorthand.LLDBThe input ofp xxxPerform XXX
  • poexpression -OThe abbreviations. Input againhelp expression.po : expression --object-descriptionLLDBThe input ofpo xxxExecute the description method of XXX

Since p is to execute a method, then LLDB input: p the self. The backgroundColor = [UIColor redColor]; Enter, hit the breakpoint and self.view becomes red.

You can also do more with the P instruction. Create a new Person class like this:

// // person. h // LLDB debug // // Created by ABC on 2019/10/27. // Copyright © 2019 ABC. All rights reserved. //#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject

@property (nonatomic,strong) NSString *name;

@property (nonatomic,assign) int age;

@end

NS_ASSUME_NONNULL_END
Copy the code

And then the ViewController has at sign property (nonatomic,strong) NSMutableArray *dataArray; , the next operation is as follows (pictures are not used here for easy copying) :

(lldb) b -f ViewController.m -r touch
Breakpoint 1: where= LLDB debug '-[ViewController Began:withEvent:] + 77 at ViewController.m:43:5, address = 0x0000000106421c0d (lldb) c Process 2221 resuming (lldb) po self <ViewController: 0x7fb2d5d07c20> (lldb) po self.dataArray <__NSArrayM 0x600003705440>( ) (lldb) p [self.dataArray addObject:[Person new]]; (lldb) po self.dataArray <__NSArrayM 0x600003705440>( <Person: 0x60000395b820> ) (lldb) p self.dataArray.lastObject; (Person *)$3 = 0x000060000395b820
(lldb) p [(Person *)$3 setValue:@"Zhang" forKey:@"name"];
(lldb) p (Person *)self.dataArray.lastObject
(Person *) $4 = 0x000060000395b820
(lldb) p $4.name;
(__NSCFString *) A $5 = 0x0000600003972d40 @"Zhang"
(lldb) p $4.name = @"Bill";
(__NSCFString *) $6 = 0x0000600003972500 @"Bill"
(lldb) p $4.name;
(__NSCFString *) $7 = 0x0000600003972500 @"Bill"(lldb) p Person *person = [Person new]; person.name = @"Fifty"; person.age = 12; [self.dataArray addObject:person]; (lldb) p self.dataArray (__NSArrayM *)$8 = 0x0000600003705440 @"2 elements"
(lldb)  p (Person *)self.dataArray.lastObject
(Person *) $9 = 0x0000600003972dc0
(lldb) p $9.name;
(__NSCFString *) $10 = 0x0000600003972da0 @"Fifty"
(lldb) p $9.age;
(int) $11 = 12
(lldb) 
Copy the code

As you can see above, we can use LLDB to add objects to an array, or we can use LLDB to generate an object, assign values to its properties, and then add it to the array. I have to say the LLDB is powerful.

Note:(Person *)self.dataArray.lastObjectJust add its type to the class of the object when fetching the value, for example:(Person *), we can just use the returned one$4Object takes the value of its property$4.name.

Next look at the function call stack. Add the following code to viewController.m (with the same substitution).

- (void)lldbText1 {
    [self lldbText2];
}

- (void)lldbText2 {
    [self lldbText3];
}

- (void)lldbText3 {
    [self lldbText4];
}

- (void)lldbText4 {
    NSLog(@"%s",__func__);
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"Hit screen 111.");
    NSLog(@"点击了界面222");
    [self lldbText1];
}
Copy the code

The console gives – (void)lldbText3; B -f viewController. m -r lldbText3 – (void)lldbText3; LLDB () to view the call queue stack, enter bt as shown below:

To go back to the previous method LLDB type up, go to the next down.

Frame Select 1 and frame Select 3 can also be used to directly jump to the corresponding queue stack.

If you want to look at the parameters in lldbText2 you can use frame variable, and that kind of tells us that self in the method doesn’t have to be our current ViewController.

Add STR to lldbText1, lldbText2, lldbText3, lldbText4 and set a breakpoint to lldbText3.

If we enter lldbText2 with up and change STR, will the output of lldbText4 change?

It turns out that it won’t, because our lldbText2 method has already passed, just as we couldn’t change it in the past.

But do you have to change it?

We could have used thread return, but the method went to lldbText2, changed the STR in lldbText2, crossed the breakpoint, and did not print lldbText4. Adds a return to the end of the current method, so no further execution is done.

There are also flow control instructions

  • $continue c
  • Step by step, executing a subfunction as a whole in one step$n next, used under assemblyni
  • Step by step, it goes in when it hits a subfunction$s, used under assemblysi

Other instructions

  • image list
  • p
  • b -[xxx xxx]
  • x
  • register read
  • po
  • stop-hookLet you in every timestop(breakpoint) to execute some commands only againstbreadpoint.watchpoint

4. LLDB command line breakpoint setting (reverse development)

The above instructions are of little use in reverse development ~~~~ and feel a bit broken.

When we’re developing forward, we have a symbol file table, and Xcode will parse all the methods for us, but when we upload an app to the AppStore, we don’t have a symbol file. For example, when we use the Crash collection tool (Bugly, Umen or Xcode), we will upload the symbol file table, otherwise it will not be able to parse, which is also a protection measure for the application.

Without the symbol table, we can only print out a bunch of things that we can’t understand, so we can’t debug other apps or use function names to set breakpoints, so the above instructions are basically useless in reverse development.

Since there are so many ways to do things forward, there are also ways to do things backwards, and in reverse engineering, we can do memory breakpoints.

1, the use of memory breakpoints

Modify the viewDidLoad code as follows:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Person *p1 = [Person new];
    p1.name = @"111";
    p1.age = 1;
    
    Person *p2 = [Person new];
    p2.name = @"222";
    p2.age = 2;
    
    Person *p3 = [Person new];
    p3.name = @"333";
    p3.age = 3;
    
    [self.dataArray addObject:p1];
    [self.dataArray addObject:p2];
    [self.dataArray addObject:p3];
}
Copy the code

TouchesBegan :(NSSet

*) Touches withEvent:(UIEvent *)

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    Person *p1 = [self.dataArray firstObject];
    p1.name = @"ABC";
}
Copy the code

To the [super viewDidLoad]; This line adds a breakpoint, rerunts, and then uses the N or Xcode tool to make the LLDB walk to p1.

After p1 is created, the object of P1 already exists in the heap, pointer to p1 object because [self.dataArray addObject:p1]; Method, which is still saved after the viewDidLoad method is done.

Watchpoint set variable p1->_name The LLDB clearly tells us the address of the memory breakpoint and the size of the pointer (the OC object is 8 bytes).

When we get past the breakpoint, we click on the screen to trigger the p1.name = @”ABC” assignment method of touchesBegan, and a memory breakpoint is triggered. The two addresses printed at the top of the Po, we can see the old value and the new value. Then type BT to view the call stack to see the call queue stack clearly.

We can also use p1->_name memory pointer address to p1->_name memory breakpoint.

  • To obtainp1->_nameMemory address of:&p1->_name
  • Down memory breakpoint: usewatchpoint set expressionaddp1->_nameMemory address of
  • Tap the screen to trigger assignment method validation

Like symbolic breakpoints, memory breakpoints can be viewed and deleted

  • View memory breakpoints:watchpoint list
  • Delete memory breakpoints:watchpoint delete

Add multiple instructions to a breakpoint

Modify the code in touchesBegan:withEvent as follows.

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"Hit screen 111.");
    NSLog(@"点击了界面222");
    [self lldbText1:@"123"];
}
Copy the code

Then add a symbolic breakpoint b -[ViewController lldbText1:] to lldbText1:.

Enter breakpoint list on LLDB and add multiple breakpoint commands to breakpoint 1. Then enter breakpoint command add 1 after >. After each command is completed, press Enter to enter the next command.

Text version is easy to copy

(lldb) breakpoint command add 1
Enter your debugger command(s).  Type 'DONE' to end.
> po self
> p self.view.backgroundColor
> p self.view.backgroundColor = [UIColor redColor];
> DONE
Copy the code

After the breakpoint is dropped, the command is executed. After the breakpoint is dropped, the screen turns red.

To delete breakpoint 1, run breakpoint command delete 1.

Add multiple instructions to all breakpoints

If we add multiple instructions to all breakpoints, we will execute our instructions as soon as any breakpoints come.

For example, we often use the frame variable directive (view all the parameters of a method). Target stop-hook add -o “frame variable” to all breakpoints.

  • target stop-hookThe target is the break point
  • addadd
  • -o--oneTo add an instruction
  • "frame variable"Instructions to add

Press enter, get over the breakpoint, add a breakpoint to the touchesBegan withEvent, click on the screen, enter the breakpoint, and execute the frame variable.

Some other instructions

  • target stop-hook listCheck the list
  • target stop-hook delete 1Delete the first set of breakpoints
  • target stop-hook deleteDelete all breakpoints
  • target stop-hook disable 1Disable the first set of breakpoints
  • undisplay 1Delete the first set of breakpoints, andtarget stop-hook delete 1Same function.

4. Add multiple instructions to all breakpoints using scripts

Every time Xcode is run, LLDB starts to load a file. Lldbinit. Type ls -a in the ~ directory (list all files, including hidden files,. Target stop-hook add -o “frame variable” target stop-hook add -o “frame variable” Press ESC and enter :wq to save the configuration and exit.

Since it is added to the LLDB of the system, it is valid for every project.

And then we go back to our Xcode and we just arbitrarily set a breakpoint.

4. Image instruction

  • image list: View all loaded libraries
  • Image lookup -t Class nameView header file information for a class

5. Method breakpoints

There are no symbol files in reverse, so how do we break the method?

At this point, we need to use a tool called Hopper Disassembler and drag our project’s lldb. MachO file into the Hopper Disassembler.

You need to add a breakpoint to the lldbText1: method of the ViewController. The memory address for this method is 0x100001980.

Warning: Failed to set breakpoint site at 0x100001980 for Breakpoint 2.1 warning: Failed to set breakpoint site at 0x100001980 for Breakpoint 2.1 error: 0 sending the breakpoint request

The current breakpoint did not succeed, so why?

Because the memory address of our method is calculated relative to the memory address of the MachO file.

LldbText1: the offset in the file is 0x1980. To get to the method’s memory breakpoint correctly, you need the address of the MachO file in memory.

The first line is the address of MachO in memory, and the offset of lldbText1: is the address of the real runtime lldbText1 memory.

The address of MachO in the currently running project is 0x102f10000(which changes with each run), lldbText1: LLDB: b -a 0x102F11980, press Enter, break through, hit screen test, break point lldbText1:

ASLR

In computer science, Address Space Layout randomization (ASLR, also known as Address space configuration randomization, Address space layout randomization) is a computer security technology to prevent memory corruption vulnerability from being exploited.

We know: physical address = ASLR + method virtual address

So we are currently running MachO memory address 0x102f10000, so ASLR is 0x2F10000, and then we add lldbText1 directly: B -a 0x2F10000 +0x100001980 is the virtual address of the Hopper Disassembler. Methods.

The above are the different use methods of LLDB in forward and backward. Welcome to point out any questions.