How to find all processes in Linux manually
Linux kernel already provides a MACRO called for_each_process to go through each process. However, you may need to find all the processes manually sometimes. Following is the method:
Environment:
QEMU 0.10.2
QEMU VM: Cent OS 5.3 (Linux 2.6.18)
ARCH :X86-32
Basic idea:
We know that every process has a task_struct in Linux. The task_struct has a member called “tasks”. It is a list_head and all the processes are linked together by task_struct.tasks.
Therefore, to find out all the processes, we could find one task_struct and then follow the tasks member. Other useful members in task_struct are: pid (it is similar to thread id on Windows), tgid ( it is similar to process id on Windows), comm (command line, can be used as process name ).
Next, we are going to use QEMU to find all the processes manually from QEMU monitor. In GDB, we could use “p task->tgid” command to print out the tgid. But QEMU does not support that. So we have to know the exact offset for each interesting member of task_struct.
To find out the offset for members such as tasks, pid, I use a kernel module to print out them. Following is the result: (pid =0xbc means the offset of pid in tasks_struct is at 0xbc)
pid = 0Xbc
tgid = 0Xc0
comm = 0X1AC
tasks = 0X80
The next thing we need to know is how to find the first task_struct. You can read ULK3 or LKD2 to find the answer. In sum, find esp first, in QEMU, esp can be obtained by using “p $esp”, let’s say it is 0xc100,4566. Set the low 13bit of the esp to 0, we get 0xc100,4000. This is the value of “current”, and it’s first member is the *task_struct.
OK, let’s do a real experiment :
1) Setup a QEMU VM with CentOS 5.3 installed as the guest OS. And run it.
2) Press alt+ctrl+2 to switch to QEMU monitor. Then type “stop” in the QEMU monitor. This stops the QEMU emulation so that we don’t need to worry about the memory changes due to a process exit.
3) Type p$esp to find esp. It is 0xc3a94f78 in my experiment.
4) Find THEAD_INFO . That is to set the low 13bit of esp to 0. We got 0xc3a94000
5) x /20w 0xc3a94000 . This will show the content of THREAD_INFO. The first member is the *task. The result is 0xc3aaa370. (Note that, sometimes the value here might be 0, just press “c” to let QEMU continue and “stop” to try more times.)
6) Now we know the address for task_struct, then it is easy to find tgid, tasks and comm. For example, pid is at 0xc3aaa42c (task_struct+0XBC). Note that when checking the content of “comm”, use following command in QEMU : x /20b 0xc3aaa51c. Otherwise, the byte order is reversed by QEMU.
7) Now we know the info about the current process. To find out the next one, just follow task_struct->tasks. Note that the address of task_struct->tasks->next is not the base address of task_struct. The base address of next task_strcut is 0x80 smaller. Then you can repeat the above steps to find out all the processes.
Showing posts with label process. Show all posts
Showing posts with label process. Show all posts
Thursday, February 25, 2010
Wednesday, January 27, 2010
QEMU小实验:手工遍历所有进程的方法
QEMU小实验:手工遍历所有进程的方法
在内核中已经提供了遍历所有进程的方法,比如用for_each_process宏。但是如果你想加深对这部分的了解,那么可以不用这个宏,完全手工遍历一遍。下面介绍了在QEMU中,利用QEMU MONITOR,手工找出所有PROCESS的方法
环境:
QEMU 0.9.1
QEMU VM: CENT OS 5.3 (LINUX 2.6.18)
ARCH :X86-32
主要思路:
我们已经知道LINUX中的所有进程都对应一个TASK_STRUCT. 同时这些TASK_STRUCT里面有一个成员叫做TASKS。它的类型是一个LIST_HEAD(有NEXT, PRE2个成员,构成一个双向链表)。所有的进程就是通过这个TASK_STRUCT里的TASKS连接在一起的。
想遍历进程的话,可以找到一个上面说的结构,然后顺着链表一个一个找下去。另外,还有一些重要的信息在TASK_STRUCT中。常用的有PID(线程ID), TGID(进程ID), COMM(进程的命令参数)。
(关于PID, TGID,可以看下面这个帖子:http://linux.chinaunix.net/bbs/thread-1155667-1-1.html)
如果是在GDB里,那么找到了TASK_STRUCT之后,可以直接用 p task->pid 的方法来把PID之类的打印出来。但是我们的目的就是不用GDB的功能,而只用QEMU MONITOR的功能,纯手工的找出PID这些成员。
这样一来,我们需要自己计算下PID, TGID等成员在TASK_STRUCT中的偏移量。怎么算呢?最天真的办法是按照 .H 文件里TASK_STRUCT的声明,自己一个一个算过去,比如一个CHAR占一个字节,一个INT 4个字节等。但是由于TASK_STRUCT是一个很大的结构(包括几十或者上百个成员),同时考虑到编译的时候还有对齐的问题。这样手工算可以说既费力又不一定对。
最厉害的办法是自己写个类似的C编译器,直接把编译后的输出打印出来。感兴趣的可以看看CIL(C Intermediate Language)。但是CIL还是有点麻烦的。它是用OCAML语言写的。我不是很熟悉。
于是我采用了一个比较折中的办法:自己写个KERNEL MODULE, 在这个MODULE里直接定义一个TASK_STRUCT,然后把感兴趣的那些成员的地址和基地址都打印出来。或者直接把偏移量打印出来。
我就是用上述办法得到了几个关键成员的偏移量:
(前面是TASK_STRUCT里的成员,后面是它距离TASK_STRUCT基地址的偏移量)
pid = 0Xbc
tgid = 0Xc0
comm = 0X1AC
tasks = 0X80
还有一点,我们怎么找到第一个TASK_STRUCT呢?可以看这篇文章(如何找出CURRENT):
http://linux.chinaunix.net/bbs/viewthread.php?tid=1147973&extra=
好了,万事具备,开始行动吧。
1) 运行一个QEMU VM。我是在WINDOWS HOST上跑的QEMU. 在LINUX上也可以跑QEMU。但是LINUX上的QEMU有一点不好,那就是它的QEMU MONITOR的大小是固定的。太小了。而在WINDOWS上面,QEMU MONITOR可以变得很大。
2) 按ALT+CTRL+2, 切换到QEMU MONITOR. 输入STOP. 这样QEMU 就会暂停下来了。这样的好处是你可以花很多时间来遍历进程。而不用担心某个进程结束后,带来的地址无效的问题。
3) p $esp :找出当前的ESP。我实验的时的输出是 0xc3a94f78
4) 找出THREAD_INFO:也就是把ESP与上0XFFFFE000。得到0xc3a94000
5) x /20w 0xc3a94000。显示的这个内容的第一个指针(前4个字节)就是当前进程的TASK_STRUCT。因为THREAD_INFO里的第一个成员就是struct task_struct *task
我这里得到的结果是0xc3aaa370。
(注意:有的时候这个地方显示的数据全都是0。我怀疑是因为进程正在切换中,内核栈刚刚清空。碰到这种情况,可以在QEMU MONITOR里输入c, 让QEMU继续跑一段时间,然后输入stop. 从头开始。有时要多试几次)
6) 找到了TASK_STRUCT之后,根据前面找到的偏移量,可以方便的找到PID, TGID, COMM, TASKS 等成员的值。比如PID的位置在0xc3aaa42c (TASK+0XBC)。
注意,在看COMM的时候,要用下面这个命令: x /20b 0xc3aaa51c. 否则的话,QEMU会把数据当成DWORD处理,并自动转换Endian. 使得看到的字符串的顺序是反过来的。
7) 这样一来,当前进程的信息已经知道了 。在我的输出中,PID,TGID=0,COMM=SWAPPER. 我们开始找下一个。下一个进程是通过TASK_STRUCT->TASKS 连接在一起的。有一点要注意,TASK_STRUCT->TASKS->NEXT中的地址不是下个TASK_STRUCT的起始地址,而是下个TASK_STRUCT中的TASKS的地址。所以有了这个地址后,要先减去0X80才得到基地址。然后就可以用上面的方法找出PID, TGID, COMM来了。
在内核中已经提供了遍历所有进程的方法,比如用for_each_process宏。但是如果你想加深对这部分的了解,那么可以不用这个宏,完全手工遍历一遍。下面介绍了在QEMU中,利用QEMU MONITOR,手工找出所有PROCESS的方法
环境:
QEMU 0.9.1
QEMU VM: CENT OS 5.3 (LINUX 2.6.18)
ARCH :X86-32
主要思路:
我们已经知道LINUX中的所有进程都对应一个TASK_STRUCT. 同时这些TASK_STRUCT里面有一个成员叫做TASKS。它的类型是一个LIST_HEAD(有NEXT, PRE2个成员,构成一个双向链表)。所有的进程就是通过这个TASK_STRUCT里的TASKS连接在一起的。
想遍历进程的话,可以找到一个上面说的结构,然后顺着链表一个一个找下去。另外,还有一些重要的信息在TASK_STRUCT中。常用的有PID(线程ID), TGID(进程ID), COMM(进程的命令参数)。
(关于PID, TGID,可以看下面这个帖子:http://linux.chinaunix.net/bbs/thread-1155667-1-1.html)
如果是在GDB里,那么找到了TASK_STRUCT之后,可以直接用 p task->pid 的方法来把PID之类的打印出来。但是我们的目的就是不用GDB的功能,而只用QEMU MONITOR的功能,纯手工的找出PID这些成员。
这样一来,我们需要自己计算下PID, TGID等成员在TASK_STRUCT中的偏移量。怎么算呢?最天真的办法是按照 .H 文件里TASK_STRUCT的声明,自己一个一个算过去,比如一个CHAR占一个字节,一个INT 4个字节等。但是由于TASK_STRUCT是一个很大的结构(包括几十或者上百个成员),同时考虑到编译的时候还有对齐的问题。这样手工算可以说既费力又不一定对。
最厉害的办法是自己写个类似的C编译器,直接把编译后的输出打印出来。感兴趣的可以看看CIL(C Intermediate Language)。但是CIL还是有点麻烦的。它是用OCAML语言写的。我不是很熟悉。
于是我采用了一个比较折中的办法:自己写个KERNEL MODULE, 在这个MODULE里直接定义一个TASK_STRUCT,然后把感兴趣的那些成员的地址和基地址都打印出来。或者直接把偏移量打印出来。
我就是用上述办法得到了几个关键成员的偏移量:
(前面是TASK_STRUCT里的成员,后面是它距离TASK_STRUCT基地址的偏移量)
pid = 0Xbc
tgid = 0Xc0
comm = 0X1AC
tasks = 0X80
还有一点,我们怎么找到第一个TASK_STRUCT呢?可以看这篇文章(如何找出CURRENT):
http://linux.chinaunix.net/bbs/viewthread.php?tid=1147973&extra=
好了,万事具备,开始行动吧。
1) 运行一个QEMU VM。我是在WINDOWS HOST上跑的QEMU. 在LINUX上也可以跑QEMU。但是LINUX上的QEMU有一点不好,那就是它的QEMU MONITOR的大小是固定的。太小了。而在WINDOWS上面,QEMU MONITOR可以变得很大。
2) 按ALT+CTRL+2, 切换到QEMU MONITOR. 输入STOP. 这样QEMU 就会暂停下来了。这样的好处是你可以花很多时间来遍历进程。而不用担心某个进程结束后,带来的地址无效的问题。
3) p $esp :找出当前的ESP。我实验的时的输出是 0xc3a94f78
4) 找出THREAD_INFO:也就是把ESP与上0XFFFFE000。得到0xc3a94000
5) x /20w 0xc3a94000。显示的这个内容的第一个指针(前4个字节)就是当前进程的TASK_STRUCT。因为THREAD_INFO里的第一个成员就是struct task_struct *task
我这里得到的结果是0xc3aaa370。
(注意:有的时候这个地方显示的数据全都是0。我怀疑是因为进程正在切换中,内核栈刚刚清空。碰到这种情况,可以在QEMU MONITOR里输入c, 让QEMU继续跑一段时间,然后输入stop. 从头开始。有时要多试几次)
6) 找到了TASK_STRUCT之后,根据前面找到的偏移量,可以方便的找到PID, TGID, COMM, TASKS 等成员的值。比如PID的位置在0xc3aaa42c (TASK+0XBC)。
注意,在看COMM的时候,要用下面这个命令: x /20b 0xc3aaa51c. 否则的话,QEMU会把数据当成DWORD处理,并自动转换Endian. 使得看到的字符串的顺序是反过来的。
7) 这样一来,当前进程的信息已经知道了 。在我的输出中,PID,TGID=0,COMM=SWAPPER. 我们开始找下一个。下一个进程是通过TASK_STRUCT->TASKS 连接在一起的。有一点要注意,TASK_STRUCT->TASKS->NEXT中的地址不是下个TASK_STRUCT的起始地址,而是下个TASK_STRUCT中的TASKS的地址。所以有了这个地址后,要先减去0X80才得到基地址。然后就可以用上面的方法找出PID, TGID, COMM来了。
Linux中的task,process, thread 简介
本文的主要目的是介绍在Linux内核中,task,process, thread这3个名字之间的区别和联系。并且和WINDOWS中的相应观念进行比较。如果你已经很清楚了,那么就不用往下看了。
LINUX版本:2.6.18
ARCH: X86
首先要明确的是,按照LKD 2里面的说法,LINUX和其他OS 比如WINDOWS, SOLARIS之间一个很大的不同是没有严格定义的线程(thread)。那么你也许会问,如果LINUX中没有线程,那么如何来表示类似WINDOWS 线程的那种执行观念呢?答案是LINUX中,PROCESS(进程)可以当作线程。
那么你也许又会问,WINDOWS中的多线程程序在LINUX中是怎样表示的呢?具体来说,LINUX中的PROCESS有2种。一种是独立的 PROCESS。自己有自己的地址空间,资源列表,代码等。另外一种PROCESS是和其他PROCESS共享一个地址空间,资源列表的。这种 PROCESS就类似于WINDOWS中的线程。
在看LINUX内核代码的时候,你会同时看到process, task, thread这3个名字。下面简要介绍下他们之间的区别:
1、task 可以理解为一个LINUX PROCESS。最著名的定义TASK的数据结构叫做struct task_struct, 在linux\sched.h中。我觉得这个名字起得不好。因为大家都已经对PROCESS, THREAD之类得观念很熟悉了。现在又冒出来个TASK,很容易让人搞混。不过也许是历史原因吧。这个TASK一直保留着。
在 task_struct 中有一堆的成员。其中有PID 和TGID. PID实际上类似于WINDOWS中的THREAD ID。而TGID (thead group id) 对应于WINDOWS中的PID。PID对于独立的PROCESS来说,就是它的PID。这时PID == TGID。对于和其他PROCESS共享地址空间的PROCESS来说,每个都有独立的PID,但是他们的TGID是一样的。
2、thead虽然说LINUX不支持THREAD. 但是在内核代码里又可以看到THREAD这个名字。这时可以把他们和WINDOWS中的THREAD对应起来。一个比较著名的是thread_info 结构。
3、kernel thread在LINUX中,kernel thread是一个专门的名词。它的特点是没有独立的地址空间(MM结构为NULL). 他们只运行在KERNEL SPACE.不能切换到USER SPACE。
最后,总结下,在LINUX中,一个PROCESS即可能是一个WINDOWS PROCESS类似的观念,也可能是一个与WINDOWS THREAD类似的观念。而且有时还被叫做TASK(感觉有点乱)。不过最常用的还是与WINDOWS PROCESS类似的观念。比如在内核代码中有一个for_each_process宏。它就是只遍历那些主要的,独立的PROCESS。
参考资料:
1、LKD 2
2. http://blog.csdn.net/pppjob/archive/2009/02/05/3864020.aspx
LINUX版本:2.6.18
ARCH: X86
首先要明确的是,按照LKD 2里面的说法,LINUX和其他OS 比如WINDOWS, SOLARIS之间一个很大的不同是没有严格定义的线程(thread)。那么你也许会问,如果LINUX中没有线程,那么如何来表示类似WINDOWS 线程的那种执行观念呢?答案是LINUX中,PROCESS(进程)可以当作线程。
那么你也许又会问,WINDOWS中的多线程程序在LINUX中是怎样表示的呢?具体来说,LINUX中的PROCESS有2种。一种是独立的 PROCESS。自己有自己的地址空间,资源列表,代码等。另外一种PROCESS是和其他PROCESS共享一个地址空间,资源列表的。这种 PROCESS就类似于WINDOWS中的线程。
在看LINUX内核代码的时候,你会同时看到process, task, thread这3个名字。下面简要介绍下他们之间的区别:
1、task 可以理解为一个LINUX PROCESS。最著名的定义TASK的数据结构叫做struct task_struct, 在linux\sched.h中。我觉得这个名字起得不好。因为大家都已经对PROCESS, THREAD之类得观念很熟悉了。现在又冒出来个TASK,很容易让人搞混。不过也许是历史原因吧。这个TASK一直保留着。
在 task_struct 中有一堆的成员。其中有PID 和TGID. PID实际上类似于WINDOWS中的THREAD ID。而TGID (thead group id) 对应于WINDOWS中的PID。PID对于独立的PROCESS来说,就是它的PID。这时PID == TGID。对于和其他PROCESS共享地址空间的PROCESS来说,每个都有独立的PID,但是他们的TGID是一样的。
2、thead虽然说LINUX不支持THREAD. 但是在内核代码里又可以看到THREAD这个名字。这时可以把他们和WINDOWS中的THREAD对应起来。一个比较著名的是thread_info 结构。
3、kernel thread在LINUX中,kernel thread是一个专门的名词。它的特点是没有独立的地址空间(MM结构为NULL). 他们只运行在KERNEL SPACE.不能切换到USER SPACE。
最后,总结下,在LINUX中,一个PROCESS即可能是一个WINDOWS PROCESS类似的观念,也可能是一个与WINDOWS THREAD类似的观念。而且有时还被叫做TASK(感觉有点乱)。不过最常用的还是与WINDOWS PROCESS类似的观念。比如在内核代码中有一个for_each_process宏。它就是只遍历那些主要的,独立的PROCESS。
参考资料:
1、LKD 2
2. http://blog.csdn.net/pppjob/archive/2009/02/05/3864020.aspx
Monday, December 7, 2009
调试KERNEL时,找出当前进程信息的方法
我们知道,一个常用的内核数据结构叫做 current. 它指向当前的进程,包括很多有用的信息,比如PID, 进程名等。如果是自己写内核代码,那么可以直接引用current。 但是如果是调试的话,直接p current是不行的。因为current是一个宏。
那么这时如何找出current呢?在Linux 2.6版本中,current是放在堆栈(STACK)的最低下。假如内核栈是8K。起始地址为0XC100,2000. 那么current就在0XC100,0000 (堆栈是倒着长的). 根据这个情况,可以用如下方法找出current。
1)找出ESP。p $esp. 假设输出为0XC123,4566
2) 把esp与上0XFFFF,E000 (低13位置为0)。 得到0XC123,4000. 这个值就是CURRENT的值了。可以转换后进行使用,比如
3) p ((* struct thread_info) 0xc1234000)->task->comm
以上方法在X86-32, ARM上都可以。 其他体系结构不太清楚,似乎也可以。或者那位知道的可以补充。
那么这时如何找出current呢?在Linux 2.6版本中,current是放在堆栈(STACK)的最低下。假如内核栈是8K。起始地址为0XC100,2000. 那么current就在0XC100,0000 (堆栈是倒着长的). 根据这个情况,可以用如下方法找出current。
1)找出ESP。p $esp. 假设输出为0XC123,4566
2) 把esp与上0XFFFF,E000 (低13位置为0)。 得到0XC123,4000. 这个值就是CURRENT的值了。可以转换后进行使用,比如
3) p ((* struct thread_info) 0xc1234000)->task->comm
以上方法在X86-32, ARM上都可以。 其他体系结构不太清楚,似乎也可以。或者那位知道的可以补充。
Subscribe to:
Posts (Atom)