DynamoRIO is a dynamic binary piling/translation platform. Through it, you can manipulate the running code of a program, that is, it can simulate running a program and allow you to transform and control any place of the running code. It is used for dynamic analysis, optimization and translation of programs.
DynamoRIO is a cooperation project between HP and MIT. Dynamo comes from HP’s laboratory, RIO (Runtime Introspection and Optimization) comes from MIT’s computer science laboratory. The history is shown as follows.
DynamoRIO’s architecture is like this. It is between the operating system and the application so that it can get the system calls and the applications’ code easily.
This picture is the Toolchain Control Points.
The process flow is as follows. The original program goes through the “basic block builder”, “trace selector”, “basic block cache” and “trace cache” to get the emulation propose.
DynamoRIO is separated from the code of applications by the “context switch” as shown in the picture above. The applications’ code is copied to the instruction cache. The code in these caches will execute as native code. Until a jump instruction is encountered, the applications’ “machine state” will be saved, and the control will turn back to DynamoRIO to find the basic block where the jump instruction is located. DynamoRIO is much faster than pure emulations by “code cache”.
There are several improvements in this project. The picture above is the first one — Basic Block Cache. If you copy each basic block into a code cache and run it natively, it greatly reduces the overhead of interpreting, however, we still need to explain each jump instruction, and then return to DynamoRIO to find the target instruction. If a target instruction already exists in the code cache and is referred to by a direct jump instruction, DynamoRIO can directly jump to the target instruction in the code cache to avoid the overhead of the context switch, which is called “Linking Direct Branches”.
The next improvement is “Linking Indirect Branches” since a conditional branch instruction can not be linked like a direct jump instruction because it has more than one goal and needs to make decisions and find the list’s jump target.
Some basic blocks, which are often executed sequentially, are combined into one execution stream to reduce the number of branches and increase the locality of the program. It reduces some overhead of indirect branch search, because it has put indirect brach in this trace as well. This is also the last improvement — Trace Building.
It has three transparency principles which are “As few changes as possible”, “Hide necessary changes” and “Separate resources”. Changes in these areas are few: application code, stored addresses, threads and application data. Changes in these fields are hidden: application addresses, address space, error transparency and code cache consistency. This picture shows the principle 3 well. DynamoRIO’s own code also uses share libraries when loading applications, which may cause some conflicts if the application also uses the same library. The solution is that, DynamoRIO doesn’t use the library directly, calling system call on Linux and calling system call via windows win32 API profile.
The heap memory allocated by DynamoRIO itself is distinguished from the heap memory requested by the application. In addition, DynamoRIO uses its own I/O routines for input and output to avoid conflicts with the applications’ I/O buffers. What’s more, since the use of shared locks can also cause conflicts between DynamoRIO and applications, it also has synchronization transparency.
To avoid conflicts with applications, DynamoRIO doesn’t create its own thread, instead spawns threads in the application process to distinguish between its own status and applications’ status via a “Context Switch” as the first picture shows. Further more, it chooses to leave the stack of application processes intact, creating a private stack of each thread.
All data streams must go through handlers generated by the dispatcher. The data flow is like this.
DynamoRIO has developed some event driven APIs that allow developers to customize instrument instructions. Using it, you can achieve some proposes such as: memory checking, performance testing, system call tracking, code coverage calculation.
本文链接： http://home.meng.uno/articles/a331aaad/ 欢迎转载！