Advanced+apple+debugging (6)

Source: Internet
Author: User
Tags stack trace uikit

You've learned how to create breakpoints, how to print and modify values, and how to execute code when the debugger stops. But you haven't learned how to switch and check the data freely in the debugger. It's time to learn!
In this chapter, you will learn how to switch freely between functions and functions of the debugger when LLDB is paused.
This is an important skill because you often want to check the values inside or outside the code snippet as the value changes.

Stack 101

When the computer executes the application, it stores the values in the stack and heap. Both have their own merits. As a senior debugger, you need to understand how they work. Now, let's take a look at the stack briefly.
You may have seen a lot of knowledge about stacks in computer-related knowledge. In any case, it needs to have a basic understanding of how a thread tracks code and variables as it executes. This knowledge allows you to conveniently use LLDB to wander through the code.
The stack is LIFO (Last-in-first-out) with a last-in-first-out queue to store a reference to the code you are currently executing. The order of LIFO means that whatever you end up with will be removed first. Think of the stack as a plate. Add a plate to the top and it will be taken first by you.
The stack pointer points to the top of the current stack. In the plate analogy, the stack pointer points to the top of the plate, telling you where to pick the plate next time, or where to put the plate next time.

Page69image15224.png

In this chart, the highest address is displayed at the top (0xFFFFFFFF) and the lower address shown at the bottom (0x00000000) shows that the stack is growing downward.
Some charts have a high address at the bottom that matches the plate analogy, and the stack is growing downward. However, I believe that any stack shown on the chart should be grown from a high address, otherwise we will have some headaches when we discuss the offset of the stack pointer.
You'll see some more in-depth questions about stack pointers and registers in the 12th chapter, "Assembly and the Stack," but in this chapter you'll explore several different ways to step through the code in the stack.

Check the frame of the stack

You will still use the signals project in this chapter.
In this chapter you will use a little of the knowledge of the assembly. Don't be afraid! But make sure that you're using the iphone 7 simulator in this chapter because the assembler code may be a little different if it's on iOS. This is because the real machine uses the ARM architecture, The simulator uses your Mac's local instruction set x86_64.
Open the signals project in Xcode. Next, add a symbol breakpoint at the function name below. Make sure that a space is added to the function label or the breakpoint will not recognize the write symbol.

Signals.MasterViewController.viewWillAppear (Swift.bool) ()
This line of code creates a symbolic breakpoint at the Masterviewcontroller ' s Viewwillappear (_:) method.
Page70image17024.png

Build and run the program. As expected, the program will stop at Masterviewcontroller's Viewwillappear (_:) method. Next, locate the stack trace panel on the left side of Xcode. If you haven't seen it, click Debug on the left panel Navigator or press Command + 6 shortcut key.
Make sure that the three buttons in the bottom-right corner are disabled. These buttons are used to help you filter those functions that only appear in your source code. Since you have to learn the public codes and learn the private code, you should always keep these buttons disabled so that you can see the full information of the stack trace.
Page71image1232.png

In the debug navigation panel, the stack trace panel will appear and display a list of stack frames, the first of which is the Viewwillappear (_:) function. followed by a swift/objective-c bridging method, @objc Masterviewcontroller.viewwillappear (Bool)-> ():. This method is automatically generated so that objective-c can go inside the swift code.
Behind this, there are some uikit objective-c code stack frames. A little bit further down, you'll see some C + + code that belongs to Coreanimation. A little deeper, You will see a set of methods that are included in the cfrunloop that belong to Corefoundation. Finally, the main function to do the end (yes, the SWIFT program still has the main function, but it is hidden).
The information you see in Xcode is a sample of what lldb can tell you. Now let's take a look.
Enter the following in the LLDB console:
(LLDB) Thread BackTrace
You can also simply enter BT, or you can achieve the same effect. They are actually two different commands, and you can also check their differences with your trusty friend Help.
After executing the above command, you will see a stack trace that is consistent with the debug bar of your Xcode.
Enter the following instruction in the LLDB console:

(LLDB) Frame info
You will get some output similar to the following:

Frame #0:0x00000001075d0ae0
Signals ' Masterviewcontroller.viewwillappear (animated=<invalid> (0xd1),
SELF=0X00007FFF5862DAC0) at masterviewcontroller.swift:47
As you can see, this output is consistent with what you see in the Debug bar. So that's why you see pretty important things in the debug bar? OK, use the LLDB console to give you the granularity to control the information you want to see. In addition, The custom lldb scripts you make make these commands very useful. We also know where Xcode gets the information, right?
Let's go back to the debug bar and see, you'll see some numbers incrementing from 0 in the call stack. These numbers can help you remember the stack frame you're looking at. Enter the following command to select a stack:

(LLDB) Frame Select 1
Xcode will be transferred to the @objc bridge method, which is numbered 1 in the stack.
If you're using a simulator instead of a real machine, you'll get some compilations that look similar to the following:

Page72image14976.png
Watch the Green Line in the assembly. The line in front of the right is the CALLQ directive, which represents the breakpoint you set before executing Viewwillappear (_:).

Step

In mastering the LLDB, the most important three navigation actions you can do when the program is paused are stepping in the program. Through LLDB, you can step through the code and step into and out.
Each of them allows you to continue executing the code of the program, but in a small whole you can detect how the program's code executes.

Step Over

Step over allows you to execute the next code statement (usually the next line) where the debugger is currently paused. This means that if the current statement calls another function, LLDB will continue to run until the function finishes and returns.
Let me actually take a look.
Enter the following code in the LLDB console:

(LLDB) Run
This restarts the signals program with Xcode without recompiling the project. Xcode stops at the symbol breakpoint you created earlier.
Next, enter the following:

(LLDB) Next
The debugger moves a line of code forward. This is step over. Simple, but useful!

Entered

Stepping means that if the next statement calls a function, the debugger moves to the beginning of the function and pauses again.
Let's actually take a look.
Start the breakpoint program again from LLDB:

(LLDB) Run
Next Enter:

(LLDB) Step
Unfortunately, it is. The program has stepped in because this line of code contains a function call.
In this case, LLDB is actually more like "step over" instead of "step into." This is because LLDB, by default, ignores stepping a function if there is no debug symbol in the function. Here, the function in the Uikit is called, where you do not have the debug symbol.
But here's another way to set lldb behavior when stepping into a function that doesn't have a debug symbol. Execute the following command in LLDB and see what the directive does:

(LLDB) Settings show Target.process.thread.step-in-avoid-nodebug
If true, stepping into these instances is actually performed as a step. You can also change this setting (this is what you do later), or tell the debugger to ignore this setting (this is what you do now).
Enter the following command in the LLDB console:

(LLDB) step-a0
This instruction tells Lldb to perform a step-up operation whether or not there are debug symbols.

Step out

Stepping out means that the function will continue to execute and then pause when it returns. From the stack's point of view, continue execution until the stack frame is ejected.
Run the signals project again, this time with a quick look at the stack trace when the debugger pauses. Next, enter the following command in LLDB:

(LLDB) Finish
You'll notice that the debugger is now paused on a stack-traced function. Try to execute this command a few more times. Remember, when you simply press ENTER, LLDB executes the code you entered last time. The finish command notifies Lldb to step out of the current function. A bit more patience with a stack frame next to one in the left panel.

Stepping in Xcode

Although you already know a lot about using console-controlled subdivision instructions, Xcode has provided you with these options as buttons on the LLDB console. These buttons appear when a program is running.

Page74image17480.png

Their order is stepping over, stepping in and stepping over.
Finally, step over and walk in there are more features. You can manually control the execution of different threads by pressing control and SHIFT while clicking on these buttons.
This is done by stepping over the currently paused thread of the debugger while the rest of the threads are still paused. This is a very useful technique when you are debugging some hard-to-debug concurrency code like a network request or GCD code.
Of course lldb do the same thing in the console by using the--run-mode option, or simply follow the appropriate options with-M.
Detecting data in a stack

A very interesting command in the frame command is the frame variable subcommand. This command will fetch the debug symbol information found in the header file you executed and extract the information from the specified stack frame. Thanks for debugging information, frame The variable command simply tells you the scope of all variables in your function and any global variables in your program with the appropriate options.
Run the signals project again and make sure that you have triggered the breakpoint in Viewwillappear (_:). You can then find the top of the stack by tapping the top of the Xcode debug bar or by entering frame Select 0 in the console.
Next, enter the following:

(LLDB) Frame variable
You will see output similar to the following:

(Bool) animated = False
(signals.masterviewcontroller) Self = 0x00007fb3d160aad0 {
Uikit.uitableviewcontroller = {
[email protected] = <extracting data from value failed>
_tableviewstyle = 0
_keyboardsupport = Nil
_staticdatasource = Nil
_filtereddatasource = 0x000061800005f0b0
_filtereddatatype = 0
}
Detailviewcontroller = Nil
}
This extracts the variables and code that are available for the current stack frame. If possible, he will also extract all instance variables from the current available variables, both public and private.
If you are an observant reader, you may notice that the output of frame variable is consistent with the contents of the variable view in the left panel of the console window.
If you don't see the variable view, you can expand the variable view by tapping the button in the left pane of the right-hand corner of Xcode. You can compare the output of frame variable to the contents of a variable view. You'll notice that frame variable provides you with more information about variables than using the variable view of Apple's private API.
Page76image11200.png

Next, enter the following:
(LLDB) frame variable-f Self
This is a simple way to view all the available private variables for Masterviewcontroller. It uses the-f option, which represents the flat.
This would keep the 0 indent and just print out the information about self in this would keep the indentation to 0.
You will get something similar to the following output:

Self = 0X00007FFF5540EB40
Self =
Self =
Self =
Self = {}
Self.detailviewcontroller = 0x00007fc728816e00
Self.detailViewController.some =
Self.detailViewController.some =
Self.detailViewController.some = {}
Self.detailViewController.some.signal = 0x00007fc728509de0
As you can see, this is an attractive way to deal with Apple's frame.

Why are we learning this?

In this chapter you learned to browse stack frames and their content. You also learned how to use stepping, step out, and step over to switch in the code.
The thread command has many options that you have not found. Try the help thread command to get to know them and see if you can learn some cool commands.
Take a moment to look at the thread until, the thread jump, and the thread return command. You'll use them later, and you can now see what they do.

Advanced+apple+debugging (6)

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.