Skip to content

Commit 3c937fa

Browse files
committed
feat:using @_silgen_name("mach_backtrace")
1 parent 8f7bb4b commit 3c937fa

File tree

5 files changed

+76
-54
lines changed

5 files changed

+76
-54
lines changed

SKApmTools.podspec

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ TODO: Add long description of the pod here.
3030

3131
s.ios.deployment_target = '10.0'
3232

33-
s.source_files = 'SKApmTools/Classes/**/*'
33+
s.source_files = 'SKApmTools/Classes/**/*.{swift,h,c}'
34+
35+
s.pod_target_xcconfig = {
36+
"DEFINES_MODULE" => "YES"
37+
}
3438

3539
# s.resource_bundles = {
3640
# 'SKApmTools' => ['SKApmTools/Assets/*.png']

SKApmTools/Classes/ANR/SKANRMonitor.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import Foundation
99

10-
open class SKANRMonitor: NSObject{
10+
@objc open class SKANRMonitor: NSObject{
1111

1212
@objc public static let sharedInstance = SKANRMonitor()
1313
/// 单次耗时较长的卡顿阈值: 默认值为300ms,单位:毫秒
@@ -25,7 +25,7 @@ open class SKANRMonitor: NSObject{
2525
/// 卡顿次数记录
2626
fileprivate var count: Int = 0
2727

28-
fileprivate var pendingEntities: [SKBacktraceEntity] = []
28+
@objc public var pendingEntities: [SKBacktraceEntity] = []
2929

3030
fileprivate var pendingEntityDict: [String: SKBacktraceEntity] = [:]
3131

@@ -36,7 +36,7 @@ open class SKANRMonitor: NSObject{
3636
fileprivate var filePath: String? {
3737
get {
3838
let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first as NSString?
39-
if let filePath = path?.appendingPathComponent("wd_apm_anr.archive") {
39+
if let filePath = path?.appendingPathComponent("sk_apm_anr.archive") {
4040
return filePath
4141
}
4242
return nil
@@ -58,21 +58,21 @@ open class SKANRMonitor: NSObject{
5858
}
5959

6060
/// 监测到一个卡顿回调
61-
public class func monitorCallback(_ callback: @escaping MonitorCallback) {
61+
@objc public class func monitorCallback(_ callback: @escaping MonitorCallback) {
6262
SKANRMonitor.sharedInstance.callback = callback
6363
}
6464

6565
/// 获取卡顿数据
66-
public class func getPendingEntities() -> [SKBacktraceEntity] {
66+
@objc public class func getPendingEntities() -> [SKBacktraceEntity] {
6767
return SKANRMonitor.sharedInstance.pendingEntities
6868
}
6969

7070
/// 清理卡顿数据
71-
public class func clearPendingEntities() {
71+
@objc public class func clearPendingEntities() {
7272
SKANRMonitor.sharedInstance._clearEntities()
7373
}
7474

75-
public func _clearEntities() {
75+
private func _clearEntities() {
7676
os_unfair_lock_lock(&lock)
7777
pendingEntities.removeAll()
7878
pendingEntityDict.removeAll()
@@ -118,6 +118,10 @@ open class SKANRMonitor: NSObject{
118118
}
119119

120120
private func handleEntity(_ entity: SKBacktraceEntity) {
121+
// filter invalid data
122+
if entity.validFunction == "main" {
123+
return
124+
}
121125
let key = "\(entity.validAddress)_\(entity.validFunction)"
122126
if !self.pendingEntityDict.keys.contains(key) {
123127
os_unfair_lock_lock(&lock)
@@ -158,7 +162,7 @@ open class SKANRMonitor: NSObject{
158162
}
159163
}
160164

161-
fileprivate func observerCallBack() -> CFRunLoopObserverCallBack {
165+
private func observerCallBack() -> CFRunLoopObserverCallBack {
162166
return {(observer, activity, pointer) in
163167
SKANRMonitor.sharedInstance.activity = activity
164168
if let semaphore = SKANRMonitor.sharedInstance.semaphore {

SKApmTools/Classes/BackTrace/SKBackTrace.swift

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,29 @@ public class SKBackTrace {
1717
let addrs = UnsafeMutablePointer<UnsafeMutableRawPointer?>.allocate(capacity: Int(stackSize))
1818
defer { addrs.deallocate() }
1919
let frameCount = mach_back_trace(mach_thread, stack: addrs, maxSymbols: Int32(stackSize))
20-
let buf = UnsafeBufferPointer(start: addrs, count: Int(frameCount))
2120
var validAddress = "", validFunction = "", traceContent = ""
2221
var symbols : [SKStackSymbol] = []
23-
let bundleName = Bundle.main.infoDictionary?["CFBundleName"] // like SKApmTools_Example
22+
let info = Bundle.main.infoDictionary
23+
let bundleName = "\(info?["CFBundleExecutable"] ?? "")_\(info?["CFBundleName"] ?? "")"// like SKApmTools_Example
24+
25+
let buf = UnsafeBufferPointer(start: addrs, count: Int(frameCount))
2426
/// 解析堆栈地址
2527
for (index, addr) in buf.enumerated() {
2628
guard let addr = addr else { continue }
27-
let address = UInt(bitPattern: addr)
28-
let symbol = mach_O_parseSymbol(with: address, index: index)
29+
let symbol = mach_O_parseSymbol(with: addr, index: index)
2930
traceContent.append("\(symbol.info)")
3031
symbols.append(symbol)
31-
if let bundleName = bundleName, validAddress.count == 0, bundleName as! String == symbol.baseAddress {
32+
let demangledSymbol = symbol.demangledSymbol
33+
if validFunction.count == 0, demangledSymbol.count > 0, bundleName.contains(symbol.module) {
3234
validAddress = symbol.formatAddress
33-
validFunction = symbol.demangledSymbol
35+
validFunction = demangledSymbol
3436
}
3537
}
36-
if validAddress.count == 0 {
38+
if validFunction.count == 0 {
3739
validAddress = symbols.first?.formatAddress ?? ""
3840
validFunction = symbols.first?.demangledSymbol ?? ""
3941
}
42+
4043
let time = Date.timeIntervalSinceReferenceDate
4144
let entity = SKBacktraceEntity(threadId: UInt(mach_thread), validAddress: validAddress, validFunction: validFunction, traceContent: traceContent, traceSymbols: symbols, occurenceTime: time)
4245
return entity
@@ -92,11 +95,17 @@ public class SKBackTrace {
9295

9396
}
9497

98+
/// 声明C的符号
9599
@_silgen_name("mach_backtrace")
96100
public func mach_back_trace(_ thread: thread_t,
97101
stack: UnsafeMutablePointer<UnsafeMutableRawPointer?>,
98102
maxSymbols: Int32) -> Int32
99103

104+
@_silgen_name("backtrace_symbols")
105+
private func backtrace_symbols(_ stack: UnsafePointer<UnsafeMutableRawPointer?>!, _ frame: Int32) -> UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!
106+
107+
108+
100109
extension Character {
101110
var isAscii: Bool {
102111
return unicodeScalars.allSatisfy { $0.isASCII }

SKApmTools/Classes/BackTrace/SKDynamicSymbolic.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import Foundation
1111
public private(set) var _appASLR : Int = 0
1212

1313
/// 根据 Mach-O 符号表 解析符号
14-
func mach_O_parseSymbol(with address: UInt, index: Int) -> SKStackSymbol {
14+
func mach_O_parseSymbol(with addr: UnsafeMutableRawPointer, index: Int) -> SKStackSymbol {
1515
var info = dl_info()
16-
sk_dladdr(address, &info)
16+
let address = UInt(bitPattern: addr)
17+
// sk_dladdr(address, &info)
18+
dladdr(addr, &info)
1719

1820
return SKStackSymbol(symbol: _symbol(info: info),
1921
file: _dli_fname(with: info),
@@ -24,11 +26,6 @@ func mach_O_parseSymbol(with address: UInt, index: Int) -> SKStackSymbol {
2426
index: index)
2527
}
2628

27-
/// 从动态符号表查找符号
28-
private func _dynamicParseSymbol(with address: UInt, aslr: Int) -> SKBacktraceEntry? {
29-
return nil
30-
}
31-
3229
/// the symbol nearest the address
3330
private func _symbol(info: dl_info) -> String {
3431
if

SKApmTools/Classes/BackTrace/SKStackSymbol.swift

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,62 +7,70 @@
77

88
import Foundation
99

10-
public struct SKStackSymbol: Codable {
11-
public let symbol: String
12-
public let file: String
13-
public let address: UInt
14-
public let symbolAddress: UInt
15-
public let image: String
16-
public let offset: UInt
17-
public let index: Int
10+
@objc public class SKStackSymbol: NSObject, Codable {
11+
@objc public var symbol: String
12+
@objc public var file: String
13+
@objc public var address: UInt
14+
@objc public var symbolAddress: UInt
15+
@objc public var image: String
16+
@objc public var offset: UInt
17+
@objc public var index: Int
1818

19-
public var demangledSymbol: String {
19+
@objc public var demangledSymbol: String {
2020
return _stdlib_demangleName(symbol)
2121
}
2222

23-
public var baseAddress: String {
23+
@objc public var module: String {
2424
return image.utf8CString.withUnsafeBufferPointer { (imageBuffer: UnsafeBufferPointer<CChar>) -> String in
2525
return String(format: "%s", UInt(bitPattern: imageBuffer.baseAddress))
2626
}
2727
}
2828

29-
public var formatAddress: String {
29+
@objc public var formatAddress: String {
3030
#if arch(x86_64) || arch(arm64)
3131
return String(format: "0x%016llx", address)
3232
#else
3333
return String(format: "0x%08lx", address)
3434
#endif
3535
}
3636

37-
public var info: String {
37+
@objc public var info: String {
3838
return image.utf8CString.withUnsafeBufferPointer { (imageBuffer: UnsafeBufferPointer<CChar>) -> String in
39-
let add = UInt(bitPattern: imageBuffer.baseAddress)
39+
let module = UInt(bitPattern: imageBuffer.baseAddress)
4040
#if arch(x86_64) || arch(arm64)
41-
return String(format: "%-4ld%-35s 0x%016llx %@ + %ld \n", index, add, address, demangledSymbol, offset)
41+
return String(format: "%-4ld%-35s 0x%016llx %@ + %ld \n", index, module, address, demangledSymbol, offset)
4242
#else
43-
return String(format: "%-4d%-35s 0x%08lx %@ + %d \n", index, add, address, demangledSymbol, offset)
43+
return String(format: "%-4d%-35s 0x%08lx %@ + %d \n", index, module, address, demangledSymbol, offset)
4444
#endif
4545
}
4646
}
47+
48+
init(symbol: String, file: String, address: UInt, symbolAddress: UInt, image: String, offset: UInt, index: Int) {
49+
self.symbol = symbol
50+
self.file = file
51+
self.address = address
52+
self.symbolAddress = symbolAddress
53+
self.image = image
54+
self.offset = offset
55+
self.index = index
56+
}
4757
}
4858

49-
50-
public struct SKBacktraceEntity: Codable {
51-
public let threadId: UInt // 259
52-
public let validAddress: String // address
53-
public let validFunction: String // function
54-
public let traceContent: String
55-
public let traceSymbols: [SKStackSymbol]
56-
public let occurenceTime: TimeInterval
57-
}
58-
59-
public struct SKBacktraceEntry: Codable {
60-
public let `class`: String
61-
public let name: String
62-
public let address: UInt
59+
@objc public class SKBacktraceEntity: NSObject, Codable {
60+
@objc public var threadId: UInt // 259
61+
@objc public var validAddress: String // address
62+
@objc public var validFunction: String // function
63+
@objc public var traceContent: String
64+
@objc public var traceSymbols: [SKStackSymbol]
65+
@objc public var occurenceTime: TimeInterval
6366

64-
public var log: String {
65-
return "calss: \(self.class) name:\(name) address:\(String(address, radix: 16))\n"
67+
init(threadId: UInt, validAddress: String, validFunction: String, traceContent: String, traceSymbols: [SKStackSymbol], occurenceTime: TimeInterval) {
68+
self.threadId = threadId
69+
self.validAddress = validAddress
70+
self.validFunction = validFunction
71+
self.traceContent = traceContent
72+
self.traceSymbols = traceSymbols
73+
self.occurenceTime = occurenceTime
6674
}
6775
}
6876

0 commit comments

Comments
 (0)