debugging 如何使用Thread.callStackSymbols解析从另一个线程调用的父方法的ID?

cgvd09ve  于 2023-10-24  发布在  其他
关注(0)|答案(2)|浏览(125)

我正在尝试实现一个小型的分析解决方案,以自动化的方式跟踪整个代码库中的调用。
不幸的是,我对底层操作系统的东西一无所知,我甚至不知道如何谷歌这些东西。因此,以下几点对我来说是不清楚的:
1.堆栈跟踪中的列指的是什么?
1.什么是内存加载地址?
1.什么是回邮地址?
我确实发现,在堆栈跟踪中索引2处的0x1234列是调用方法的唯一标识符,索引3处的列是其父方法的唯一标识符。这样我就可以跟踪同一个线程中的子方法和父方法。(有时这个0x1234似乎被重用,但这没关系,因为在那一点上我已经跟踪了跟踪。)
1.如何在子方法中跟踪父方法,当它被另一个线程调用时?
1.如何在stacktrace中看到子方法通过闭包完成?
当在Xcode中调试时,我在Xcode侧面板中看到了这些信息,所以它一定是某个地方!

除此之外,我迷路了,请帮帮忙?
我还附上了这个例子的代码:

import Foundation

struct Dog {
    func bark() {
        print("CallStackSymbols for '\(#function)':")
        print("\t\(Thread.callStackSymbols.joined(separator: "\n\t"))")
        
        DispatchQueue.global(qos: .userInitiated).async {
            barkInBackground()
        }
    }
    
    func barkInBackground() {
        print("CallStackSymbols for '\(#function)':")
        print("\t\(Thread.callStackSymbols.joined(separator: "\n\t"))")
    }
}

let dog = Dog()
dog.bark()
sleep(1000)
ergxz8rk

ergxz8rk1#

libdispatch是达尔文系统中处理队列和运行块等的一部分。这也是调试器查询”谁在何时调度了什么“历史信息的代理。然而,安装的调度运行时库:/usr/lib/system/libdispatch.dylib并不收集这些信息。(或者实际上甚至添加了这样做的启示)会减慢执行速度,增加内存使用,并且libdispatch并不需要它来完成它的真实的工作。dispatch是系统的一个非常关键的性能部分,因此库的普通版本无法承受做不必要的工作。
相反,有一个“内省”版本的libdispatch,当你启用“队列调度”功能时,Xcode会加载它而不是普通版本。这个版本的libdispatch确实收集了这些信息,并提供了一个API来访问它,lldb使用它来生成这些“历史线程”。你可以看到你确实在使用变体库:如果在Xcode中停止时,你运行lldb命令:

(lldb) image list libdispatch.dylib
[  0] 6C6BE4E9-B201-3B02-8E69-33DF61FF3A44 0x0000000102ad8000 /usr/lib/system/introspection/libdispatch.dylib

这就是所使用的libdispatch的内省版本。
但是在达尔文系统上正常运行的应用程序不应该加载这个库,因此不会收集有关队列和分派的历史信息,也不会提供查询此信息的API。因此,如果您想自己跟踪它,您必须手动完成,如您所示。

hec6srdp

hec6srdp2#

经过大量的研究,我自己找到了问题的答案。

  • 我将省略对以下问题的回答,因为根据新的信息,它们已经变得无关紧要,我觉得自己没有足够的能力来满意地回答它们:*

1.* 堆栈跟踪中的列指的是什么?*
1.* 什么是内存加载地址 *
1.* 什么是回邮地址 *

重新定义问题#1:“How to get a "parent" thread for NSThread in iOS?

你不能。没有父线程这样的东西。线程是一个独立的实体,即使一个线程可以与其他线程通信,但没有涉及层次结构。(Source

重新定义问题#2:“如何跨多线程跟踪方法的逻辑跟踪?”

当一个新的任务被赋予一个后台队列(这可能会在后台创建一个新的线程)时,你必须向DispatchQueue的闭包传递一个id。
(这里不可能进行干净的方法混合,因为您必须更改原始的实现,而不是添加一些东西。
下面是一个工作的示例代码(=>希望跟踪包含多个线程的客户,必须使用自定义 Package 器(例如扩展方法)因为iOS没有公开任何接口以自动方式完成此操作)。

let traceId = UUID().uuidString
DispatchQueue.global(qos: .userInitiated).async {
    Tracker.trackMethod(self, parentId: traceId)
    barkInBackground()
}

相关问题