//===--- CoreSymbolication.swift - Shims for CoreSymbolication ------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // CoreSymbolication is a private framework, which makes it tricky to link // with from here and also means there are no headers on customer builds. // //===----------------------------------------------------------------------===// #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) import Swift internal import Darwin internal import BacktracingImpl.OS.Darwin // .. Dynamic binding .......................................................... private let coreFoundationPath = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" private let coreFoundationHandle = dlopen(coreFoundationPath, RTLD_LAZY)! private let coreSymbolicationPath = "/System/Library/PrivateFrameworks/CoreSymbolication.framework/CoreSymbolication" private let coreSymbolicationHandle = dlopen(coreSymbolicationPath, RTLD_LAZY)! private let crashReporterSupportPath = "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport" private let crashReporterSupportHandle = dlopen(crashReporterSupportPath, RTLD_LAZY)! private func symbol(_ handle: UnsafeMutableRawPointer, _ name: String) -> T { guard let result = dlsym(handle, name) else { fatalError("Unable to look up \(name) in CoreSymbolication") } return unsafeBitCast(result, to: T.self) } // Define UniChar typealias UniChar = UInt16 private enum Sym { // CRCopySanitizedPath static let CRCopySanitizedPath: @convention(c) (CFString, CFIndex) -> CFString = symbol(crashReporterSupportHandle, "CRCopySanitizedPath") // Base functionality static let CSRetain: @convention(c) (CSTypeRef) -> CSTypeRef = symbol(coreSymbolicationHandle, "CSRetain") static let CSRelease: @convention(c) (CSTypeRef) -> () = symbol(coreSymbolicationHandle, "CSRelease") static let CSEqual: @convention(c) (CSTypeRef, CSTypeRef) -> CBool = symbol(coreSymbolicationHandle, "CSEqual") static let CSIsNull: @convention(c) (CSTypeRef) -> CBool = symbol(coreSymbolicationHandle, "CSIsNull") // CSSymbolicator static let CSSymbolicatorCreateWithBinaryImageList: @convention(c) (UnsafeMutablePointer, UInt32, UInt32, CSNotificationBlock?) -> CSSymbolicatorRef = symbol(coreSymbolicationHandle, "CSSymbolicatorCreateWithBinaryImageList") static let CSSymbolicatorGetSymbolOwnerWithAddressAtTime: @convention(c) (CSSymbolicatorRef, vm_address_t, CSMachineTime) -> CSSymbolOwnerRef = symbol(coreSymbolicationHandle, "CSSymbolicatorGetSymbolOwnerWithAddressAtTime") static let CSSymbolicatorForeachSymbolOwnerAtTime: @convention(c) (CSSymbolicatorRef, CSMachineTime, @convention(block) (CSSymbolOwnerRef) -> Void) -> UInt = symbol(coreSymbolicationHandle, "CSSymbolicatorForeachSymbolOwnerAtTime") // CSSymbolOwner static let CSSymbolOwnerGetName: @convention(c) (CSSymbolOwnerRef) -> UnsafePointer? = symbol(coreSymbolicationHandle, "CSSymbolOwnerGetName") static let CSSymbolOwnerGetSymbolWithAddress: @convention(c) (CSSymbolOwnerRef, vm_address_t) -> CSSymbolRef = symbol(coreSymbolicationHandle, "CSSymbolOwnerGetSymbolWithAddress") static let CSSymbolOwnerGetSourceInfoWithAddress: @convention(c) (CSSymbolOwnerRef, vm_address_t) -> CSSourceInfoRef = symbol(coreSymbolicationHandle, "CSSymbolOwnerGetSourceInfoWithAddress") static let CSSymbolOwnerForEachStackFrameAtAddress: @convention(c) (CSSymbolOwnerRef, vm_address_t, CSStackFrameIterator) -> UInt = symbol(coreSymbolicationHandle, "CSSymbolOwnerForEachStackFrameAtAddress") static let CSSymbolOwnerGetBaseAddress: @convention(c) (CSSymbolOwnerRef) -> vm_address_t = symbol(coreSymbolicationHandle, "CSSymbolOwnerGetBaseAddress") // CSSymbol static let CSSymbolGetRange: @convention(c) (CSSymbolRef) -> CSRange = symbol(coreSymbolicationHandle, "CSSymbolGetRange") static let CSSymbolGetName: @convention(c) (CSSymbolRef) -> UnsafePointer? = symbol(coreSymbolicationHandle, "CSSymbolGetName") static let CSSymbolGetMangledName: @convention(c) (CSSymbolRef) -> UnsafePointer? = symbol(coreSymbolicationHandle, "CSSymbolGetMangledName") // CSSourceInfo static let CSSourceInfoGetPath: @convention(c) (CSSourceInfoRef) -> UnsafePointer? = symbol(coreSymbolicationHandle, "CSSourceInfoGetPath") static let CSSourceInfoGetLineNumber: @convention(c) (CSSourceInfoRef) -> UInt32 = symbol(coreSymbolicationHandle, "CSSourceInfoGetLineNumber") static let CSSourceInfoGetColumn: @convention(c) (CSSourceInfoRef) -> UInt32 = symbol(coreSymbolicationHandle, "CSSourceInfoGetColumn") // CFString static let CFStringCreateWithBytes: @convention(c) (CFAllocator?, UnsafeRawPointer?, CFIndex, CFStringEncoding, Bool) -> CFString? = symbol(coreFoundationHandle, "CFStringCreateWithBytes") static let CFStringGetLength: @convention(c) (CFString) -> CFIndex = symbol(coreFoundationHandle, "CFStringGetLength") static let CFStringGetCStringPtr: @convention(c) (CFString, CFStringEncoding) -> UnsafePointer? = symbol(coreFoundationHandle, "CFStringGetCStringPtr") static let CFStringGetBytes: @convention(c) (CFString, CFRange, CFStringEncoding, UInt8, Bool, UnsafeMutableRawPointer?, CFIndex, UnsafeMutablePointer?) -> CFIndex = symbol(coreFoundationHandle, "CFStringGetBytes") static let CFStringGetCharactersPtr: @convention(c) (CFString) -> UnsafePointer? = symbol(coreFoundationHandle, "CFStringGetCharactersPtr") } // .. Core Foundation miscellany ............................................... internal func CFRangeMake(_ location: CFIndex, _ length: CFIndex) -> CFRange { return CFRange(location: location, length: length) } internal func CFStringCreateWithBytes(_ allocator: CFAllocator?, _ bytes: UnsafeRawPointer?, _ length: CFIndex, _ encoding: CFStringEncoding, _ isExternalRepresentation: Bool) -> CFString? { return Sym.CFStringCreateWithBytes(allocator, bytes, length, encoding, isExternalRepresentation) } internal func CFStringGetLength(_ s: CFString) -> CFIndex { return Sym.CFStringGetLength(s) } internal func CFStringGetCStringPtr(_ s: CFString, _ encoding: CFStringEncoding) -> UnsafePointer? { return Sym.CFStringGetCStringPtr(s, encoding) } internal func CFStringGetCharactersPtr(_ s: CFString) -> UnsafePointer? { return Sym.CFStringGetCharactersPtr(s); } internal func CFStringGetBytes(_ s: CFString, _ range: CFRange, _ encoding: CFStringEncoding, _ lossByte: UInt8, _ isExternalRepresentation: Bool, _ buffer: UnsafeMutableRawPointer?, _ maxBufLen: CFIndex, _ usedBufLen: UnsafeMutablePointer?) -> CFIndex { return Sym.CFStringGetBytes(s, range, encoding, lossByte, isExternalRepresentation, buffer, maxBufLen, usedBufLen) } // .. Crash Reporter support ................................................... // We can't import swiftFoundation here, so there's no automatic bridging for // CFString. As a result, we need to do the dance manually. private func toCFString(_ s: String) -> CFString! { var s = s return s.withUTF8 { return CFStringCreateWithBytes(nil, $0.baseAddress, $0.count, CFStringBuiltInEncodings.UTF8.rawValue, false) } } private func fromCFString(_ cf: CFString) -> String { let length = CFStringGetLength(cf) if length == 0 { return "" } if let ptr = CFStringGetCStringPtr(cf, CFStringBuiltInEncodings.ASCII.rawValue) { let buffer = UnsafeRawBufferPointer(start: ptr, count: length) return String(decoding: buffer, as: UTF8.self) } else if let ptr = CFStringGetCharactersPtr(cf) { let buffer = UnsafeBufferPointer(start: ptr, count: length) return String(decoding: buffer, as: UTF16.self) } else if let ptr = CFStringGetCStringPtr(cf, CFStringBuiltInEncodings.UTF8.rawValue) { let buffer = UnsafeRawBufferPointer(start: ptr, count: length) return String(decoding: buffer, as: UTF8.self) } else { var byteLen = CFIndex(0) _ = CFStringGetBytes(cf, CFRangeMake(0, length), CFStringBuiltInEncodings.UTF8.rawValue, 0, false, nil, 0, &byteLen) let buffer = UnsafeMutableBufferPointer.allocate(capacity: byteLen) defer { buffer.deallocate() } _ = CFStringGetBytes(cf, CFRangeMake(0, length), CFStringBuiltInEncodings.UTF8.rawValue, 0, false, buffer.baseAddress, buffer.count, nil) return String(decoding: buffer, as: UTF8.self) } } func CRCopySanitizedPath(_ path: String, _ options: Int) -> String { return fromCFString(Sym.CRCopySanitizedPath(toCFString(path), CFIndex(options))) } // .. Base functionality ....................................................... func CSRetain(_ obj: CSTypeRef) -> CSTypeRef { return Sym.CSRetain(obj) } func CSRelease(_ obj: CSTypeRef) { Sym.CSRelease(obj) } func CSEqual(_ a: CSTypeRef, _ b: CSTypeRef) -> Bool { return Sym.CSEqual(a, b) } func CSIsNull(_ obj: CSTypeRef) -> Bool { return Sym.CSIsNull(obj) } // .. CSSymbolicator ........................................................... let kCSSymbolicatorDisallowDaemonCommunication = UInt32(0x00000800) struct BinaryRelocationInformation { var base: vm_address_t var extent: vm_address_t var name: String } struct BinaryImageInformation { var base: vm_address_t var extent: vm_address_t var uuid: CFUUIDBytes var arch: CSArchitecture var path: String var relocations: [BinaryRelocationInformation] var flags: UInt32 } func CSSymbolicatorCreateWithBinaryImageList( _ imageInfo: [BinaryImageInformation], _ flags: UInt32, _ notificationBlock: CSNotificationBlock?) -> CSSymbolicatorRef { // Convert the Swifty types above to suitable input for the C API var pathBuf: [UInt8] = [] let imageList = UnsafeMutableBufferPointer.allocate(capacity: imageInfo.count) defer { imageList.deallocate() } var totalRelocations = 0 for image in imageInfo { totalRelocations += image.relocations.count pathBuf.insert(contentsOf: image.path.utf8, at: pathBuf.count) pathBuf.append(0) } let relocationList = UnsafeMutableBufferPointer.allocate(capacity: totalRelocations) defer { relocationList.deallocate() } return pathBuf.withUnsafeBufferPointer { $0.withMemoryRebound(to: CChar.self) { pathData in var pathPtr = pathData.baseAddress! var relocationPtr = relocationList.baseAddress! for (n, image) in imageInfo.enumerated() { imageList[n].base = image.base imageList[n].extent = image.extent imageList[n].uuid = image.uuid imageList[n].arch = image.arch imageList[n].path = pathPtr imageList[n].relocations = relocationPtr imageList[n].relocationCount = UInt32(image.relocations.count) imageList[n].flags = image.flags pathPtr += strlen(pathPtr) + 1 for relocation in image.relocations { relocationPtr.pointee.base = relocation.base relocationPtr.pointee.extent = relocation.extent withUnsafeMutablePointer(to: &relocationPtr.pointee.name) { $0.withMemoryRebound(to: CChar.self, capacity: 17) { buf in var utf8Iterator = relocation.name.utf8.makeIterator() var ndx = 0 while let ch = utf8Iterator.next(), ndx < 16 { buf[ndx] = CChar(bitPattern: ch) ndx += 1 } buf[ndx] = 0 } } relocationPtr += 1 } } return Sym.CSSymbolicatorCreateWithBinaryImageList( imageList.baseAddress!, UInt32(imageList.count), flags, notificationBlock ) } } } func CSSymbolicatorGetSymbolOwnerWithAddressAtTime( _ symbolicator: CSSymbolicatorRef, _ addr: vm_address_t, _ time: CSMachineTime ) -> CSSymbolOwnerRef { return Sym.CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator, addr, time) } func CSSymbolicatorForeachSymbolOwnerAtTime( _ symbolicator: CSSymbolicatorRef, _ time: CSMachineTime, _ symbolIterator: (CSSymbolOwnerRef) -> Void ) -> UInt { return Sym.CSSymbolicatorForeachSymbolOwnerAtTime(symbolicator, time, symbolIterator) } // .. CSSymbolOwner ............................................................ func CSSymbolOwnerGetName(_ sym: CSTypeRef) -> String? { Sym.CSSymbolOwnerGetName(sym) .map(String.init(cString:)) } func CSSymbolOwnerGetSymbolWithAddress( _ owner: CSSymbolOwnerRef, _ address: vm_address_t ) -> CSSymbolRef { return Sym.CSSymbolOwnerGetSymbolWithAddress(owner, address) } func CSSymbolOwnerGetSourceInfoWithAddress( _ owner: CSSymbolOwnerRef, _ address: vm_address_t ) -> CSSourceInfoRef { return Sym.CSSymbolOwnerGetSourceInfoWithAddress(owner, address) } func CSSymbolOwnerForEachStackFrameAtAddress( _ owner: CSSymbolOwnerRef, _ address: vm_address_t, _ iterator: CSStackFrameIterator ) -> UInt { return Sym.CSSymbolOwnerForEachStackFrameAtAddress(owner, address, iterator) } func CSSymbolOwnerGetBaseAddress( _ owner: CSSymbolOwnerRef ) -> vm_address_t { return Sym.CSSymbolOwnerGetBaseAddress(owner) } // .. CSSymbol ................................................................. func CSSymbolGetRange(_ symbol: CSSymbolRef) -> CSRange { return Sym.CSSymbolGetRange(symbol) } func CSSymbolGetName(_ symbol: CSSymbolRef) -> String? { return Sym.CSSymbolGetName(symbol).map{ String(cString: $0) } } func CSSymbolGetMangledName(_ symbol: CSSymbolRef) -> String? { return Sym.CSSymbolGetMangledName(symbol).map{ String(cString: $0) } } // .. CSSourceInfo ............................................................. func CSSourceInfoGetPath(_ sourceInfo: CSSourceInfoRef) -> String? { return Sym.CSSourceInfoGetPath(sourceInfo).map{ String(cString: $0) } } func CSSourceInfoGetLineNumber(_ sourceInfo: CSSourceInfoRef) -> UInt32 { return Sym.CSSourceInfoGetLineNumber(sourceInfo) } func CSSourceInfoGetColumn(_ sourceInfo: CSSourceInfoRef) -> UInt32 { return Sym.CSSourceInfoGetColumn(sourceInfo) } #endif // os(Darwin)