Macos OSX内核死机诊断。如何翻译回溯地址

Macos OSX内核死机诊断。如何翻译回溯地址,macos,debugging,kernel,backtrace,xnu,Macos,Debugging,Kernel,Backtrace,Xnu,我正在调试一个在我的mac上导致内核转储的驱动程序。它显示由一系列地址组成的长回溯: panic(cpu 6 caller 0xffffff8004dc9986): trying to interlock destroyed mutex (0xffffff8049deedb0) Backtrace (CPU 6), Frame : Return Address 0xffffff93b1c8bb50 : 0xffffff8004ce5307 0xffffff93b1c8bbd0 : 0xff

我正在调试一个在我的mac上导致内核转储的驱动程序。它显示由一系列地址组成的长回溯:

panic(cpu 6 caller 0xffffff8004dc9986): trying to interlock destroyed mutex  
(0xffffff8049deedb0)
Backtrace (CPU 6), Frame : Return Address
0xffffff93b1c8bb50 : 0xffffff8004ce5307 
0xffffff93b1c8bbd0 : 0xffffff8004dc9986 
0xffffff93b1c8bbe0 : 0xffffff8004d099eb 
0xffffff93b1c8bc20 : 0xffffff7f85604899 
0xffffff93b1c8bc50 : 0xffffff800519776b 
0xffffff93b1c8bc90 : 0xffffff80051f336c 
0xffffff93b1c8be00 : 0xffffff8005205fb3 
0xffffff93b1c8bef0 : 0xffffff80052028a6 
0xffffff93b1c8bf60 : 0xffffff800522afd1 
0xffffff93b1c8bfb0 : 0xffffff8004df4b16 
我假设,由于计算机重新启动,地址转换现在是无用的,因为每次启动迭代后内存映射可能不同

是否可以选择将相关方法与retrospect中的每个地址相匹配,或者预先设置适当的配置?
谢谢

是的,您完全可以用符号表示内核死机跟踪,但要追溯执行,您需要从死机日志中获得更多信息,而不仅仅是原始堆栈跟踪。正如您所说,地址仅相对于加载地址有意义

苹果公司关于这个主题的官方文件有点过时。它给出的例子来自Darwin9,即OSX10.5,自那以后,随着内核ASLR和KEXTUUID的引入,情况发生了一些变化。我会试着给你一个非常快速的最新指南

1。简单的方法

如果您的恐慌是可复制的,那么最简单的方法就是让内核为您象征它。使用内核引导参数
keepsyms=1
意味着内核不会丢弃内核和kext映像中存储的任何符号,并在出现死机时在堆栈跟踪中查找返回指针

只需将
keepsyms=1
添加到
/Library/Preferences/SystemConfiguration/com.apple.Boot.plist
中的内核标志设置中,或添加到
Boot args
NVRAM变量中即可。重新启动,任何后续的恐慌都将被自动符号化。可以通过<代码> C++ +文件> /COD>命令行实用程序来运行被损坏的C++符号,以获得适当的C++函数签名。比如说,

$ echo __ZN32IOPCIMessagedInterruptController17registerInterruptEP9IOServiceiPvPFvS2_S2_S2_iES2_ | c++filt
IOPCIMessagedInterruptController::registerInterrupt(IOService*, int, void*, void (*)(void*, void*, void*, int), void*)
2。手动方式

如果你有一种似乎无法再现的无符号、神秘的恐慌,那么简单的方法没有多大帮助

紧接着堆栈跟踪,在紧急日志中查找以“backtrace中的内核扩展:”开头的部分。这将列出与死机相关的任何KEXT,包括它们的加载地址、版本和UUID。地址以范围形式给出;起始地址位于
->
的左侧,紧跟在
@
之后。最后一个地址在箭头的右边。通过这些信息,您应该能够识别堆栈跟踪中列出的每个代码地址(右侧的十六进制数)所在的kext

除了其中一些不会匹配任何kext。除非在某些奇怪的情况下,否则这些将来自内核本身。内核映像(kernel或mach_kernel)加载地址在更下方,上面写着“kernel text base:”

一旦您知道要查看哪个可执行映像,
atos
命令将允许您对每个地址进行符号化

例如,让我们假设这一行处于恐慌状态:

…
0xffffff8098c1bba0 : 0xffffff7f80c343f2
…
我们还发现:

  Kernel Extensions in backtrace:
     com.apple.iokit.IOPCIFamily(2.9)[BDA92C3B-AD86-33E5-A7F1-1603465350A7]@0xffffff7f80c1a000->0xffffff7f80c4dfff
请注意,0xFFFF7F80C343F2大于(或等于)0xFFFF7F80C1A000且小于(或等于)0xFFFF7F80C4DFFF,因此所讨论的代码属于IOPCIficifamily

这使我看到以下命令(及其输出):

-o
指定可执行文件。这通常位于.kext包的Contents/MacOS/子目录中,但苹果的一些kext直接位于.kext目录中。对于内核本身中的函数,请提供内核映像,例如
/Library/Developer/KDKs/KDK_10.10.5_14F27.KDK/System/Library/Kernels/Kernels

-l
参数指定加载地址。即开始/文本库

最后,只需列出要在该文件中标记的所有地址。在本例中,只能列出一个,但可以列出多个。您也可以从stdin读取它们(如果命令行中没有列出)

有了这个,你应该能够解码你的整个跟踪

关于UUID的说明

您会注意到跟踪中的每个kext以及内核本身都列出了一个UUID。这对于确保使用正确的版本进行符号化非常方便。这是Mach-O二进制文件中LC_UUID loader命令的UUID。您可以使用以下方法检查kext的UUID:

$ otool -l /Library/Developer/KDKs/KDK_10.10.5_14F27.kdk/System/Library/Extensions/IOPCIFamily.kext/IOPCIFamily | grep uuid
    uuid BDA92C3B-AD86-33E5-A7F1-1603465350A7

确认用于象征的kext确实与处于恐慌状态的kext匹配。当你遇到奇怪的版本控制问题时,或者当你在kext缓存中遇到问题时,这非常好。

非常感谢,我已经设法使用了一种简单的方法,在这种情况下,恐慌是先验的,如果我遇到意外的恐慌,我肯定会尝试手动方法。再次感谢!谢谢你的信息!我能问一下你是从哪里学到这个更先进的程序的吗?有什么新的文档我可以检查吗?@ravron我想没有任何公开的规范文档。这主要是我在过去6-7年的Mac内核编程中学到的东西,因为他们慢慢地一次对每个操作系统版本进行一到两次更改。我可能应该把它写得更详细,作为一篇博客文章;我已经在我们的内部维基上写了一个文档,它甚至比上面更详细,可以转换成博客文章……苹果最新的公共kext文档可能是WWDC 2013 session 707。
$ otool -l /Library/Developer/KDKs/KDK_10.10.5_14F27.kdk/System/Library/Extensions/IOPCIFamily.kext/IOPCIFamily | grep uuid
    uuid BDA92C3B-AD86-33E5-A7F1-1603465350A7