OS X 内核恐慌诊断。如何翻译回溯地址
OS X kernel panic diagnostics. How to translate backtrace addresses
我正在调试导致 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
我假设由于计算机经历了重新启动,地址转换现在没有用,因为每次启动迭代后内存映射可能不同。
是否有任何选项可以在回溯时为每个地址匹配相关方法,或者提前设置适当的配置?
谢谢
是的,您绝对可以符号化内核恐慌痕迹,但要追溯执行此操作,您需要来自恐慌日志的更多信息,而不仅仅是原始堆栈跟踪。如您所说,地址仅相对于加载地址有意义。
Apple 关于该主题的官方文档,TN2063 有点过时了。它给出的示例来自 Darwin 9,即 OS X 10.5,从那时起,随着内核 ASLR 和 kext UUID 的引入,情况发生了一些变化。我会尽量给你一个非常快速的最新指南。
1.简单的方法
如果您的恐慌是可重现的,最简单的方法就是让内核为您符号化它。使用内核引导参数 keepsyms=1
意味着内核不会丢弃存储在内核和 kext 映像中的任何符号,并且会在出现恐慌时在堆栈跟踪中查找 return 指针。
只需将 keepsyms=1
添加到 /Library/Preferences/SystemConfiguration/com.apple.Boot.plist
中的内核标志设置或添加到 boot-args
NVRAM 变量。重新启动,任何后续的恐慌都将被自动符号化。您可以通过 c++filt
命令行实用程序 运行 损坏的 C++ 符号来获得正确的 C++ 函数签名。例如,
$ echo __ZN32IOPCIMessagedInterruptController17registerInterruptEP9IOServiceiPvPFvS2_S2_S2_iES2_ | c++filt
IOPCIMessagedInterruptController::registerInterrupt(IOService*, int, void*, void (*)(void*, void*, void*, int), void*)
2。手动方式
如果您遇到了无法重现的无符号化、神秘的恐慌,那么简单的方法也无济于事。
紧接着堆栈跟踪,在紧急日志中查找以 "Kernel Extensions in backtrace:" 开头的部分。这将列出恐慌中涉及的所有内核扩展,包括它们的加载地址、版本和 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
注意0xffffff7f80c343f2大于(或等于)0xffffff7f80c1a000且小于(或等于)0xffffff7f80c4dfff,所以有问题的代码在IOPCIFamily中。
这引导我执行以下命令(及其输出):
$ atos -o /Library/Developer/KDKs/KDK_10.10.5_14F27.kdk/System/Library/Extensions/IOPCIFamily.kext/IOPCIFamily -l 0xffffff7f80c1a000 0xffffff7f80c343f2
IOPCIMessagedInterruptController::registerInterrupt(IOService*, int, void*, void (*)(void*, void*, void*, int), void*) (in IOPCIFamily) (IOPCIMessagedInterruptController.cpp:85)
-o
指定可执行文件。这通常在 .kext 包的 Contents/MacOS/ 子目录中,但一些 Apple 的 kexts 直接在 .kext 目录中。对于内核本身的功能,提供内核映像,例如/Library/Developer/KDKs/KDK_10.10.5_14F27.kdk/System/Library/Kernels/kernel
.
-l
参数指定加载地址。 IE。 start/text基地。
最后,只需列出您要在该文件中符号化的所有地址。在这种情况下,只有一个,但您可以列出多个。您也可以从标准输入读取它们(如果 none 列在命令行上)。
有了这个,你应该能够解码你的整个踪迹。
关于 UUID 的注释
您会注意到跟踪中的每个 kext 以及内核本身都列出了一个 UUID。这对于确保您使用正确的版本进行符号化非常方便。这是来自 Mach-O 二进制文件中 LC_UUID 加载程序命令的 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 确实与 panic 中的 kext 匹配。当您遇到奇怪的版本控制问题或遇到 kext 缓存问题时,这非常有用。
我正在调试导致 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
我假设由于计算机经历了重新启动,地址转换现在没有用,因为每次启动迭代后内存映射可能不同。
是否有任何选项可以在回溯时为每个地址匹配相关方法,或者提前设置适当的配置? 谢谢
是的,您绝对可以符号化内核恐慌痕迹,但要追溯执行此操作,您需要来自恐慌日志的更多信息,而不仅仅是原始堆栈跟踪。如您所说,地址仅相对于加载地址有意义。
Apple 关于该主题的官方文档,TN2063 有点过时了。它给出的示例来自 Darwin 9,即 OS X 10.5,从那时起,随着内核 ASLR 和 kext UUID 的引入,情况发生了一些变化。我会尽量给你一个非常快速的最新指南。
1.简单的方法
如果您的恐慌是可重现的,最简单的方法就是让内核为您符号化它。使用内核引导参数 keepsyms=1
意味着内核不会丢弃存储在内核和 kext 映像中的任何符号,并且会在出现恐慌时在堆栈跟踪中查找 return 指针。
只需将 keepsyms=1
添加到 /Library/Preferences/SystemConfiguration/com.apple.Boot.plist
中的内核标志设置或添加到 boot-args
NVRAM 变量。重新启动,任何后续的恐慌都将被自动符号化。您可以通过 c++filt
命令行实用程序 运行 损坏的 C++ 符号来获得正确的 C++ 函数签名。例如,
$ echo __ZN32IOPCIMessagedInterruptController17registerInterruptEP9IOServiceiPvPFvS2_S2_S2_iES2_ | c++filt
IOPCIMessagedInterruptController::registerInterrupt(IOService*, int, void*, void (*)(void*, void*, void*, int), void*)
2。手动方式
如果您遇到了无法重现的无符号化、神秘的恐慌,那么简单的方法也无济于事。
紧接着堆栈跟踪,在紧急日志中查找以 "Kernel Extensions in backtrace:" 开头的部分。这将列出恐慌中涉及的所有内核扩展,包括它们的加载地址、版本和 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
注意0xffffff7f80c343f2大于(或等于)0xffffff7f80c1a000且小于(或等于)0xffffff7f80c4dfff,所以有问题的代码在IOPCIFamily中。
这引导我执行以下命令(及其输出):
$ atos -o /Library/Developer/KDKs/KDK_10.10.5_14F27.kdk/System/Library/Extensions/IOPCIFamily.kext/IOPCIFamily -l 0xffffff7f80c1a000 0xffffff7f80c343f2
IOPCIMessagedInterruptController::registerInterrupt(IOService*, int, void*, void (*)(void*, void*, void*, int), void*) (in IOPCIFamily) (IOPCIMessagedInterruptController.cpp:85)
-o
指定可执行文件。这通常在 .kext 包的 Contents/MacOS/ 子目录中,但一些 Apple 的 kexts 直接在 .kext 目录中。对于内核本身的功能,提供内核映像,例如/Library/Developer/KDKs/KDK_10.10.5_14F27.kdk/System/Library/Kernels/kernel
.
-l
参数指定加载地址。 IE。 start/text基地。
最后,只需列出您要在该文件中符号化的所有地址。在这种情况下,只有一个,但您可以列出多个。您也可以从标准输入读取它们(如果 none 列在命令行上)。
有了这个,你应该能够解码你的整个踪迹。
关于 UUID 的注释
您会注意到跟踪中的每个 kext 以及内核本身都列出了一个 UUID。这对于确保您使用正确的版本进行符号化非常方便。这是来自 Mach-O 二进制文件中 LC_UUID 加载程序命令的 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 确实与 panic 中的 kext 匹配。当您遇到奇怪的版本控制问题或遇到 kext 缓存问题时,这非常有用。