We found a solution to improve performance of accessing to a child process' memory. We create two pipes between the tracing process (monitor) and the traced process, one for reading (read-pipe) and one for writing (write-pipe). In order to start running the process, the monitor spawns a child using fork and then runs a given executable inside the child. The communication pipes are created after the child is spawned and before executing the executable. To keep the pipes open after the execution, the monitor uses execve to start the execution.
When the process is stopped at a system call and control is transfered back to the monitor, it replaces the original system call with a write to one of the pipes provided for reading from the process (read-pipe). It also gives the address of the buffer that the monitor needs to read and its length to the write. The process is resumed and the kernel executes the write and writes the contents of the process' memory to the read-pipe. The OS notifies the monitor after executing the call and the monitor reads the contents of the buffer from the pipe at once using a single read. Writing to the process' memory is done in a similar way, but the monitor first writes the data to the write-pipe and then the system call is replaced by a read from the pipe to a desired address with the specified length.
It is not always faster to read and write the memory of a traced process through the pipes. Our experiments have shown that for buffers shorter than 40 bytes in length, ptrace is more efficient and for buffers larger than 40 bytes, pipes are faster.
Thursday, November 15, 2007
Subscribe to:
Posts (Atom)