呼叫跟踪包含如下条目:
[<deadbeef>] FunctionName+0xAB/0xCD [module_name] [<f00fface>] ? AnotherFunctionName+0x12/0x40 [module_name] [<deaffeed>] ClearFunctionName+0x88/0x88 [module_name]
‘是什么意思?标记在AnotherFunctionName之前?
‘?’ 表示有关此堆栈条目的信息可能不可靠。
堆栈输出机制(请参见dump_trace()函数的实现)无法证明其找到的地址是调用堆栈中的有效返回地址。
‘?’ 本身由printk_stack_address()输出。
堆栈条目可能有效还是无效。有时,人们可能只是跳过它。研究所涉及模块的拆卸以查看在哪个位置ClearFunctionName+0x88(或在x86上紧接该位置的位置)调用了哪个函数可能会有所帮助。
ClearFunctionName+0x88
关于可靠性
在x86,当dump_stack()被调用时,实际检查堆栈中的功能是print_context_stack()中所定义arch/x86/kernel/dumpstack.c。看一下它的代码,我将在下面解释。
arch/x86/kernel/dumpstack.c
我假设DWARF2堆栈展开功能在您的Linux系统中不可用(很可能不是,如果不是OpenSUSE或SLES,则它们不可用)。在这种情况下,print_context_stack()似乎可以执行以下操作。
print_context_stack()
它从保证是堆栈位置地址的地址(代码中的“ stack”变量)开始。它实际上是中的局部变量的地址dump_stack()。
dump_stack()
该函数反复递增该地址(while (valid_stack_ptr ...) { ... stack++}),并检查其指向的内容是否也可能是内核代码(if (__kernel_text_address(addr)) ...)中的地址。这样,当这些函数被调用时,它将尝试查找推入堆栈的函数的返回地址。
while (valid_stack_ptr ...) { ... stack++}
if (__kernel_text_address(addr)) ...
当然,并非每个看起来像返回地址的无符号long值实际上都是一个返回地址。因此该函数尝试对其进行检查。如果在内核代码中使用了帧指针(如果设置了CONFIG_FRAME_POINTER,则使用%ebp /%rbp寄存器),则可以使用它们遍历函数的堆栈帧。函数的返回地址位于帧指针的上方(即%ebp/%rbp + sizeof(unsigned long))。print_context_stack对此进行了精确检查。
%ebp/%rbp + sizeof(unsigned long)
如果存在一个栈帧,其值“ stack”指向的是返回地址,则该值被视为可靠的栈条目。ops->address将被调用reliable == 1,最终将被调用,printk_stack_address()并且该值将作为可靠的调用堆栈条目输出。否则,该地址将被视为不可靠。无论如何都将输出,但带有“?” 前置。
ops->address
reliable == 1
printk_stack_address()
[NB]如果帧指针信息不可用(例如默认情况下在Debian 6中是这样),则出于这个原因,所有调用堆栈条目都将被标记为不可靠。
具有DWARF2展开支持(并设置了CONFIG_STACK_UNWIND)的系统则完全是另外一回事了。