Some examples with ELF shared objects


A simple elf-preload example
/* Timetravel Preload Library  -  by Clifford Wolf, 2001-06-25 */
/* gcc -Wall -O2 -ldl --shared -o timetravel.so timetravel.c   */
/* LD_PRELOAD=./timetravel.so date                             */

#define _GNU_SOURCE
#define _REENTRANT

#include <unistd.h>
#include <stdlib.h>
#include <dlfcn.h>

extern time_t time(time_t *t);

time_t time(time_t *t)
{
        int (*orig_time)(time_t *);
        time_t returncode;
        
        orig_time = dlsym(RTLD_NEXT,"time");
        returncode = orig_time(NULL) - (24*60*60*10);

        if (t != NULL) *t = returncode;
        return returncode;
}

(
download)


Embedded backtracing debug code
#define _GNU_SOURCE
#include <dlfcn.h>
/* ... */

void myfunction()
{
        /* .... */
#if DEBUG == 1
        {
                Dl_info dli;
                /* this only works in a shared object context */
                dladdr(__builtin_return_address(0), &dli);
                fprintf(stderr, "debug trace [%d]: %s "
                                "called by %p [ %s(%p) %s(%p) ].\n",
                                getpid(), __func__,
                                 __builtin_return_address(0),
                                strrchr(dli.dli_fname, '/') ?
                                        strrchr(dli.dli_fname, '/')+1 : dli.dli_fname,
                                dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
                dladdr(__builtin_return_address(1), &dli);
                fprintf(stderr, "debug trace [%d]: %*s "
                                "called by %p [ %s(%p) %s(%p) ].\n",
                                getpid(), strlen(__func__), "...",
                                __builtin_return_address(1),
                                strrchr(dli.dli_fname, '/') ?
                                        strrchr(dli.dli_fname, '/')+1 : dli.dli_fname,
                                dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
        }
#endif
        /* .... */
}
(
download)


A loadable plugin for the bash shell
/* Litte example for writing freestanding bash plugins (this is cool stuff!)
 * Partly written and mostly copy&pasted from bash sources by Clifford Wolf.
 *
 * Examples of hosted loadables can be found in:
 *      bash-2.05b/examples/loadables/
 *
 * Usage:
 *      gcc -shared -fPIC -Wall -o hellobash.so hellobash.c
 *      enable -f ./hellobash.so hellobash
 *
 *      hellobash one two three; echo $?
 *      hellobash one two three; echo $?
 *      hellobash one two three; echo $?
 *      echo $three
 *
 *      enable -d hellobash
 */


/* Some declarations copied from bash-2.05b headers */

#include <stdint.h>

typedef struct word_desc {
        char *word;
        int flags;
} WORD_DESC;

typedef struct word_list {
        struct word_list *next;
        WORD_DESC *word;
} WORD_LIST;

typedef int sh_builtin_func_t(WORD_LIST *);

#define BUILTIN_ENABLED 0x1

struct builtin {
        char *name;
        sh_builtin_func_t *function;
        int flags;
        char * const *long_doc;
        const char *short_doc;
        char *handle;
};

struct variable;
typedef intmax_t arrayind_t;

typedef struct variable *sh_var_value_func_t(struct variable *);
typedef struct variable *sh_var_assign_func_t(struct variable *, char *, arrayind_t);

typedef struct variable {
        char *name;
        char *value;
        char *exportstr;
        sh_var_value_func_t *dynamic_value;
        sh_var_assign_func_t *assign_func;
        int attributes;
        int context;
} SHELL_VAR;

extern SHELL_VAR *find_variable(const char *);
extern SHELL_VAR *bind_variable(const char *, char *);
#define value_cell(var) ((var)->value)


/* my hellobash builtin */

#include <stdio.h>

static const char *getvar(char *name)
{
        SHELL_VAR *var;
        var = find_variable(name);
        return var ? value_cell(var) : 0;
}
#define setvar(a,b) bind_variable(a,b)

int hellobash_builtin(WORD_LIST *list)
{
        static int retval=0, count=0;

        printf("Hello Bash!\n");
        while (list) {
                const char *oldval;
                char newval[50];

                oldval = getvar(list->word->word);
                if ( !oldval ) oldval = "undef";

                sprintf(newval, "hello bash %d", count++);

                printf("Parameter: %s (\"%s\" -> \"%s\")\n",
                                list->word->word, oldval, newval);

                setvar(list->word->word, newval);
                list = list->next;
        }
        fflush(stdout);
        return retval++;
}

char *hellobash_doc[] = {
        "this is really cool stuff",
        0
};

struct builtin hellobash_struct = {
        "hellobash",
        &hellobash_builtin,
        BUILTIN_ENABLED,
        hellobash_doc,
        "this is cool",
        0
};

(
download)