Beispiel #1
0
void
hashtable_delete(hashtable_t *table)
{
    uint i;
    if (table->synch)
        dr_mutex_lock(table->lock);
    for (i = 0; i < HASHTABLE_SIZE(table->table_bits); i++) {
        hash_entry_t *e = table->table[i];
        while (e != NULL) {
            hash_entry_t *nexte = e->next;
            if (table->str_dup)
                hash_free(e->key, strlen((const char *)e->key) + 1);
            if (table->free_payload_func != NULL)
                (table->free_payload_func)(e->payload);
            hash_free(e, sizeof(*e));
            e = nexte;
        }
    }
    hash_free(table->table, (size_t)HASHTABLE_SIZE(table->table_bits) *
              sizeof(hash_entry_t*));
    table->table = NULL;
    table->entries = 0;
    if (table->synch)
        dr_mutex_unlock(table->lock);
    dr_mutex_destroy(table->lock);
}
Beispiel #2
0
/* caller must hold lock */
static bool
hashtable_check_for_resize(hashtable_t *table)
{
    size_t capacity = (size_t) HASHTABLE_SIZE(table->table_bits);
    if (table->config.resizable &&
        /* avoid fp ops.  should check for overflow. */
        table->entries * 100 > table->config.resize_threshold * capacity) {
        hash_entry_t **new_table;
        size_t new_sz;
        uint i, old_bits;
        /* double the size */
        old_bits = table->table_bits;
        table->table_bits++;
        new_sz = (size_t) HASHTABLE_SIZE(table->table_bits) * sizeof(hash_entry_t*);
        new_table = (hash_entry_t **) hash_alloc(new_sz);
        memset(new_table, 0, new_sz);
        /* rehash the old table into the new */
        for (i = 0; i < HASHTABLE_SIZE(old_bits); i++) {
            hash_entry_t *e = table->table[i];
            while (e != NULL) {
                hash_entry_t *nexte = e->next;
                uint hindex = hash_key(table, e->key);
                e->next = new_table[hindex];
                new_table[hindex] = e;
                e = nexte;
            }
        }
        hash_free(table->table, capacity * sizeof(hash_entry_t*));
        table->table = new_table;
        return true;
    }
    return false;
}
Beispiel #3
0
void
hashtable_init_ex(hashtable_t *table, uint num_bits, hash_type_t hashtype, bool str_dup,
                  bool synch, void (*free_payload_func)(void*),
                  uint (*hash_key_func)(void*), bool (*cmp_key_func)(void*, void*))
{
    hash_entry_t **alloc = (hash_entry_t **)
        hash_alloc((size_t)HASHTABLE_SIZE(num_bits) * sizeof(hash_entry_t*));
    memset(alloc, 0, (size_t)HASHTABLE_SIZE(num_bits) * sizeof(hash_entry_t*));
    table->table = alloc;
    table->hashtype = hashtype;
    table->str_dup = str_dup;
    ASSERT(!str_dup || hashtype == HASH_STRING || hashtype == HASH_STRING_NOCASE,
           "hashtable_init_ex internal error: invalid hashtable type");
    table->lock = dr_mutex_create();
    table->table_bits = num_bits;
    table->synch = synch;
    table->free_payload_func = free_payload_func;
    table->hash_key_func = hash_key_func;
    table->cmp_key_func = cmp_key_func;
    ASSERT(table->hashtype != HASH_CUSTOM ||
           (table->hash_key_func != NULL && table->cmp_key_func != NULL),
           "hashtable_init_ex missing cmp/hash key func");
    table->entries = 0;
    table->config.size = sizeof(table->config);
    table->config.resizable = true;
    table->config.resize_threshold = 75;
}
Beispiel #4
0
bool
hashtable_remove_range(hashtable_t *table, void *start, void *end)
{
    bool res = false;
    uint i;
    hash_entry_t *e, *prev_e, *next_e;
    if (table->synch)
        hashtable_lock(table);
    for (i = 0; i < HASHTABLE_SIZE(table->table_bits); i++) {
        for (e = table->table[i], prev_e = NULL; e != NULL; e = next_e) {
            next_e = e->next;
            if (e->key >= start && e->key < end) {
                if (prev_e == NULL)
                    table->table[i] = e->next;
                else
                    prev_e->next = e->next;
                if (table->str_dup)
                    hash_free(e->key, strlen((const char *)e->key) + 1);
                if (table->free_payload_func != NULL)
                    (table->free_payload_func)(e->payload);
                hash_free(e, sizeof(*e));
                table->entries--;
                res = true;
            } else
                prev_e = e;
        }
    }
    if (table->synch)
        hashtable_unlock(table);
    return res;
}
Beispiel #5
0
void
hashtable_delete(hashtable_t *table)
{
    if (table->synch)
        dr_mutex_lock(table->lock);
    hashtable_clear_internal(table);
    hash_free(table->table, (size_t)HASHTABLE_SIZE(table->table_bits) *
              sizeof(hash_entry_t*));
    table->table = NULL;
    table->entries = 0;
    if (table->synch)
        dr_mutex_unlock(table->lock);
    dr_mutex_destroy(table->lock);
}
Beispiel #6
0
/* if drcontext == NULL uses global memory */
static void
htable_free(void *drcontext, trace_head_entry_t **table)
{
    /* assume during process exit so no lock needed */
    int i;
    /* clean up memory */
    for (i = 0; i < HASHTABLE_SIZE(HASH_BITS); i++) {
        trace_head_entry_t *e = table[i];
        while (e) {
            trace_head_entry_t *nexte = e->next;
            dr_global_free(e, sizeof(trace_head_entry_t));
            e = nexte;
        }
        table[i] = NULL;
    }
    dr_global_free(table, TABLE_SIZE);
}
Beispiel #7
0
void
symcache_exit(void)
{
    uint i;
    ASSERT(initialized, "symcache was not initialized");
    dr_mutex_lock(symcache_lock);
    for (i = 0; i < HASHTABLE_SIZE(symcache_table.table_bits); i++) {
        hash_entry_t *he;
        for (he = symcache_table.table[i]; he != NULL; he = he->next) {
            mod_cache_t *modcache = (mod_cache_t *) he->payload;
            symcache_write_symfile(modcache->modname, modcache);
        }
    }
    hashtable_delete(&symcache_table);
    dr_mutex_unlock(symcache_lock);
    dr_mutex_destroy(symcache_lock);
}
Beispiel #8
0
static void
hashtable_clear_internal(hashtable_t *table)
{
    uint i;
    for (i = 0; i < HASHTABLE_SIZE(table->table_bits); i++) {
        hash_entry_t *e = table->table[i];
        while (e != NULL) {
            hash_entry_t *nexte = e->next;
            if (table->str_dup)
                hash_free(e->key, strlen((const char *)e->key) + 1);
            if (table->free_payload_func != NULL)
                (table->free_payload_func)(e->payload);
            hash_free(e, sizeof(*e));
            e = nexte;
        }
        table->table[i] = NULL;
    }
    table->entries = 0;
}
Beispiel #9
0
size_t
hashtable_persist_size(void *drcontext, hashtable_t *table, size_t entry_size,
                       void *perscxt, hasthable_persist_flags_t flags)
{
    uint count = 0;
    if (table->hashtype == HASH_INTPTR &&
        TESTANY(DR_HASHPERS_ONLY_IN_RANGE | DR_HASHPERS_ONLY_PERSISTED, flags)) {
        /* synch is already provided */
        uint i;
        ptr_uint_t start = 0;
        size_t size = 0;
        if (perscxt != NULL) {
            start = (ptr_uint_t) dr_persist_start(perscxt);
            size = dr_persist_size(perscxt);
        }
        count = 0;
        for (i = 0; i < HASHTABLE_SIZE(table->table_bits); i++) {
            hash_entry_t *he;
            for (he = table->table[i]; he != NULL; he = he->next) {
                if ((!TEST(DR_HASHPERS_ONLY_IN_RANGE, flags) ||
                     key_in_range(table, he, start, size)) &&
                    (!TEST(DR_HASHPERS_ONLY_PERSISTED, flags) ||
                     dr_fragment_persistable(drcontext, perscxt, he->key)))
                    count++;
            }
        }
    } else
        count = table->entries;
    /* we could have an OUT count param that user must pass to hashtable_persist,
     * but that's actually a pain for the user when persisting multiple tables,
     * and usage should always call hashtable_persist() right after calling
     * hashtable_persist_size().
     */
    table->persist_count = count;
    return sizeof(count) +
        (TEST(DR_HASHPERS_REBASE_KEY, flags) ? sizeof(ptr_uint_t) : 0) +
        count * (entry_size + sizeof(void*));
}
Beispiel #10
0
/* caller must hold symcache_lock */
static void
symcache_write_symfile(const char *modname, mod_cache_t *modcache)
{
    uint i;
    file_t f;
    hashtable_t *symtable = &modcache->table;
    char buf[SYMCACHE_BUFFER_SIZE];
    size_t sofar = 0;
    ssize_t len;
    size_t bsz = BUFFER_SIZE_ELEMENTS(buf);
    size_t filesz_loc;
    char symfile[MAXIMUM_PATH];
    char symfile_tmp[MAXIMUM_PATH];
    int64 file_size;

    ASSERT(dr_mutex_self_owns(symcache_lock), "missing symcache lock");

    /* if from file, we assume it's a waste of time to re-write file:
     * the version matched after all, unless we appended to it.
     */
    if (modcache->from_file && !modcache->appended)
        return;
    if (symtable->entries == 0)
        return; /* nothing to write */

    /* Open the temp symcache that we will rename.  */
    symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile));
    f = INVALID_FILE;
    i = 0;
    while (f == INVALID_FILE && i < SYMCACHE_MAX_TMP_TRIES) {
        dr_snprintf(symfile_tmp, BUFFER_SIZE_ELEMENTS(symfile_tmp),
                    "%s.%04d.tmp", symfile, i);
        NULL_TERMINATE_BUFFER(symfile_tmp);
        f = dr_open_file(symfile_tmp, DR_FILE_WRITE_REQUIRE_NEW);
        i++;
    }
    if (f == INVALID_FILE) {
        NOTIFY("WARNING: Unable to create symcache temp file %s"NL,
               symfile_tmp);
        return;
    }

    BUFFERED_WRITE(f, buf, bsz, sofar, len, "%s %d\n",
                   SYMCACHE_FILE_HEADER, SYMCACHE_VERSION);
    /* Leave room for file size for self-consistency check */
    filesz_loc = sofar;  /* XXX: Assumes that the buffer hasn't been flushed. */
    BUFFERED_WRITE(f, buf, bsz, sofar, len,
                   "%"STRINGIFY(SYMCACHE_SIZE_DIGITS)"u,", 0);
#ifdef WINDOWS
    BUFFERED_WRITE(f, buf, bsz, sofar, len,
                   UINT64_FORMAT_STRING","UINT64_FORMAT_STRING","
                   UINT64_FORMAT_STRING",%u,%u,%lu\n",
                   modcache->module_file_size, modcache->file_version.version,
                   modcache->product_version.version,
                   modcache->checksum, modcache->timestamp,
                   modcache->module_internal_size);
#else
    BUFFERED_WRITE(f, buf, bsz, sofar, len, UINT64_FORMAT_STRING",%u",
                   modcache->module_file_size, modcache->timestamp);
# ifdef MACOS
    BUFFERED_WRITE(f, buf, bsz, sofar, len, ",%u,%u,",
                   modcache->current_version, modcache->compatibility_version);
    /* For easy sscanf we print as 4 ints */
    for (i = 0; i < 4; i++)
        BUFFERED_WRITE(f, buf, bsz, sofar, len, "%08x,", *(int*)(&modcache->uuid[i*4]));
# endif
    BUFFERED_WRITE(f, buf, bsz, sofar, len, "\n");
#endif
    BUFFERED_WRITE(f, buf, bsz, sofar, len, "%u\n", modcache->has_debug_info);
    for (i = 0; i < HASHTABLE_SIZE(symtable->table_bits); i++) {
        hash_entry_t *he;
        for (he = symtable->table[i]; he != NULL; he = he->next) {
            offset_list_t *olist = (offset_list_t *) he->payload;
            offset_entry_t *e;
            if (olist == NULL)
                continue;
            /* skip symbol in dup entries to save space */
            BUFFERED_WRITE(f, buf, bsz, sofar, len, "%s", he->key);
            e = olist->list;
            while (e != NULL) {
                BUFFERED_WRITE(f, buf, bsz, sofar, len, ",0x%x\n", e->offs);
                e = e->next;
            }
        }
    }

    /* now update size */
    FLUSH_BUFFER(f, buf, sofar);
    if ((file_size = dr_file_tell(f)) < 0 ||
        dr_snprintf(buf, BUFFER_SIZE_ELEMENTS(buf),
                    "%"STRINGIFY(SYMCACHE_SIZE_DIGITS)"u", (uint)file_size) < 0 ||
        !dr_file_seek(f, filesz_loc, DR_SEEK_SET) ||
        dr_write_file(f, buf, SYMCACHE_SIZE_DIGITS) != SYMCACHE_SIZE_DIGITS) {
        /* If any steps fail, warn and give up. */
        NOTIFY("WARNING: Unable to write symcache file size."NL);
        dr_close_file(f);
        dr_delete_file(symfile_tmp);
        return;
    } else {
        LOG(3, "Wrote symcache %s file size %u to pos "SZFMT"\n",
            modname, (uint)file_size, filesz_loc);
        ASSERT(strlen(buf) <= SYMCACHE_SIZE_DIGITS, "not enough space for file size");
    }

    dr_close_file(f);

    if (!dr_rename_file(symfile_tmp, symfile, /*replace*/true)) {
        NOTIFY_ERROR("WARNING: Failed to rename the symcache file."NL);
        dr_delete_file(symfile_tmp);
    }
}