In a production app with the debug information stripped out, how do you convert the output of:
NSLog(#"Stack Trace: %#", [exception callStackSymbols]);
To an legible class and method name? A line number would be a blessing.
Here's the output I'm getting:
0 CoreFoundation 0x23d82f23 <redacted> + 154
1 libobjc.A.dylib 0x23519ce7 objc_exception_throw + 38
2 CoreFoundation 0x23cb92f1 <redacted> + 176
3 MyApp 0x23234815 MyApp + 440341
The final line is the bread and butter line, but when I use dwarf to find the address, nothing exists.
dwarfdump --arch armv7 MyApp.dSYM --lookup 0x00234815 | grep 'Line table'
I've read here that you need to convert the stack address to something else for dwarf or atos:
https://stackoverflow.com/a/12464678/2317728
How would I find the load address or slide address to perform the calculation? Is there not a way to calculate all this prior to sending the stacktrace to the log from within the app? If not, how would I determine and calculate these values after receiving the stack trace? Better yet, is there an easier solution I'm missing?
Note I cannot just wait for crash reports since the app is small and they will never come. I'm planning on sending the stack traces to our server to be fixed as soon as they appear.
EDITORIAL
The crash reporting tools in iOS are very rough, particularly when compared to Android. In android, the buggy lines are sent to Google analytics, you use the map to debug the line--simple (comparatively). For iOS, you are confronted with: a) waiting on user bug reports (not reasonable for a small app), b) sending stack traces to a server where there are scant tools or information on how to symbolicate the stack traces, c) relying on large quasi-commercial 3rd party libraries. This definitely makes it harder to build and scale up--hoping Apple will eventually take notice. Even more hopeful someone has spotted an easier solution I might have missed ;)
Thanks for your help!
A suggestion, you can easily get the method name, exception reason and line number using:
NSLog(#"%# Exception in %s on %d due to %#",[exception name],__PRETTY_FUNCTION__,__LINE__,[exception reason]);
Related
I am running helgrind to check for data races in my program. Helgrind reports 222 errors, all of them are:
Thread #21: Bug in libpthread: pthread_cond_wait succeeded without prior pthread_cond_post
I could not find anything about this error message on google. Within the valgrind source code, this seems to originate here:
if (!timeout && !libhb_so_everSent(cvi->so)) {
/* Hmm. How can a wait on 'cond' succeed if nobody signalled
it? If this happened it would surely be a bug in the threads
library. Or one of those fabled "spurious wakeups". */
HG_(record_error_Misc)( thr, "Bug in libpthread: pthread_cond_wait "
"succeeded"
" without prior pthread_cond_post");
}
However, I can not believe that I got 222 spurious wake-ups in about a second.
What could be the cause of this?
There are two condition variables, both in shared memory. The error always seems to happen with one of them, not with the other.
(1)Some of our users said that our app sometimes does not work fluently, so how can we get the stack trace in order to know what happens at that moment?
(2)we want to get the stack trace like this:
0 CoreFoundation 0x000000018146ad8c 0x181325000 + 1334668
it should at lease includes these elements so that we can symbolicate them: the addresses of executable code, load address of the binary image, binary image name.
(3)"[NSThread callStackSymbols]" can not meet the requirements.
In researching debugging exceptions using LLDB, I found the following article and thread, as well as others giving the same information:
https://www.natashatherobot.com/xcode-debugging-trick/
Xcode/LLDB: How to get information about an exception that was just thrown?
When trying variations of these, the best I can get is an int as a result:
(lldb) po $rax
106377751137688
When plugging this into the Xcode memory viewer, trying it as both a base-10 and hex value, there didn't seem to be an object stored there. I get results such as B8 0B 0C 16 01 00 00 00 03... followed by zeros as far as the eye can see. I've tried calling methods like description on the int as if it were an address, casting it as NSException*, which yield the result:
error: Execution was interrupted, reason: Attempted to dereference an invalid ObjC Object or send it an unrecognized selector. The process has been returned to the state before expression evaluation.
Was there a recent change to LLDB that would have broken the expected functionality? I'm using Xcode 9.2 and a mix of swift and objective-c. It might also be worth noting that I don't see the frame objc_exception_throw in the call stack, but rather __cxa_throw at frame 0, which is what I select to get a result.
The exception in particular I'm looking at is generated by a call to -[UIStoryboard instantiateViewControllerWithIdentifier:]
EDIT: If I manually create an NSException and #throw it, I can view it with po $rax. I noticed in this case, frame 0 of the call stack is objc_exception_throw. I've edited the title to specify the type of exception I'm asking about.
The normal course of an ObjC exception is that the system calls objc_exception_throw passing in the exception object to start the exception. But under the covers, ObjC uses the same exception throwing mechanism that C++ uses to implement the actual unwinding of the stack. So objc_exception_throw will turn around and call __cxa_throw - which also happens to be the C++ exception start point.
When ObjC does this, the object thrown at __cxa_throw - which happens to be its first argument - is an ObjC object. But there are also parts of the system that throw real C++ exceptions on occasion. If you stop in __cxa_throw without first stopping in objc_exception_throw, that's going to be a C++ exception object NOT an NSException, and po does nothing for them.
BTW, when you stop in __cxa_throw the stack hasn't been unwound yet, so the backtrace should show you who is throwing the exception, if you are curious.
In sum, if you want to only see ObjC exceptions, don't stop at the __cxa_throw, just stop at objc_exception_throw. Stopping at __cxa_throw won't add any information, and will cause you to have to sort the spurious pure C++ exceptions from the ObjC ones you care about.
In Xcode, you do this by choosing the ObjC exception breakpoint not "All Exceptions". In command line lldb, do this with:
(lldb) break set -E objc
The line numbers in stack traces for IOS builds do not seem to
correspond to either the original sources or the .m sources generated
by the build process. Is there a way to interpret them ?
For example, in the trade below online_root.start:721 is refers to
a method in a file with only 111 lines. The correspinding .m file
has only 319 lines.
*** CN1 log ****
[null] 0:0:48,666 - Exception: java.lang.NullPointerException - null
java.lang.NullPointerException
at online_Root.start:721
at util_JWSApplication.runMain:216
at util_JWSApplication.xmain:124
at com_boardspace_BoardspaceLauncher.launchLobby:110
at com_boardspace_BoardspaceLauncher.doit:0
at com_boardspace_BoardspaceLauncher.run:51
at java_lang_Thread.runImpl:153
*** End of CN1 log ****
Try using a platform for crashing such as HockeyApp or Crashlytics, that would be easiest way to interpret the crash logs on an iOS device. If you don't go that route, you will need to understand the atos command, basically address to symbol. There are plenty of resources here about atos and how to get it working, this is the route I took and works well.
I have a question regarding dSYM. I made an experiment with my app and added following code to it:
if (currentMenuPage_ == MenuPageAttrsVals) {
return ((ValueAndId *) [currentValues_ objectAtIndex:-1]).name;
}
as expected application crashed and crash log was generated.
However Xcode and atos can not tell me exact line where the crash is.
2 CoreFoundation 0x3192c23d -[__NSArrayI objectAtIndex:] + 165
3 MyApp 0x00053487 0x49000 + 42119
4 MyApp 0x0005102d 0x49000 + 32813
Do I have to set some special settings when building my app to generate proper dSYM?
If I call dwarfdump --uuid MyApp.app.dSYM I get a number. Does this number should appear somewhere in my crash log?
That number should appear in the first line under the Binary Images section. (It might be formatted differently, e.g. lowercase and without the - chars).
Please remember, every time you do a build, this UUID changes, and if you did not save the previous dSYM, it won't symbolicate it.
If you did not change a lot (any) code, you could replace the UUID string in the Binary Images section (keep the format in there) with the new one from the latest dSYM.
If symbolication did not work, and the UUID is correct, that folder is most likely not indexed by Spotlight, so the symbolication script can't find the dSYM.