2014-03-05 31 views
0

從給定進程的內存轉儲中,我想提取th​​read_info的值,例如, preempt_count。給定進程的thread_info的打印值

它是在在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 Kernel Development」)。

我測試用於與PID 2419的處理(I開始/斌/慶典),用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

可以映射結構來存儲,我想地址0xbf870000是錯誤的... (GDB)符號文件/usr/lib/debug/boot/vmlinux-3.2.0-52-generic -pae 讀取/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 ... – Markus

回答

1

我找到了解決方案。就業的俄羅斯是正確的,東西在於內核空間。你可以使用stap(apt-get install systemtap on ubuntu)來檢查結構。

請注意,您可以使用它來檢查thread_info和task_struct的任何進程。

這是我的工作流程:

  1. 啓動外殼和回聲鍵入$$將shell的PID

$> echo $$ 5296 2.創建STAP腳本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 [email protected]/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() 
} 
  1. 作爲根,輸入

    $> STAP -x 5296 thread_info.stp

    Execname的過程5296:bash的

    UTIME過程:174

    CPU:0

    的bash == bash的???然而

-2

但是,基本上以這種方式檢索thread_info數據是合理的。我對GBD並不是很熟悉,如果我錯了,請糾正我。當你通過gdb附加一個線程,然後「print $ sp」的時候,你怎麼知道寄存器正在用作「堆棧指針」而不是「普通的puspose寄存器」?您應該檢索「sp」確實分配爲堆棧的正確SP。

+0

你在你的答案的每一點都很*錯。 –

+0

你最好解釋哪裏是誤導性的部分。請看下面的例子,爲什麼我說「SP並不總是代表堆棧指針的目的」。 (在臂裝配中) Mov r4,SP ---> SP保存 LDR SP,[r5] ---> SP啓動用作通用寄存器。 LDMIA sp!,{r0-r3} CMP r0,#0 BEQ bad_value MOV r4,sp ----> SP恢復 – user3373708

+0

順便說一下,據我所知,0xbf870000是內核地址和打字「信息堆棧」將顯示調用堆棧在內核空間中,無論如何,我不是GDB的專家,歡迎任何解釋。 – user3373708

0

我相信你很困惑:

struct thread_info內核結構,居住在內核 8K線程堆棧。

然而,您希望通過屏蔽和轉換用戶空間堆棧指針來在用戶空間中找到它。

您要查找的數據是用戶空間中的而不是。如果是這樣,用戶空間程序可以自由地覆蓋它,並導致內核的各種混亂。