从给定进程的内存转储中,我想提取thread_info的值,例如: preempt_count。
在x86中定义:
struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
__u32 flags;
__u32 status;
__u32 cpu;
int preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
void __user *sysenter_return;
#ifdef CONFIG_X86_32
unsigned long previous_esp;
__u8 supervisor_stack[0];
#endif
int uaccess_err;
};
并驻留在流程堆栈的底部。
在x86上,可以通过屏蔽堆栈指针的13个最低有效位(假设堆栈大小为8KB)来获得thread_info结构的地址。这是通过current_thread_info()函数完成的(参见Love,“Linux内核开发”)。
我测试了一个带有pid 2419(我开始/ bin / bash)的进程,使用gdb获取stackpointer和python的值来获取内存地址:
$ gdb --pid 2419
(gdb) print $sp
$1 = (void *) 0xbf870fa8
(gdb) python print "%x" % (0xbf870fa8 & 0xffffe000)
bf870000
因此,thread_info应驻留在bf870000:
(gdb) x/40xb 0xbf870000
0xbf870000: 0x08 0x66 0x2d 0x0a 0x08 0x66 0x2d 0x0a
0xbf870008: 0x88 0x8f 0x08 0x0a 0xb8 0x18 0x07 0x08
0xbf870010: 0xe8 0xe6 0x60 0x0a 0x08 0x65 0x2d 0x0a
0xbf870018: 0x08 0x60 0x61 0x0a 0x88 0x8f 0x08 0x0a
0xbf870020: 0x08 0x66 0x2d 0x0a 0x88 0x8f 0x08 0x0a
问题是:如何将此数据连接到thread_info结构?
现在我可以将结构映射到内存,但是,我认为地址0xbf870000是错误的......
(gdb) symbol-file /usr/lib/debug/boot/vmlinux-3.2.0-52-generic-pae
Reading symbols from /usr/lib/debug/boot/vmlinux-3.2.0-52-generic-pae...done.
(gdb) p (struct thread_info *)0xbf870000
$2 = (struct thread_info *) 0xbf870000
(gdb) p *$2
$4 = {task = 0xa2d6608, exec_domain = 0xa2d6608, flags = 168333192, status = 134682808, cpu = 174122728, preempt_count = 170747144, addr_limit = {seg = 174153736}, restart_block = {
fn = 0xa088f88, {futex = {uaddr = 0xa2d6608, val = 168333192, flags = 174153736, bitset = 134622139, time = 580707212407115656, uaddr2 = 0x1524}, nanosleep = {clockid = 170747400,
rmtp = 0xa088f88, expires = 578197684496719880}, poll = {ufds = 0xa2d6608, nfds = 168333192, has_timeout = 174153736, tv_sec = 134622139, tv_nsec = 168333192}}},
sysenter_return = 0xbf87007c, previous_esp = 4294967264, supervisor_stack = 0xbf870044 "\274F\017\b\002", uaccess_err = 135218876}
感谢您的帮助!
答案 0 :(得分:1)
我相信你很困惑:
struct thread_info
是内核结构,驻留在内核 8K线程堆栈中。
然而,您希望通过屏蔽和转换用户空间堆栈指针,在用户空间堆栈中找到它。
您在用户空间中搜索的数据不。如果是这样的话,用户空间程序可以自由地覆盖它并对内核造成各种各样的混乱。
答案 1 :(得分:1)
我找到了解决方案。雇用俄语是对的,东西在于内核空间。您可以使用stap(ubuntu上的apt-get install systemtap)来检查结构。
请注意,您可以将其用于任何进程以检查thread_info和task_struct。
这是我的工作流程:
$> echo $$
5296
2.创建订阅脚本thread_info.stp:
#cf. /usr/share/doc/systemtap-doc/examples/process/dumpstack.stp
// Add a dummy probe for loading kernel symbols.
probe kernel.function("printk") { next }
probe begin {
process_pid = target()
//pid2task(process_pid) defined in /usr/share/systemtap/tapset/task.stp
//returns task_struct of process_pid
//pt:long serves as "pointer to task_struct"
pt = pid2task(process_pid)
//task_execname(pt): defined in /usr/share/systemtap/tapset/task.stp
printf("Execname of process %d: %s\n", process_pid, task_execname(pt) )
pt_utime = @cast(pt, "task_struct", "kernel<linux/sched.h>")->utime
printf("Utime of process: %d\n", pt_utime)
//taken from task_cpu@/usr/share/systemtap/tapset/task.stp
ti = (@defined(@cast(pt, "task_struct", "kernel<linux/sched.h>")->stack)
? @cast(pt, "task_struct", "kernel<linux/sched.h>")->stack
: @cast(pt, "task_struct", "kernel<linux/sched.h>")->thread_info);
printf("Cpu: %d\n", @cast(ti, "thread_info", "kernel<linux/sched.h>")->cpu)
//does the above code make sense?
printf("%s == %s ???\n", task_execname(pt), task_execname(@cast(ti, "thread_info", "kernel<linux/sched.h>")->task))
exit()
}
以root身份输入
$&GT; stap -x 5296 thread_info.stp
进程5296的执行名称:bash
过程的时间:174
Cpu:0
bash == bash ???
答案 2 :(得分:-2)
然而,基本上以这种方式检索thread_info数据听起来是合理的。我对GBD不是很熟悉,如果我错了请纠正我。当你通过gdb附加一个线程然后“打印$ sp”时,你怎么知道寄存器用作“堆栈指针”而不是“通用寄存器”?您应该检索正确的SP,其中“sp”实际上被指定为堆栈。