atos and dwarfdump won't symbolicate my address
I used the following arithmetic to figure it out:
slide
+ stack address
- load address
= symbol address
and
stack address
is the hex value I get from my stack dump crash report (not a .crash file, just the stack dump).
and
slide
is the vmaddr of the LC_SEGMENT cmd when running otool -arch armv7 -l APP_BINARY_PATH
. Mine usually ends up being 0x00001000.
and
load address
is the complicated piece. It is actually the difference between the bottommost stack address of the main thread and the FIRST address of the portion of my binary that contains symbols when running dwarfdump --arch armv7 --all DSYM_BINARY_PATH
. This is simply the symbolic address of the main
function. So if your bottom most crash address is 0x8000 and your main function's symbolic address is 0x2000 then your load address
is 0x6000.
Now with ALL these pieces I can calculate the symbol address and put that into atos or dwarfdump: dwarfdump --lookup SYM_ADDR --arch armv7 APP_BINARY_PATH
.
Example of the dump (you can see that the load address
was 0x00003af4):
----------------------------------------------------------------------
File: /Users/user/Desktop/MyApp.xcarchive/dSYMs/MyApp.app.dSYM/Contents/Resources/DWARF/MyApp (armv7)
----------------------------------------------------------------------
0x00000024: [0x00003af4 - 0x00003b4e) main
0x00000098: [0x00003b50 - 0x00003d8c) -[MyAppDelegate application: didFinishLaunchingWithOptions:]
... the rest of the dump
The hardest part was realizing that one of the 2 static libraries I'd included had their symbols stripped before being link to my app's binary! That left a HUGE gap of symbol addresses so I only ended up with two-thirds of the symbols I needed in my dSYM.
Be sure to have the following flags set to NO in your static libraries xcode project so that when you link against it, you can pull in the symbols to your app's binary (which can later be stripped): COPY_PHASE_STRIP
, DEAD_CODE_STRIPPING
, and STRIP_INSTALLED_PRODUCT
.
Now you may ask, "what do I do if the stack dump does not include the main function since it isn't on the main thread so that I cannot get the main function's stack address?". To that I would reply, "I haven't a friggin' clue!". Just cross your fingers and hope you can get a stack trace that includes the symbol address or use a crash reporting system that mimics Apple's crash logs, like PLCrashReporter.
[EDIT May 26, 2013] -
It was brought to my attention that the load address
is really the address of the mach-o binary. Though what I described above can often work - it's not actually correct. This can be obtained via the CRASH REPORT, however the point of this answer was to provide the symbols of a crash when you don't have a crash report. The best way I've come to figuring out the load address
when wanting to symbolicate is by making sure I log the load address
with the stack addresses
.
I've personally created a system for logging crashes (not crash reports) and having them sent to an S3 bucket where I can retrieve them later for debugging. When I start my application I cache the slide
, the load address
and the main function address
for use if my app crashes and I send up a the stack addresses
.
NOTE: the dyld functions use #include <mach-o/dyld.h>
slide
= the address returned by _dyld_get_image_vmaddr_slide(0)
load address
= the address returned by _dyld_get_image_header(0)
main function address
= the last address in [NSThread callStackReturnAddresses]
when
called on the main thread
At crash time I'm sure to log [NSThread callStackReturnAddresses]
and [NSThread callStackSymbols]
as well as the architecture which can be retrieve by having this method:
- (NSString*) arch
{
NSString* arch =
#ifdef _ARM_ARCH_7
@"armv7";
#elif defined (_ARM_ARCH_6)
@"armv6";
#else
nil;
#endif
return arch;
}
I don't yet know how to differentiate between armv7 and armv7s though.
So this may help in the future. I plan on taking everything I've learned and turning this into a simple crash tool - better than the natos tool (probably natos v2).
I've updated natos to support supplying the load address
manually: https://github.com/NSProgrammer/natos
First of all check if the dSYM is really the correct one for that app:
dwarfdump --uuid kidsapp.app/kidsapp
dwarfdump --uuid kidsapp.app.dSYM
Both should return the same result.
Next check if the dSYM has any valid content
dwarfdump --all kidsapp.app.dSYM
This should give at least some info, other than not found
.
I guess that the dSYM is corrupt. In general you might want to use a crash reporter that gives you a full crash report with all threads and last exception backtrace information. I recommend using something based on PLCrashReporter, e.g. QuincyKit (Open Source SDK + Server + symbolication on your mac) or HockeyApp (Open Source SDK + Paid service + server side symbolication) (Note: I am one of the developers both!)
For whom that certain times doesn't have the value for Load Address like this:
Jan 14 11:02:39 Dennins-iPhone AppName[584] <Critical>: Stack Trace: (
0 CoreFoundation 0x2c3084b7 <redacted> + 150
1 libobjc.A.dylib 0x39abec8b objc_exception_throw + 38
2 CoreFoundation 0x2c21cc35 CFRunLoopRemoveTimer + 0
3 AppName 0x0005a7db AppName + 272347
I've created a simple bash to help me debug:
#! /bin/bash
read -p "[Path] [App Name] [Stack Address] [Relative Address] " path appName runtimeAddress relativeAddress
loadAddress=`echo "obase=16;ibase=10;$((runtimeAddress-relativeAddress))" | bc`
atos -o $path/Payload/$appName.app/$appName -l $loadAddress $runtimeAddress -arch armv7
It just reads the path for the app, the app name, the runtime address, and the value after "+" signal (the decimal value) and then find the value for load address to run atos command.
So my case: I'm receiving the crash strings out of the NSException.callStackSymbols.
The crash stack trace looks this way:
2 AppName 0x00000001006c75b4 AppName + 2356660\r3 AppName 0x00000001004f5cfc AppName + 449788\r4 UIKit 0x000000018c0a8968 \u003credacted\u003e + 108\r5 UIKit 0x000000018c0a9328 \u003credacted\u003e + 28\r6 UIKit 0x000000018beea250 \u003credacted\u003e + 1320\r7 UIKit 0x000000018beede98 \u003credacted\u003e + 188\r8 UIKit 0x000000018bcb5820 \u003credacted\u003e + 116\r9 UIKit 0x000000018bbdec88 \u003credacted\u003e + 760\r10 UIKit 0x000000018bbde610 \u003credacted\u003e + 312\r11 UIKit 0x000000018bbde31c \u003credacted\u003e + 296\r12 UIKit 0x000000018bbde3bc \u003credacted\u003e + 456\r13 QuartzCore 0x0000000185b93b7c \u003credacted\u003e + 284\r14 libdispatch.dylib 0x00000001811a8a2c \u003credacted\u003e + 16\r15 libdispatch.dylib 0x00000001811b5654 \u003credacted\u003e + 1012\r16 CoreFoundation 0x0000000181851650 \u003credacted\u003e + 12\r17 CoreFoundation 0x000000018184f1a8 \u003credacted\u003e + 2272\r18 CoreFoundation 0x000000018176f488 CFRunLoopRunSpecific + 552\r19 GraphicsServices 0x0000000183735020 GSEventRunModal + 100\r20 UIKit 0x000000018bc09cc0 UIApplicationMain + 236\r21 AppName 0x000000010048f714 AppName + 30484\r22 libdyld.dylib 0x000000018120dfc0 \u003credacted\u003e + 4
Don't include bitcode, as Apple can recompile your code, and dsym files from your archive in Organizer won't match.
Run such bash script:
#!/bin/bash
appName=AppName
runtimeAddress=0x00000001006c75b4
relativeAddress=2356660
loadAddress=`echo "obase=16;ibase=10;$((runtimeAddress-relativeAddress))" | bc`
atos -o $appName.app/$appName -l $loadAddress $runtimeAddress -arch arm64
Assuming, that you've created a test.sh (touch test.sh). If it's not possible to run the sctipt (./test.sh) because of the permissions issue: call chmod +x test.sh Now ./test.sh should work. And generate the result.
As well it's possible to symbolicate the crash file using AppName.app.dSYM file:
#!/bin/bash
appName=AppName
runtimeAddress=0x00000001006c75b4
relativeAddress=2356660
loadAddress=`echo "obase=16;ibase=10;$((runtimeAddress-relativeAddress))" | bc`
atos -o $appName.app.dSYM/Contents/Resources/DWARF/$appName -l $loadAddress $runtimeAddress -arch arm64
I think this post may help you, https://stackoverflow.com/a/12559150/1773317. Joe's commit soled my problem.
The reason is that my .app and .dSYM files can't be indexed by spotlight, so my XCode can't symbolicate the crash info correctly.