lks9 / src-tracer

Other
0 stars 0 forks source link

Instrument and trace only pointer calls #61

Closed lks9 closed 4 months ago

lks9 commented 4 months ago

Solves #36.

Now approach to instrument pointer calls. The instrumenter inserts _POINTER_CALL(call) around such calls. Then the tracer ignores _FUNC(num) except that we had a _POINTER_CALL().

Example:

foo( x );
void (*fun)(int) = foo;
fun( x );
mystruct->myfun( x );
metafun( y ) ( x );
fun( random() );

Instrumented: with instrumenter.py FILENAME --pointer-calls

foo( x );
void (*fun)(int) = foo;
_POINTER_CALL(fun( x ));
_POINTER_CALL(mystruct->myfun( x ));
_POINTER_CALL_AFTER(metafun( y )) ( x );
fun( _POINTER_CALL_AFTER(random()) );

Note: To make use of it when tracing/retracing, compile with -D_TRACE_POINTER_CALLS_ONLY! Then we trace only function numbers for pointer calls. Otherwise the macros will be without effect and every function number gets traced.

Technical details: The clang.cindex, well, does not exactly expose pointer calls. But it is possible to indirectly detect "normal" function calls, by checking if they reference a CursorKind.FUNCTION_DECL. Otherwise, it would reference for example a CursorKind.VAR_DECL or to a member in a struct. Or if you use pointer-arithmetic, there could be no reference at all.

When in trace mode, _POINTER_CALL(...) sets a global variable _trace_pointer_call to true. _FUNC(num) is only active when this variable is true. After _FUNC(num) is done, _trace_pointer_call is set to false again. Since the pointer and function arguments are evaluated before the call, we use the _POINTER_CALL_AFTER(other_call) in these situtations instead, to set _trace_pointer_call only after the other call finished.