예제 #1
0
/*
 * Find/create a class file node in the VM's class file table.
 *
 * If the class already exists, the hash must be the same, otherwise
 * a LinkageError is stored. Bump the reference count on the existing node.
 *
 * If no class by this name exists, add a new node with reference count 1.
 *
 * 'cbytes' should be NULL unless object generation is enabled and the
 * classfile was loaded by a user-defined class loader. If successful,
 * it will be copied to any newly created node.
 *
 * Stores an exception if unsuccessful.
 *
 * NOTE: This assumes the VM global mutex is locked.
 */
_jc_class_node *
_jc_ref_class_node(_jc_env *env, const char *name,
	jlong hash, _jc_classbytes *cbytes)
{
	_jc_jvm *const vm = env->vm;
	_jc_class_node *node;
	_jc_class_node key;
	size_t nlen;

	/* Sanity check */
	_JC_MUTEX_ASSERT(env, vm->mutex);
	_JC_ASSERT(cbytes == NULL || cbytes->hash == hash);

	/* If code generation is disabled, don't save the class file bytes */
	if (!vm->generation_enabled)
		cbytes = NULL;

	/* Search for existing node */
	key.name = name;
	if ((node = _jc_splay_find(&vm->classfiles, &key)) != NULL) {

		/* Hash values must be the same */
		if (hash != node->hash) {
			_JC_EX_STORE(env, LinkageError, "class file for `%s'"
			    " has an unexpected hash value 0x%" _JC_JLONG_FMT
			    " != 0x%" _JC_JLONG_FMT, name, hash, node->hash);
			return NULL;
		}

		/* Save class file if we don't have it yet */
		if (cbytes != NULL && node->bytes == NULL)
			node->bytes = _jc_dup_classbytes(cbytes);

		/* Increment node reference count */
		node->refs++;

		/* Return node */
		return node;
	}

	/* Create a new class file node */
	nlen = strlen(name);
	if ((node = _jc_vm_alloc(env, sizeof(*node) + nlen + 1)) == NULL)
		return NULL;
	memcpy(node + 1, name, nlen + 1);
	node->name = (char *)(node + 1);
	node->hash = hash;
	node->refs = 1;
	node->bytes = cbytes != NULL ? _jc_dup_classbytes(cbytes) : NULL;

	/* Add node to our classfile tree */
#ifndef NDEBUG
	memset(&node->node, 0, sizeof(node->node));
#endif
	_jc_splay_insert(&vm->classfiles, node);

	/* Done */
	return node;
}
예제 #2
0
void *
_jc_vm_realloc(_jc_env *env, void *mem, size_t size)
{
	void *new_mem;

	if ((new_mem = realloc(mem, size)) == NULL) {
		_JC_EX_STORE(env, OutOfMemoryError, "system heap");
		return NULL;
	}
	return new_mem;
}
예제 #3
0
void *
_jc_vm_alloc(_jc_env *env, size_t size)
{
	void *mem;

	if ((mem = malloc(size)) == NULL) {
		_JC_EX_STORE(env, OutOfMemoryError, "system heap");
		return NULL;
	}
	return mem;
}
예제 #4
0
char *
_jc_vm_strdup(_jc_env *env, const char *s)
{
	char *result;

	if ((result = strdup(s)) == NULL) {
		_JC_EX_STORE(env, OutOfMemoryError, "system heap");
		return NULL;
	}
	return result;
}
예제 #5
0
char *
_jc_vm_strndup(_jc_env *env, const char *s, size_t len)
{
	char *result;

	if ((result = malloc(len + 1)) == NULL) {
		_JC_EX_STORE(env, OutOfMemoryError, "system heap");
		return NULL;
	}
	memcpy(result, s, len);
	result[len] = '\0';
	return result;
}
예제 #6
0
파일: mutex.c 프로젝트: archiecobbs/jcvm
/*
 * Initialize a condition variable.
 *
 * If unsuccessful an exception is stored.
 */
jint
_jc_cond_init(_jc_env *env, pthread_cond_t *cond)
{
	int error;

	/* Initialize mutex attributes */
	if ((error = pthread_cond_init(cond, NULL)) != 0) {
		_JC_EX_STORE(env, InternalError,
		    "%s: %s", "pthread_cond_init", strerror(error));
		return JNI_ERR;
	}

	/* Done */
	return JNI_OK;
}
예제 #7
0
파일: mutex.c 프로젝트: archiecobbs/jcvm
/*
 * Initialize a mutex
 *
 * If unsuccessful an exception is stored.
 */
jint
_jc_mutex_init(_jc_env *env, pthread_mutex_t *mutex)
{
	pthread_mutexattr_t attr;
	int error;

	/* Initialize mutex attributes */
	if ((error = pthread_mutexattr_init(&attr)) != 0) {
		_JC_EX_STORE(env, InternalError,
		    "%s: %s", "pthread_mutexattr_init", strerror(error));
		return JNI_ERR;
	}

#if NDEBUG
	/* Enable debug checks */
	if ((error = pthread_mutexattr_settype(&attr,
	    PTHREAD_MUTEX_ERRORCHECK)) != 0) {
		_JC_EX_STORE(env, InternalError,
		    "%s: %s", "pthread_mutexattr_settype", strerror(error));
		pthread_mutexattr_destroy(&attr);
		return JNI_ERR;
	}
#endif

	/* Initialize mutex */
	if ((error = pthread_mutex_init(mutex, &attr)) != 0) {
		_JC_EX_STORE(env, InternalError,
		    "%s: %s", "pthread_mutex_init", strerror(error));
		pthread_mutexattr_destroy(&attr);
		return JNI_ERR;
	}

	/* Clean up */
	pthread_mutexattr_destroy(&attr);
	return JNI_OK;
}
예제 #8
0
파일: elf.c 프로젝트: archiecobbs/jcvm
/*
 * Resolve a symbol in an ELF object. There are two cases here.
 *
 * If 'resolver' is NULL, only symbols resolvable internally are
 * resolved, and exceptions are stored, not posted. Otherwise,
 * only symbols resolvable externally are resolved, 'resolver' is
 * used to resolve them, and exceptions are posted.
 */
static inline jint
_jc_elf_resolve_sym(_jc_env *env, _jc_elf *elf, _jc_elf_loadable *loadable,
	const Elf_Rela *rela, _jc_elf_resolver *resolver, void *arg)
{
	const Elf_Word type = ELF_R_TYPE(rela->r_info);
	_jc_elf_info *const info = elf->info;
	const Elf_Sym *const sym = &info->symbols[ELF_R_SYM(rela->r_info)];
	const char *name = info->strings + sym->st_name;

	switch (sym->st_shndx) {
	case SHN_ABS:
		if (resolver != NULL)
			break;
		if (_jc_elf_arch_reloc(env, elf->pathname,
		    loadable->vaddr, rela->r_offset, type,
		    sym->st_value, rela->r_addend) != JNI_OK)
			return JNI_ERR;
		break;
	case SHN_UNDEF:
	    {
		Elf_Addr value;

		if (resolver == NULL)
			break;
		if ((*resolver)(env, arg,
		    info->strings + sym->st_name, &value) != JNI_OK)
			return JNI_ERR;
		if (_jc_elf_arch_reloc(env, elf->pathname, loadable->vaddr,
		    rela->r_offset, type, value, rela->r_addend) != JNI_OK) {
			_jc_post_exception_info(env);
			return JNI_ERR;
		}
		break;
	    }
	case SHN_COMMON:
		_JC_ASSERT(resolver == NULL);
		_JC_EX_STORE(env, LinkageError,
		    "%s: ELF symbol `%s' is common (not supported)",
		    elf->pathname, name);
		return JNI_ERR;
	default:
	    {
		const _jc_elf_loadable *sym_section;

		/* Skip if only resolving externals */
		if (resolver != NULL)
			break;

		/* Sanity check the symbol's section */
		if (sym->st_shndx >= info->ehdr->e_shnum
		    || (sym_section
		      = info->shdr2section[sym->st_shndx]) == NULL) {
			_JC_EX_STORE(env, LinkageError,
			    "%s: invalid section index %d for symbol `%s'",
			    elf->pathname, sym->st_shndx, name);
			return JNI_ERR;
		}

		/* Apply relocation */
		if (_jc_elf_arch_reloc(env, elf->pathname,
		    loadable->vaddr, rela->r_offset, type,
		    (Elf_Addr)(sym_section->vaddr + sym->st_value),
		    rela->r_addend) != JNI_OK)
			return JNI_ERR;
		break;
	    }
	}

	/* Done */
	return JNI_OK;
}
예제 #9
0
/*
 * Process stabs line number information.
 *
 * If unsuccessful an exception is stored.
 */
jint
_jc_debug_line_stabs(_jc_env *env, _jc_elf *elf, _jc_splay_tree *tree)
{
	_jc_elf_info *const info = elf->info;
	const Elf_Shdr *const shdr = info->debug_lines.loadable.shdr;
	_jc_stab *const stabs = (_jc_stab *)(info->map_base + shdr->sh_offset);
	const int num_stabs = shdr->sh_size / sizeof(*stabs);
	_jc_map_state state;
	_jc_method *method;
	int i;

	/* Sanity check */
	_JC_ASSERT(info->debug_lines.type == _JC_LINE_DEBUG_STABS);

	/* Initialize state */
	memset(&state, 0, sizeof(state));
	method = NULL;

	/* Run through stabs section */
	for (i = 0; i < num_stabs; i++) {
		_jc_stab *const stab = &stabs[i];

		/* Check type */
		switch (stab->type) {
		case STAB_FUN:
		    {
			_jc_method_node *node;
			_jc_method_node key;
			const char *fun;
			const char *s;

			/* Check for end of method; reset state if so */
			if (stab->sindex == 0) {

				/* Were we skipping this method? */
				if (method == NULL)
					continue;

				/* Finalize map */
				if (_jc_debug_line_finish(env,
				    method, elf->loader, &state) != JNI_OK)
					goto fail;
				method = NULL;
				break;
			}

			/* Already doing this function? */
			if (method != NULL)
				continue;

			/* Get FUN string containing function name */
			fun = (const char *)info->debug_lines.strings
			    + stab->sindex;

			/* Sanity check not already within a method */
			if (method != NULL) {
				_JC_EX_STORE(env, LinkageError,
				    "double opening stabs FUN entry `%s'", fun);
				goto fail;
			}

			/* Try to parse out class & method name from symbol */
			if (strncmp(fun, "_jc_", 4) != 0
			    || (s = strchr(fun + 4, '$')) == NULL
			    || strncmp(s + 1, "method$", 7) != 0)
				continue;
			key.cname = fun + 4;
			key.clen = s - key.cname;
			key.mname = s + 8;
			if ((s = strchr(key.mname, ':')) == NULL)
				s += strlen(s);		/* can this happen? */
			key.mlen = s - key.mname;

			/* Find corresponding method node, if any */
			if ((node = _jc_splay_find(tree, &key)) == NULL)
				continue;
			method = node->method;
			_JC_ASSERT(method != NULL);
			_JC_ASSERT(method->function != NULL);
			_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
			_JC_ASSERT(method->u.exec.function_end != NULL);

			/* If method has no line number table, nothing to do */
			if (method->u.exec.u.linenum.len == 0) {
				memset(&method->u.exec.u,
				    0, sizeof(method->u.exec.u));
				method = NULL;
				continue;
			}

			/* Initialize state for this method */
			_JC_ASSERT(state.pc_map.len == 0);
			_JC_ASSERT(state.last_linenum == 0);
			_JC_ASSERT(state.last_map == 0);
			state.linenum = method->u.exec.u.linenum;
			memset(&method->u.exec.u, 0, sizeof(method->u.exec.u));
			break;
		    }
		case STAB_SLINE:

			/* If skipping this method, skip lines */
			if (method == NULL)
				continue;

			/* Add entry */
			if (_jc_debug_line_add(env, &state,
			    (const char *)method->function + stab->value,
			    stab->desc) != JNI_OK)
				goto fail;
			break;
		default:
			break;
		}
	}

	/* Clean up and exit */
	_jc_vm_free(&state.pc_map.map);
	return JNI_OK;

fail:
	/* Clean up after failure */
	_jc_vm_free(&state.pc_map.map);
	return JNI_ERR;
}
예제 #10
0
/*
 * Process DWARF2 line number information.
 *
 * If unsuccessful an exception is stored.
 */
jint
_jc_debug_line_dwarf2(_jc_env *env, _jc_elf *elf, _jc_splay_tree *tree)
{
	_jc_elf_info *const info = elf->info;
	const Elf_Shdr *const shdr = info->debug_lines.loadable.shdr;
	const u_char *ptr = (const u_char *)info->map_base + shdr->sh_offset;
	const u_char *const section_end = ptr + shdr->sh_size;
	jboolean using64bit = JNI_FALSE;
	_jc_dwarf2_line_hdr *hdr;
	_jc_method_node **nodes;
	_jc_map_state state;
	_jc_method *method;
	unsigned long totlen;
	union _jc_value jvalue;
	int node_index;
	const u_char *ptr_end;
	const u_char *pc;
	int num_nodes;
	int cline;
	int i;

	/* Put nodes in a list and elide methods with no line number table */
	if ((nodes = _JC_STACK_ALLOC(env,
	    tree->size * sizeof(*nodes))) == NULL)
		goto fail;
	_jc_splay_list(tree, (void **)nodes);
	for (i = num_nodes = 0; i < tree->size; i++) {
		_jc_method_node *const node = nodes[i];
		_jc_method *const method = node->method;

		_JC_ASSERT(method != NULL);
		_JC_ASSERT(method->function != NULL);
		_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
		_JC_ASSERT(method->u.exec.function_end != NULL);
		if (method->u.exec.u.linenum.len > 0)
			nodes[num_nodes++] = nodes[i];
	}

	/* Anything to do? */
	if (num_nodes == 0)
		return JNI_OK;

	/* Sort methods by starting address */
	qsort(nodes, num_nodes, sizeof(*nodes), _jc_method_addr_cmp);

	/* Initialize map state */
	memset(&state, 0, sizeof(state));
	node_index = 0;
	method = NULL;

again:
	/* Read prologue header */
	memcpy(&jvalue, ptr, sizeof(jint));
	ptr += sizeof(jint);
	totlen = jvalue.i;
	if (totlen == 0xffffffff) {
		memcpy(&jvalue, ptr, sizeof(jlong));
		ptr += sizeof(jlong);
		totlen = jvalue.j;
		using64bit = JNI_TRUE;
	} else if (totlen == 0) {
		memcpy(&jvalue, ptr, sizeof(jint));
		ptr += sizeof(jint);
		totlen = jvalue.i;
		using64bit = JNI_TRUE;
	}
	ptr_end = ptr + totlen;
	ptr += 2;					/* skip version */
	ptr += 4;					/* skip header len */
	if (using64bit)
		ptr += 4;
	hdr = (_jc_dwarf2_line_hdr *)ptr;
	ptr += sizeof(*hdr) + hdr->opcode_base - 1;

	/* Skip over directory table */
	while (*ptr++ != '\0')
		ptr += strlen((const char *)ptr) + 1;

	/* Skip over file name table */
	while (*ptr++ != '\0') {
		ptr += strlen((const char *)ptr) + 1;
		(void)_jc_read_leb128(&ptr, JNI_FALSE);
		(void)_jc_read_leb128(&ptr, JNI_FALSE);
		(void)_jc_read_leb128(&ptr, JNI_FALSE);
	}

	/* Initialize statement program state */
	pc = NULL;
	cline = 1;

	/* Process statement program */
	while (ptr < ptr_end) {
		jboolean writeout = JNI_FALSE;
		jboolean reset = JNI_FALSE;
		u_char opcode;

		if ((opcode = *ptr++) >= hdr->opcode_base) {	/* special */
			opcode -= hdr->opcode_base;
			pc += (opcode / hdr->line_range)
			    * hdr->minimum_instruction_length;
			cline += hdr->line_base + opcode % hdr->line_range;
			writeout = JNI_TRUE;
		} else if (opcode == 0) {			/* extended */
			unsigned int oplen;
			u_char exop;

			oplen = _jc_read_leb128(&ptr, JNI_FALSE);
			exop = *ptr++;
			switch (exop) {
			case DW_LNE_end_sequence:
				reset = JNI_TRUE;
				writeout = JNI_TRUE;
				break;
			case DW_LNE_set_address:
			    {
				const u_char *new_pc;

				/* Get new PC */
				memcpy(&new_pc, ptr, sizeof(new_pc));

				/* We don't support out-of-spec reversals */
				if (new_pc < pc) {
					_JC_EX_STORE(env, LinkageError,
					    "address reversals in .debug_line"
					    " section are not supported");
					goto fail;
				}

				/* OK */
				pc = new_pc;
				break;
			    }
			default:
				break;
			}
			ptr += oplen - 1;
		} else {					/* standard */
			switch (opcode) {
			case DW_LNS_copy:
				writeout = JNI_TRUE;
				break;
			case DW_LNS_advance_pc:
				pc += _jc_read_leb128(&ptr, JNI_FALSE)
				    * hdr->minimum_instruction_length;
				break;
			case DW_LNS_advance_line:
				cline += _jc_read_leb128(&ptr, JNI_TRUE);
				break;
			case DW_LNS_const_add_pc:
				pc += ((255 - hdr->opcode_base)
				      / hdr->line_range)
				    * hdr->minimum_instruction_length;
				break;
			case DW_LNS_fixed_advance_pc:
			    {
				uint16_t advance;

				memcpy(&advance, ptr, 2);
				pc += advance;
				ptr += 2;
				break;
			    }
			default:
				for (i = 0; i < hdr->standard_opcode_lengths[
				    opcode - 1]; i++)
					_jc_read_leb128(&ptr, JNI_FALSE);
				break;
			}
		}

		/* Have we reached the next method? */
		if (method == NULL
		    && (const void *)pc
		      >= nodes[node_index]->method->function) {

			/* Initialize state for this method */
			_JC_ASSERT(state.pc_map.len == 0);
			_JC_ASSERT(state.last_linenum == 0);
			_JC_ASSERT(state.last_map == 0);
			method = nodes[node_index]->method;
			_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
			state.linenum = method->u.exec.u.linenum;
			memset(&method->u.exec.u, 0, sizeof(method->u.exec.u));
		}

		/* Finished with the current method? */
		if (method != NULL
		    && (const void *)pc >= method->u.exec.function_end) {

			/* Finalize map for current method */
			if (_jc_debug_line_finish(env,
			    method, elf->loader, &state) != JNI_OK)
				goto fail;
			method = NULL;

			/* Look for next method */
			if (++node_index == num_nodes)
				goto done;
		}

		/* Write matrix row */
		if (writeout && method != NULL) {
			if (_jc_debug_line_add(env,
			    &state, pc, cline) != JNI_OK)
				goto fail;
		}

		/* Reset after DW_LNE_end_sequence */
		if (reset) {
			pc = NULL;
			cline = 1;
		}
	}
	if (ptr < section_end)
		goto again;

done:
	/* Sanity check */
	_JC_ASSERT(method == NULL);
#ifndef NDEBUG
	for (i = 0; i < num_nodes; i++) {
		_jc_method_node *const node = nodes[i];
		_jc_method *const method = node->method;

		_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
		_JC_ASSERT(method->u.exec.u.pc_map.map != NULL);
	}
#endif

	/* Done */
	return JNI_OK;

fail:
	/* Failed */
	return JNI_ERR;
}