crash工具查询gs寄存器以及per-cpu基地址

2020-05-29 13:00:19 浏览数 (1)

经常在vmcore里反汇编函数时会看到操作%gs相关的:

那么怎么获取每个cpu gs寄存器的值呢?

以这里为例:

#define in_interrupt() (irq_count())

#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK

| NMI_MASK))

#define preempt_count() (current_thread_info()->preempt_count)

#define this_cpu_read_stable(var) percpu_stable_op("mov", var)

因为per-cpu变量kernel_stack为unsigned long类型,因此命中case 8:

asm(op "q "__percpu_arg(P1)",%0"

: "=r" (pfo_ret__)

: "p" (&(var)));

展开为:

asm("movq %%gs:%P1, %0" : "=r"(pfo_ret__) : "p"(&(kernel_stack)));

这行代码的含义为将约束输入部分必须为有效的地址&(kernel_stack)(p约束), 将段寄存器gs加偏移量&(kernel_stack)通过寄存器(r约束)赋值给 pfo_ret__.

当前测试环境tasklist_read_lock函数对应反汇编代码:

当前测试环境&kernel_stack的值为0x10e38:

我们看下每cpu变量kernel_stack的值:

per-cpu基地址的值:

对应cpu0:

kernel_stack- per-cpu base address

crash> px 0xffff9d745fc10e38-0xffff9d745fc00000

$2 = 0x10e38

crash>

得出的结果0x10e38就是下面这条指令的0x10e38:

crash> dis tasklist_read_lock

...

...

0xffffffff9d88dcb6 <tasklist_read_lock 6>: mov %gs:0x10e38,%rax

...

...

因此可以知道实际上kmem -o的输出就是每个cpu上对应的gs寄存器的值了。

实际上这里0x10e38就是&kernel_stack的值:

crash> p &kernel_stack

$3 = (unsigned long *) 0x10e38

crash>

crash>

对应到上面的汇编语言

asm("movq %%gs:%P1, %0" : "=r"(pfo_ret__) : "p"(&(kernel_stack)));

转换为:

movq %%gs:&kernel_stack, pfo_ret__

pfo_ret__=ffff9d745fc00000 0x10e38=ffff9d745fc10e38

另外kmem -o实际上也是per-cpu 变量的基地址,跟__per_cpu_offset数组的值是对应的:

代码语言:javascript复制
#define per_cpu_ptr(ptr, cpu)	SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)))
#ifndef SHIFT_PERCPU_PTR
/* Weird cast keeps both GCC and sparse happy. */
#define SHIFT_PERCPU_PTR(__p, __offset)	({				
	__verify_pcpu_ptr((__p));					
	RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); 
})
#endif
#ifndef __per_cpu_offset
extern unsigned long __per_cpu_offset[NR_CPUS];
#define per_cpu_offset(x) (__per_cpu_offset[x])
#endif

0 人点赞