I have an API wrapper, which is logging all URLs requested by URLSession. I need to breakpoint at specific URL call, for a possibility to easily find a place in UI, from where API call is initialized.
There is no problem to stop at any URLSession dataTask. I'm doing this with lldb command br set -F '-[__NSCFURLSessionTask resume]':
Then the program stops:
So, the question:
Is there any way to obtain URL from context on the screenshot above, match it with provided URL, and continue if URLs doesn't match?
Or maybe some other ideas (lldb python script for example)?
Let's start with figuring out the instance pointer value at the breakpoint.
Since an Objective-C selector is being sent inside the Swift .resume() call we must fallback to the actual implementation of:
objc_msgSend(receiver, selector, arg1, arg2, ...)
Without going into too much details we rely on MacOS/iOS ABI specifying which cpu registers are used for passing arguments. We're interested specifically in the 1st argument to find the receiver instance pointer value.
Private class __NSCFURLSessionTask happens to have following method:
- (NSURL*)currentRequest_URL;
#JimIngham pointed out an amazing shortcut to accomplish this with universal argument synonyms being $arg1 $arg2 ... in lldb. (notice that selector's arg1 arg2 would be lldb's $arg3 $arg4 respectively) This simplifies it to:
po [$arg1 currentRequest_URL]
https://www.google.com
In case of x86 32bit Simulator which would correspond to devices lower than iPhone 5S you would use instead:
(lldb) x/x $esp+4
0xbff9e050: 0x7874dd70
(lldb) po [0x7874dd70 currentRequest_URL]
https://www.google.com
Related
I'm new at lldb debugging and hope you can help me :)
basically I want to express some functions as e.g.
(lldb) expr device.up()
(lldb) expr device.down()
to watch the changing behaviour of the UI at the Simulator. (lot of animations..)
I can achieve this when i set a breakpoint at my UIViewController, and then type the commands. But after pressing start again it waits for a delegate and i only can pause it manually to get the debug console again. And there comes my question: Is it possible, when I pause the application, to debug at the same environment (of the specific, activ UIViewController) as before where I set the breakpoint?
I'm glad for your tips and lldb experience and pls write if my question is unclear! :)
If the stack frame you were evaluating expression in is still on the stack somewhere, you can select that thread & frame:
(lldb) thread 5
(lldb) frame 7
then run the expression. If the frame is no longer on the stack, you can't do that. If the expression you were evaluating refer to local variables, you won't be able to recover them, the memory they occupied is gone.
But you can store values away in lldb convenience variables. For instance, if you were using C++ and "device" was a reference to an object of type SomeType, you could do:
(lldb) expr SomeType *$reference_to_device = &device
Then later you could do:
(lldb) expr $reference_to_device->up()
Capturing the address isn't going to keep the object alive, however, something actually in your program will have to do that.
XCode 7.2.1
iPad Retina iOS 9.2 Simulator
I have several breakpoints set in a particular class in an XCode project.
Everything I discuss below takes place in this one class file.
I set the breakpoints on -(int16_t)areaNbr by clicking in the gutter, and set no conditions or anything on them. I confirmed they existed as far as LLDB is concerned by running breakpoint list from the LLDB prompt.
The project scheme is set to build for debugging, not release.
I run the project in the simulator, and stop at a breakpoint in a different method than the one in question, at which time I want to go to the LLDB prompt and call po [self areaNbr] and step through areaNbr.
Please note, as this may be quite relevant, I have NO code in the project itself that calls
-(int16_t)areaNbr
Now, I CAN get this to stop at my breakpoints on -(int16_t)areaNbr if I add some code to the project that calls the method.
For example, if I add something like NSLog(#"... %d", [self areaNbr])
I know the issue has nothing to do with compiling away the method simply because nothing calls it, because if that were true, then my call to po [self areaNbr] wouldn't be spitting out the result to the debugger window as pictured below. So the method is being compiled, and certainly recognized as existing by the debugger for execution purposes... just not for stepping purposes.
FYI, [self area] is returning "Area01"
Calling breakpoint list in LLDB returns the following
By default, lldb does not stop at breakpoints in hand-called code. The majority of folks use expr & expr -O -- i.e. po to print values & objects and were annoyed if they stopped at breakpoints they had set for other purposes.
However, it is easy to control this behavior, just use:
(lldb) expr -i 0 -- [self areaNbr]
Then you will stop at your breakpoint.
In this example, I left out the -O which is the object printing part, since if you just want to call this method, you likely don't care about calling description on the result after the expression is evaluated.
You can see all the options for expression evaluation by doing:
(lldb) help expr
Usually when I set lldb watchpoints, when they're hit, lldb says watchpoint hit old value: new value. However, I set a watchpoint on an address that seems to be getting written to inside a 3rd party library (libjpeg-turbo) and instead of the usual watchpoint hit, I'm seeing EXC_BREAKPOINT code=258, subcode=0xADDRESS.
In all cases, I can see that the subcode must be the address, as it's always equal to the address or close to the one I set the watchpoint to. Can anyone confirm this?
If I delete the watchpoint and keep going, lldb won't pause with EXC_BREAKPOINT. But what does the code mean and where can I find some offical documentation on this?
The exc_types.h doesn't give any detailed information on it.
For anyone who is interested in this question there is a nice article about the topic:
Understanding iOS Exception Types
In all cases, I can see that the subcode must be the address, as it's always equal to the address or close to the one I set the watchpoint to. Can anyone confirm this?
There is not much information in exception_types.h headers:
open -t /Applications/Xcode.app//Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/mach/exception_types.h
I can confirm that I always see EXC_BREAKPOINT to have address in subcode.
However other types in the header say that subcode can have different kinds of information:
#define EXC_EMULATION 4 /* Emulation instruction */
/* Emulation support instruction encountered */
/* Details in code and subcode fields */
We had to investigate on one Swift crash that produced: EXC_BREAKPOINT. In our case it boiled down to Swift type coercions. Both of the following cause EXC_BREAKPOINT on ARM devices:
func test_crash() {
let num = Int(DBL_MAX)
}
func test_crash_2() {
let num = Int(Double(0) / Double(0))
}
In both of these cases EXC_BREAKPOINT has a subcode with an address which is the address of sbrk instruction if you look at the assembly.
exc_types.h only has the architecture independent parts of the exception definitions. You need to look in the i386/arm subdirectories to find the architecture specific parts. If you are on Yosemite, the arm directory won't be in /usr/include/mach, you'll have to look for it in the iPhoneOS SDK inside of Xcode.app. Anyway, mach/arm/exception.h says:
#define EXC_ARM_DA_DEBUG 0x102 /* Debug (watch/break) Fault */
And as you suspect the subcode is the address of the access.
But lldb doesn't report bare exceptions if it recognizes the exception as implementing some higher level task. In this case, it should be reporting the stop reason as a watchpoint hit. For some reason it doesn't recognize this as your watchpoint. Is the subcode address exactly the same as the one reported by watch list?
Say have a few blocks of code in my project with this pattern:
dispatch_semaphore_wait(mySemaphore);
// Arbitrary code here that I could get stuck on and not signal
dispatch_semaphore_signal(mySemaphore);
And let's say I pause in my debugger to find that I'm stuck on:
dispatch_semaphore_wait(mySemaphore);
How can I easily see where the semaphore was last consumed? As in, where can I see dispatch_semaphore_wait(mySemaphore); was called and got through to the next line of code? The trivial way would be to use NSLog's, but is there a fancier/faster way to do this in the debugger with Xcode 4?
You can print debugDescription of the semaphore object in the debugger (e.g. via po), which will give you the current and original value (i.e. value at creation) of the semaphore.
As long as current value < 0, dispatch_semaphore_wait will wait for somebody else to dispatch_semaphore_signal to increment the value.
There is currently no automatic built-in way to trace calls to dispatch_semaphore_signal/dispatch_semaphore_wait over time, but that is a useful feature request to file at bugreport.apple.com
One way to trace this yourself would be by creating symbolic breakpoints on those functions in Xcode, adding a 'Debugger Command' breakpoint action that executes bt and setting the flag to "Automatically continue after evaluating" the breakpoint.
Another option would be to use DTrace pid probes to trace those functions with an action that calls ustack().
i connect to iphone's debugserver and able to send GDB Serial Protocol packets. I can set breakpoint and wait until it reached. When it did i want to call objc_msgSend with known parameters, get it's output and continue execution. For now i am simulating it's process in xcode and lldb, so i can not use just 'call objc_msgSend(object, _cmd)'.
what i do:
set breakpoint to some code
register read pc // read next operation address
register write lr 0x0x0000253a // set return address to continue execution (pc value)
register write pc 0x30300c88 // my objc_msgSend address
register write r0 0x16ed30 // my object address
register write r1 0x3161 // my selector address
breakpoint set -a 0x0x0000253a
continue
So i have my method called, but then app crashes and never reaches my 'return address' 0x0x0000253a. Also it rewrites r0 with return value, so my method is totally incomplete. I understand that what i do is hardcore overwriting registers without storing and restoring previous values so please help. How can i store/restore registers state, what i am doing wrong or what necessary things i do not do?
Also it could be very helpful to trace xcode's debugger for what it is doing while 'call objc_msgSend'. I tried to use this code and fruitstrap to use dtruss and then research it's output - it had thousands of memory reads and breakpoint sets, useless for me.
Note: i can use only GDB Serial Protocol.