Code instrumentationΒΆ
This is a howto on code instrumentation. Code instrumentation is the action of adding extra code to your program. A good example is function call tracing. With function call tracing, you can execute a custom action whenever a function is entered. It is also fun and easy to enter infinite recursions by doing so.
Lets demonstrate how this works with an example!
Say, we have a simple function, and would like to instrument this code.
So, first define a function in C, called my_add
, and turn it into IR-code:
>>> import io
>>> from ppci import api
>>> source = """
... int my_add(int a, int b) { return a + b; }
... """
>>> arch = api.get_arch('arm')
>>> module = api.c_to_ir(io.StringIO(source), arch)
>>> api.optimize(module, level=2)
>>> module.display()
module main;
global function i32 my_add(i32 a, i32 b) {
my_add_block0: {
i32 tmp_3 = a + b;
return tmp_3;
}
}
Now comes the cool part, the addition of tracing functionality. Since we have IR-code, we can add tracing to it. This means the tracing functionality is target independent!
>>> from ppci.irutils.instrument import add_tracer
>>> add_tracer(module)
>>> module.display()
module main;
external procedure trace(ptr);
global function i32 my_add(i32 a, i32 b) {
my_add_block0: {
blob<7:1> func_name = literal '6d795f61646400';
ptr name_ptr = &func_name;
call trace(name_ptr);
i32 tmp_3 = a + b;
return tmp_3;
}
}
Notice the extra code inserted! Now, we could turn this into machine code like this:
>>> print(api.ir_to_assembly([module], arch))
section data
global trace
type trace func
section data
section code
global my_add
type my_add func
my_add:
push LR, R11
mov R11, SP
push R5, R6
mov R6, R1
mov R5, R2
my_add_block0:
ldr R1, my_add_literal_1
bl trace
add R0, R6, R5
b my_add_epilog
my_add_epilog:
pop R5, R6
pop PC, R11
ALIGN(4)
my_add_literal_0:
db 109
db 121
db 95
db 97
db 100
db 100
db 0
ALIGN(4)
my_add_literal_1:
dcd =my_add_literal_0
ALIGN(4)
Notice here as well the extra call to the trace
function.