Advanced+apple+debugging (5)

Source: Internet
Author: User

Now that you've learned how to create breakpoints, the debugger will stop in your code and it's time to get some useful information from the program you're debugging.
You should often want to see the object's instance variables. But, you know, you can even execute arbitrary code through LLDB? In detail, you can declare, initialize, and inject code to help you understand the application through Objective-c's runtime.
In this chapter you will learn the expression command. This command allows you to execute arbitrary code in the debugger.

Formatting P and PO

You may be familiar with go-to this debug command. po This command is often used to print out information about an object. It can be an instance variable of an object, a reference to an object, or an object in a register. It can even be the memory address of any object in memory.
If you view the quick Help for a PO in the LLDB console, you will find that the PO is actually an abbreviation for an expression Expression-o. The-o parameter is used to print out the Description.po of the object. P is an abbreviation for an expression that omits the-o option--.
The information printed by P depends on the LLDB type system. The formatted type of the value of the LLDB determines its output and is fully customizable (as you'll see later).
It's time to learn how to get their content with P and Po. In this chapter you still use the signals project.
Open the signals project in Xcode. Next open the Masterviewcontroller.swift and add the following code above the class:

Override Var description:string {
Return "yay! Debugging "+ super.description
}
The following code is added to the Super.viewdidload () in Viewdidload:

Print ("(self)")
Now create a breakpoint in Masterviewcontroller.swift below the Print method you just added.
Build and run the app:

Page56image16240.png

When signals stops in Viewdidload (), enter the following code in the LLDB console:
(LLDB) PO Self
You should see the following output:

yay! Debugging <Signals.MasterViewController:0x7f8a0ac06b70>
Note the output of the print statement and its match with the PO self output that you performed in the debugger.
You can do it further. NSObject There is another description method for debugging called Debugdescription. Now try to implement it. Add the following code below the description variable definition:

Override Var debugdescription:string {
Return "Debugdescription:" + super.debugdescription
}
Build and run the application. When the debugger stops at the breakpoint, print self again:

(LLDB) PO Self
The output of the LLDB console should look like this:

debugdescription:yay! Debugging <signals.masterviewcontroller:
0x7fb71fd04080>
Note the difference between the output of PO self and the print itself after you have implemented the debugdescription. When you print an object in Lldb, you call debugdescription instead of description, notice!
As you can see, when the NSObject class or its subclasses have a description or Debugdescription method, it affects the output of the PO.
So which objects need to rewrite the description method? You can simply use the image Lookup command plus a regular expression to capture objects that override this method. What you learned in the previous chapters will come in handy.
For example, if you want to know which Objective-c class overrides the Debugdescription method, you can query all of these methods with the following command:

(lldb) Image lookup-rn ' \ debugdescription] '
As you can see from the output, the author of the foundation framework has added debugdescription to many foundation types (for example: Nsarray), making it easier to debug. There are also private classes that override the Debugdescription method.
You can notice that there are calayer classes in the list. Let's look at the differences between description and Debugdescription in the Calayer class.
Enter the following in the LLDB console:

(LLDB) Po self.view!. Layer.description
You will see output similar to the following:

"<CALayer:0x61000022e980>"
Only a little bit of information. Now enter the following:

(LLDB) Po self.view!. Layer
You will see the following output:

<CALayer:0x61000022e980; Position = Cgpoint (187.5 333.5); Bounds =
CGRect (0 0; 375 667); Delegate = <UITableView:0x7fdd04857c00; frame =
(0 0; 375 667); Clipstobounds = YES; AutoResize = w+h; Gesturerecognizers
= <NSArray:0x610000048220>; Layer = <CALayer:0x61000022e980>;
Contentoffset: {0, 0}; Contentsize: {375, 0}>; Sublayers = (<calayer:
0x61000022d480>, <calayer:0x61000022da60>, <CALayer:0x61000022d8c0>);
Maskstobounds = YES; allowsgroupopacity = YES; BackgroundColor = <cgcolor
0x6100000a64e0> [<cgcolorspace 0x61800002c580> (kcgcolorspaceiccbased;
Kcgcolorspacemodelrgb; SRGB iec61966-2.1; Extended Range)] (1 1 1 1) >
There's more to it-and it's even more useful! It is clear that core animation developers need to use description to get more clear information by reference. But if you're in the debugger, you'll see more information. We don't know why they make these differences. Perhaps these debug description need to perform a lot of calculations, so they are only used when absolutely necessary.
Next, you should still stay in the debugger and try to execute P self:

(LLDB) P self
You should get some information similar to the following:

(signals.masterviewcontroller) $R 2 = 0x00007fb71fd04080 {
Uikit.uitableviewcontroller = {
[email  Protected] = <extracting data from value failed>
_tableviewstyle = 0
_keyboardsupport = Nil
_ Staticdatasource = Nil
_filtereddatasource = 0x000061800024bd90
_filtereddatatype = 0
}
Detailviewcontroller = Nil
}
This may seem intimidating, but let's take a look at it.
First, LLDB outputs the class name of self. Here is Signals.masterviewcontroller. The following is a pointer that you can use to refer to this object in Lldb. In the example above, it is $r2. You may be different because this number is incremented when you use LLDB.
This reference is useful when you want to return to this object in a later Lldb session, perhaps you are not the same object in a different range. You can refer to this object by R2 here. You want to know how to quote, then look down:

(LLDB) P $R 2
You will see the same output. You will learn more about the use of this lldb variable later in this chapter.
After the name of the LLDB variable is the address of the object, followed by some explicit information about the class. Here, it shows Uitableviewcontroller related details, Masterviewcontroller's parent class, followed by an instance variable of Detailviewcontroller.
As you can see, the P command outputs information that is different from the PO command output. The output of P depends on the type format, the LLDB author has been added to Objective-c, Swift, and other languages within each of the internal data structures. It is important to note that Swift's output format may be slightly different in different Xcode distributions.
Since type formatting is handled by LLDB, you have the ability to change them if you want. In your lldb session, enter the following command:

(LLDB) Type summary add Signals.masterviewcontroller--summary-string
"Wahoo!"
You've already told LLDB that when you print an instance of a Masterviewcontroller class, you just want to return a static string, wahoo!. The essence of the signals prefix is for the Swift class to prevent namespace collisions in view of Swift's inclusion of this module class name. Now try outputting self again, like this:

(LLDB) P self
The output should look like this:

(LLDB) (Signals.masterviewcontroller) $R 3 = 0x00007fb71fd04080 wahoo!
This format is lldb remembered when it is launched through the app, so make sure you remove it after you practice the P command. The following instructions can be used to remove the LLDB session:

(LLDB) Type summary clear
The input P self will return to the LLDB author's default implementation. Type formatting is a topic that deserves our detailed discussion in later chapters. Because it can help you debug your application in detail without the source code.

Swift vs objective-c Debug environment

Note that there are two debugging environments here that are important when debugging your code: a non-swift debugging environment and a swift debugging environment. By default, when you stop in the OBJECTIVE-C code, LLDB will use non-swift (objective-c debugging environment, when you stop in Swift code, LLDB will use the Swift debugging environment. Sounds logical, doesn't it?
If you stop the debugger outside of a blue breakpoint, LLDB will select the OBJECTIVE-C environment by default. Make sure that the breakpoint you created in the GUI is still there and still available and then build and run the app. When the breakpoint is triggered, enter the following in your LLDB session:

(LLDB) PO [uiapplication sharedapplication]
LLDB will throw an error to you:

Error: <expr>:3:16:error:expected ', ' separator
[UIApplication Sharedapplication]
^ ,
You've stopped in swift code, so you're in the swift environment. But you're trying to run Objective-c's code. That's not going to work. Similar to running swift code in a OBJECTIVE-C environment is not feasible.
You can select a language with the-l option to force the expression to use the OBJECTIVE-C environment. However, because the PO is an abbreviation for Expression-o, you will not be able to use the PO command because of the parameters provided in---this means that you will have to enter expression. In Lldb, enter the following:

(LLDB) Expression-l objc-o--[UIApplication sharedapplication]
Here you have told Lldb to use the OBJC language for objective-c. If necessary, you can also use objc++ for objective-c++.
LLDB will output a reference to the shared application. Try to do the same thing in Swift. Now that you have stopped in the swift environment, try to print out the UIApplication reference in Swift's syntax, like this:

(LLDB) PO uiapplication.shared
You will get the output in the OBJECTIVE-C environment. Enter continue to continue running the application, and then pause the signals item outside the blue breakpoint.
Here, press the UP arrow button to get the swift command you just executed and see what happened:

(LLDB) PO uiapplication.shared
LLDB will throw an error again:

Error:property ' shared ' not found on object of type ' uiapplication '
Remember, stopping outside the blue breakpoint will allow LLDB to enter the OBJECTIVE-C environment. That's why you throw an error when you try to execute the SWIFT code.
You should be aware of what locale the debugger is currently parked in.

User-defined variables

As you've seen before, LLDB automatically maintains local variables when it prints out objects. You can also create your own variables.
Remove all breakpoints from the program build and run the app. Stop the debugger outside the blue breakpoint so the default is the OBJECTIVE-C environment. ENTER here:

(LLDB) PO id test = [nsobject new]
LLDB will execute this code, which will create a new NSObject object and store it in the test variable. Now try to print this object:

(LLDB) PO test
You will get an error similar to the following:

Error:use of undeclared identifier ' test '
This is because you need to let lldb remember this variable and you will have to use the $ modifier.
Try declaring the test variable before adding $:

(LLDB) po id $test = [nsobject new]
(LLDB) PO $test
<NSObject:0x60000001d190>
This variable is created as a Objective-c object. But what happens if you want to access this variable in a swfit environment? Try entering the following:

(LLDB) expression-l Swift-o--$test
So far, it's been good. Now try to execute Swift-style code on this objective-c class.

(LLDB) exppression-l swift-o--$test. Description
You will get an error similar to the following:

Error: <expr>:3:1: Error:use of unresolved identifier ' $test '
$test. Description
^~~~~
If you create a LLDB variable in the OBJECTIVE-C environment and then go to the swift environment, don't expect everything to work as usual. With the loss of time we will see improvements in swift and objective-c through LLDB bridging.
So how do you create a reference to your app and your real environment in LLDB? You can put a reference in an object and execute arbitrary code of your choice. To see the actual effect, you can create a symbolic breakpoint in Masterviewcontroller's parent view controller, Mastercontainerviewcontroller uses a Xcode symbol breakpoint in the Viewdidload method.
In the Symbol section, enter:

Signals.MasterContainerViewController.viewDidLoad () ()
Note the space between the parameter and the return value, or the breakpoint is not in effect.
Your breakpoint should look something like this:

Page62image17352.png

Building and running App.xcode will now have breakpoints in Mastercontainerviewcontroller.viewdidload (). From there, type the following:

(LLDB) P self
Since this is the first parameter that you execute in the Swift debugging environment, LLDB will create a variable $r0. Enter continue in LLDB to continue executing the program.
Because execution moves to a larger and better running loop event and stays in the Viewdidload (), you cannot now refer to the Mastercontainerviewcontroller instance by using self.
But you still have $r0 this variable! Now you can apply Mastercontainerviewcontroller and even execute arbitrary code to help you debug.
Manually pause the app in the debugger, and then type the following:

(LLDB) PO $R 0.title
Unfortunately, you will get:

Error:use of undeclared identifier ' $R 0 '
You parked the debugger outside the Blue breakpoint! Remember, the LLDB default is the OBJECTIVE-C environment. You need to use the-l option to enter the SWIFT environment:

(LLDB) expression-l Swift--$R 0.title
This will output the following:

(String?) $R 1 = "quarterback"
Of course, this is the title of the view controller that is displayed on the navigation bar.
Now, enter the following:

(LLDB) expression-l Swift--$R 0.title = "!!!!!"
Enter continue to continue running the app.

Page64image1064.png

As you see, you can easily manipulate the variables you want to manipulate.
In addition, you can create a breakpoint in the code, execute the code, and pause when the breakpoint is triggered. This is useful if you are debugging something and want to execute a function with a specific input to see how it executes.
For example, you still have a symbolic breakpoint in viewdidload (), so try executing that method to check the code. Pause the execution of the program, and then enter:
(LLDB) expression-l swift-o--$R 0.viewDidLoad ()
Nothing has happened. No breakpoint is triggered. How did this happen? In fact, Mastercontainerviewcontroller has implemented this method, but by default, LLDB ignores any breakpoints when executing a command. You can durable this feature with the-I option.
Enter the following in the LLDB console:

(LLDB) expression-l Swift-o-I 0--$R 0.viewDidLoad ()
Now Lldb will stop at the symbol breakpoint you created earlier. This strategy is a great way to test your method logic. For example, you can implement test-driven debugging by giving a different argument to a function to see how it handles different inputs.

Type formatting

A good option in LLDB is that you can perform the output format of the base data type. This makes LLDB a learning compiler is a great tool for formatting basic C types. This is what you must know when you learn the chapters behind the assembly.
Enter the following command in the LLDB console:

(LLDB) Expression-g X--10
The-G option tells LLDB what format you want to output. G represents the GDB format. You may not know that GDB is the debugger of the previous generation of LLDB. In this case, the x used represents the hexadecimal format.
You will see the following output:

(int) $ = 0x0000000a
This is the hexadecimal output of the decimal 10.
LLDB also has a shorter syntax that specifies the output format. Enter the following command:

(LLDB) p/x 10
You will see the same output as before. But this time you are typing less!
This is useful for learning the representation of a C data type. For example, how do you represent the number 10 in binary?

(LLDB) p/t 10
/t indicates the binary form. You will see how decimal 10 is represented in binary notation.
How is negative 10 expressed?

(LLDB) p/t-10
A two-part 10 binary 10. Clear enough!
Floating point 10.0 How to use binary representation?

(LLDB) p/t 10.0
This may come in handy!
What is the ASCII value of the character d?

(LLDB) p/d ' d '
So d is the 68!/d specified is the decimal form.
Finally, what are the abbreviations that are hidden after integers?

(LLDB) P/C 1430672467
/C indicates the character form. It converts the number to binary, every 8 bits as a whole (1 bytes), and then converts each byte into ASCII characters. Here, it has a 4 character code STFU.
The following is a list of all output formats (refer to: [Https://sourceware.org/gdb/onlinedocs/gdb/Output-Formats.html] (https://sourceware.org/gdb/ onlinedocs/gdb/output-formats.html)):
? X:hexadecimal
? D:decimal
? u:unsigned Decimal
? O:octal
? T:binary
? A:address
? C:CHARACTER constant
? F:float
? S:string
If this format is not enough for you, you can use the LLDB extension format, but you will not be able to use the GDB format syntax.
The LLDB format can be used as follows:

(LLDB) expression-f Y--1430672467
This will output the following:

(int) $ A = STFU
This explains the previous FOURCC code!
LLDB has the following format (refer to varformats.html "rel=" nofollow ">http://lldb.llvm.org/
varformats.html):
? B:boolean
? B:binary
? Y:bytes
? Y:bytes with ASCII
? C:character
? c:printable character
? F:complex float
? S:c-string
? I:decimal
? E:enumeration
? X:hex
? F:float
? O:octal
? O:ostype
? U:unicode16
? u:unsigned Decimal
? P:pointer

Why do we have to learn this?

Try to see other expression options by executing help expression and see what you can do with them.

Advanced+apple+debugging (5)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.