低开销的方式来访问跟踪过程的内存空间?

我正在寻找一种有效的方法来访问(对于读取和写入操作)我的ptracedsubprocess的内存空间。 被访问块的大小可能会从几个字节到几兆字节大小不等,所以使用PTRACE_PEEKDATAPTRACE_POKEDATA一次只读取一个字,并在每次被调用时切换上下文的ptrace调用看起来像是毫无意义的浪费资源。 然而我唯一能find的替代解决scheme是/proc/<pid>/mem文件,但是它早已变成只读了。

有没有其他(相对简单)的方式来做这个工作? 理想的解决scheme是以某种方式共享我的subprocess的地址空间,然后使用简单的memcpy调用来双向复制我需要的数据,但是我没有线索如何做以及从哪里开始。

有任何想法吗?

Solutions Collecting From Web of "低开销的方式来访问跟踪过程的内存空间?"

如果这是Linux(标签所示),则可以通过使用具有CLONE_VM标志的clone()与父级共享子级的整个地址空间。 由于这两个进程共享相同的VM空间,因此所有修改都将在两者之间立即可见,基本上为零开销。

这意味着你不能然后exec()在孩子; 因为它将取代这两个进程的虚拟机空间。

你在控制子进程和源代码吗? 如果是这样,你可以考虑使用共享内存 。

考虑将一些调试功能注入ptraced进程并通过ptrace_setregs调用它。 就像gdb如何运行ptraced进程的任何函数一样。

你也可以尝试通过LD_PRELOAD注入一些代码到进程中。 你甚至可以尝试在没有使用信号的情况下工作。

upd1:Gdb注入或“劣等函数调用”相当复杂。 请参阅文件gdb-6.6.50.20070809> gdb> infcall.c中的函数call_function_by_hand: http : //sources.debian.net/src/gdb/7.6.2-1/gdb/infcall.c? hl=462#L462

 /* All this stuff with a dummy frame may seem unnecessarily complicated (why not just save registers in GDB?). The purpose of pushing a dummy frame which looks just like a real frame is so that if you call a function and then hit a breakpoint (get a signal, etc), "backtrace" will look right. Whether the backtrace needs to actually show the stack at the time the inferior function was called is debatable, but it certainly needs to not display garbage. So if you are contemplating making dummy frames be different from normal frames, consider that. */ /* Perform a function call in the inferior. ARGS is a vector of values of arguments (NARGS of them). FUNCTION is a value, the function to be called. Returns a value representing what the function returned. May fail to return, if a breakpoint or signal is hit during the execution of the function. ARGS is modified to contain coerced values. */ struct value * call_function_by_hand (struct value *function, int nargs, struct value **args) { ... frame = get_current_frame (); gdbarch = get_frame_arch (frame); if (!gdbarch_push_dummy_call_p (gdbarch)) error (_("This target does not support function calls.")); /* A cleanup for the inferior status. This is only needed while we're preparing the inferior function call. */ inf_status = save_infcall_control_state (); inf_status_cleanup = make_cleanup_restore_infcall_control_state (inf_status); /* Save the caller's registers and other state associated with the inferior itself so that they can be restored once the callee returns. To allow nested calls the registers are (further down) pushed onto a dummy frame stack. Include a cleanup (which is tossed once the regcache has been pushed). */ caller_state = save_infcall_suspend_state (); make_cleanup_restore_infcall_suspend_state (caller_state); ... sp = push_dummy_code (gdbarch, sp, funaddr, args, nargs, target_values_type, &real_pc, &bp_addr, get_current_regcache ()); ... pass args ... /* Create the dummy stack frame. Pass in the call dummy address as, presumably, the ABI code knows where, in the call dummy, the return address should be pointed. */ sp = gdbarch_push_dummy_call (gdbarch, function, get_current_regcache (), bp_addr, nargs, args, sp, struct_return, struct_addr); ... /* Everything's ready, push all the info needed to restore the caller (and identify the dummy-frame) onto the dummy-frame stack. */ dummy_frame_push (caller_state, &dummy_id); ... /* Run the inferior until it stops. */ e = run_inferior_call (tp, real_pc); } 

如果你在控制子进程,也许你可以添加一个调试接口,允许你写入有问题的内存?

对于阅读而言,最好的办法是解析/proc/<pid>/maps文件以获得感兴趣的内存区域的虚拟地址。

然后可以通过打开/proc/<pid>/mem来读取这些文件,并在感兴趣的区域执行read()调用。

对于编写,我还没有找到一个简单的方法来编写整个块,我相信这是与子进程的锁定和稳定性有关,通过ptrace()调用可以保证这一点,但直接访问另一个进程的内存不能。 我通常围绕ptrace(PTRACE_POKEDATA, ...)写一个包装来镜像Windows的WriteProcessMemory()

克隆或mmap是你在找什么。 在两个进程之间映射临时文件,并使用该内存空间来回传递数据。