Linux 在不中断的情况下读取活动进程内存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12977179/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading living process memory without interrupting it
提问by hmhmhmmm
I would like to explore the memory of a living process, and when I do so, the process must not get disturbed - so attaching gdb to the process (which would stop it) is not an option. Therefore I would like to get this info from /proc/kcore (if you know of another way to do this please let me know). So I made a little experiment. I created a file called TEST with only "EXTRATESTEXTRA" inside. Then I opened it with less
我想探索一个活动进程的内存,当我这样做时,进程不能受到干扰 - 所以将 gdb 附加到进程(这会阻止它)不是一种选择。因此,我想从 /proc/kcore 获取此信息(如果您知道另一种方法,请告诉我)。所以我做了一个小实验。我创建了一个名为 TEST 的文件,里面只有“EXTRATESTEXTRA”。然后我用less打开它
$ less TEST
I got the PID of this process with
我得到了这个过程的PID
$ ps aux | grep TEST
user 7785 0.0 0.0 17944 992 pts/8 S+ 16:15 0:00 less TEST
user 7798 0.0 0.0 13584 904 pts/9 S+ 16:16 0:00 grep TEST
And then I used this script to create a dump of all files :
然后我使用这个脚本来创建所有文件的转储:
#!/bin/bash
grep rw-p /proc//maps | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/ /p' | while read start stop; do gdb --batch --pid -ex "dump memory -$start-$stop.dump 0x$start 0x$stop"; done
(I found it on this site https://serverfault.com/questions/173999/dump-a-linux-processs-memory-to-file)
(我在这个网站上找到了它https://serverfault.com/questions/173999/dump-a-linux-processs-memory-to-file)
$ sudo ./dump_all_pid_memory.sh 7785
After this, I looked for "TRATESTEX" in all dumped files :
在此之后,我在所有转储文件中寻找“TRATESTEX”:
$ grep -a -o -e '...TRATESTEX...' ./*.dump
./7785-00624000-00628000.dump:HEXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA
So I concluded that there must be an occurance of this string somewhere between 0x00624000 and 0x00628000 . Therefore I converted the offsets into decimal numbers and used dd to get the memory from /proc/kcore :
所以我得出结论,这个字符串一定在 0x00624000 和 0x00628000 之间出现。因此,我将偏移量转换为十进制数并使用 dd 从 /proc/kcore 获取内存:
$ sudo dd if="/proc/kcore" of="./y.txt" skip="0" count="1638400" bs=1
To my surprise, the file y.txt was full of zeros (I didn't find the string I was looking for in it).
令我惊讶的是,文件 y.txt 全是零(我没有在其中找到我要查找的字符串)。
As a bonus surprise, I ran a simmilar test at the same time with a different test file and found that the other test string i was using (both processes with less were running at the same time) should be found at the same location (the dumping and greping gave the same offset). So there must be something I don't understand clearly.
作为额外的惊喜,我用不同的测试文件同时运行了一个类似的测试,发现我正在使用的另一个测试字符串(两个较少的进程同时运行)应该在同一个位置( dumping 和 grep 给出了相同的偏移量)。所以一定有什么我不明白的地方。
Isn't the /proc/pid/maps supposed to show the offset of the memory (i.e. : if it would say "XXX" is at offset 0x10, another program could not be using the same offset am I right? - this is the source of my second surprise)
How can I read /proc/kmap to get the memory that belongs to a process which's pid I know ?
/proc/pid/maps 不应该显示内存的偏移量(即:如果它说“XXX”在偏移量 0x10 处,另一个程序不能使用相同的偏移量,对吗?-这是我的第二个惊喜的来源)
如何读取 /proc/kmap 以获取属于我知道的 pid 进程的内存?
采纳答案by Basile Starynkevitch
For process 1234 you can get its memory map by reading sequentially /proc/1234/maps
(a textual pseudo-file) and read the virtual memory by e.g. read(2)-ing or mmap(2)-ing appropriate segments of the /proc/1234/mem
sparse pseudo-file.
对于进程 1234,您可以通过顺序读取/proc/1234/maps
(文本伪文件)获取其内存映射,并通过例如read(2)-ing 或mmap(2)-ing/proc/1234/mem
稀疏伪文件的适当段来读取虚拟内存。
However, I believe you cannot avoid some kind of synchronization (perhaps with ptrace(2), as gdb
does), since the process 1234 can (and does) alter its address space at any time (with mmap
& related syscalls).
但是,我相信您无法避免某种同步(可能与ptrace(2)一样gdb
),因为进程 1234 可以(并且确实)随时(使用mmap
& 相关系统调用)更改其地址空间。
The situation is different if the monitored process 1234 is not arbitrary, but if you could improve it to communicate somehow with the monitoring process.
如果受监控进程 1234 不是任意的,但如果您可以改进它以与监控进程以某种方式进行通信,则情况会有所不同。
I'm not sure to understand why do you ask this. And gdb
is able to watch
some location without stopping the process.
我不确定你为什么问这个。并且gdb
能够在watch
不停止过程的情况下到达某个位置。
回答by user1621581
You'll have to use /proc//mem to read process memory, I wouldn't recommend trying to read /proc/kcore or any of the kernel memory functions (which is time consuming)
您必须使用 /proc//mem 来读取进程内存,我不建议尝试读取 /proc/kcore 或任何内核内存函数(这很耗时)
回答by dr jimbob
If you have root access and are on a linux system, you can use the following linux script (adapted from Gilles' excellent unix.stackexchange.com answerand the answer originally given in the question above but including SyntaxErrors and not being pythonic):
如果您具有 root 访问权限并且在 linux 系统上,则可以使用以下 linux 脚本(改编自Gilles 出色的 unix.stackexchange.com 答案和最初在上述问题中给出的答案,但包括 SyntaxErrors 而不是 Pythonic):
#!/usr/bin/env python
import re
import sys
def print_memory_of_pid(pid, only_writable=True):
"""
Run as root, take an integer PID and return the contents of memory to STDOUT
"""
memory_permissions = 'rw' if only_writable else 'r-'
sys.stderr.write("PID = %d" % pid)
with open("/proc/%d/maps" % pid, 'r') as maps_file:
with open("/proc/%d/mem" % pid, 'r', 0) as mem_file:
for line in maps_file.readlines(): # for each mapped region
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r][-w])', line)
if m.group(3) == memory_permissions:
sys.stderr.write("\nOK : \n" + line+"\n")
start = int(m.group(1), 16)
if start > 0xFFFFFFFFFFFF:
continue
end = int(m.group(2), 16)
sys.stderr.write( "start = " + str(start) + "\n")
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
print chunk, # dump contents to standard output
else:
sys.stderr.write("\nPASS : \n" + line+"\n")
if __name__ == '__main__': # Execute this code when run from the commandline.
try:
assert len(sys.argv) == 2, "Provide exactly 1 PID (process ID)"
pid = int(sys.argv[1])
print_memory_of_pid(pid)
except (AssertionError, ValueError) as e:
print "Please provide 1 PID as a commandline argument."
print "You entered: %s" % ' '.join(sys.argv)
raise e
If you save this as write_mem.py, you can run this (with python2.6 or 2.7) or early in python2.5 (if you add from __future__ import with_statement
) as:
如果将其保存为 write_mem.py,则可以将其(使用 python2.6 或 2.7)或在 python2.5 早期(如果添加from __future__ import with_statement
)运行为:
sudo python write_mem.py 1234 > pid1234_memory_dump
to dump pid1234 memory to the file pid1234_memory_dump.
将 pid1234 内存转储到文件 pid1234_memory_dump。
回答by Mansur Ali
i achieved this by issuing the below command
我通过发出以下命令来实现这一点
[root@stage1 ~]# echo "Memory usage for PID [MySql]:"; for mem in {Private,Rss,Shared,Swap,Pss};do grep $mem /proc/ps aux |grep mysql |awk '{print $2}'|head -n 1
/smaps | awk -v mem_type="$mem" '{i=i+$2} END {print mem_type,"memory usage:"i}' ;done
[root@stage1 ~]# echo "PID [MySql] 的内存使用情况:"; 对于 {Private,Rss,Shared,Swap,Pss} 中的 mem;做 grep $mem /proc/ ps aux |grep mysql |awk '{print $2}'|head -n 1
/smaps | awk -v mem_type="$mem" '{i=i+$2} END {print mem_type,"memory usage:"i}' ;done
Result Output
结果输出
Memory usage for PID [MySql]:
PID [MySql] 的内存使用情况:
Private memory usage:204
私有内存使用:204
Rss memory usage:1264
Rss 内存使用:1264
Shared memory usage:1060
共享内存使用:1060
Swap memory usage:0
交换内存使用:0
Pss memory usage:423
ps 内存使用:423
回答by Calmarius
Since the 3.2 version of the kernel. You can use the process_vm_readvsystem call to read process memory without interruption.
从3.2版本的内核开始。您可以使用process_vm_readv系统调用不间断地读取进程内存。
ssize_t process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags);
These system calls transfer data between the address space of the calling process ("the local process") and the process identified by pid ("the remote process"). The data moves directly between the address spaces of the two processes, without passing through kernel space.
ssize_t process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags);
这些系统调用在调用进程(“本地进程”)和由 pid 标识的进程(“远程进程”)的地址空间之间传输数据。数据直接在两个进程的地址空间之间移动,不经过内核空间。