/* 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; }
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; } }
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; }
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 {
/* 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; }