/** * Process the commands that were created by the client * * \param tgdb * The TGDB context * * \return * -1 on error, 0 on success */ int Ctgdb::Process_client_commands() { struct tgdb_list *client_command_list; tgdb_list_iterator *iterator; struct tgdb_command *command; client_command_list = tgdb_client_get_client_commands (tcc); iterator = tgdb_list_get_first (client_command_list); while (iterator) { command = (struct tgdb_command *) tgdb_list_get_item (iterator); if (Run_or_queue_command(command) == -1) { Logger_write_pos( __FILE__, __LINE__, "Run_or_queue_command failed"); return -1; } iterator = tgdb_list_next (iterator); } /* free the list of client commands */ tgdb_list_clear (client_command_list); return 0; }
int rline_rl_complete (struct rline *rline, struct tgdb_list *list, display_callback display_cb) { int size; int key; rl_command_func_t *compare_func = NULL; if (!rline) return -1; /* Currently, if readline output's the tab completion to rl_outstream, it will fill * the pty between it and CGDB and will cause CGDB to hang. */ if (!display_cb) return -1; size = tgdb_list_size (list); if (size == 0) { rl_completion_word_break_hook = NULL; rl_completion_entry_function = NULL; } else { rl_completion_word_break_hook = rline_rl_cpvfunc_t; rl_completion_entry_function = rline_rl_completion_entry_function; } rl_completion_display_matches_hook = display_cb; rline_local_iter = tgdb_list_get_first (list); /* This is probably a hack, however it works for now. * * Basically, rl_complete is working fine. After the call to rl_complete, * rl_line_buffer contains the proper data. However, the CGDB main loop * always call rline_rl_forced_update_display, which in the case of tab * completion does this, (gdb) b ma(gdb) b main * * Normally, this works fine because the user hits '\n', which puts the prompt * on the next line. In this case, the user hit's \t. * * In order work around this problem, simply putting the \r should work * for now. * * This obviously shouldn't be done when readline is doing * `?' means list the possible completions. * style completion. Because that actuall does list all of the values on * a different line. In this situation the \r goes after the completion * is done, since only the current prompt is on that line. */ /* Another confusing comparison. This checks to see if the last * readline function and the current readline function and the * tab completion callback are all the same. This ensures that this * is the second time the user hit \t in a row. Instead of simply * calling rl_complete_internal, it's better to call, rl_completion_mode * because this checks to see what kind of completion should be done. */ if (rline->rline_rl_last_func == rline->tab_completion && rline->rline_rl_last_func == rl_last_func) compare_func = rline->tab_completion; key = rl_completion_mode (compare_func); if (key == TAB) fprintf (rline->output, "\r"); rl_complete_internal (key); if (key != TAB) fprintf (rline->output, "\r"); return 0; }
/** * This function does most of the dirty work in TGDB. It is capable of * processing the output of the debugger, to either satisfy a previously * made request, or to simply get console output for the caller to have. * * The data returned from this function is the console output of the * debugger. * * \param tgdb * An instance of the tgdb library to operate on. * * \param buf * The output of the debugger will be returned in this buffer. * The buffer passed back will not exceed N in size. * * \param n * Tells libtgdb how large the buffer BUF is that the client passed in. * * \param is_finished * If this is passed in as NULL, it is not set. * * If it is non-null, it will be set to 1 if TGDB finished processing the * current request. Otherwise, it will be set to 0 if TGDB needs more input * in order to finish processing the current requested command. * * @return * The number of valid bytes in BUF on success, or -1 on error. */ size_t Ctgdb::Process(char *buf, size_t n, int *is_finished, ITarget** target) { char local_buf[10 * n]; ssize_t size; size_t buf_size = 0; int is_busy; /* make the queue empty */ Delete_responses(); *target = m_target; /* TODO: This is kind of a hack. * Since I know that I didn't do a read yet, the next select loop will * get me back here. This probably shouldn't return, however, I have to * re-write a lot of this function. Also, I think this function should * return a malloc'd string, not a static buffer. * * Currently, I see it as a bigger hack to try to just append this to the * beggining of buf. */ if (last_gui_command != NULL) { int ret; if (IsBusy( &is_busy) == -1) { Logger_write_pos( __FILE__, __LINE__, "tgdb_is_busy failed"); return -1; } *is_finished = !is_busy; if (show_gui_commands) { strcpy (buf, last_gui_command); ret = strlen (last_gui_command); } else { strcpy (buf, "\n"); ret = 1; } free (last_gui_command); last_gui_command = NULL; return ret; } if (has_sigchld_recv) { int tgdb_will_quit; /* tgdb_get_quit_command will return right away, it's asynchrounous. * We call it to determine if it was GDB that died. * If GDB didn't die, things will work like normal. ignore this. * If GDB did die, this get's the quit command and add's it to the list. It's * OK that the rest of this function get's executed, since the read will simply * return EOF. */ int val = Get_quit_command(&tgdb_will_quit); if (val == -1) { Logger_write_pos( __FILE__, __LINE__, "tgdb_get_quit_command error"); return -1; } has_sigchld_recv = 0; if (tgdb_will_quit) goto tgdb_finish; } /* set buf to null for debug reasons */ memset (buf, '\0', n); /* 1. read all the data possible from gdb that is ready. */ if ((size = io_read (debugger_stdout, local_buf, n)) < 0) { Logger_write_pos( __FILE__, __LINE__, "could not read from masterfd"); buf_size = -1; Add_quit_command(); goto tgdb_finish; } else if (size == 0) { /* EOF */ Add_quit_command(); goto tgdb_finish; } local_buf[size] = '\0'; /* 2. At this point local_buf has everything new from this read. * Basically this function is responsible for seperating the annotations * that gdb writes from the data. * * buf and buf_size are the data to be returned from the user. */ { /* unused for now */ char *infbuf = NULL; size_t infbuf_size; int result; result = tgdb_client_parse_io (tcc, local_buf, size, buf, &buf_size, infbuf, &infbuf_size, command_list); Process_client_commands(); if (result == 0) { /* success, and more to parse, ss isn't done */ } else if (result == 1) { /* success, and finished command */ IS_SUBSYSTEM_READY_FOR_NEXT_COMMAND = 1; } else if (result == -1) { Logger_write_pos( __FILE__, __LINE__, "tgdb_client_parse_io failed"); } } /* 3. if ^c has been sent, clear the buffers. * If a signal has been recieved, clear the queue and return */ Handle_signals(); /* 4. runs the users buffered command if any exists */ if (Has_command_to_run ()) Unqueue_and_deliver_command(); tgdb_finish: /* Set the iterator to the beggining. So when the user * calls tgdb_get_command it, it will be in the right spot. */ command_list_iterator = tgdb_list_get_first(command_list); if (IsBusy (&is_busy) == -1) { Logger_write_pos( __FILE__, __LINE__, "tgdb_is_busy failed"); return -1; } *is_finished = !is_busy; return buf_size; }
static void process_commands(struct tgdb *tgdb) { struct tgdb_response *item; while ((item = tgdb_get_response(tgdb)) != NULL) { switch (item->header) { /* This updates all the breakpoints */ case TGDB_UPDATE_BREAKPOINTS: { struct sviewer *sview = if_get_sview(); char *file; struct tgdb_list *list = item->choice.update_breakpoints.breakpoint_list; tgdb_list_iterator *iterator; struct tgdb_breakpoint *tb; source_clear_breaks(if_get_sview()); iterator = tgdb_list_get_first(list); while (iterator) { /* For each breakpoint */ tb = (struct tgdb_breakpoint *) tgdb_list_get_item(iterator); file = tb->file; if (tb->enabled) source_enable_break(sview, file, tb->line); else source_disable_break(sview, file, tb->line); iterator = tgdb_list_next(iterator); } if_show_file(NULL, 0); break; } /* This means a source file or line number changed */ case TGDB_UPDATE_FILE_POSITION: { struct tgdb_file_position *tfp; tfp = item->choice.update_file_position.file_position; /* Update the file */ source_reload(if_get_sview(), tfp->absolute_path, 0); if_show_file(tfp->absolute_path, tfp->line_number); source_set_relative_path(if_get_sview(), tfp->absolute_path, tfp->relative_path); break; } /* This is a list of all the source files */ case TGDB_UPDATE_SOURCE_FILES: { struct tgdb_list *list = item->choice.update_source_files.source_files; tgdb_list_iterator *i = tgdb_list_get_first(list); char *s; if_clear_filedlg(); while (i) { s = tgdb_list_get_item(i); if_add_filedlg_choice(s); i = tgdb_list_next(i); } if_set_focus(FILE_DLG); kui_input_acceptable = 1; break; } /* The user is trying to get a list of source files that make up * the debugged program but libtgdb is claiming that gdb knows * none. */ case TGDB_SOURCES_DENIED: if_display_message("Error:", 0, " No sources available! Was the program compiled with debug?"); kui_input_acceptable = 1; break; /* This is the absolute path to the last file the user requested */ case TGDB_FILENAME_PAIR: { const char *apath = item->choice.filename_pair.absolute_path; const char *rpath = item->choice.filename_pair.relative_path; if_show_file((char *) apath, 1); source_set_relative_path(if_get_sview(), apath, rpath); break; } /* The source file requested does not exist */ case TGDB_ABSOLUTE_SOURCE_DENIED: { struct tgdb_source_file *file = item->choice.absolute_source_denied.source_file; if_show_file(NULL, 0); /* com can be NULL when tgdb orig requests main file */ if (file->absolute_path != NULL) if_display_message("No such file:", 0, " %s", file->absolute_path); break; } case TGDB_INFERIOR_EXITED: { /* * int *status = item->data; * This could eventually go here, but for now, the update breakpoint * display function makes the status bar go back to the name of the file. * * if_display_message ( "Program exited with value", 0, " %d", *status ); */ /* Clear the cache */ break; } case TGDB_UPDATE_COMPLETIONS: { struct tgdb_list *list = item->choice.update_completions.completion_list; do_tab_completion(list); break; } case TGDB_UPDATE_CONSOLE_PROMPT_VALUE: { const char *new_prompt = item->choice.update_console_prompt_value.prompt_value; change_prompt(new_prompt); break; } case TGDB_QUIT: cleanup(); exit(0); break; /* Default */ default: break; } } }