Tools¶
Example use:zerospy¶
Here we take zerospy as an example to show the use of VClinic internal tools.
1. Create source file¶
Create a simple C program and save it as a file named sample.cc.
2. Compile your application¶
To generate an executable binary, compile your application with GCC Compiler.
$ gcc -g sample.cc -o sample
Tip
If the executable is built with -g opinion, the client will show more information, such as source code line number and source file path.
3. Run application using client¶
Run the generated binary sample using zerospy client.
$ build/bin64/drrun -t zerospy -- ./sample
The client outputs:
[ZEROSPY INFO] Sampling Disabled
--------------- Dumping INTEGER Redundancy Info ----------------
*************** Dump Data from Thread 0 ****************
Total redundant bytes = 46.832358 %
INFO : Total redundant bytes = 46.832358 % (2693549 / 5751470)
======= (14.850296) % of total Redundant, with local redundant 100.000000 % (400000 Bytes / 400000 Bytes) ======
======= with All Zero Redundant 100.000000 % (100000 / 100000) ======
======= Redundant byte map : [0] [AccessLen=4] =======
---------------------Redundant load with---------------------------
#0 0x00007fa056474170 "mov eax, dword ptr [rdx+rax]" in foo at [/home/lkl/samples/sample.cc:7]
#1 0x00007fa0564741a3 "call 0x00007fa056474129" in main at [/home/lkl/samples/sample.cc:11]
#2 0x00007fa0572f50b1 "call rax" in __libc_start_main at [/home/lkl/samples/sample.cc:0]
#3 0x00007fa056474068 "call <rel> qword ptr [0x00007fa056476fe0]" in _start at [:0]
#4 0xffffffffffffffff "<NULL>" in THREAD[0]_ROOT_CTXT at [<NULL>:0]
#5 0x0000000000000000 "<NULL>" in PROCESS[2057914]_ROOT_CTXT at [<NULL>:0]
======= (14.850296) % of total Redundant, with local redundant 100.000000 % (400000 Bytes / 400000 Bytes) ======
======= with All Zero Redundant 100.000000 % (100000 / 100000) ======
======= Redundant byte map : [0] [AccessLen=4] =======
---------------------Redundant load with---------------------------
#0 0x00007fa0564741cc "mov edx, dword ptr [rdx+rax]" in main at [/home/lkl/samples/sample.cc:13]
#1 0x00007fa0572f50b1 "call rax" in __libc_start_main at [/home/lkl/samples/sample.cc:0]
#2 0x00007fa056474068 "call <rel> qword ptr [0x00007fa056476fe0]" in _start at [:0]
#3 0xffffffffffffffff "<NULL>" in THREAD[0]_ROOT_CTXT at [<NULL>:0]
#4 0x0000000000000000 "<NULL>" in PROCESS[2057914]_ROOT_CTXT at [<NULL>:0]
======= (6.155188) % of total Redundant, with local redundant 41.448250 % (165793 Bytes / 400000 Bytes) ======
======= with All Zero Redundant 0.001000 % (1 / 100000) ======
======= Redundant byte map : [0] [AccessLen=4] =======
---------------------Redundant load with---------------------------
#0 0x00007fa05647418e "add dword ptr [rbp-0x04], 0x01" in foo at [/home/lkl/samples/sample.cc:6]
#1 0x00007fa0564741a3 "call 0x00007fa056474129" in main at [/home/lkl/samples/sample.cc:11]
#2 0x00007fa0572f50b1 "call rax" in __libc_start_main at [/home/lkl/samples/sample.cc:0]
#3 0x00007fa056474068 "call <rel> qword ptr [0x00007fa056476fe0]" in _start at [:0]
#4 0xffffffffffffffff "<NULL>" in THREAD[0]_ROOT_CTXT at [<NULL>:0]
#5 0x0000000000000000 "<NULL>" in PROCESS[2057914]_ROOT_CTXT at [<NULL>:0]
...
Tip
Intepreting the text output: The client zerospy identifys redundant zeros caused by useless computation and outputs its frequency as the metric, pc, assemble code, and full call path which reveals the locations where the redundant zeros happen in source lines and calling contexts. The full call path starts on the bottom with two dummy PROCESS_ROOT and THREAD_ROOT and ends on the top with the fuction that encloses the pc.
Build Your Own Tool¶
We demonstrate how to create and build a VClinic client by taking a deep dive into vprofile_all_opnd.
Basic structure of a client¶
This section describes the basic structure of a VClinic client.
The following code is the specific implementation of vprofile_all_opnd:
#include "dr_api.h"
#include "vprofile.h"
vtrace_t* vtrace;
template<int size, int esize, bool is_float>
void update(val_info_t *info) {
return;
}
static void
ClientInit(int argc, const char *argv[])
{
}
static void
ClientExit(void)
{
vprofile_unregister_trace(vtrace);
vprofile_exit();
}
#ifdef __cplusplus
extern "C" {
#endif
DR_EXPORT void
dr_client_main(client_id_t id, int argc, const char *argv[])
{
dr_set_client_name("DynamoRIO Client 'vprofile_all_opnd'",
"http://dynamorio.org/issues");
ClientInit(argc, argv);
vprofile_init(VPROFILE_FILTER_ALL_INSTR, NULL, NULL, NULL,
VPROFILE_DEFAULT);
vtrace = vprofile_allocate_trace(VPROFILE_TRACE_DEFAULT | VPROFILE_TRACE_BEFORE_WRITE);
vprofile_register_trace_template_cb(vtrace, VPROFILE_FILTER_ALL_OPND, VPROFILE_OPND_MASK_ALL, update);
dr_register_exit_event(ClientExit);
}
#ifdef __cplusplus
}
#endif
The diagram below shows the key functions in vprofile_all_opnd.cpp and how they relate to each other.
The easiest way to understand the client is to think of it as event driven. Each function is called upon the occurence of an event during the application execution:
DynamoRIO loads and runs the client, calling
dr_client_main()before the application execution.
In
dr_client_main(), the client callsvprofile_init(), which initializes VClinic.
In
dr_client_main(), the client callsvprofile_allocate_trace()andvprofile_register_trace_template_cb(), which registers trace that can collect and provide any information you want in trace buffer with custom filter(VPROFILE_FILTER_ALL_OPND) and callback function(update).
opnd_filterwill Estimate the filled in slots for detecting potential trace buffer overflow.
updatecallback function will provide the collected information to the user for customized analysis when the trace buffer is detected as full. In fact,vprofile_all_opnddoes not use the collected information but returns directly in the callback function.
The application stops running and DynamoRIO calls ClientExit(), where one can output the analysis results..
Add a new client to VClinic¶
If you want to add a new client, you need to create a folder with the client name in VClinic/src/clients, and put the client_name.cpp and CMakeLists.txt in it. Then, when you finish the programming, you can run “sh build.sh” in the VClinic root directory to build it. One can refer to any of the example clients to see how to edit the CMakeLists.txt.