Advanced+apple+debugging (7)

Source: Internet
Author: User
Tags stack trace uikit

Now you have a solid foundation for debugging. You can find and attach to the program you are interested in, efficiently create regular expression breakpoints to cover a broad range, navigate the stack frame and use the expression command to view the variables.
However, it is time to look at the code of interest with a powerful lldb. In this chapter, you will learn more about the image command.
The image command is the alias of the target modules command. Image is specifically used to query the module (modules) related information; Rather, the code is loaded into a thread to execute. The module can contain many things, including the main execution code, the framework, or the plug-in. However, most of the modules come from dynamic libraries. For example, iOS Uikit and MacOS AppKit are common dynamic libraries.
The image command is useful for querying information about any private framework, and for classes and methods that are not exposed in the header file.

Wait a minute... Module?

You will continue to use the signals project. Open the project and build and run it with the IPhone7 simulator.
Pause the debugger and enter the following command in the LLDB console:

(LLDB) Image list
This command will list all the modules that are currently loaded. You will see a lot! The beginning of this list should look like this:

[0] 13a9466a-2576-3abb-ad9d-d6bc16439b8f 0x00000001013aa000/usr/lib/
Dyld
[1] 493d07df-3f9f-30e0-96ef-4a398e59ec4a 0x000000010118e000/
applications/xcode.app/contents/developer/platforms/
iphonesimulator.platform/developer/sdks/iphonesimulator.sdk/usr/lib/
Dyld_sim
[2] 4969a6db-ce85-3051-9fb2-7d7b2424f235 0x000000010115c000/users/
derekselander/library/developer/xcode/deriveddata/signals-
bqrjxlceauwfuihjesxmgfodimef/build/products/debug-iphonesimulator/
Signals.app/signals
The first two are dynamic loaders: One is System-based and the other is specifically added to the simulator. These are necessary codes that allow your program to load a dynamic library into memory for program execution. The third is the main binary file of the app, signals.
But there's more to this list! You can just filter out what you're interested in. Enter the following command in LLDB:

(lldb) image list Foundation
You will get output similar to the following:

[0] 4212f72c-2a19-323a-84a3-91feaba7f900 0x0000000101435000/
applications/xcode.app/contents/developer/platforms/
iphonesimulator.platform/developer/sdks/iphonesimulator.sdk//system/
Library/frameworks/foundation.framework/foundation
This is useful for displaying only the information that you want to see in the module.
Let's take a look at these outputs. Here are some interesting things to do:

The first thing to print out is the module's UUID (4212f72c-2a19-323a-84a3-91feaba7f900). This UUID is important for capturing symbolic information and uniquely marking the foundation module.
2. Immediately after the UUID is the load address (0x0000000101435000). This indicates the address of the foundation module after it is loaded into the signals executable process space.
3. Finally, you will get the full path of the binary file for this module in the local.
Let's go deep into another common module, Uikit. Enter the following command in LLDB:
(lldb) Image dump Symtab uikit-s address
This command extracts all the available symbol table information from the Uikit. The output of this command is arranged in the order in which the function is implemented in Uikit, which is the function of the-s address.
There's a lot of useful information here, but you can't read all the content. You need an efficient way to find the code that interests you in Uikit.
The image Lookup command can perfectly filter out all the data. Enter the following command:

(lldb) Image Lookup-n "-[uiviewcontroller viewdidload]"
This extracts only the content related to the Viewdidload instance method of Uiviewcontroller. You'll see the name of the symbol associated with this method, and the code that implements that method in the Uikit framework.
This is good and full, but typing in the text is a bit tedious and this only extracts the specified instance.
But that's exactly what regular expressions do. The-r option will allow you to use regular expression queries. Enter the following command in LLDB:

(lldb) Image Lookup-rn Uiviewcontroller
This instruction will not only extract all the Uiviewcontroller methods, And will lose a method like Uiviewcontrollerbuiltintransitionviewanimator that contains uiviewcontroller words. You can also use this expression to output only the Uiviewcontroller method. Enter in Lldb The contents of the polygon:

(lldb) Image lookup-rn ' [Uiviewcontroller\ '
Of course it's good, but how do you deal with classification? They are Uiviewcontroller (CategoryName) Form. Try searching all categories of Uiviewcontroller:

(lldb) Image Lookup-rn ' [Uiviewcontroller (\w+) \ '
Now the instructions are getting complicated. The backslash at the beginning indicates that you want to use [the literal meaning, then the Uiviewcontroller. The last is (literally, then one or more literal numbers or underscore characters (meaning w+).), followed by a space.
The knowledge of regular expressions will help your creative queries load the public or private code of any module into a binary file.
This will not only print out the public and private methods, but will also give the method of the parent class covered by the Uiviewcontroller class.

Capture Code

Whether you're capturing public code or private code, sometimes you just want to figure out how the compiler generates a function name for a particular function. You've simply used the image above The lookup command found the Uiviewcontroller method. You also found the setters and Getter methods for swift properties in the fourth chapter.
However, there are a number of examples here that can help you better understand how the code is generated and how to set breakpoints where you are interested. A special example is the method declaration that looks at the OBJECTIVE-C code block.
So what's the best way to search for OBJECTIVE-C code block method declarations? Given that you don't have any clues to find out where the code block is named, a good way to do this is to create a breakpoint inside the code block and start checking there.
Open UNIXSIGNALHANDLER.M, and then find the Singleton method Sharedhandler. Find the following code in this function:

Dispatch_once (&oncetoken, ^{
Sharedsignalhandler = [[Unixsignalhandler alloc] initprivate];
});
Set a breakpoint in Xcode at the beginning of the Sharedsignalhandler. Then build and run. Xcode will now stop where you set breakpoints. View the top of the stack frame in the Debug window.

Page82image1080.png

You can find the name of your function in Xcode. In the debug bar you will see the stack trace and you can see frame 0. It's a little hard to copy and paste. We can replace it with the following command:

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

Frame #0:0x0000000100cb20a0 Commons '34+[unixsignalhandler
Sharedhandler]_block_invoke ((NULL) =0x0000000100cb7210) + at
unixsignalhandler.m:68
As you can see, the full name of the function is
34+[unixsignalhandler sharedhandler]_block_invoke.
There is a very interesting part of the function name, _block_invoke. This is probably the flag that helps you identify a block of code in OBJECTIVE-C. Enter the following command in LLDB:

(lldb) Image Lookup-rn _block_invoke
This command searches the keyword _block_invoke with regular expressions. It will handle the content containing _block_invoke as a wildcard character for _block_invoke.
But wait! Actually you print out all the OBJECTIVE-C code loaded into the program quickly. This search contains Uikit,foundation,iphonesimulator All code blocks in the SDK and so on. You should confine your search to the signals module. Enter the following command in LLDB:

(lldb) Image Lookup-rn _block_invoke signals
There's nothing to print out. What happened? Open the File Inspector panel on the right side of Xcode. or press? + Option + 1.

Page83image8096.png

If you see where unixsignalhandler.m is compiled, you will find that it is actually compiled into the Commons framework. So, re-search and search the Commons module for the OBJECTIVE-C code block. Enter the following command in the LLDB:
(lldb) Image Lookup-rn _block_invoke Commons
Finally, you'll see some output.
You will now see the output of all OBJECTIVE-C code blocks found in the Commons framework.
Now, let's create a breakpoint on a subset of the code block you find.
Enter the following command in the LLDB:

(LLDB) RB appendsignal. _block_invoke-s Commons
Note: There are some subtle differences between searching for code in a module and searching for a module in code. Use the command above to make an example. When you want to search Commons for all the code blocks in the framework, you should use image lookup -rn _block_invoke Commons . When you want to Commons set a breakpoint for a block of code in a frame, you should use the ' RB Appendsignal.
Block_invoke-s .注意 The space following the Commons-s ' argument.
This command sets a breakpoint at the code block of all appendsignal methods.
Enter continue in LLDB to continue running the program. Jump into the terminal and enter the following command:

Pkill-sigio Signals
The signal you send to the program will be processed. However, your regular breakpoint will be triggered before the signal is updated to TableView.
The first breakpoint that is triggered should be:

__38-[unixsignalhandler Appendsignal:sig:]_block_invoke
Continue running the debugger and skip this step.
Next you will trigger another breakpoint:

__38-[unixsignalhandler appendsignal:sig:]_block_invoke_2
This function name has an interesting place compared to the first function name; Notice the number 2. The compiler uses the <function_name>_block_invoke format to define the blocks called <FUNCTION_NAME>. However, when there is not only one block in the function, A number is added to the tail.
As you learned in the previous section, the frame variable command will print out all known instance variables in the specified function. Now try executing this command to see a reference to this block. Enter the following command:

(LLDB) Frame variable
The output should look something like this:

(__block_literal_5 ) = 0x0000608000275e80
(int) sig = <read Memory from 0x41 failed (0 of 4 bytes read) >
(siginfo_t
) Siginfo = <read Memory from 0x39 failed (0 of 8 bytes
Read) >
(Unixsignalhandler *const) self = <read memory from 0x31 failed (0 of 8
Bytes read) >
These read memory failures look unfriendly! Step over once, you can use Xcode or you can enter next in Lldb. Next, the frame variable is executed again in LLDB.
This time you will see output similar to the following:

(__block_literal_5 ) = 0x0000608000275e80
(int) sig = 23
(siginfo_t
) Siginfo = 0x00007fff587525e8
(Unixsignalhandler ) self = 0x000061800007d440
(Unixsignal
) Unixsignal = 0x000000010bd9eebe
You need to step over the declaration of the function so that the code block can perform some initialization logic to set the function. A function declaration is a compilation-related content that you will learn in the second part.

This is actually very interesting. First you see an object referencing this block of code, which is the place to be called. Here is __block_literal_5. Then there are the sig and Siginfo parameters that are passed to the Objective-c method that calls this block of code. How are these uploaded into the code block?
Well, when a block of code is created, the compiler is smart enough to figure out what parameters it will use. Then it creates a function and takes these parameters in. When the code is called, the function is called and the relevant parameters are put in.
Enter the following command in the LLDB:

(lldb) Image dump Symfile Commons
You'll see a lot of output. Use? + F Search by compiler for block type declaration: __block_literal_5. One of the more important things to remind you is that the type you get when LLVM is updated may be slightly different, so make sure you get the correct type from the output of the frame variable command.
There are several different scenarios when searching for a block type declaration. Searches the declaration of a struct that matches the line number of a block. For example, the 123-line breakpoint You originally created can also be searched in the declaration. Eventually you will get some output similar to the following:

0X7FEFE24BCF90:TYPE{0X100000E06}, name = "block_literal_5", size =
Decl = unixsignalhandler.m:123, Compiler_type = 0x00007fefd86d0410
struct block_literal_5 {
void *
Isa;
int flags;
int
reserved;
void (funcptr) ();
block_descriptor_withcopydispose
__descriptor;
Unixsignalhandler const Self;
siginfo_t
Siginfo;
int sig;
}
This is the object that defines the code block!
As you can see, this is like having a header file that tells you how to freely find what you want in the memory of your code block.
you can easily print out all of the variables referenced by this block as long as you provide the block_literal_5 in-memory application you find. Get the variable information for the stack frame again by entering the following command:

(LLDB) Frame variable
Next, locate the memory address of the __block_literal_5 object and print it in the following way:

(LLDB) PO ((__block_literal_5 *) 0x0000618000070200)
You will see output similar to the following:

<nsmallocblock: 0x0000618000070200>
If your output is not the same as above, make sure that the block_literal_5 memory address you use is the address of your block and that the memory address will be slightly different every time you run it.
Now you can query
the memory structure of block_literal_5. In the LLDB, enter:

(LLDB) p/x ((block_literal_5 *) 0x0000618000070200), funcptr
This command extracts the position of this block's function pointer. The output should look something like this:

(Void (*) ()) $ = 0x000000010756d8a0 (Commons ' __38-[unixsignalhandler appendsignal:sig:]_block_invoke_2 at unixsignalhandler.m:123)
The block's function pointer points to the function at runtime when the block is called. They are the same address now when they are executed! You can enter the following command to confirm the address of the function pointer printed with your last command, replacing the following address:

(lldb) Image Lookup-a 0x000000010756d8a0
This is followed by the-A (address) option behind the image lookup to see the symbols associated with the given address. Returning to the block struct member variable, you can still print out all the parameters passed to the block.
Enter the following command again to replace the address below with your block's address:

(LLDB) PO ((__block_literal_5 *) 0x0000618000070200)->sig
This will output the ordinal number of the signal as the parameter of the block's parent function. There is also a unixsignalhandler reference in the member variable of the struct called Self.
Why would that be? Take a look at this block and capture the following line of code:

[(Nsmutablearray *) self.signals addobject:unixsignal];
It is a reference to the self that the block captures., which is used to find the offset of the signals array. So block needs to know what self is. It's cool, isn't it?
Using the image Dump Symfile command together with the module is a good way to learn about an unknown data type. It's also a great tool for learning how compilers generate code from your source.
In addition, you can check how blocks holds references to external blocks-a very useful tool when a running loop occurs.

Spy

You already know how to check the instance variables of a private class in a static way, but leaving the block's memory address alone is too much torture. Try to print it out and view it in a dynamic way. Enter the following to replace the following address with your block's address:

PO 0x0000618000070200
LLDB will extract a class that indicates that he is a objective-c class:

<nsmallocblock: 0x618000070200>
This is interesting. This is a Nsmallocblock class. Now that you've learned how to extract the common and private methods of a class, it's time to look at the nsmallocblock implementation. Enter in LLDB:

(lldb) Image Lookup-rn Nsmallocblock
Nothing has happened. This means that nsmallocblock does not overwrite any methods of its parent class. Enter the following command to view the parent class of the Nsmallocblock :

(LLDB) PO [nsmallocblock Superclass]
This time produces a similar name called the __nsmallocblock class-notice the missing underline at the tail. What information can you find in this class? Does this class implement or override some of the methods? Enter the following command in the LLDB:

(lldb) Image Lookup-rn Nsmallocblock
The method extracted using this command indicates
that Nsmallocblock is responsible for memory management because it implements methods such as retain and release. What is the parent of __nsmallocblock? Enter the following command in LLDB:

(LLDB) PO [__nsmallocblock Superclass]
You'll get another class of nsblock. What does this class do? What else does it do? Enter the following command in LLDB:

(lldb) Image lookup-rn ' nsblock\ '
Note the last backslash and space. Remember-this ensures that no other class can match the query, and if it does not, other classes that contain the Nsblock name will be matched. Some of the methods will be output. There is a method called Invoke that looks extremely interesting:

ADDRESS:COREFOUNDATION[0X000000000018FD80] (corefoundation. TEXT. Text

    • 1629760)
      Summary:corefoundation '-[nsblock invoke]
      Now you will be trying to invoke this method in block. However, you do not want the reference to hold this block to disappear at release, release reduces its retaincount, so the block has the risk of being released.
      There is a very simple way to keep this block-only need retain! Enter the following command to replace the address in the following code with the address of your block:

(LLDB) po id $block = (ID) 0x0000618000070200
(LLDB) PO [$block retain]
(LLDB) PO [$block Invoke]
In the last line you will see the following output:

Appending new Signal:sigio
Nil
This indicates that your block has been called once. Clean and beautiful!
The reason it works is that all settings are ready when the block is called, because you are now properly parked at the start of the block.
This type of approach to viewing public and private classes, and then viewing the methods they implement, is a good way to learn the underlying implementation of the program. You will use the same procedure to find the method and analyze the assembly code when the methods are executed, giving you a source code that is very close to the Origin method.

Debugging Private Methods

The image Lookup command is beautiful in finding private methods and public methods that will run through your entire Apple development career.
However, there are some hidden methods that are useful when debugging your own code. For example, a method that begins with _ usually indicates that it is a private (and potentially important) method.
Let's search all the modules for all the objective-c that contain the underscore character and contain the description keyword.
Build and run the project again. When the breakpoint at the Sharedhandler is triggered, enter the following in the LLDB:

(lldb) Image lookup-rn (? i) \ \w+description]
This expression is a bit complicated, so let's just parse it.
This expression searches for spaces (preceded by one) followed by underscores, followed by one or more letters or numbers followed by the description word, followed by the character's method.
There is an interesting character set (? i) where the regular expression begins. This indicates a case-insensitive search.
This expression has a backslash prefix character. This indicates that you want to use the literal character instead of the word regular in the expression. This is called ' escaping '. For example, in a regular expression, the] character has a specific meaning, so you need to use it.
The \w character in the regular expression above is an exception. The search content It specifies is an underscore, a letter or a number (for example
, A-Z, A-Z, 0-9).
If you are reading this line of code and still do not understand the place, it is highly recommended that you look at https://docs.python.org/2/library/re.html in-depth understanding of the regular expression query. Go back. Regular expressions can only become more complex.
Carefully review the output of the image lookup. Finding the best answer is tedious, so make sure you look at all the output.
You may notice several interesting methods in the classification ivardescription of a nsobject in several uikit.
Try to print only the contents of this category. Enter the following in LLDB:

(lldb) Image Lookup-rn NSObject (ivardescription)
The console will output all of the methods implemented by this classification. There are several interesting ways to print out these methods:

_ivardescription
_propertydescription
_methoddescription
Because this is the classification of NSObject, all nsobject subclasses can invoke these methods. This makes everything more perfect, of course!
Try to use these methods on UIApplication. Enter the following command in the LLDB:

(LLDB) PO [[uiapplication sharedapplication] _ivardescription]
Because UIApplication holds many instance variables, you get a lot of output. Look closely and find what you are interested in. Don't go back to reading until you find something interesting. It's important!
After a closer look at the output, you will see a private class Uistatusbar referenced. Uistatusbar's Objective-c setter method There, I hear you ask? Let's have a look! Enter the following in the LLDB:

(lldb) Image Lookup-rn ' [uistatusbar\ set '
This extracts all the available setter methods for Uistatusbar. In addition to the methods declared and overridden in Uistatusbar, you can access all the methods that are available to its parent class. See if Uistatusbar is a subclass of UIView.

(LLDB) PO (BOOL) [[Uistatusbar class] Issubclassofclass:[uiview class]
Tip, you can reuse the superclass method to climb up this inheritance tree. As you can see, Uistatusbar looks like a subclass of UIView, so backgroundcolor attributes are available in this class. Let's practice a bit.
First, enter the following instruction in the LLDB:

(LLDB) PO [[uiapplication sharedapplication] StatusBar]
You will see some output similar to the following;

<UIStatusBar:0x7fb8d400d200; frame = (0 0; 375 20); opaque = NO;
AutoResize = W+BM; Layer = <CALayer:0x61800003aec0>>
Print out the Uistatusbar instance of your app. Next, use the address of the status bar and output the following command in LLDB:

(LLDB) PO [0x7fb8d400d200 setbackgroundcolor:[uicolor Purplecolor]
In Lldb, delete all the breakpoints you created earlier:

(lldb) Breakpoint Delete
Keep running the app and see the world you created with your fingertips!

Page91image1048.png
It's not the most beautiful app yet, but at least you've found a private way to do something fun with it!

Why do we have to learn this?

As a challenge, try using the image Lookup command to find all the closures in the signals module. Once you have done that, create a breakpoint in each swift closure of each signals module. If it's too easy for you, try to find code that can stop at the Didset/willset property, or do some/try/catch ' blocks.
It is also possible to find more private methods hidden in foundation or Uikit. Learn to be happy!

Advanced+apple+debugging (7)

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.