Exemplo n.º 1
0
/* Sets modcache->has_debug_info.
 * No lock is needed as we assume the caller hasn't exposed modcache outside this
 * thread yet.
 */
static bool
symcache_read_symfile(const module_data_t *mod, const char *modname,
                      mod_cache_t *modcache)
{
    hashtable_t *symtable = &modcache->table;
    bool res = false;
    const char *line, *next_line;
    char symbol[MAX_SYMLEN];
    size_t offs;
    uint64 map_size;
    size_t actual_size;
    bool ok;
    void *map = NULL;
    char symfile[MAXIMUM_PATH];
    file_t f;

    symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile));
    f = dr_open_file(symfile, DR_FILE_READ);
    if (f == INVALID_FILE)
        goto symcache_read_symfile_done;
    LOG(2, "processing symbol cache file for %s\n", modname);
    /* we avoid having to do our own buffering by just mapping the whole file */
    ok = dr_file_size(f, &map_size);
    if (ok) {
        actual_size = (size_t) map_size;
        ASSERT(actual_size == map_size, "file size too large");
        map = dr_map_file(f, &actual_size, 0, NULL, DR_MEMPROT_READ, 0);
    }
    if (!ok || map == NULL || actual_size < map_size) {
        NOTIFY_ERROR("Error mapping symcache file for %s"NL, modname);
        goto symcache_read_symfile_done;
    }
    if (strncmp((char *)map, SYMCACHE_FILE_HEADER, strlen(SYMCACHE_FILE_HEADER)) != 0) {
        WARN("WARNING: symbol cache file is corrupted\n");
        goto symcache_read_symfile_done;
    }
    /* i#1057: We use dr_sscanf() because sscanf() from ntdll will call strlen()
     * and read off the end of the mapped file if it doesn't hit a null.
     */
    if (dr_sscanf((char *)map + strlen(SYMCACHE_FILE_HEADER) + 1, "%d",
                  (uint *)&offs) != 1 ||
        /* neither forward nor backward compatible */
        offs != SYMCACHE_VERSION) {
        WARN("WARNING: symbol cache file has wrong version\n");
        goto symcache_read_symfile_done;
    }
    line = strchr((char *) map, '\n');
    if (line != NULL)
        line++;

    if (line != NULL) {
        /* Module consistency checks */
        uint cache_file_size;
        uint64 module_file_size;
        uint timestamp;
#ifdef WINDOWS
        version_number_t file_version;
        version_number_t product_version;
        uint checksum;
        size_t module_internal_size;
        if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING","UINT64_FORMAT_STRING","
                      UINT64_FORMAT_STRING",%u,%u,%lu",
                      &cache_file_size, &module_file_size, &file_version.version,
                      &product_version.version, &checksum, &timestamp,
                      &module_internal_size) != 7) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size ||
            file_version.version != modcache->file_version.version ||
            product_version.version != modcache->product_version.version ||
            checksum != modcache->checksum ||
            timestamp != modcache->timestamp ||
            module_internal_size != modcache->module_internal_size) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            LOG(2, "\t"UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                "%u vs %u, %u vs %u, %lu vs %lu\n",
                module_file_size, modcache->module_file_size,
                file_version.version, modcache->file_version.version,
                product_version.version, modcache->product_version.version,
                checksum, modcache->checksum,
                timestamp, modcache->timestamp,
                module_internal_size, modcache->module_internal_size);
            goto symcache_read_symfile_done;
        }
#elif defined(LINUX)
        if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING",%u",
                      &cache_file_size, &module_file_size, &timestamp) != 3) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size ||
            timestamp != modcache->timestamp) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            goto symcache_read_symfile_done;
        }
#elif defined(MACOS)
        uint current_version;
        uint compatibility_version;
        byte uuid[16];
        /* XXX: if dr_sscanf supported %n maybe we could split these into
         * separate scans on the same string and share code w/ Linux.
         */
        if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING",%u,%u,%u,%x,%x,%x,%x",
                      &cache_file_size, &module_file_size, &timestamp,
                      &current_version, &compatibility_version,
                      (uint*)(&uuid[0]), (uint*)(&uuid[4]),
                      (uint*)(&uuid[8]), (uint*)(&uuid[12])) != 9) {
            WARN("WARNING: %s symbol cache file has bad consistency header B\n", modname);
            goto symcache_read_symfile_done;
        }
        if (current_version != modcache->current_version ||
            compatibility_version != modcache->compatibility_version ||
            memcmp(uuid, modcache->uuid, sizeof(uuid)) != 0) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            goto symcache_read_symfile_done;
        }
#endif
        /* We could go further w/ CRC or even MD5 but not worth it for dev tool */
        if (cache_file_size != (uint)map_size) {
            WARN("WARNING: %s symbol cache file is corrupted: map=%d vs file=%d\n",
                 modname, (uint)map_size, cache_file_size);
            goto symcache_read_symfile_done;
        }
    }
    line = strchr(line, '\n');
    if (line != NULL)
        line++;
    if (line != NULL) {
        uint has_debug_info;
        if (dr_sscanf(line, "%u", &has_debug_info) != 1) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (has_debug_info) {
            /* We assume that the current availability of debug info doesn't matter */
            modcache->has_debug_info = true;
        } else {
            /* We delay the costly check for symbols until we've read the symcache
             * b/c if its entry indicates symbols we don't need to look
             */
            if (module_has_symbols(mod)) {
                LOG(1, "module now has debug info: %s symbol cache is stale\n", modname);
                goto symcache_read_symfile_done;
            }
        }
    }
    line = strchr(line, '\n');
    if (line != NULL)
        line++;

    symbol[0] = '\0';
    for (; line != NULL && line < ((char *)map) + map_size; line = next_line) {
        const char *comma = strchr(line, ',');
        const char *newline = strchr(line, '\n');
        size_t symlen = (comma != NULL ? comma - line : 0);
        if (newline == NULL) {
            next_line = ((char *)map) + map_size + 1; /* handle EOF w/o trailing \n */
        } else {
            next_line = newline + 1;
        }
        if (symlen > 0 && symlen < MAX_SYMLEN) {
            strncpy(symbol, line, symlen);
            symbol[symlen] = '\0';
        }
        if (comma != NULL && symlen < MAX_SYMLEN && symbol[0] != '\0' &&
            dr_sscanf(comma, ",0x%x", (uint *)&offs) == 1) {
#ifdef WINDOWS
            /* Guard against corrupted files that cause DrMem to crash (i#1465) */
            if (offs >= modcache->module_internal_size) {
                /* This one we want to know about */
                NOTIFY("SYMCACHE ERROR: %s file has too-large entry "PIFX" for %s"NL,
                       modname, offs, symbol);
                goto symcache_read_symfile_done;
            }
#endif
            symcache_symbol_add(modname, symtable, symbol, offs);
        } else {
            WARN("WARNING: malformed symbol cache line \"%.*s\"\n",
                 next_line - line - 1, line);
            /* We abort in case there were two dueling writes to the file
             * and it somehow got past the self-consistency check,
             * putting a header in the middle of the file, and we can't
             * trust subsequent lines since they may belong to a different
             * version of the module
             */
            break; /* res should still be true */
        }
    }
    res = true;
 symcache_read_symfile_done:
    if (map != NULL)
        dr_unmap_file(map, actual_size);
    if (f != INVALID_FILE)
        dr_close_file(f);
    if (!res)
        modcache->has_debug_info = module_has_symbols(mod);

    return res;
}
Exemplo n.º 2
0
/* file I/O */
void md_read_from_file (module_t * head, file_t file, bool extra_info){

	uint64 map_size;
	size_t actual_size;
	bool ok;
	void * map = NULL;
	char * line;

	/*loop variables*/
	int i;
	int j;

	/* linked list structure specific variables */
	int no_modules;
	int no_instructions;
	unsigned int addr;
	char module_name[MAX_STRING_LENGTH];

	/* for filling up the linked list data structure */
	module_t * elem;

	ok = dr_file_size(file,&map_size);
	if(ok){
		actual_size = (size_t)map_size;
		DR_ASSERT(actual_size == map_size);
		map = dr_map_file(file, &actual_size, 0, NULL, DR_MEMPROT_READ, 0);
	}


	dr_sscanf((char *)map,"%d\n",&no_modules);
	//dr_printf("%d\n",no_modules);  //debug

	line = (char *)map;
	for(i=0;i<no_modules;i++){

		line = strchr(line,'\n');
		line++; //start of the next line

		//dr_sscanf(line,"%[^\t\n]\n",module_name);
		dr_get_token(line,module_name,MAX_STRING_LENGTH);
		//getFinalName(module_name);


		//dr_printf("%s\n",module_name); //debug

		line = strchr(line,'\n');
		line++; //start of the next line
		dr_sscanf(line,"%d\n",&no_instructions);
		//dr_printf("%d\n",no_instructions);  //debug

		//create a new element
		elem = new_elem(module_name,no_instructions+2);
		head->next = elem;
		head = elem;

		for(j=0;j<no_instructions;j++){

			line = strchr(line,'\n');
			line++; //start of the next line
			dr_sscanf(line,"%u\n",&addr);
			//dr_printf(line,"%x\n",addr); //debug
			add_bb_to_list(head->bbs,addr, extra_info, head->size_bbs);
		}

	}

}
Exemplo n.º 3
0
drcovlib_status_t
drmodtrack_offline_read(file_t file, const char **map,
                        OUT void **handle, OUT uint *num_mods)
{
    module_read_info_t *info = NULL;
    uint i;
    uint64 file_size;
    size_t map_size = 0;
    const char *buf, *map_start;
    uint version;

    if (handle == NULL || num_mods == NULL)
        return DRCOVLIB_ERROR_INVALID_PARAMETER;
    if (file == INVALID_FILE) {
        if (map == NULL)
            return DRCOVLIB_ERROR_INVALID_PARAMETER;
        map_start = *map;
    } else {
        if (!dr_file_size(file, &file_size))
            return DRCOVLIB_ERROR_INVALID_PARAMETER;
        map_size = (size_t)file_size;
        map_start = (char *) dr_map_file(file, &map_size, 0, NULL, DR_MEMPROT_READ, 0);
        if (map_start == NULL || map_size < file_size)
            return DRCOVLIB_ERROR_INVALID_PARAMETER; /* assume bad perms or sthg */
    }
    if (map_start == NULL)
        return DRCOVLIB_ERROR_INVALID_PARAMETER;
    buf = map_start;

    /* Module table header, handling the pre-versioning legacy format. */
    if (dr_sscanf(buf, "Module Table: %u\n", num_mods) == 1)
        version = 1;
    else if (dr_sscanf(buf, "Module Table: version %u, count %u\n", &version,
                       num_mods) != 2 ||
             version != MODULE_FILE_VERSION)
        goto read_error;
    buf = move_to_next_line(buf);
    if (version > 1) {
        // Skip header line
        buf = move_to_next_line(buf);
    }

    info = (module_read_info_t *)dr_global_alloc(sizeof(*info));
    if (file != INVALID_FILE) {
        info->map = map_start;
        info->map_size = map_size;
    } else
        info->map = NULL;
    info->num_mods = *num_mods;
    info->mod = (module_read_entry_t *)dr_global_alloc(*num_mods * sizeof(*info->mod));

    /* module lists */
    for (i = 0; i < *num_mods; i++) {
        uint mod_id;
        if (version == 1) {
            if (dr_sscanf(buf, " %u, %" INT64_FORMAT"u, %[^\n\r]",
                          &mod_id, &info->mod[i].size, info->mod[i].path) != 3 ||
                mod_id != i)
                goto read_error;
        } else {
            app_pc end, entry;
#ifdef WINDOWS
            uint checksum, timestamp;
            if (dr_sscanf(buf, " %u, "PIFX", "PIFX", "PIFX", 0x%x, 0x%x, %[^\n\r]",
                          &mod_id, &info->mod[i].base, &end, &entry,
                          &checksum, &timestamp,
                          info->mod[i].path) != 7 ||
                mod_id != i)
                goto read_error;
#else
            if (dr_sscanf(buf, " %u, "PIFX", "PIFX", "PIFX", %[^\n\r]",
                          &mod_id, &info->mod[i].base, &end, &entry,
                          info->mod[i].path) != 5 ||
                mod_id != i)
                goto read_error;
#endif
            info->mod[i].size = end - info->mod[i].base;
        }
        buf = move_to_next_line(buf);
    }
    if (file == INVALID_FILE)
        *map = buf;
    *handle = (void *)info;
    return DRCOVLIB_SUCCESS;

 read_error:
    if (info != NULL) {
        dr_global_free(info->mod, *num_mods * sizeof(*info->mod));
        dr_global_free(info, sizeof(*info));
    }
    if (file != INVALID_FILE)
        dr_unmap_file((char *)map_start, map_size);
    return DRCOVLIB_ERROR;
}
Exemplo n.º 4
0
void
symcache_module_load(void *drcontext, const module_data_t *mod, bool loaded)
{
    /* look for cache file for this module.
     * fill in hashtable: key is string, value is list of offsets
     */
    mod_cache_t *modcache;
    const char *modname = dr_module_preferred_name(mod);
    file_t f;
    if (modname == NULL)
        return; /* don't support caching */

    /* if smaller than threshold, not worth caching */
    if (mod->end - mod->start < op_modsize_cache_threshold) {
        LOG(1, "%s: module %s too small to cache\n", __FUNCTION__, modname);
        return;
    }

    ASSERT(initialized, "symcache was not initialized");

    /* support initializing prior to module events => called twice */
    dr_mutex_lock(symcache_lock);
    modcache = (mod_cache_t *) hashtable_lookup(&symcache_table,
                                                (void *)mod->full_path);
    dr_mutex_unlock(symcache_lock);
    if (modcache != NULL)
        return;

    modcache = (mod_cache_t *) global_alloc(sizeof(*modcache), HEAPSTAT_HASHTABLE);
    memset(modcache, 0, sizeof(*modcache));
    hashtable_init_ex(&modcache->table, SYMCACHE_MODULE_TABLE_HASH_BITS,
                      HASH_STRING, true/*strdup*/, true/*synch*/,
                      symcache_free_list, NULL, NULL);

    /* store consistency fields */
    f = dr_open_file(mod->full_path, DR_FILE_READ);
    if (f != INVALID_FILE) {
        bool ok = dr_file_size(f, &modcache->module_file_size);
        if (!ok)
            WARN("WARNING: unable to determine size of %s\n", mod->full_path);
        dr_close_file(f);
    } else
        WARN("WARNING: unable to open %s\n", mod->full_path);
#ifdef WINDOWS
    modcache->file_version = mod->file_version;
    modcache->product_version = mod->product_version;
    modcache->checksum = mod->checksum;
    modcache->timestamp = mod->timestamp;
    modcache->module_internal_size = mod->module_internal_size;
#endif

    modcache->modname = drmem_strdup(modname, HEAPSTAT_HASHTABLE);
    modcache->from_file = symcache_read_symfile(mod, modname, modcache);

    dr_mutex_lock(symcache_lock);
    if (!hashtable_add(&symcache_table, (void *)mod->full_path, (void *)modcache)) {
        /* this should be really rare to have dup paths (xref i#729) -- and
         * actually we now have a lookup up above so we should only get here
         * on a race while we let go of the lock
         */
        WARN("WARNING: duplicate module paths: only caching symbols from first\n");
        hashtable_delete(&modcache->table);
        global_free(modcache, sizeof(*modcache), HEAPSTAT_HASHTABLE);
    }
    dr_mutex_unlock(symcache_lock);
}
Exemplo n.º 5
0
static bool
symcache_read_symfile(const module_data_t *mod, const char *modname, mod_cache_t *modcache)
{
    hashtable_t *symtable = &modcache->table;
    bool res = false;
    const char *line, *next_line;
    char symbol[MAX_SYMLEN];
    size_t offs;
    uint64 map_size;
    size_t actual_size;
    bool ok;
    void *map = NULL;
    char symfile[MAXIMUM_PATH];
    file_t f;

    symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile));
    f = dr_open_file(symfile, DR_FILE_READ);
    if (f == INVALID_FILE)
        return res;
    LOG(2, "processing symbol cache file for %s\n", modname);
    /* we avoid having to do our own buffering by just mapping the whole file */
    ok = dr_file_size(f, &map_size);
    if (ok) {
        actual_size = (size_t) map_size;
        ASSERT(actual_size == map_size, "file size too large");
        map = dr_map_file(f, &actual_size, 0, NULL, DR_MEMPROT_READ, 0);
    }
    if (!ok || map == NULL || actual_size < map_size) {
        NOTIFY_ERROR("Error mapping symcache file for %s"NL, modname);
        goto symcache_read_symfile_done;
    }
    if (strncmp((char *)map, SYMCACHE_FILE_HEADER, strlen(SYMCACHE_FILE_HEADER)) != 0) {
        WARN("WARNING: symbol cache file is corrupted\n");
        goto symcache_read_symfile_done;
    }
    if (sscanf((char *)map + strlen(SYMCACHE_FILE_HEADER) + 1, "%d", &offs) != 1 ||
        /* neither forward nor backward compatible */
        offs != SYMCACHE_VERSION) {
        WARN("WARNING: symbol cache file has wrong version\n");
        goto symcache_read_symfile_done;
    }
    line = strchr((char *) map, '\n');
    if (line != NULL)
        line++;

    if (line != NULL) {
        /* Module consistency checks */
        uint cache_file_size;
        uint64 module_file_size;
#ifdef WINDOWS
        version_number_t file_version;
        version_number_t product_version;
        uint checksum;
        uint timestamp;
        size_t module_internal_size;
        if (sscanf(line, " %u,"UINT64_FORMAT_STRING","UINT64_FORMAT_STRING","
                   UINT64_FORMAT_STRING",%u,%u,%lu",
                   &cache_file_size, &module_file_size, &file_version.version,
                   &product_version.version, &checksum, &timestamp,
                   &module_internal_size) != 7) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size ||
            file_version.version != modcache->file_version.version ||
            product_version.version != modcache->product_version.version ||
            checksum != modcache->checksum ||
            timestamp != modcache->timestamp ||
            module_internal_size != modcache->module_internal_size) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            LOG(2, "\t"UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                "%u vs %u, %u vs %u, %lu vs %lu\n",
                module_file_size, modcache->module_file_size,
                file_version.version, modcache->file_version.version,
                product_version.version, modcache->product_version.version,
                checksum, modcache->checksum,
                timestamp, modcache->timestamp,
                module_internal_size, modcache->module_internal_size);
            goto symcache_read_symfile_done;
        }
#else
        if (sscanf(line, "%u,"UINT64_FORMAT_STRING,
                   &cache_file_size, &module_file_size) != 2) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            goto symcache_read_symfile_done;
        }
#endif
        /* We could go further w/ CRC or even MD5 but not worth it for dev tool */
        if (cache_file_size != (uint)map_size) {
            WARN("WARNING: %s symbol cache file is corrupted\n", modname);
            goto symcache_read_symfile_done;
        }
    }
    line = strchr(line, '\n');
    if (line != NULL)
        line++;

    symbol[0] = '\0';
    for (; line != NULL && line < ((char *)map) + map_size; line = next_line) {
        const char *newline = strchr(line, '\n');
        if (newline == NULL) {
            next_line = ((char *)map) + map_size + 1; /* handle EOF w/o trailing \n */
        } else {
            next_line = newline + 1;
        }
        if (sscanf(line, "%"MAX_SYMLEN_MINUS_1_STR"[^,],0x%x", symbol, &offs) == 2) {
            symcache_symbol_add(modname, symtable, symbol, offs);
        } else if (symbol[0] != '\0' && sscanf(line, ",0x%x", &offs) == 1) {
            /* duplicate entries are allowed to not list the symbol, to save
             * space in the file (mainly for post-call caching i#669)
             */
            symcache_symbol_add(modname, symtable, symbol, offs);
        } else {
            WARN("WARNING: malformed symbol cache line \"%.*s\"\n",
                 next_line - line - 1, line);
            /* We abort in case there were two dueling writes to the file
             * and it somehow got past the self-consistency check,
             * putting a header in the middle of the file, and we can't
             * trust subsequent lines since they may belong to a different
             * version of the module
             */
            break; /* res should still be true */
        }
    }
    res = true;
 symcache_read_symfile_done:
    if (map != NULL)
        dr_unmap_file(map, actual_size);
    if (f != INVALID_FILE)
        dr_close_file(f);
    return res;
}