How to get iOS stack trace in release build? - ios

(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.

Related

How to make FastMM log file more readable

I recently started using FastMM, now I want to know if is it possible to configure FastMM log file to be a bit more readable so that it can give me direction on where exactly the the memory is being leaked, like specifying the actual unit and function/line number, in most cases I would get something like...
A memory block has been leaked. The size is: 20
This block was allocated by thread 0xE7C, and the stack trace (return addresses) at the time was:
5005995A [System.pas][System][System.#GetMem][4316]
5005E99F [System.pas][System][System.TObject.NewInstance][15447]
5005F292 [System.pas][System][System.#ClassCreate][16757]
23A606 [FireDAC.Stan.Util.pas][FireDAC.Stan.Util][FireDAC.Stan.Util.TFDBuffer.Create][1516]
4C46D3 [FireDAC.Phys.IBWrapper][Phys.Ibwrapper.TIBDatabase.$bctr$qqrp29Firedac.Phys.Ibwrapper.TIBEnvp14System.TObject]
4C4730 [FireDAC.Phys.IBWrapper][Phys.Ibwrapper.TIBDatabase.$bctr$qqrp29Firedac.Phys.Ibwrapper.TIBEnvpvp14System.TObject]
4CEF79 [FireDAC.Phys.IBBase][Phys.Ibbase.TFDPhysIBConnectionBase.InternalConnect$qqrv]
E4A553 [FireDAC.Phys.pas][FireDAC.Phys][FireDAC.Phys.TFDPhysConnection.ConnectBase][3161]
E4A60E [FireDAC.Phys.pas][FireDAC.Phys][FireDAC.Phys.TFDPhysConnection.DoConnect][3187]
E4B11C [FireDAC.Phys.pas][FireDAC.Phys][FireDAC.Phys.TFDPhysConnection.Open][3361]
34A14C [FireDAC.Comp.Client.pas][FireDAC.Comp.Client][FireDAC.Comp.Client.TFDCustomConnection.DoInternalLogin][3642]
The block is currently used for an object of class: TFDBuffer
Which does not really give me what I need.

line numbers in stack trace

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.

What's the meaning of the EXC_BREAKPOINT code and subcode?

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?

iOS: convert stacktrace entry to method name with line number

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]);

build settings to generate proper dSYM

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.

Resources