I want to symbolicate the stack trace symbols logged using [NSThread callStackSymbols] to identify the full stack backtrace calls. But, this doesn't give symbolicated trace.
0 TestApp 0x0029616f TestApp + 1823087
1 TestApp 0x003ef18d TestApp + 3236237
2 UIKit 0x2ab7bb1f <redacted> + 438
3 UIKit 0x2ac0bea3 <redacted> + 306
4 UIKit 0x2ab7bb1f <redacted> + 438
5 CoreFoundation 0x2757546d <redacted> + 48
6 CoreFoundation 0x2756e4c3 <redacted> + 234
7 UIKit 0x2ab7bc9b <redacted> + 818
8 UIKit 0x2ae32799 <redacted> + 584
9 UIKit 0x2abdfbd9 <redacted> + 308
10 UIKit 0x2ab5bdd7 <redacted> + 458
11 CoreFoundation 0x2760fffd <redacted> + 20
12 CoreFoundation 0x2760d6bb <redacted> + 278
13 CoreFoundation 0x2760dac3 <redacted> + 914
14 CoreFoundation 0x2755b3b1 CFRunLoopRunSpecific + 476
15 CoreFoundation 0x2755b1c3 CFRunLoopRunInMode + 106
16 GraphicsServices 0x2eb88201 GSEventRunModal + 136
17 UIKit 0x2abc543d UIApplicationMain + 1440
18 TestApp 0x0031581b TestApp + 2344987
19 libdyld.dylib 0x35a6baaf <redacted> + 2
I tried this with development as well as enterprise build. Neither worked out. Is there anyway to symbolicate this? I searched lot of forums and all are asking to do this with atos command like below
atos -arch armv7 -o 'app name.app'/'app name' 0x000000000
But, I am not sure whats the memory address i have to use for the above command and how to get it.
Any help would be greatly appreciated, thanks.
There's a few pieces you're skipping here. The memory addresses in atos should reference the load address and the stack address, and you'll need the dSYM file as well.
There's actually a very good writeup on apteligent called Symbolicating an iOS Crash Report about doing this manually. I would suggest reading it thoroughly to understand how symbolication works.
Here an example of how you can get binary image information at runtime.
The output of below code looks like this for example:
YourApp 0x00000001adb1e000 - arm64e - E9B05479-3D07-390C-BD36-73EEDB2B1F75
CoreGraphics 0x00000001a92dd000 - arm64e - 2F7F6EE8-635C-332A-BAC3-EFDA4894C7E2
CoreImage 0x00000001afc00000 - arm64e - CF56BCB1-9EE3-392D-8922-C8894C9F94C7
You then use the memory address of the binary image whose frame you want to symbolicate as argument in the atos
command you mentioned.
Code:
import Foundation
import MachO
public struct BinaryImagesInspector {
#if arch(x86_64) || arch(arm64)
typealias MachHeader = mach_header_64
#else
typealias MachHeader = mach_header
#endif
/// Provides binary infos that are then used with the atos command to symbolicate stack traces
/// - Parameter imageNamesToLog: an optional array of binary image names to restrict the infos to
/// - Returns: An array of strings containing info on loaded binary name, its load address, architecture
/// - Note: Example:
///
/// atos -arch arm64 -o [YOUR-DSYM-ID].dSYM/Contents/Resources/DWARF/[YOUR APP] -l 0x0000000000000000 0x0000000000000000
public static func getBinaryImagesInfo(imageNamesToLog: [String]? = nil) -> [String] {
let count = _dyld_image_count()
var stringsToLog = [String]()
for i in 0..<count {
guard let dyld = _dyld_get_image_name(i) else { continue }
let dyldStr = String(cString: dyld)
let subStrings = dyldStr.split(separator: "/")
guard let imageName = subStrings.last else { continue }
if let imageNamesToLog = imageNamesToLog {
guard imageNamesToLog.contains(String(imageName)) else { continue }
}
guard let uncastHeader = _dyld_get_image_header(i) else { continue }
let machHeader = uncastHeader.withMemoryRebound(to: MachHeader.self, capacity: MemoryLayout<MachHeader>.size) { $0 }
guard let info = NXGetArchInfoFromCpuType(machHeader.pointee.cputype, machHeader.pointee.cpusubtype) else { continue }
guard let archName = info.pointee.name else { continue }
let uuid = getBinaryImageUUID(machHeader: machHeader)
let logStr = "\(imageName) \(machHeader.debugDescription) - \(String(cString: archName)) - \(uuid ?? "uuid not found")"
stringsToLog.append(logStr)
}
return stringsToLog
}
private static func getBinaryImageUUID(machHeader: UnsafePointer<MachHeader>) -> String? {
guard var header_ptr = UnsafePointer<UInt8>.init(bitPattern: UInt(bitPattern: machHeader)) else {
return nil
}
header_ptr += MemoryLayout<MachHeader>.size
guard var command = UnsafePointer<load_command>.init(bitPattern: UInt(bitPattern: header_ptr)) else {
return nil
}
for _ in 0..<machHeader.pointee.ncmds {
if command.pointee.cmd == LC_UUID {
guard let ucmd_ptr = UnsafePointer<uuid_command>.init(bitPattern: UInt(bitPattern: header_ptr)) else { continue }
let ucmd = ucmd_ptr.pointee
let cuuidBytes = CFUUIDBytes(byte0: ucmd.uuid.0,
byte1: ucmd.uuid.1,
byte2: ucmd.uuid.2,
byte3: ucmd.uuid.3,
byte4: ucmd.uuid.4,
byte5: ucmd.uuid.5,
byte6: ucmd.uuid.6,
byte7: ucmd.uuid.7,
byte8: ucmd.uuid.8,
byte9: ucmd.uuid.9,
byte10: ucmd.uuid.10,
byte11: ucmd.uuid.11,
byte12: ucmd.uuid.12,
byte13: ucmd.uuid.13,
byte14: ucmd.uuid.14,
byte15: ucmd.uuid.15)
guard let cuuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, cuuidBytes) else {
return nil
}
let suuid = CFUUIDCreateString(kCFAllocatorDefault, cuuid)
let encoding = CFStringGetFastestEncoding(suuid)
guard let cstr = CFStringGetCStringPtr(suuid, encoding) else {
return nil
}
let str = String(cString: cstr)
return str
}
header_ptr += Int(command.pointee.cmdsize)
guard let newCommand = UnsafePointer<load_command>.init(bitPattern: UInt(bitPattern: header_ptr)) else { continue }
command = newCommand
}
return nil
}
}
Further reading:
Also available as swift package on GitHub .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.