mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
145 lines
4.2 KiB
C
145 lines
4.2 KiB
C
/**
|
|
* @file tlib/injection.c
|
|
*
|
|
* @copyright 2014-2024 Bill Zissimopoulos
|
|
*/
|
|
|
|
#include <tlib/injection.h>
|
|
#include <tlib/callstack.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#undef NDEBUG
|
|
#include <assert.h>
|
|
|
|
#define NBUCKETS 256
|
|
struct injection_cond_s
|
|
{
|
|
struct injection_cond_s *cnext;
|
|
char *sym;
|
|
unsigned trigger, count;
|
|
};
|
|
struct injection_entry_s
|
|
{
|
|
struct injection_entry_s *hnext;
|
|
char *name;
|
|
struct injection_cond_s *clist;
|
|
};
|
|
struct injection_htab_s
|
|
{
|
|
struct injection_entry_s **buckets;
|
|
};
|
|
|
|
static inline size_t hash_chars(const char *s, size_t length)
|
|
{
|
|
/* djb2: see http://www.cse.yorku.ca/~oz/hash.html */
|
|
size_t h = 5381;
|
|
for (const char *t = s + length; t > s; ++s)
|
|
h = 33 * h + *s;
|
|
return h;
|
|
}
|
|
static struct injection_htab_s *injection_htab()
|
|
{
|
|
static struct injection_htab_s *htab;
|
|
if (0 == htab)
|
|
{
|
|
htab = calloc(1, sizeof *htab);
|
|
assert(0 != htab);
|
|
htab->buckets = calloc(NBUCKETS, sizeof(struct injection_entry_s *));
|
|
}
|
|
return htab;
|
|
}
|
|
static struct injection_entry_s *injection_lookup(const char *name)
|
|
{
|
|
struct injection_htab_s *htab = injection_htab();
|
|
size_t i = hash_chars(name, strlen(name)) & (NBUCKETS - 1);
|
|
for (struct injection_entry_s *entry = htab->buckets[i]; entry; entry = entry->hnext)
|
|
if (0 == strcmp(entry->name, name))
|
|
return entry;
|
|
return 0;
|
|
}
|
|
static struct injection_entry_s *injection_insert(const char *name)
|
|
{
|
|
struct injection_htab_s *htab = injection_htab();
|
|
size_t i = hash_chars(name, strlen(name)) & (NBUCKETS - 1);
|
|
struct injection_entry_s *entry = calloc(1, sizeof *entry);
|
|
assert(0 != entry);
|
|
entry->name = strdup(name);
|
|
entry->hnext = htab->buckets[i];
|
|
htab->buckets[i] = entry;
|
|
return entry;
|
|
}
|
|
static struct injection_cond_s *injection_cond_get(struct injection_entry_s *entry, const char **syms)
|
|
{
|
|
struct injection_cond_s *deinjection_centry = 0;
|
|
for (struct injection_cond_s *centry = entry->clist; centry; centry = centry->cnext)
|
|
if ('*' == centry->sym[0] && '\0' == centry->sym[1])
|
|
deinjection_centry = centry;
|
|
else
|
|
{
|
|
for (const char *sym; 0 != (sym = *syms); syms++)
|
|
if (0 == strcmp(centry->sym, sym))
|
|
return centry;
|
|
}
|
|
return deinjection_centry;
|
|
}
|
|
static void injection_cond_set(struct injection_entry_s *entry, const char *sym, unsigned trigger)
|
|
{
|
|
for (struct injection_cond_s *centry = entry->clist; centry; centry = centry->cnext)
|
|
if (0 == strcmp(centry->sym, sym))
|
|
{
|
|
centry->trigger = trigger;
|
|
return;
|
|
}
|
|
struct injection_cond_s *centry = calloc(1, sizeof *centry);
|
|
assert(0 != centry);
|
|
centry->sym = strdup(sym);
|
|
centry->trigger = trigger;
|
|
centry->cnext = entry->clist;
|
|
entry->clist = centry;
|
|
}
|
|
static void injection_cond_remove(struct injection_entry_s *entry, const char *sym)
|
|
{
|
|
struct injection_cond_s **p = &entry->clist;
|
|
for (; *p; p = &(*p)->cnext)
|
|
if (0 == strcmp((*p)->sym, sym))
|
|
break;
|
|
if (*p) /* did we find the condition? */
|
|
{
|
|
struct injection_cond_s *q = *p;
|
|
*p = q->cnext;
|
|
free(q->sym);
|
|
free(q);
|
|
}
|
|
}
|
|
|
|
void *tlib_injection(const char *name)
|
|
{
|
|
struct injection_entry_s *entry = injection_lookup(name);
|
|
if (0 == entry)
|
|
entry = injection_insert(name);
|
|
return entry;
|
|
}
|
|
int tlib_injection_trace(void *injection)
|
|
{
|
|
if (0 == ((struct injection_entry_s *)injection)->clist)
|
|
return 0;
|
|
struct tlib_callstack_s stack;
|
|
tlib_callstack(2, TLIB_MAX_SYMRET, &stack);
|
|
struct injection_cond_s *centry = injection_cond_get(injection, stack.syms);
|
|
if (0 == centry)
|
|
return 0;
|
|
return centry->count++ == centry->trigger || ~0 == centry->trigger;
|
|
}
|
|
void tlib_injection_enable(const char *name, const char *sym, unsigned trigger)
|
|
{
|
|
struct injection_entry_s *entry = tlib_injection(name);
|
|
injection_cond_set(entry, sym, trigger);
|
|
}
|
|
void tlib_injection_disable(const char *name, const char *sym)
|
|
{
|
|
struct injection_entry_s *entry = tlib_injection(name);
|
|
injection_cond_remove(entry, sym);
|
|
}
|