这是一个如何在运行时获取二进制图像信息的示例。
下面代码的输出如下所示:
YourApp 0x00000001adb1e000 - arm64e - E9B05479-3D07-390C-BD36-73EEDB2B1F75
CoreGraphics 0x00000001a92dd000 - arm64e - 2F7F6EE8-635C-332A-BAC3-EFDA4894C7E2
CoreImage 0x00000001afc00000 - arm64e - CF56BCB1-9EE3-392D-8922-C8894C9F94C7
然后,您使用要符号化其帧的二进制图像的内存地址作为atos
您提到的命令中的参数。
代码:
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
}
}
进一步阅读:
也可作为GitHub 上的 swift 包使用。