Exemple #1
0
/* New interface. Returns malloced strings through output parameters,
 * which caller must free result strings if returnval is true */
bool symtable_lookup(unsigned int eip, char **func, char **file, int *line)
{
	conf_object_t *table = get_symtable();
	if (table == NULL) {
		return false;
	}

	attr_value_t idx = SIM_make_attr_integer(eip);
	attr_value_t result = SIM_get_attribute_idx(table, "source_at", &idx);
	if (!SIM_attr_is_list(result)) {
		SIM_free_attribute(idx);
		return false;
	}
	assert(SIM_attr_list_size(result) >= 3);

	/* Copy out the function name and line number. However, need to
	 * do some checks on the filename before copying it out as well. */
	if (testing_userspace() && eip == GUEST_CONTEXT_SWITCH_ENTER) {
		*func = MM_XSTRDUP("[context switch]");
#ifdef GUEST_HLT_EXIT
	} else if (testing_userspace() && eip == GUEST_HLT_EXIT) {
		*func = MM_XSTRDUP("[kernel idle]");
#endif
	} else {
		*func = MM_XSTRDUP(SIM_attr_string(SIM_attr_list_item(result, 2)));
	}
	const char *maybe_file = SIM_attr_string(SIM_attr_list_item(result, 0));
	*line = SIM_attr_integer(SIM_attr_list_item(result, 1));

	/* A hack to make the filenames shorter */
	if (strstr(maybe_file, LIKELY_DIR) != NULL) {
		maybe_file = strstr(maybe_file, LIKELY_DIR) + strlen(LIKELY_DIR);
	}

	/* The symbol table will claim that unknown assembly comes from
	 * 410kern/boot/head.S. Print an 'unknown' message instead. */
	if (strncmp(maybe_file, UNKNOWN_FILE, strlen(maybe_file)) == 0) {
		*file = NULL;
	} else {
		*file = MM_XSTRDUP(maybe_file);
	}

	SIM_free_attribute(result);
	SIM_free_attribute(idx);
	return true;
}
Exemple #2
0
static set_error_t set_ls_cmd_file_attribute(
	void *arg, conf_object_t *obj, attr_value_t *val, attr_value_t *idx)
{
	struct ls_state *ls = (struct ls_state *)obj;
	if (ls->cmd_file == NULL) {
		ls->cmd_file = MM_XSTRDUP(SIM_attr_string(*val));
		return Sim_Set_Ok;
	} else {
		return Sim_Set_Not_Writable;
	}
}
Exemple #3
0
bool cause_test(conf_object_t *kbd, struct test_state *t, struct ls_state *ls,
		const char *test_string)
{
	if (t->test_is_running || t->current_test) {
		lsprintf(INFO, "can't run \"%s\" with another test running\n",
			 test_string);
		return false;
	}

	/* save the test string */
	t->current_test = MM_XSTRDUP(test_string);

	/* feed input */
	for (int i = 0; i < strlen(test_string); i++) {
		cause_keypress(kbd, test_string[i]);
	}
	if (test_string[strlen(test_string)-1] != '\n') {
		cause_keypress(kbd, '\n');
		lsprintf(BRANCH, "caused test %s\n", test_string);
	} else {
		lsprintf(BRANCH, "caused test %s", test_string);
	}

	t->test_ever_caused = true;

	/* Record how many people are alive at the start of the test */
	if (ls->sched.num_agents != ls->sched.most_agents_ever) {
	       lsprintf(BUG, "WARNING: somebody died before test started!\n");
	       ls->sched.most_agents_ever = ls->sched.num_agents;
	}
	t->start_population = ls->sched.num_agents;

	/* Record the size of the heap at the start of the test */
	t->start_heap_size = ls->mem.heap_size;

	return true;
}
Exemple #4
0
void pps_init(struct pp_config *p)
{
	p->dynamic_pps_loaded = false;
	ARRAY_LIST_INIT(&p->kern_withins, 16);
	ARRAY_LIST_INIT(&p->user_withins, 16);
	ARRAY_LIST_INIT(&p->data_races,   16);
	p->output_pipe_filename = NULL;
	p->input_pipe_filename  = NULL;

	/* Load PPs from static config (e.g. if not running under quicksand) */

	static const unsigned int kfuncs[][3] = KERN_WITHIN_FUNCTIONS;
	for (int i = 0; i < ARRAY_SIZE(kfuncs); i++) {
		struct pp_within pp = { .func_start = kfuncs[i][0],
		                        .func_end   = kfuncs[i][1],
		                        .within     = (kfuncs[i][2] != 0) };
		ARRAY_LIST_APPEND(&p->kern_withins, pp);
	}

	static const unsigned int ufuncs[][3] = USER_WITHIN_FUNCTIONS;
	for (int i = 0; i < ARRAY_SIZE(ufuncs); i++) {
		struct pp_within pp = { .func_start = ufuncs[i][0],
		                        .func_end   = ufuncs[i][1],
		                        .within     = (ufuncs[i][2] != 0) };
		ARRAY_LIST_APPEND(&p->user_withins, pp);
	}

	/* [i][0] is instruction pointer of the data race;
	 * [i][1] is the current TID when the race was observed;
	 * [i][2] is the last_call'ing eip value, if any;
	 * [i][3] is the most_recent_syscall when the race was observed. */
	static const unsigned int drs[][4] = DATA_RACE_INFO;
	for (int i = 0; i < ARRAY_SIZE(drs); i++) {
		struct pp_data_race pp = { .addr                = drs[i][0],
		                           .tid                 = drs[i][1],
		                           .last_call           = drs[i][2],
		                           .most_recent_syscall = drs[i][3] };
		ARRAY_LIST_APPEND(&p->data_races, pp);
#ifdef PREEMPT_EVERYWHERE
		assert(0 && "DR PPs incompatible with preempt-everywhere mode.");
#endif
	}
}

bool load_dynamic_pps(struct ls_state *ls, const char *filename)
{
	struct pp_config *p = &ls->pps;
	if (p->dynamic_pps_loaded) {
		return false;
	}

	lsprintf(DEV, "using dynamic PPs from %s\n", filename);
	FILE *pp_file = fopen(filename, "r");
	assert(pp_file != NULL && "failed open pp file");
	char buf[BUF_SIZE];
	while (fgets(buf, BUF_SIZE, pp_file) != NULL) {
		unsigned int x, y, z, w;
		int ret;
		if (buf[strlen(buf) - 1] == '\n') {
			buf[strlen(buf) - 1] = 0;
		}
		if (buf[0] == 'O') { /* capital letter o, not numeral 0 */
			/* expect filename to start immediately after a space */
			assert(buf[1] == ' ');
			assert(buf[2] != ' ' && buf[2] != '\0');
			assert(p->output_pipe_filename == NULL);
			p->output_pipe_filename = MM_XSTRDUP(buf + 2);
			lsprintf(DEV, "output %s\n", p->output_pipe_filename);
		} else if (buf[0] == 'I') {
			/* expect filename to start immediately after a space */
			assert(buf[1] == ' ');
			assert(buf[2] != ' ' && buf[2] != '\0');
			assert(p->input_pipe_filename == NULL);
			p->input_pipe_filename = MM_XSTRDUP(buf + 2);
			lsprintf(DEV, "input %s\n", p->input_pipe_filename);
		} else if ((ret = sscanf(buf, "K %x %x %i", &x, &y, &z)) != 0) {
			/* kernel within function directive */
			assert(ret == 3 && "invalid kernel within PP");
			lsprintf(DEV, "new PP: kernel %x %x %x\n", x, y, z);
			struct pp_within pp = { .func_start = x, .func_end = y,
			                        .within = (z != 0) };
			ARRAY_LIST_APPEND(&p->kern_withins, pp);
		} else if ((ret = sscanf(buf, "U %x %x %i", &x, &y, &z)) != 0) {
			/* user within function directive */
			assert(ret == 3 && "invalid user within PP");
			lsprintf(DEV, "new PP: user %x %x %x\n", x, y, z);
			struct pp_within pp = { .func_start = x, .func_end = y,
			                        .within = (z != 0) };
			ARRAY_LIST_APPEND(&p->user_withins, pp);
		} else if ((ret = sscanf(buf, "DR %x %i %i %i", &x, &y, &z, &w)) != 0) {
			/* data race preemption poince */
			assert(ret == 4 && "invalid data race PP");
			lsprintf(DEV, "new PP: dr %x %x %x %x\n", x, y, z, w);
			struct pp_data_race pp =
				{ .addr = x, .tid = y, .last_call = z,
				  .most_recent_syscall = w };
			ARRAY_LIST_APPEND(&p->data_races, pp);
#ifdef PREEMPT_EVERYWHERE
			assert(0 && "DR PPs incompatible with preempt-everywhere mode.");
#endif
		} else {
Exemple #5
0
/* Caller has to free the return value. */
char *stack_trace(conf_object_t *cpu, int eip, int tid)
{
	char *buf = MM_XMALLOC(MAX_TRACE_LEN, char);
	int pos = 0, old_pos;
	int stack_offset = 0; /* Counts by 1 - READ_STACK already multiplies */

	ADD_STR(buf, pos, MAX_TRACE_LEN, "TID%d at 0x%.8x in ", tid, eip);
	ADD_FRAME(buf, pos, MAX_TRACE_LEN, eip);

	int stop_ebp = 0;
	int ebp = GET_CPU_ATTR(cpu, ebp);
	int rabbit = ebp;
	int frame_count = 0;

	while (ebp != 0 && (unsigned)ebp < USER_MEM_START && frame_count++ < 1024) {
		bool extra_frame;

		do {
			int eip_offset;
			bool iret_block = false;

			extra_frame = false;
			/* at the beginning or end of a function, there is no
			 * frame, but a return address is still on the stack. */
			if (function_eip_offset(eip, &eip_offset)) {
				if (eip_offset == 0) {
					extra_frame = true;
				} else if (eip_offset == 1 &&
				           READ_BYTE(cpu, eip - 1)
				           == OPCODE_PUSH_EBP) {
					stack_offset++;
					extra_frame = true;
				}
			}
			if (!extra_frame) {
				int opcode = READ_BYTE(cpu, eip);
				if (opcode == OPCODE_RET) {
					extra_frame = true;
				} else if (opcode == OPCODE_IRET) {
					iret_block = true;
					extra_frame = true;
				}
			}
			if (extra_frame) {
				eip = READ_STACK(cpu, stack_offset);
				ADD_STR(buf, pos, MAX_TRACE_LEN, "%s0x%.8x in ",
					STACK_TRACE_SEPARATOR, eip);
				ADD_FRAME(buf, pos, MAX_TRACE_LEN, eip);
				if (iret_block)
					stack_offset += IRET_BLOCK_WORDS;
				else
					stack_offset++;;
			}
		} while (extra_frame);

		/* pushed return address behind the base pointer */
		eip = READ_MEMORY(cpu, ebp + WORD_SIZE);
		stack_offset = ebp + 2;
		ADD_STR(buf, pos, MAX_TRACE_LEN, "%s0x%.8x in ",
			STACK_TRACE_SEPARATOR, eip);
		old_pos = pos;
		ADD_FRAME(buf, pos, MAX_TRACE_LEN, eip);
		/* special-case termination condition */
		if (pos - old_pos >= strlen(ENTRY_POINT) &&
		    strncmp(buf + old_pos, ENTRY_POINT,
		            strlen(ENTRY_POINT)) == 0) {
			break;
		}

		if (rabbit != stop_ebp) rabbit = READ_MEMORY(cpu, ebp);
		if (rabbit == ebp) stop_ebp = ebp;
		if (rabbit != stop_ebp) rabbit = READ_MEMORY(cpu, ebp);
		if (rabbit == ebp) stop_ebp = ebp;
		ebp = READ_MEMORY(cpu, ebp);
	}

	char *buf2 = MM_XSTRDUP(buf); /* truncate to save space */
	MM_FREE(buf);

	return buf2;
}