Dynamic Dynamic Loader logo

Dynamic Dynamic Loader (DDL) Project

NMSU

HOME

EVENT TOOL FRAMEWORK

DOCUMENTATION

DOWNLOAD

WRAPPER REDIRECTION

TABLE BASED REDIRECTION

REDIRECTION USING TCL

C++ REDIRECTION

FAQ

RESEARCH GROUP

PUBLICATIONS

FUTURE DIRECTIONS



Back to PLEASE Lab



Wrapper Redirection

Before using DDL we might need to make some changes in our source code so that we can intercept calls to all the functions which we want to wrap/redirect.
 

Changes Required In C Code

  1. The target functions (the functions which we want to redirect) should be non-static.
  2. The target functions that are present in the main executable and are not in the shared object should be “called” from a shared object file, these calls may never execute, and by doing this the linker links the calls to these functions dynamically and we are able to intercept them.
  3. To make sure that there is no statically linked call to any target function we can use objdump command:
    objdump -d executable_file | grep call | grep target_func_name
We don't need to make any change for the functions which are already present in shared objects.

Writing Wrapper Functions

In normal redirection each target functions is wrapped by a different wrapper function, unlike table based redirection in which all the target functions are wrapped by a single function.

We have added two mechanisms that make writing wrappers and runtime monitors much easier.

The first is a function void redirect_ignore_next(char *name, char* libname). This function, when called with a function name and the library name of the wrapper library as parameters, tells the redirection code to ignore the next link request for this function. That is, it will not redirect the next link request for this function, even if this function is on the list of functions to be redirected.

What this means is that a wrapper, e.g., named "func_wrap", can simply call the actual function, e.g., "func", by name, by first doing a void redirect_ignore_next("func","wraplib"), and then calling the function. This mechanism will only ignore the single next call to the function. It automatically disables itself after one call.

Of course, the dynamic linking process only happens once, on the first call to this function in this shared object, so after the call to the function, the wrapper should do a void redirect_ignore_next("","") to disable the ignoring of the function.

The second mechanism is a global flag do_redirect (note this should be changed to a set/clear API). This turns on redirection globally. It is very similar to the _redirect_isactive flag we added to the linker itself, but this controls the user-level redirection library. This is useful to turning off redirection while you are in your analysis or monitoring code, or whatever code in your wrapper you want to avoid doing any redirection on.

You might be wondering why the first (specific) mechanism is needed if we have a global flag. The reason that you cannot use the above flag to disable redirection for the wrapped function call is that the wrapped function may call other functions in the application, and you may want to intercept those. So, general redirection needs to be on when we enter application code, but to get there we have to disable the redirection for the specific next function call.

So, a wrapper might look like:

A Sample Wrapper Function
void myputchar (int c)
{
  // turn off redirection for my wrapper code
  do_redirect = 0; 

  //
  // put my pre-call monitoring/logging/whatever code in here
  //

  // now be sure not to redirect my own putchar call
  redirect_ignore_next("putchar","libWrappers");

  // turn redirection back on
  do_redirect = 1;

  // call the real putchar function
  putchar (c);

  // turn off redirection again, for the rest of my wrapper
  do_redirect = 0;

  // turn off skipping redirection of putchar
  _dl_ignore_next("");

  //
  // put my post-call monitoring/logging/whatever code here
  //

  // turn on redirection before we leave
  do_redirect = 1;

  return;
}


Compiling Wrapper functions


The wrapper functions can be compiled in two ways:

1.    Write wrapper functions and compile them into a shared object file. Add this file to LD_WRAP_LIB. Our loader will load this library before the main executable is loaded. The wrapper shared object should be compiled in this way :
    cc -fPIC -shared -Wall

2.    Write wrapper functions in the file that contains the main function. This becomes necessary when we want to access any global variable, which is declared in the main file, from our wrapper function. The reason behind this is we need to declare global variables as extern in our wrapper functions and as the loader tries to load the wrapper library before the main executable is loaded, it fails to resolve the external references.