MR_bool MR_trace_remove_alias(const char *name) { MR_bool found; int slot; int i; int count; MR_bsearch(MR_alias_record_next, slot, found, strcmp(MR_alias_records[slot].MR_alias_name, name)); if (! found) { return MR_FALSE; } else { count = MR_alias_records[slot].MR_alias_word_count; for (i = 0; i < count; i++) { MR_free(MR_alias_records[slot].MR_alias_words[i]); } MR_free(MR_alias_records[slot].MR_alias_name); MR_free(MR_alias_records[slot].MR_alias_words); for (i = slot; i < MR_alias_record_next - 1; i++) { MR_assign_structure(MR_alias_records[slot], MR_alias_records[slot + 1]); } MR_alias_record_next--; return MR_TRUE; } }
void MR_trace_add_alias(char *name, char **words, int word_count) { MR_bool found; int slot; int i; int count; MR_bsearch(MR_alias_record_next, slot, found, strcmp(MR_alias_records[slot].MR_alias_name, name)); if (found) { count = MR_alias_records[slot].MR_alias_word_count; for (i = 0; i < count; i++) { MR_free(MR_alias_records[slot].MR_alias_words[i]); } MR_free(MR_alias_records[slot].MR_alias_name); MR_free(MR_alias_records[slot].MR_alias_words); } else { MR_ensure_room_for_next(MR_alias_record, MR_Alias, INIT_ALIAS_COUNT); MR_prepare_insert_into_sorted(MR_alias_records, MR_alias_record_next, slot, strcmp(MR_alias_records[slot].MR_alias_name, name)); } MR_alias_records[slot].MR_alias_name = MR_copy_string(name); MR_alias_records[slot].MR_alias_word_count = word_count; MR_alias_records[slot].MR_alias_words = MR_NEW_ARRAY(char *, word_count); for (i = 0; i < word_count; i++) { MR_alias_records[slot].MR_alias_words[i] = MR_copy_string(words[i]); } }
char * MR_trace_readline_raw(FILE *fp) { char *contents; int content_max; int c; int i; contents = NULL; content_max = 0; i = 0; while ((c = getc(fp)) != EOF && c != '\n') { MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN); contents[i++] = c; } if (c == '\n' || i > 0) { MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN); contents[i] = '\0'; return contents; } else { MR_free(contents); return NULL; } }
int MR_setenv(const char *name, const char *value, int overwrite) { #if defined(MR_HAVE_SETENV) return setenv(name, value, overwrite); #elif defined(MR_HAVE_PUTENV) || defined(MR_HAVE__PUTENV) char *env; int length; int result; if (!overwrite && getenv(name) != NULL) { return 0; } length = strlen(name) + strlen(value) + 2; env = MR_NEW_ARRAY(char, length); env[0] = '\0'; strcat(env, name); strcat(env, "="); strcat(env, value); result = putenv(env); MR_free(env); return result; #else #error "MR_setenv: unable to define" #endif }
MR_Next MR_trace_cmd_trust(char **words, int word_count, MR_TraceCmdInfo *cmd, MR_EventInfo *event_info, MR_Code **jumpaddr) { MR_ProcSpec spec; MR_MatchesInfo matches; if (word_count == 2) { spec.MR_proc_module = NULL; spec.MR_proc_name = NULL; spec.MR_proc_arity = -1; spec.MR_proc_mode = -1; spec.MR_proc_prefix = (MR_ProcPrefix) -1; MR_register_all_modules_and_procs(MR_mdb_out, MR_TRUE); /* First see if the argument is a module name */ spec.MR_proc_module = words[1]; matches = MR_search_for_matching_procedures(&spec); if (matches.match_proc_next > 0) { MR_decl_add_trusted_module(words[1]); fprintf(MR_mdb_out, "Trusting module %s\n", words[1]); } else if (MR_parse_proc_spec(words[1], &spec)) { /* Check to see if the argument is a pred/func */ matches = MR_search_for_matching_procedures(&spec); MR_filter_user_preds(&matches); if (matches.match_proc_next == 0) { fprintf(MR_mdb_err, "mdb: there is no such module, predicate or function.\n"); } else if (matches.match_proc_next == 1) { MR_decl_add_trusted_pred_or_func(matches.match_procs[0]); fprintf(MR_mdb_out, "Trusting "); MR_print_pred_id_and_nl(MR_mdb_out, matches.match_procs[0]); } else { MR_Unsigned i; char buf[80]; char *line2; fprintf(MR_mdb_out, "Ambiguous predicate or function" " specification. The matches are:\n"); for (i = 0; i < matches.match_proc_next; i++) { fprintf(MR_mdb_out, "%" MR_INTEGER_LENGTH_MODIFIER "u: ", i); MR_print_pred_id_and_nl(MR_mdb_out, matches.match_procs[i]); } sprintf(buf, "\nWhich predicate or function " "do you want to trust (0-%" MR_INTEGER_LENGTH_MODIFIER "u or *)? ", matches.match_proc_next - 1); line2 = MR_trace_getline(buf, MR_mdb_in, MR_mdb_out); if (line2 == NULL) { /* This means the user input EOF. */ fprintf(MR_mdb_out, "none of them\n"); } else if (MR_streq(line2, "*")) { for (i = 0; i < matches.match_proc_next; i++) { MR_decl_add_trusted_pred_or_func( matches.match_procs[i]); fprintf(MR_mdb_out, "Trusting "); MR_print_pred_id_and_nl(MR_mdb_out, matches.match_procs[i]); } MR_free(line2); } else if(MR_trace_is_natural_number(line2, &i)) { if (0 <= i && i < matches.match_proc_next) { MR_decl_add_trusted_pred_or_func( matches.match_procs[i]); fprintf(MR_mdb_out, "Trusting "); MR_print_pred_id_and_nl(MR_mdb_out, matches.match_procs[i]); } else { fprintf(MR_mdb_out, "no such match\n"); } MR_free(line2); } else { fprintf(MR_mdb_out, "none of them\n"); MR_free(line2); } } } } else if (word_count == 3 && ((MR_streq(words[1], "std") && MR_streq(words[2], "lib")) || (MR_streq(words[1], "standard") && MR_streq(words[2], "library")))) { MR_decl_trust_standard_library(); fprintf(MR_mdb_out, "Trusting the Mercury standard library\n"); } else { MR_trace_usage_cur_cmd(); } return KEEP_INTERACTING; }
char * MR_trace_readline(const char *prompt, FILE *in, FILE *out) { #if (defined(isatty) || defined(MR_HAVE_ISATTY)) \ && (defined(fileno) || defined(MR_HAVE_FILENO)) \ && !defined(MR_NO_USE_READLINE) char *line; MR_bool in_isatty; char *last_nl; in_isatty = isatty(fileno(in)); if (in_isatty || MR_force_readline) { rl_instream = in; rl_outstream = out; /* ** The cast to (void *) silences a spurious "assignment from ** incompatible pointer type" warning (old versions of readline ** are very sloppy about declaring the types of function pointers). */ rl_completion_entry_function = (void *) &MR_trace_line_completer; rl_readline_name = "mdb"; if (!in_isatty) { /* ** This is necessary for tests/debugger/completion, otherwise ** we get lots of messages about readline not being able to get ** the terminal settings. This is possibly a bit flaky, but it is ** only used by our tests. */ rl_prep_term_function = (void *) MR_dummy_prep_term_function; rl_deprep_term_function = (void *) MR_dummy_deprep_term_function; } /* ** If the prompt contains newlines then readline doesn't ** display it properly. */ last_nl = strrchr(prompt, '\n'); if (last_nl != NULL) { char *real_prompt; char *pre_prompt; real_prompt = (char *) MR_malloc(strlen(last_nl)); strcpy(real_prompt, last_nl + 1); pre_prompt = (char *) MR_malloc(last_nl - prompt + 2); strncpy(pre_prompt, prompt, last_nl - prompt + 1); pre_prompt[last_nl - prompt + 1] = '\0'; fputs(pre_prompt, out); line = readline((char *) real_prompt); MR_free(real_prompt); MR_free(pre_prompt); } else { line = readline((char *) prompt); } /* ** readline() allocates with malloc(), and we want to return something ** allocated with MR_malloc(), but that's OK, because MR_malloc() and ** malloc() are interchangable. */ #if 0 { char *tmp = line; line = MR_copy_string(line); free(tmp); } #endif if (line != NULL && line[0] != '\0') { add_history(line); } return line; } #endif /* have isatty && have fileno && !MR_NO_USE_READLINE */ /* otherwise, don't use readline */ fprintf(out, "%s", prompt); fflush(out); return MR_trace_readline_raw(in); }
char * MR_trace_readline_from_script(FILE *fp, char **args, int num_args) { char *line = NULL; size_t line_length; int line_index; size_t expanded_line_length; char *expanded_line; int expanded_line_index; int arg_num; size_t arg_length; char *arg; do { if (line != NULL) { MR_free(line); } line = MR_trace_readline_raw(fp); if (line == NULL) { return NULL; } /* ** Ignore lines starting with '#'. */ } while (*line == '#'); line_length = strlen(line); expanded_line_length = line_length; expanded_line = (char*) MR_malloc(line_length + 1); expanded_line[0] = '\0'; expanded_line_index = 0; for (line_index = 0; line_index < line_length; line_index++) { if ((line[line_index] == '$') && (line_index < (line_length - 1)) && (line[line_index + 1] >= '1') && (line[line_index + 1] <= '9')) { arg_num = (int)(line[line_index + 1] - '1'); if (arg_num < num_args) { arg = args[arg_num]; arg_length = strlen(arg); /* ** Subtract 2 for the "$n" which will not occur ** in the expanded string. */ expanded_line_length += arg_length - 2; expanded_line = MR_realloc(expanded_line, expanded_line_length + 1); expanded_line[expanded_line_index] = '\0'; strcat(expanded_line, arg); expanded_line_index += arg_length; } /* Skip the digit after the '$'. */ line_index++; } else { expanded_line[expanded_line_index] = line[line_index]; expanded_line_index++; } } MR_free(line); expanded_line[expanded_line_index] = '\0'; return expanded_line; }
static void MR_dump_live_variables(const MR_LabelLayout *label_layout, MR_MemoryZone *heap_zone, MR_bool top_frame, MR_Word *stack_pointer, MR_Word *current_frame) { int short_var_count; int long_var_count; int i; MR_TypeInfo type_info; MR_Word value; MR_TypeInfoParams type_params; MR_Word saved_regs[MR_MAX_FAKE_REG]; MR_Float saved_f_regs[MR_MAX_VIRTUAL_F_REG]; MR_Word *current_regs; MR_Float *current_f_regs; long_var_count = MR_long_desc_var_count(label_layout); short_var_count = MR_short_desc_var_count(label_layout); // For the top stack frame, we should pass a pointer to a filled-in // saved_regs instead of NULL. For other stack frames, passing NULL // is fine, since output arguments are not live yet for any call // except the top one. MR_restore_registers(); MR_copy_regs_to_saved_regs(MR_MAX_FAKE_REG - 1, saved_regs, MR_MAX_VIRTUAL_F_REG - 1, saved_f_regs); if (top_frame) { current_regs = saved_regs; current_f_regs = saved_f_regs; } else { current_regs = NULL; current_f_regs = NULL; } type_params = MR_materialize_type_params_base(label_layout, current_regs, stack_pointer, current_frame); for (i = 0; i < long_var_count; i++) { fprintf(stderr, "%-12s\t", ""); if (MR_PROC_LAYOUT_HAS_PROC_ID(label_layout->MR_sll_entry)) { MR_print_proc_id(stderr, label_layout->MR_sll_entry); } MR_dump_long_value(MR_long_desc_var_locn(label_layout, i), heap_zone, stack_pointer, current_frame, top_frame); fprintf(stderr, "\n"); fflush(NULL); if (MR_debug_agc_print_vars) { // Call Mercury but use the debugging heap. MR_hp_word = MR_ENGINE(MR_eng_debug_heap_zone->MR_zone_min); MR_virtual_hp_word = MR_ENGINE(MR_eng_debug_heap_zone->MR_zone_min); if (MR_get_type_and_value_base(label_layout, i, current_regs, stack_pointer, current_frame, current_f_regs, type_params, &type_info, &value)) { printf("\t"); MR_write_variable(type_info, value); printf("\n"); } fflush(NULL); } } for (i = 0; i < short_var_count; i++) { fprintf(stderr, "%-12s\t", ""); if (MR_PROC_LAYOUT_HAS_PROC_ID(label_layout->MR_sll_entry)) { MR_print_proc_id(stderr, label_layout->MR_sll_entry); } MR_dump_short_value(MR_short_desc_var_locn(label_layout, i), heap_zone, stack_pointer, current_frame, top_frame); fprintf(stderr, "\n"); fflush(NULL); if (MR_debug_agc_print_vars) { // Call Mercury but use the debugging heap. MR_hp_word = MR_ENGINE(MR_eng_debug_heap_zone->MR_zone_min); MR_virtual_hp_word = MR_ENGINE(MR_eng_debug_heap_zone->MR_zone_min); if (MR_get_type_and_value_base(label_layout, i, current_regs, stack_pointer, current_frame, current_f_regs, type_params, &type_info, &value)) { printf("\t"); MR_write_variable(type_info, value); printf("\n"); } fflush(NULL); } } MR_copy_saved_regs_to_regs(MR_MAX_FAKE_REG - 1, saved_regs, MR_MAX_VIRTUAL_F_REG - 1, saved_f_regs); MR_save_registers(); MR_free(type_params); }
MR_bool MR_trace_get_action(MR_IoActionNum action_number, MR_ConstString *proc_name_ptr, MR_Word *is_func_ptr, MR_Word *arg_list_ptr) { const MR_TableIoDecl *table_io_decl; const MR_ProcLayout *proc_layout; MR_ConstString proc_name; MR_Word is_func; MR_Word arg_list; MR_Word arg; int filtered_arity; int arity; int hv; MR_TrieNode answer_block_trie; MR_Word *answer_block; MR_TypeInfo *type_params; MR_TypeInfo type_info; if (! (MR_io_tabling_start <= action_number && action_number < MR_io_tabling_counter_hwm)) { return MR_FALSE; } MR_TABLE_START_INT(NULL, MR_tabledebug, MR_FALSE, answer_block_trie, (MR_TrieNode) &MR_io_tabling_pointer, MR_io_tabling_start, action_number); answer_block = answer_block_trie->MR_answerblock; if (answer_block == NULL) { return MR_FALSE; } table_io_decl = (const MR_TableIoDecl *) answer_block[0]; proc_layout = table_io_decl->MR_table_io_decl_proc; filtered_arity = table_io_decl->MR_table_io_decl_filtered_arity; MR_generate_proc_name_from_layout(proc_layout, &proc_name, &arity, &is_func); type_params = MR_materialize_answer_block_type_params( table_io_decl->MR_table_io_decl_type_params, answer_block, filtered_arity); MR_restore_transient_hp(); arg_list = MR_list_empty(); MR_save_transient_hp(); for (hv = filtered_arity; hv >= 1; hv--) { type_info = MR_create_type_info(type_params, table_io_decl->MR_table_io_decl_ptis[hv - 1]); MR_restore_transient_hp(); MR_new_univ_on_hp(arg, type_info, answer_block[hv]); arg_list = MR_univ_list_cons(arg, arg_list); MR_save_transient_hp(); } MR_free(type_params); *proc_name_ptr = proc_name; *is_func_ptr = is_func; *arg_list_ptr = arg_list; return MR_TRUE; }
const char * MR_trace_source_open_server(MR_TraceSourceServer *server, const char *window_cmd, int timeout, MR_bool verbose) { const char *real_window_cmd; const char *real_server_cmd; char *name; const char *msg; char system_call[MR_SYSCALL_BUFFER_SIZE]; int status; size_t base_len; size_t i; if (window_cmd != NULL) { real_window_cmd = window_cmd; } else { real_window_cmd = MR_DEFAULT_SOURCE_WINDOW_COMMAND; } if (server->server_cmd != NULL) { real_server_cmd = server->server_cmd; } else { real_server_cmd = MR_DEFAULT_SOURCE_SERVER_COMMAND; } // 1) check that display is set; // 2) check that server is valid; // 3) start a server with a unique name; // 4) wait until the server is found; // 5) (if required) split the window. msg = MR_trace_source_check_display(); if (msg != NULL) { return msg; } msg = MR_trace_source_check_server_cmd(real_server_cmd, verbose); if (msg != NULL) { return msg; } // If possible, we generate a unique name of the form // '<basename>.<hostname>.<pid>', but if the required functions // aren't available, we fall back to appending numbers to the // basename in sequence until one is found that is not being used. // This is quite a slow way of doing things, and there is also a // race condition, but it is difficult to see a better way. // We should let the server pick a unique name for itself, but // how would you communicate this name back to this process? base_len = strlen(MR_SOURCE_SERVER_BASENAME); #if defined(MR_HAVE_GETPID) && defined(MR_HAVE_GETHOSTNAME) // Need to leave enough room for the pid, two '.'s and the // terminating zero. name = MR_malloc(base_len + MR_SERVER_HOSTNAME_CHARS + 32); strcpy(name, MR_SOURCE_SERVER_BASENAME); // Append the '.' and hostname. name[base_len] = '.'; gethostname(name + base_len + 1, MR_SERVER_HOSTNAME_CHARS); // Do this just in case gethostname didn't terminate the string: name[base_len + 1 + MR_SERVER_HOSTNAME_CHARS] = '\0'; // Find the end of the string and append the '.' and pid. i = base_len + 1 + strlen(name + base_len + 1); sprintf(name + i, ".%ld", (long) getpid()); #else i = 0; // Need to leave enough room for a '.', the integer and the // terminating zero. name = MR_malloc(base_len + 10); do { i++; sprintf(name, "%s.%lu", MR_SOURCE_SERVER_BASENAME, (unsigned long)i); // This should fail if there is no server with this name. msg = MR_trace_source_check_server(real_server_cmd, name, verbose); } while (msg == NULL); #endif server->server_name = name; // Start the server in read-only mode, to discourage the user // from trying to edit the source. sprintf(system_call, "%s %s -R --servername \"%s\" %s &", real_window_cmd, real_server_cmd, name, (verbose ? "" : "> /dev/null 2>&1")); MR_verbose_system_call(system_call, verbose); // We need to wait until the source server has registered itself // with the X server. If we don't, we may execute remote commands // before the server has started up, and this will result in vim // (rather inconveniently) starting its own server on mdb's terminal. msg = MR_trace_source_attach(server, timeout, verbose); if (msg != NULL) { // Something went wrong, so we should free the server name // we allocated just above. MR_free(server->server_name); server->server_name = NULL; return msg; } if (server->split) { // Split the window. status = MR_trace_source_send(real_server_cmd, server->server_name, MR_SOURCE_SERVER_RESET_STRING MR_SOURCE_SERVER_SPLIT_STRING, verbose); if (status != 0) { server->split = MR_FALSE; return "warning: unable to split source window"; } } return NULL; }
MR_bool MR_trace_get_action(MR_IoActionNum action_number, MR_ConstString *proc_name_ptr, MR_Word *is_func_ptr, MR_bool *have_arg_infos_ptr, MR_Word *arg_list_ptr) { const MR_TableIoEntry *table_io_entry; const MR_ProcLayout *proc_layout; MR_ConstString proc_name; MR_Word is_func; int arity; int hv; MR_TrieNode answer_block_trie; MR_Word *answer_block; if (! (MR_io_tabling_start <= action_number && action_number < MR_io_tabling_counter_hwm)) { return MR_FALSE; } MR_TABLE_START_INT(NULL, MR_tabledebug, MR_FALSE, answer_block_trie, (MR_TrieNode) &MR_io_tabling_pointer, MR_io_tabling_start, action_number); answer_block = answer_block_trie->MR_answerblock; if (answer_block == NULL) { return MR_FALSE; } table_io_entry = (const MR_TableIoEntry *) answer_block[0]; proc_layout = table_io_entry->MR_table_io_entry_proc; MR_generate_proc_name_from_layout(proc_layout, &proc_name, &arity, &is_func); *proc_name_ptr = proc_name; *is_func_ptr = is_func; if (table_io_entry->MR_table_io_entry_have_arg_infos) { int filtered_arity; MR_Word arg_list; MR_Word arg; MR_TypeInfo *type_params; MR_TypeInfo type_info; *have_arg_infos_ptr = MR_TRUE; filtered_arity = table_io_entry->MR_table_io_entry_num_ptis; type_params = MR_materialize_answer_block_type_params( table_io_entry->MR_table_io_entry_type_params, answer_block, filtered_arity); MR_restore_transient_hp(); arg_list = MR_list_empty(); MR_save_transient_hp(); for (hv = filtered_arity; hv >= 1; hv--) { type_info = MR_create_type_info(type_params, table_io_entry->MR_table_io_entry_ptis[hv - 1]); MR_restore_transient_hp(); MR_new_univ_on_hp(arg, type_info, answer_block[hv]); arg_list = MR_univ_list_cons(arg, arg_list); MR_save_transient_hp(); } MR_free(type_params); *arg_list_ptr = arg_list; } else { *have_arg_infos_ptr = MR_FALSE; // *arg_list_ptr is not meaningful when *have_arg_infos_ptr is false, // but setting it to the empty list makes it easier to catch any // caller that ignores that fact. *arg_list_ptr = MR_list_empty(); } return MR_TRUE; }