Linux内核崩溃调用跟踪中的问号'?'的含义是什么?

35

调用跟踪包含如下条目:

 [<deadbeef>] FunctionName+0xAB/0xCD [module_name]
 [<f00fface>] ? AnotherFunctionName+0x12/0x40 [module_name]
 [<deaffeed>] ClearFunctionName+0x88/0x88 [module_name]

在 AnotherFunctionName 前面的问号标记代表什么意思?

1个回答

41
“?”表示关于该堆栈条目的信息可能不可靠。

堆栈输出机制(请参见dump_trace() function的实现)无法证明它找到的地址是调用堆栈中有效的返回地址。
“?”本身由printk_stack_address()输出。
堆栈条目可能有效,也可能无效。有时可以简单地跳过它。调查涉及模块的反汇编可能有所帮助,以确定哪个函数在ClearFunctionName+0x88处被调用(或在x86上,在该位置之前立即调用的函数)。
关于可靠性
在x86上调用dump_stack()时,实际检查堆栈的函数是print_context_stack(),定义在arch/x86/kernel/dumpstack.c中。看一下它的代码,我将尝试在下面解释它。
我假设DWARF2堆栈展开工具在您的Linux系统中不可用(如果不是OpenSUSE或SLES,则很可能不可用)。在这种情况下,print_context_stack()似乎执行以下操作。
它从一个地址(代码中的“stack”变量)开始,该地址保证是堆栈位置的地址。实际上,它是dump_stack()中本地变量的地址。
该函数重复增加该地址(while (valid_stack_ptr …){…stack++}),并检查其所指向的内容是否也可能是内核代码中的地址(if (__kernel_text_address(addr))...)。这样,它试图找到这些函数调用时推送到堆栈上的函数返回地址。当然,并不是每个看起来像返回地址的 unsigned long 类型的值都实际上是返回地址。因此,该函数试图进行检查。如果内核代码中使用了帧指针 (%ebp/%rbp 寄存器用于配置 CONFIG_FRAME_POINTER),则可以使用它们来遍历函数的堆栈帧。函数的返回地址位于帧指针正上方 (即在 %ebp/%rbp + sizeof(unsigned long) 处)。print_context_stack 正是检查这一点。
如果有一个堆栈帧,其值 “stack” 指向的就是返回地址,则认为该值是可靠的堆栈条目。ops->address 将以 reliable == 1 的参数调用它,最终将调用 printk_stack_address(),并将该值作为可靠的调用堆栈条目输出。否则,该地址将被视为不可靠。无论如何,它都将被输出,但前面会加上 '?'。
[注] 如果没有帧指针信息 (例如,默认情况下 Debian 6 中没有该信息),所有调用堆栈条目都将由于此原因标记为不可靠。
支持 DWARF2 展开 (且已设置 CONFIG_STACK_UNWIND) 的系统是全新的故事。

很好的答案 - 它缺少一件事情才能使它完整(而且我对架构代码中间接级别感到有些困惑) - 是什么使得该条目不可靠? - qdot
我已经编辑了我的回答。希望我的解释不会太令人困惑。 - Eugene
很遗憾,我绝不是DWARF2方面的专家。到目前为止,我所见过的唯一DWARF2展开实现是来自SuSE Linux的那个。据我所知,主线内核尚未支持它。或者 - 它有吗?您是否使用来自SuSE或其他Linux发行版的补丁来为您的自定义内核添加对DWARF2的支持?可能存在不同的实现。 - Eugene
此外,我看到的内核要么对所有内核模式组件启用了DWARF2展开,要么根本没有启用。目前我无法确定如果内核和模块使用不同的堆栈展开方法会发生什么。 - Eugene
它确实可以被忽略 - 我只是试图理解那里发生了什么 - 二进制代码充满了查找表和类似虚函数的对象分派器。 - qdot
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接