diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index f7fe5a78398b0..82c39157df7e6 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -34,9 +34,10 @@ #include "swift/Runtime/Unreachable.h" #include -#include +#include #include #include +#include namespace { @@ -794,7 +795,7 @@ class ReflectionContext llvm::Optional iterateConformances( std::function Call) { std::string ConformancesPointerName = - "__swift_debug_protocolConformanceStatePointer"; + "_swift_debug_protocolConformanceStatePointer"; auto ConformancesAddrAddr = getReader().getSymbolAddress(ConformancesPointerName); if (!ConformancesAddrAddr) @@ -844,9 +845,9 @@ class ReflectionContext llvm::Optional iterateMetadataAllocations( std::function)> Call) { std::string IterationEnabledName = - "__swift_debug_metadataAllocationIterationEnabled"; + "_swift_debug_metadataAllocationIterationEnabled"; std::string AllocationPoolPointerName = - "__swift_debug_allocationPoolPointer"; + "_swift_debug_allocationPoolPointer"; auto IterationEnabledAddr = getReader().getSymbolAddress(IterationEnabledName); @@ -922,6 +923,50 @@ class ReflectionContext return llvm::None; } + llvm::Optional iterateMetadataAllocationBacktraces( + std::function + Call) { + std::string BacktraceListName = + "_swift_debug_metadataAllocationBacktraceList"; + + auto BacktraceListAddr = getReader().getSymbolAddress(BacktraceListName); + if (!BacktraceListAddr) + return "unable to look up debug variable " + BacktraceListName; + auto BacktraceListNextPtr = + getReader().readPointer(BacktraceListAddr, sizeof(StoredPointer)); + if (!BacktraceListNextPtr) + return llvm::None; + + auto BacktraceListNext = BacktraceListNextPtr->getResolvedAddress(); + while (BacktraceListNext) { + auto HeaderBytes = getReader().readBytes( + RemoteAddress(BacktraceListNext), + sizeof(MetadataAllocationBacktraceHeader)); + auto HeaderPtr = + reinterpret_cast *>( + HeaderBytes.get()); + if (HeaderPtr == nullptr) { + std::stringstream stream; + stream << "unable to read Next pointer 0x" << std::hex + << BacktraceListNext.getAddressData(); + return stream.str(); + } + auto BacktraceAddrPtr = + BacktraceListNext + + sizeof(MetadataAllocationBacktraceHeader); + auto BacktraceBytes = + getReader().readBytes(RemoteAddress(BacktraceAddrPtr), + HeaderPtr->Count * sizeof(StoredPointer)); + auto BacktracePtr = + reinterpret_cast(BacktraceBytes.get()); + + Call(HeaderPtr->Allocation, HeaderPtr->Count, BacktracePtr); + + BacktraceListNext = RemoteAddress(HeaderPtr->Next); + } + return llvm::None; + } + private: const TypeInfo *getClosureContextInfo(StoredPointer Context, const ClosureContextInfo &Info) { diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h index 4ffc3e31174c8..86e19642e51a7 100644 --- a/include/swift/Runtime/Debug.h +++ b/include/swift/Runtime/Debug.h @@ -17,11 +17,13 @@ #ifndef SWIFT_RUNTIME_DEBUG_HELPERS_H #define SWIFT_RUNTIME_DEBUG_HELPERS_H +#include "swift/Runtime/Config.h" +#include "swift/Runtime/Unreachable.h" +#include #include #include +#include #include -#include "swift/Runtime/Config.h" -#include "swift/Runtime/Unreachable.h" #ifdef SWIFT_HAVE_CRASHREPORTERCLIENT @@ -145,6 +147,9 @@ void swift_abortDynamicReplacementDisabling(); void dumpStackTraceEntry(unsigned index, void *framePC, bool shortOutput = false); +SWIFT_RUNTIME_ATTRIBUTE_NOINLINE +bool withCurrentBacktrace(std::function call); + SWIFT_RUNTIME_ATTRIBUTE_NOINLINE void printCurrentBacktrace(unsigned framesToSkip = 1); @@ -237,6 +242,9 @@ bool _swift_debug_metadataAllocationIterationEnabled; SWIFT_RUNTIME_STDLIB_SPI const void * const _swift_debug_allocationPoolPointer; +SWIFT_RUNTIME_STDLIB_SPI +std::atomic _swift_debug_metadataAllocationBacktraceList; + SWIFT_RUNTIME_STDLIB_SPI const void * const _swift_debug_protocolConformanceStatePointer; diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 6f4cefcdc35ed..07fab802ee940 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -54,6 +54,13 @@ enum MetadataAllocatorTags : uint16_t { GenericValueMetadataTag, }; +template struct MetadataAllocationBacktraceHeader { + TargetPointer Next; + TargetPointer Allocation; + uint32_t Count; + // Count backtrace pointers immediately follow. +}; + /// The buffer used by a yield-once coroutine (such as the generalized /// accessors `read` and `modify`). struct YieldOnceBuffer { diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h index 80a448a735f9c..01e6f43ab717f 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h @@ -331,6 +331,28 @@ swift_reflection_ptr_t swift_reflection_allocationMetadataPointer( SwiftReflectionContextRef ContextRef, swift_metadata_allocation_t Allocation); +/// Backtrace iterator callback passed to +/// swift_reflection_iterateMetadataAllocationBacktraces +typedef void (*swift_metadataAllocationIterator)( + swift_reflection_ptr_t AllocationPtr, size_t Count, + const swift_reflection_ptr_t Ptrs[], void *ContextPtr); + +/// Iterate over all recorded metadata allocation backtraces in the process. +/// +/// Calls the passed in Call function for each recorded backtrace. The function +/// is passed the number of backtrace entries and an array of those entries, as +/// pointers. The array is stored from deepest to shallowest, so main() will be +/// somewhere near the end. This array is valid only for the duration of the +/// call. +/// +/// Returns NULL on success. On error, returns a pointer to a C string +/// describing the error. This pointer remains valid until the next +/// swift_reflection call on the given context. +SWIFT_REMOTE_MIRROR_LINKAGE +const char *swift_reflection_iterateMetadataAllocationBacktraces( + SwiftReflectionContextRef ContextRef, swift_metadataAllocationIterator Call, + void *ContextPtr); + #ifdef __cplusplus } // extern "C" #endif diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 1136473999c36..c009212d2cccd 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -635,3 +635,21 @@ swift_reflection_ptr_t swift_reflection_allocationMetadataPointer( NativeAllocation.Size = Allocation.Size; return Context->allocationMetadataPointer(NativeAllocation); } + +const char *swift_reflection_iterateMetadataAllocationBacktraces( + SwiftReflectionContextRef ContextRef, swift_metadataAllocationIterator Call, + void *ContextPtr) { + auto Context = ContextRef->nativeContext; + auto Error = Context->iterateMetadataAllocationBacktraces( + [&](auto AllocationPtr, auto Count, auto Ptrs) { + // Ptrs is an array of StoredPointer, but the callback expects an array + // of swift_reflection_ptr_t. Those may are not always the same type. + // (For example, swift_reflection_ptr_t can be 64-bit on 32-bit systems, + // while StoredPointer is always the pointer size of the target system.) + // Convert the array to an array of swift_reflection_ptr_t. + std::vector ConvertedPtrs{&Ptrs[0], + &Ptrs[Count]}; + Call(AllocationPtr, Count, ConvertedPtrs.data(), ContextPtr); + }); + return convertError(ContextRef, Error); +} diff --git a/stdlib/public/runtime/EnvironmentVariables.def b/stdlib/public/runtime/EnvironmentVariables.def index 093c43f04f6fe..eca25ddea2518 100644 --- a/stdlib/public/runtime/EnvironmentVariables.def +++ b/stdlib/public/runtime/EnvironmentVariables.def @@ -26,6 +26,10 @@ VARIABLE(SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION, bool, false, "Enable additional metadata allocation tracking for swift-inspect to " "use.") +VARIABLE(SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING, bool, false, + "Enable logging of backtraces for each metadata allocation. Requires " + "SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION to be enabled.") + VARIABLE(SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT, uint8_t, 2, "Print warnings when using implicit @objc entrypoints. Set to " "desired reporting level, 0-3.") diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index efcee244d71f4..6e0dd53758bc9 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -223,8 +223,8 @@ static _Unwind_Reason_Code SwiftUnwindFrame(struct _Unwind_Context *context, voi } #endif -SWIFT_NOINLINE -void swift::printCurrentBacktrace(unsigned framesToSkip) { +SWIFT_ALWAYS_INLINE +static bool withCurrentBacktraceImpl(std::function call) { #if SWIFT_SUPPORTS_BACKTRACE_REPORTING constexpr unsigned maxSupportedStackDepth = 128; void *addrs[maxSupportedStackDepth]; @@ -237,14 +237,29 @@ void swift::printCurrentBacktrace(unsigned framesToSkip) { #else int symbolCount = backtrace(addrs, maxSupportedStackDepth); #endif - for (int i = framesToSkip; i < symbolCount; ++i) { - dumpStackTraceEntry(i - framesToSkip, addrs[i]); - } + call(addrs, symbolCount); + return true; #else - fprintf(stderr, "\n"); + return false; #endif } +SWIFT_NOINLINE +bool swift::withCurrentBacktrace(std::function call) { + return withCurrentBacktraceImpl(call); +} + +SWIFT_NOINLINE +void swift::printCurrentBacktrace(unsigned framesToSkip) { + bool success = withCurrentBacktraceImpl([&](void **addrs, int symbolCount) { + for (int i = framesToSkip; i < symbolCount; ++i) { + dumpStackTraceEntry(i - framesToSkip, addrs[i]); + } + }); + if (!success) + fprintf(stderr, "\n"); +} + #ifdef SWIFT_HAVE_CRASHREPORTERCLIENT #include diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 5d8cabca493c7..c2976cae5bfc1 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -5504,12 +5504,19 @@ AllocationPool{PoolRange{InitialAllocationPool.Pool, bool swift::_swift_debug_metadataAllocationIterationEnabled = false; const void * const swift::_swift_debug_allocationPoolPointer = &AllocationPool; +std::atomic swift::_swift_debug_metadataAllocationBacktraceList; static void checkAllocatorDebugEnvironmentVariable(void *context) { _swift_debug_metadataAllocationIterationEnabled = runtime::environment::SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION(); - if (!_swift_debug_metadataAllocationIterationEnabled) + if (!_swift_debug_metadataAllocationIterationEnabled) { + if (runtime::environment::SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING()) + swift::warning(RuntimeErrorFlagNone, + "Warning: SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING " + "without SWIFT_DEBUG_ENABLE_METADATA_ALLOCATION_ITERATION " + "has no effect.\n"); return; + } // Write a PoolTrailer to the end of InitialAllocationPool and shrink // the pool accordingly. @@ -5523,6 +5530,24 @@ static void checkAllocatorDebugEnvironmentVariable(void *context) { AllocationPool.store(poolCopy, std::memory_order_relaxed); } +static void recordBacktrace(void *allocation) { + withCurrentBacktrace([&](void **addrs, int count) { + MetadataAllocationBacktraceHeader *record = + (MetadataAllocationBacktraceHeader *)malloc( + sizeof(*record) + count * sizeof(void *)); + record->Allocation = allocation; + record->Count = count; + memcpy(record + 1, addrs, count * sizeof(void *)); + + record->Next = _swift_debug_metadataAllocationBacktraceList.load( + std::memory_order_relaxed); + while (!_swift_debug_metadataAllocationBacktraceList.compare_exchange_weak( + record->Next, record, std::memory_order_release, + std::memory_order_relaxed)) + ; // empty + }); +} + void *MetadataAllocator::Allocate(size_t size, size_t alignment) { assert(Tag != 0); assert(alignment <= alignof(void*)); @@ -5582,8 +5607,14 @@ void *MetadataAllocator::Allocate(size_t size, size_t alignment) { AllocationHeader *header = (AllocationHeader *)allocation; header->Size = size; header->Tag = Tag; - - return allocation + sizeof(AllocationHeader); + + auto *returnedAllocation = allocation + sizeof(AllocationHeader); + + if (runtime::environment :: + SWIFT_DEBUG_ENABLE_METADATA_BACKTRACE_LOGGING()) + recordBacktrace(returnedAllocation); + + return returnedAllocation; } else { return allocation; } diff --git a/tools/swift-inspect/Sources/swift-inspect/Backtrace.swift b/tools/swift-inspect/Sources/swift-inspect/Backtrace.swift new file mode 100644 index 0000000000000..1ee0f052cce1e --- /dev/null +++ b/tools/swift-inspect/Sources/swift-inspect/Backtrace.swift @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 +// +//===----------------------------------------------------------------------===// + +import SwiftRemoteMirror + +struct Backtrace { + enum Style { + case oneLine + case long + } + + /// The pointers to the locations in the backtrace. These are stored from + /// deepest to shallowest, so main() will be somewhere near the end. + var ptrs: [swift_reflection_ptr_t] + + func symbolString( + ptr: swift_reflection_ptr_t, + inspector: Inspector + ) -> String { + let symbol = inspector.getSymbol(address: ptr) + let name = symbol.name ?? "" + let library = symbol.library ?? "" + return "\(hex: ptr) (\(library)) \(name)" + } + + func symbolicatedOneLine(inspector: Inspector) -> String { + return ptrs.reversed().map { + symbolString(ptr: $0, inspector: inspector) + }.joined(separator: " | ") + } + + func symbolicatedLong(inspector: Inspector) -> String { + return ptrs.reversed().enumerated().map { + let indent = String(repeating: " ", count: $0 + 1) + return indent + symbolString(ptr: $1, inspector: inspector) + }.joined(separator: "\n") + } + + func symbolicated(style: Style, inspector: Inspector) -> String { + switch style { + case .oneLine: + return symbolicatedOneLine(inspector: inspector) + case .long: + return symbolicatedLong(inspector: inspector) + } + } +} diff --git a/tools/swift-inspect/Sources/swift-inspect/Inspector.swift b/tools/swift-inspect/Sources/swift-inspect/Inspector.swift index a77fa6bd8cd1f..40a6b3979d504 100644 --- a/tools/swift-inspect/Sources/swift-inspect/Inspector.swift +++ b/tools/swift-inspect/Sources/swift-inspect/Inspector.swift @@ -67,11 +67,19 @@ class Inspector { } func getAddr(symbolName: String) -> swift_addr_t { - let symbol = CSSymbolOwnerGetSymbolWithMangledName(swiftCore, symbolName) + let symbol = CSSymbolOwnerGetSymbolWithMangledName(swiftCore, + "_" + symbolName) let range = CSSymbolGetRange(symbol) return swift_addr_t(range.location) } - + + func getSymbol(address: swift_addr_t) -> (name: String?, library: String?) { + let symbol = CSSymbolicatorGetSymbolWithAddressAtTime(symbolicator, address, + kCSNow) + return (CSSymbolGetName(symbol), + CSSymbolOwnerGetName(CSSymbolGetSymbolOwner(symbol))) + } + enum Callbacks { static let QueryDataLayout: @convention(c) (UnsafeMutableRawPointer?, @@ -114,12 +122,12 @@ private func QueryDataLayoutFn(context: UnsafeMutableRawPointer?, inBuffer: UnsafeMutableRawPointer?, outBuffer: UnsafeMutableRawPointer?) -> CInt { switch type { - case DLQ_GetPointerSize: - let size = UInt8(MemoryLayout.stride) - outBuffer!.storeBytes(of: size, toByteOffset: 0, as: UInt8.self) - return 1 - default: - return 0 + case DLQ_GetPointerSize: + let size = UInt8(MemoryLayout.stride) + outBuffer!.storeBytes(of: size, toByteOffset: 0, as: UInt8.self) + return 1 + default: + return 0 } } diff --git a/tools/swift-inspect/Sources/swift-inspect/RemoteMirrorExtensions.swift b/tools/swift-inspect/Sources/swift-inspect/RemoteMirrorExtensions.swift index 4467eb60ca138..9a0141e1369d8 100644 --- a/tools/swift-inspect/Sources/swift-inspect/RemoteMirrorExtensions.swift +++ b/tools/swift-inspect/Sources/swift-inspect/RemoteMirrorExtensions.swift @@ -63,6 +63,20 @@ extension SwiftReflectionContextRef { try throwError(str: errStr) } + func iterateMetadataAllocationBacktraces( + _ body: (swift_reflection_ptr_t, Int, UnsafePointer) + -> Void + ) throws { + var body = body + let errStr = swift_reflection_iterateMetadataAllocationBacktraces(self, { + let callPtr = $3!.bindMemory(to: + ((swift_reflection_ptr_t, Int, UnsafePointer) + -> Void).self, capacity: 1) + callPtr.pointee($0, $1, $2!) + }, &body) + try throwError(str: errStr) + } + func metadataPointer( allocation: swift_metadata_allocation_t ) -> swift_reflection_ptr_t { @@ -82,4 +96,13 @@ extension SwiftReflectionContextRef { } return allocations } + + var allocationBacktraces: [swift_reflection_ptr_t: Backtrace] { + var backtraces: [swift_reflection_ptr_t: Backtrace] = [:] + try! iterateMetadataAllocationBacktraces { allocation, count, ptrs in + let array = Array(UnsafeBufferPointer(start: ptrs, count: count)) + backtraces[allocation] = Backtrace(ptrs: array) + } + return backtraces + } } diff --git a/tools/swift-inspect/Sources/swift-inspect/main.swift b/tools/swift-inspect/Sources/swift-inspect/main.swift index 53301f06cd21d..0c14d546c5132 100644 --- a/tools/swift-inspect/Sources/swift-inspect/main.swift +++ b/tools/swift-inspect/Sources/swift-inspect/main.swift @@ -33,16 +33,27 @@ func dumpConformanceCache(context: SwiftReflectionContextRef) throws { } } -func dumpRawMetadata(context: SwiftReflectionContextRef) throws { +func dumpRawMetadata( + context: SwiftReflectionContextRef, + inspector: Inspector, + backtraceStyle: Backtrace.Style? +) throws { + let backtraces = backtraceStyle != nil ? context.allocationBacktraces : [:] for allocation in context.allocations { print("Metadata allocation at: \(hex: allocation.ptr) " + "size: \(allocation.size) tag: \(allocation.tag)") + printBacktrace(style: backtraceStyle, for: allocation.ptr, in: backtraces, inspector: inspector) } } -func dumpGenericMetadata(context: SwiftReflectionContextRef) throws { +func dumpGenericMetadata( + context: SwiftReflectionContextRef, + inspector: Inspector, + backtraceStyle: Backtrace.Style? +) throws { let allocations = context.allocations.sorted() let metadatas = allocations.findGenericMetadata(in: context) + let backtraces = backtraceStyle != nil ? context.allocationBacktraces : [:] print("Address","Allocation","Size","Offset","Name", separator: "\t") for metadata in metadatas { @@ -53,9 +64,26 @@ func dumpGenericMetadata(context: SwiftReflectionContextRef) throws { terminator: "\t") } else { print("???\t???\t???", terminator: "\t") - } print(metadata.name) + if let allocation = metadata.allocation { + printBacktrace(style: backtraceStyle, for: allocation.ptr, in: backtraces, inspector: inspector) + } + } +} + +func printBacktrace( + style: Backtrace.Style?, + for ptr: swift_reflection_ptr_t, + in backtraces: [swift_reflection_ptr_t: Backtrace], + inspector: Inspector +) { + if let style = style { + if let backtrace = backtraces[ptr] { + print(backtrace.symbolicated(style: style, inspector: inspector)) + } else { + print("Unknown backtrace.") + } } } @@ -86,14 +114,14 @@ func makeReflectionContext( func withReflectionContext( nameOrPid: String, - _ body: (SwiftReflectionContextRef) throws -> Void + _ body: (SwiftReflectionContextRef, Inspector) throws -> Void ) throws { let (inspector, context) = makeReflectionContext(nameOrPid: nameOrPid) defer { swift_reflection_destroyReflectionContext(context) inspector.destroyContext() } - try body(context) + try body(context, inspector) } struct SwiftInspect: ParsableCommand { @@ -114,8 +142,8 @@ struct DumpConformanceCache: ParsableCommand { var nameOrPid: String func run() throws { - try withReflectionContext(nameOrPid: nameOrPid) { - try dumpConformanceCache(context: $0) + try withReflectionContext(nameOrPid: nameOrPid) { context, _ in + try dumpConformanceCache(context: context) } } } @@ -127,23 +155,43 @@ struct DumpRawMetadata: ParsableCommand { var nameOrPid: String + @Flag(help: "Show the backtrace for each allocation") + var backtrace: Bool + + @Flag(help: "Show a long-form backtrace for each allocation") + var backtraceLong: Bool + func run() throws { + let style = backtrace ? Backtrace.Style.oneLine : + backtraceLong ? Backtrace.Style.long : + nil try withReflectionContext(nameOrPid: nameOrPid) { - try dumpRawMetadata(context: $0) + try dumpRawMetadata(context: $0, inspector: $1, backtraceStyle: style) } } } struct DumpGenericMetadata: ParsableCommand { static let configuration = CommandConfiguration( - abstract: "Print the target's metadata allocations.") - @Argument(help: "The pid or partial name of the target process") + abstract: "Print the target's generic metadata allocations.") + @Argument(help: "The pid or partial name of the target process") var nameOrPid: String + @Flag(help: "Show the backtrace for each allocation") + var backtrace: Bool + + @Flag(help: "Show a long-form backtrace for each allocation") + var backtraceLong: Bool + func run() throws { + let style = backtrace ? Backtrace.Style.oneLine : + backtraceLong ? Backtrace.Style.long : + nil try withReflectionContext(nameOrPid: nameOrPid) { - try dumpGenericMetadata(context: $0) + try dumpGenericMetadata(context: $0, + inspector: $1, + backtraceStyle: style) } } } diff --git a/tools/swift-inspect/Sources/swift-inspect/symbolication.swift b/tools/swift-inspect/Sources/swift-inspect/symbolication.swift index d1096307e59df..5da69269af7e6 100644 --- a/tools/swift-inspect/Sources/swift-inspect/symbolication.swift +++ b/tools/swift-inspect/Sources/swift-inspect/symbolication.swift @@ -46,10 +46,18 @@ enum Sym { symbol(coreSymbolicationHandle, "CSSymbolGetName") static let CSSymbolGetMangledName: @convention(c) (CSTypeRef) -> UnsafePointer? = symbol(coreSymbolicationHandle, "CSSymbolGetMangledName") + static let CSSymbolGetSymbolOwner: @convention(c) + (CSSymbolRef) -> CSSymbolOwnerRef = + symbol(coreSymbolicationHandle, "CSSymbolGetSymbolOwner") static let CSSymbolIsFunction: @convention(c) (CSTypeRef) -> CBool = symbol(coreSymbolicationHandle, "CSSymbolIsFunction") static let CSSymbolGetRange: @convention(c) (CSTypeRef) -> Range = symbol(coreSymbolicationHandle, "CSSymbolGetRange") + static let CSSymbolOwnerGetName: @convention(c) (CSSymbolOwnerRef) -> UnsafePointer? = + symbol(coreSymbolicationHandle, "CSSymbolOwnerGetName") + static let CSSymbolicatorGetSymbolWithAddressAtTime: @convention(c) + (CSSymbolicatorRef, mach_vm_address_t, CSMachineTime) -> CSSymbolRef = + symbol(coreSymbolicationHandle, "CSSymbolicatorGetSymbolWithAddressAtTime") static let task_start_peeking: @convention(c) (task_t) -> kern_return_t = symbol(symbolicationHandle, "task_start_peeking") static let task_peek: @convention(c) (task_t, mach_vm_address_t, mach_vm_size_t, @@ -66,6 +74,10 @@ enum Sym { typealias CSMachineTime = UInt64 let kCSNow = CSMachineTime(Int64.max) + 1 +typealias CSSymbolicatorRef = CSTypeRef +typealias CSSymbolRef = CSTypeRef +typealias CSSymbolOwnerRef = CSTypeRef + func pidFromHint(_ hint: String) -> pid_t? { let result = Sym.pidFromHint(hint as NSString) return result == 0 ? nil : result @@ -100,12 +112,12 @@ func CSSymbolOwnerGetSymbolWithMangledName( func CSSymbolGetName(_ sym: CSTypeRef) -> String? { let name = Sym.CSSymbolGetName(sym) - return name.map({ String(cString: $0) }) + return name.map{ String(cString: $0) } } func CSSymbolGetMangledName(_ sym: CSTypeRef) -> String? { let name = Sym.CSSymbolGetMangledName(sym) - return name.map({ String(cString: $0) }) + return name.map{ String(cString: $0) } } func CSSymbolIsFunction(_ sym: CSTypeRef) -> Bool { @@ -116,6 +128,23 @@ func CSSymbolGetRange(_ sym: CSTypeRef) -> Range { Sym.CSSymbolGetRange(sym) } +func CSSymbolGetSymbolOwner(_ sym: CSTypeRef) -> CSSymbolOwnerRef { + Sym.CSSymbolGetSymbolOwner(sym) +} + +func CSSymbolOwnerGetName(_ sym: CSTypeRef) -> String? { + Sym.CSSymbolOwnerGetName(sym) + .map(String.init(cString:)) +} + +func CSSymbolicatorGetSymbolWithAddressAtTime( + _ symbolicator: CSSymbolicatorRef, + _ address: mach_vm_address_t, + _ time: CSMachineTime +) -> CSSymbolRef { + Sym.CSSymbolicatorGetSymbolWithAddressAtTime(symbolicator, address, time) +} + func task_start_peeking(_ task: task_t) -> Bool { let result = Sym.task_start_peeking(task) if result == KERN_SUCCESS {