I want to be able to specify a subset of all C++ exceptions for Xcode (lldb) to break upon. It looks like this is supported in the UI:
But for the life of me, I can't make it work. If I leave it set to the default "All C++ Exceptions", it works and every exception thrown triggers the breakpoint. If I attempt to specify an exception by name, the breakpoint is never triggered.
Has anyone else had issues with this, or is this just my problem?
Despite the UI, lldb is unable to set breakpoints on specific C++ exceptions or it does not resolve the name correctly.
I set a breakpoint for std::underflow_error and then using the lldb breakpoint list command, determined it only places a symbolic breakpoint on std::underflow_error:
9: name = 'std::underflow_error', locations = 0 (pending)
I suspect that lldb never resolves std::underflow_error to the constructor. C++ name mangling might have something to do with it too.
If you create a breakpoint for all C++ exception, you will see it creates a symbolic breakpoint on __cxa_throw:
10: name = '__cxa_throw', locations = 1, resolved = 1
10.1: where = libc++abi.dylib`__cxa_throw, address = 0x01cefa44, resolved, hit count = 0
You might be able to put a breakpoint in the constructor of the exception you are interested in, assuming it is instantiated and thrown at the same point.
Related
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?
I'm new to lldb and trying to diagnose an error by using po [$eax class]
The error shown in the UI is:
Thread 1: EXC_BREAKPOINT (code=EXC_i386_BPT, subcode=0x0)
Here is the lldb console including what I entered and what was returned:
(lldb) po [$eax class]
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0xb06b9940).
The process has been returned to the state before expression evaluation.
The global breakpoint state toggle is off.
You app is getting stopped because the code you are running threw an uncaught Mach exception. Mach exceptions are the equivalent of BSD Signals for the Mach kernel - which makes up the lowest levels of the macOS operating system.
In this case, the particular Mach exception is EXC_BREAKPOINT. EXC_BREAKPOINT is a common source of confusion... Because it has the word "breakpoint" in the name people think that it is a debugger breakpoint. That's not entirely wrong, but the exception is used more generally than that.
EXC_BREAKPOINT is in fact the exception that the lower layers of Mach reports when it executes a certain instruction (a trap instruction). That trap instruction is used by lldb to implement breakpoints, but it is also used as an alternative to assert in various bits of system software. For instance, swift uses this error if you access past the end of an array. It is a way to stop your program right at the point of the error. If you are running outside the debugger, this will lead to a crash. But if you are running in the debugger, then control will be returned to the debugger with this EXC_BREAKPOINT stop reason.
To avoid confusion, lldb will never show you EXC_BREAKPOINT as the stop reason if the trap was one that lldb inserted in the program you are debugging to implement a debugger breakpoint. It will always say breakpoint n.n instead.
So if you see a thread stopped with EXC_BREAKPOINT as its stop reason, that means you've hit some kind of fatal error, usually in some system library used by your program. A backtrace at this point will show you what component is raising that error.
Anyway, then having hit that error, you tried to figure out the class of the value in the eax register by calling the class method on it by running po [$eax class]. Calling that method (which will cause code to get run in the program you are debugging) lead to a crash. That's what the "error" message you cite was telling you.
That's almost surely because $eax doesn't point to a valid ObjC object, so you're just calling a method on some random value, and that's crashing.
Note, if you are debugging a 64 bit program, then $eax is actually the lower 32 bits of the real argument passing register - $rax. The bottom 32 bits of a 64 bit pointer is unlikely to be a valid pointer value, so it is not at all surprising that calling class on it led to a crash.
If you were trying to call class on the first passed argument (self in ObjC methods) on 64 bit Intel, you really wanted to do:
(lldb) po [$rax class]
Note, that was also unlikely to work, since $rax only holds self at the start of the function. Then it gets used as a scratch register. So if you are any ways into the function (which the fact that your code fatally failed some test makes seem likely) $rax would be unlikely to still hold self.
Note also, if this is a 32 bit program, then $eax is not in fact used for argument passing - 32 bit Intel code passes arguments on the stack, not in registers.
Anyway, the first thing to do to figure out what went wrong was to print the backtrace when you get this exception, and see what code was getting run at the time this error occurred.
Clean project and restart Xcode worked for me.
I'm adding my solution, as I've struggled with the same problem and I didn't find this solution anywhere.
In my case I had to run Product -> Clean Build Folder (Clean + Option key) and rebuild my project. Breakpoints and lldb commands started to work properly.
I am new to XCode and Objective C. I have intentionally make a mistake to assign number to NSString*.
NSString* s = #1;
[s uppercaseString];
Though XCode gives me warning, this code will compile. But at runtime I get exception. Now I see in logs, (Sorry for image, I was not able to paste is as text properly due to formatting)
In this log, how I find exact place of error. How this log tells me which code to change.
So it looks like you are running the Release build (debug symbols stripped) and if you got that crash log in a production environment you would need to symbolicate it in order to find the line.
This Apple TN gives some details of Symbolication.
In a development environment you would simply add an exception breakpoint and run it from Xcode, as the debug symbols would not be stripped.
To understand what line causes the problem, you usually need to add exception breakpoint to your project as explained in this document;
In the bottom-left corner of the breakpoints navigator, click the
Add button.
Choose Add Exception Breakpoint.
In the Exception pop-up menu, choose the type of exception on which
you want execution to stop:
All. Stops on all exceptions.
Objective-C. Stops on Objective-C exceptions.
C++. Stops on C++ exceptions. To stop on a particular C++ exception, specify the exception name.
Choose the phase of the exception handling process at which you want program execution to stop.
Click Done.
line 5 Sam : [BIDViewController viewDidLoad] + 143 , if this is a release build , you need to resolve with symbols the memory address of the function , this is called "symbolize" the crash dump...
In the log look for your project name and you will come to know.
e.g.
line 5 Sam : [BIDViewController viewDidLoad] + 143
If you want to produce real crash without warning, try following code it will produce index out of bound exception and will crash
NSArray *array = #[#"1",#"2"];
NSLog(#"Item not accessible->%#",(NSString*)array[2]);
set Exception breaking point or enable NSZombie object
or
NSZombie
From the menu bar, choose Project > Scheme > Edit Scheme
Have a system build using C++ Builder 2010 that after running for about 20 hours it starts firing of assertion failures.
Assertion failed: xdrPtr && xdrPtr == *xdrLPP, file xx.cpp, line 2349
Tried google on it like crazy but not much info. Some people seem to refer a bunch of different assertions in xx.cpp to shortcomings in the exception handling in C++ Builder. But I haven't found anything referencing this particular line in the file.
We have integrated madExcept and it seems like somewhere along the way this catches an out of memory exception, but not sure if it's connected. No matter what an assertion triggering doesn't seem correct.
Edit:
I found an instance of a if-statement that as part of it's statement used a function that could throw an exception. I wonder if this could be the culprit somehow messing up the flow of the exception handling or something?
Consider
if(foo() == 0) {
...
}
wrapped in a try catch block.
If an exception is thrown from within foo() so that no int is returned here how will the if statement react? I'm thinking it still might try to finish executing that line and this performing the if check on the return of the function which will barf since no int was returned. Is this well defined or is this undefined behaviour?
Wouldn't
int fooStatus = foo();
if(fooStatus == 0) {
...
}
be better (or should I say safer)?
Edit 2:
I just managed to get the assertion on my dev machine (the application just standing idle) without any exception about memory popping up and the app only consuming around 100 mb. So they were probably not connected.
Will try to see if I can catch it again and see around where it barfs.
Edit 3:
Managed to catch it. First comes an assertion failure notice like explained. Then the debugger shows me this exception notification.
If I break it takes me here in the code
It actually highlights the first code line after
pConnection->Open();
But it seems I can change this to anything and that line is still highlighted. So my guess is that the error is in the code above it somehow. I have seen more reports about people getting this type of assertion failure when working with databases in RAD Studio... hmmmm.
Update:
I found a thread that recursively called it's own Execute function if it wasn't able to reach the DB server. I think this is at least part of the issue. This will just keep on trying and as more and more worker threads spawn and also keep trying it can only end in disaster.
If madExcept is hinting that you have an out of memory condition, the assert could fail if the pointers are NULL (i.e. the allocation failed). What are the values of xdrPtr and xdrLPP when the assert occurs? Can you trace back to where they are allocated?
I would start looking for memory leaks.
SUMMARY
When I set an exception breakpoint, I don't get the exception message. How do I get the exception message? I already know how to get the stack trace, but that doesn't include the exception message.
DETAILS
In the past I developed iOS Apps with Xcode and when there was a problem, I'd get an error/exception. The exception would often have a message like "can't dereference null" or whatever.
Now, using Xcode 4.6.x for the past several weeks I've never gotten an exception message. I'll often get a SIGABRT. I put in the break on exception breakpoint and it will break there, but it's off in some assembly within the iOS SDK and I never get a message.
In fact, I can't remember the last time I saw anything show up in the debugger console.
Did exception info dissappear with the migration to LLVM?
It's very frustrating to have my app just crash in the SDK without knowing why. I check the last function to make sure things are set up correctly (objects allocated, etc) and they are which means I'm left with no clues.
Is it possibly a build setting held over from the past is somehow turning off exception messages?
Please reopen question. It now has an answer!
In the comments an excellent answer has been given. This should be promoted to full answer, and so I can mark the question answered and others who have this common issue can find it. In order for that to happen, the question needs to be reopened! (I'll delete this plea after that happens.)
I will update Jeff's answer here:
To have both the line causing the exception highlighted (and not UIApplicationMain() in main.m) AND to see the reason for the exception (e.g., "error: A fetch request must have an entity."), do this:
In the Breakpoint navigator:
Add (+), Add Exception Breakpoint
Select the new breakpoint, Control-Click, Edit Breakpoint
Add Action
Enter: po $arg1
The relevant part of the stack trace will be in the nagivator area.
This seems to still work in Xcode 9
Here is my addition for use with Xcode 6 and below.
Enter: po (NSException*) $eax
In Xcode 6 you must explicitly provide the object type because it is no longer inferred.
For Xcode 7-9 (based off Jeff's answer):
In the Breakpoint navigator:
Add (+), Add Exception Breakpoint
Select the new breakpoint, Control-Click, Edit Breakpoint
Add Action
Enter: po $arg1
To have both the line causing the exception highlighted (and not UIApplicationMain() in main.m) AND to see the reason for the exception (e.g., "error: A fetch request must have an entity."), do this:
In the Breakpoint navigator:
Add (+), Add Exception Breakpoint
Select the new breakpoint, Contorl-Click, Edit Breakpoint
Add Action
Enter: po $eax
The relevant part of the stack trace will be in the nagivator area.
Yes xcode is not so friendly for debugging. I like this article which helps me to understand crash logs a bit clearly))
Demystifying iOS Application Crash Logs
Also do this if you see error "message sent to deallocated instance"
'Products -> Edit Scheme -> Enable Zombie Objects'
this will enable zombie objects and when you do profile to your project choose
"zombie", cause error and you will be able to see which objects was deallocated e.g NSArray *myArray
The information I get from po $eax or po (NSException *)$eax seems to be different from what Xcode would print if no exception breakpoints are set. So I do the following,
Add an exception breakpoint
Exception occurs, breakpoint was hit -> I know the location
Temporarily disable breakpoints (second button on the left in Debug area)
Continue program execution (third button on the left in Debug area)
Details are printed -> I know the cause
Obviously not very elegant and flexible, but at least I two big questions are answered (where and why).
You can use bt or thread backtrace command to print error trace
Show the stack backtrace for the current thread.
The same stack trace you can find in crash reports
Information about current thread use currentThread
//Objective-C
po [NSThread currentThread]
//Swift
po Thread.currentThread
*Sometimes you can use fr v(or just v from XCode 10.2) when po is not working