Skip to content

Instantly share code, notes, and snippets.

@axt
Last active September 18, 2020 07:56
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save axt/9315305 to your computer and use it in GitHub Desktop.
Save axt/9315305 to your computer and use it in GitHub Desktop.
Naive hit tracer implementation using DynamoRIO.
/*
* Naive hit tracer implementation using DynamoRIO.
*
* Author: axt
*
* Build it with the following commands:
* gcc -Dbbhit_EXPORTS -DSHOW_RESULTS -DSHOW_SYMBOLS -fPIC -I../include -I../ext/include -DX86_64 -DLINUX -O2 -fno-stack-protector -o bbhit.c.o -c bbhit.c
* gcc -fPIC -O2 -DX86_64 -DLINUX -fno-stack-protector -fPIC -shared -lgcc -Wl,--hash-style=both -shared -Wl,-soname,libbbhit.so -o libbbhit.so bbhit.c.o ../lib64/debug/libdynamorio.so.4.2 ../ext/lib64/debug/libdrsyms.so
*/
#include <stddef.h>
#include <dr_api.h>
#include <drsyms.h>
#define MAX_NUM_MODULES 256
static void event_exit(void);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating);
static void event_module_load(void *drcontext, const module_data_t *info, bool loaded);
static void event_module_unload(void *drcontext, const module_data_t *info);
static int global_count;
typedef struct _module_array_t {
unsigned long base;
unsigned long end;
unsigned int count;
size_t size;
bool loaded;
module_data_t *info;
byte* bitmap;
} module_array_t;
static module_array_t mod_array[MAX_NUM_MODULES];
static int mod_count = 0;
static void *mod_lock;
DR_EXPORT void dr_init(client_id_t id) {
mod_lock = dr_mutex_create();
dr_register_exit_event(event_exit);
dr_register_bb_event(event_basic_block);
dr_register_module_load_event(event_module_load);
dr_register_module_unload_event(event_module_unload);
dr_log(NULL, LOG_ALL, 1, "Client 'bbhit' initializing\n");
}
static drsym_info_t* create_drsym_info() {
drsym_info_t* info;
info = malloc(sizeof(drsym_info_t));
info->struct_size = sizeof(drsym_info_t);
info->debug_kind = DRSYM_SYMBOLS;
info->name_size = 256;
info->file_size = 256;
info->file=malloc(256);
info->name=malloc(256);
return info;
}
static void free_drsmy_info(drsym_info_t * info) {
if (info->file != NULL)
free(info->file);
if (info->name != NULL)
free(info->name);
free(info);
}
static void event_exit(void) {
int i,j;
drsym_init(0);
drsym_info_t* syminfo = create_drsym_info();
drsym_error_t err;
dr_mutex_lock(mod_lock);
dr_printf("\n===\nModules:\n");
for (i = 0; i < mod_count; i++) {
syminfo->start_offs = 0;
syminfo->end_offs = 0;
dr_printf("\t- [%c] (%8d) %s [%s]\n", (mod_array[i].loaded ? '+':'-'), mod_array[i].count, dr_module_preferred_name(mod_array[i].info) , mod_array[i].info->full_path);
if (mod_array[i].bitmap != NULL) {
for(j=0; j < mod_array[i].size; j++) {
if (mod_array[i].bitmap[j] != 0) {
int old = (syminfo->start_offs <= j && syminfo->end_offs >= j);
if (!old)
err = drsym_lookup_address (mod_array[i].info->full_path, j, syminfo, DRSYM_LEAVE_MANGLED);
if (old || err == DRSYM_SUCCESS || err == DRSYM_ERROR_LINE_NOT_AVAILABLE) {
dr_printf("\t\t- basic_block " PFX " - [%08x -- %08x] %s\n", mod_array[i].base + j, syminfo->start_offs, syminfo->end_offs, syminfo->name);
} else {
dr_printf("\t\t- basic_block " PFX "\n", mod_array[i].base + j);
}
}
}
}
dr_free_module_data(mod_array[i].info);
if (mod_array[i].bitmap != NULL)
free(mod_array[i].bitmap);
}
dr_mutex_unlock(mod_lock);
dr_mutex_destroy(mod_lock);
free_drsmy_info(syminfo);
drsym_exit();
dr_printf("Instrumentation results:\n%10d basic block executions\n", global_count);
}
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) {
int i;
for (i = 0; i < mod_count; i++) {
global_count++;
unsigned long tag_pc = (unsigned long)tag;
if (mod_array[i].base <= tag_pc && mod_array[i].end >= tag_pc) {
mod_array[i].count++;
if (mod_array[i].bitmap != NULL)
mod_array[i].bitmap[tag_pc - mod_array[i].base] = 1;
break;
}
}
return DR_EMIT_DEFAULT;
}
static bool module_data_same(const module_data_t *d1, const module_data_t *d2) {
if (d1->start == d2->start && d1->end == d2->end && d1->entry_point == d2->entry_point &&
dr_module_preferred_name(d1) != NULL && dr_module_preferred_name(d2) != NULL &&
strcmp(dr_module_preferred_name(d1), dr_module_preferred_name(d2)) == 0)
return true;
return false;
}
static void event_module_load(void *drcontext, const module_data_t *info, bool loaded) {
int i;
dr_log(drcontext, LOG_ALL, 1, "Module load event: %s [%s]\n", dr_module_preferred_name(info) , info->full_path);
dr_mutex_lock(mod_lock);
for (i = 0; i < mod_count; i++) {
if (!mod_array[i].loaded && module_data_same(mod_array[i].info, info)) {
mod_array[i].loaded = true;
break;
}
}
if (i == mod_count) {
mod_array[i].base = (unsigned long)info->start;
mod_array[i].end = (unsigned long)info->end;
mod_array[i].loaded = true;
mod_array[i].info = dr_copy_module_data(info);
mod_array[i].count = 0;
mod_array[i].size = mod_array[i].end-mod_array[i].base;
mod_array[i].bitmap = (byte*) malloc(mod_array[i].size);
mod_count++;
}
dr_mutex_unlock(mod_lock);
}
static void event_module_unload(void *drcontext, const module_data_t *info) {
int i;
dr_log(drcontext, LOG_ALL, 1, "Module unload event: %s [%s]\n", dr_module_preferred_name(info) , info->full_path);
dr_mutex_lock(mod_lock);
for (i = 0; i < mod_count; i++) {
if (mod_array[i].loaded && module_data_same(mod_array[i].info, info)) {
mod_array[i].loaded = false;
break;
}
}
dr_mutex_unlock(mod_lock);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment