// Find path of source file SOURCE string dbx_path(const string& source) { string path; if (gdb->has_setenv_command() && gdb->has_edit_command()) { // The DBX `file' command issues only the base name of the // current file. The `edit' command, however, invokes an // editor with the entire path. So, we misuse the `edit' // command such that it reports the entire path. gdb_question("setenv EDITOR \"echo\""); path = gdb_question("edit " + source); gdb_question(string("setenv EDITOR ") + quote(getenv("EDITOR") ? getenv("EDITOR") : "vi")); } else if (gdb->type() == DBX) { // We have DBX, but no `setenv' and no `edit' command. Check // whether the `file' command with no arguments provides the // full path, as in AIX DBX 3.1. This shouldn't affect other // DBX variants as `file' will simply return the same thing // already contained in source. gdb_question("file " + source); path = gdb_question("file"); } strip_leading_space(path); if (!path.contains('/', 0) || path.contains(' ')) path = source; // Sanity check strip_trailing_space(path); return path; }
// Return 1 if the signal specified in PROGRAM_STATE is passed to the // program; 0 if not, -1 if undecided. static int passed_to_program(const string& program_state) { string signal = program_state.from("SIG"); signal = signal.through(rxalpha); if (!signal.empty()) { string signal_description = program_state.after(signal); signal_description = signal_description.after(rxwhite); if (signal_description.empty()) signal_description = signal; defineConversionMacro("SIGNAL", signal.chars()); defineConversionMacro("SIGNAL_DESCRIPTION", signal_description.chars()); string ans = gdb_question("info handle " + signal); // `info handle SIGINT' output has the form // "Signal Stop\tPrint\tPass to program\tDescription\n" // "SIGINT Yes\tYes\tNo\t\tInterrupt\n" ans.downcase(); string header = ans.before("pass "); int tabs_before_pass = header.freq('\t'); string info = ans.after('\n'); while (tabs_before_pass--) info = info.after('\t'); if (info.contains('y', 0)) return 1; if (info.contains('n', 0)) return 0; } return -1; }
static void LoadSharedLibrariesCB(Widget, XtPointer, XtPointer) { StatusDelay delay("Loading shared object library symbols"); gdb_question("sharedlibrary"); update_sources(); }
// Get list of sources into SOURCES_LIST void get_gdb_sources(StringArray& sources_list) { static const StringArray empty; sources_list = empty; string ans = gdb_question("info sources"); if (ans != NO_GDB_ANSWER) { // Create a newline-separated list of sources string new_ans; while (!ans.empty()) { string line = ans.before('\n'); ans = ans.after('\n'); if (line.empty() || line.contains(':', -1)) continue; line.gsub(", ", "\n"); new_ans += line + '\n'; } ans = new_ans; while (!ans.empty()) { string line = ans.before('\n'); ans = ans.after('\n'); sources_list += line; } smart_sort(sources_list); uniq(sources_list); } }
// Get index base of expr EXPR in dimension DIM int DispValue::index_base(const string& expr, int dim) { if (gdb->program_language() != LANGUAGE_FORTRAN) return gdb->default_index_base(); string base = expr; if (base.contains('(')) base = base.before('('); if (!type_cache.has(base)) type_cache[base] = gdb_question(gdb->whatis_command(base)); string type = type_cache[base]; // GDB issues array information as `type = real*8 (0:9,2:12)'. // However, the first dimension in the type output comes last in // the printed array. int colon = type.length(); while (colon >= 0 && dim-- >= 0) colon = type.index(':', colon - type.length() - 1); if (colon < 0) return gdb->default_index_base(); // Not found while (colon >= 0 && isdigit(type[colon - 1])) colon--; return atoi(type.chars() + colon); }
// Get information on current debuggee ProgramInfo::ProgramInfo() : file(NO_GDB_ANSWER), core(NO_GDB_ANSWER), pid(0), attached(false), running(false), state() { if (source_view->have_exec_pos()) { state = "has stopped"; running = true; } else { state = "is not being run"; running = false; } switch(gdb->type()) { case GDB: case PYDB: case DBG: { string ans; if (gdb->is_windriver_gdb()) { // Windriver GDB (VxWorks). // VxWorks allows multiple dynamically relocatable // programs to be loaded simultaneously. Before a program // is run, the 'info source' command can report // information from a source file not related to the // program just downloaded for debugging. (The WindRiver // version of gdb does not support the 'info files' // command.) // In order to tell DDD that there is indeed a source file // available, we need to first see if a program has // already been started. If so, then the 'info source' // command can be used. // Otherwise, the 'info sources' command is used, and the // first file in the list is used, assuming it is related // to the current program that was downloaded. // See if the program has been run first ans = gdb_question("info frame"); if (ans == NO_GDB_ANSWER) break; file = ""; if (ans.contains("No stack")) { // Then try using info sources and use first file listed ans = gdb_question("info sources"); if (ans == NO_GDB_ANSWER) break; if (ans.contains("Source files for which " "symbols have been read in:")) { file = ans.after("\n"); file = file.before(" "); file = unquote(file); } } else { // Try using `info source'. ans = gdb_question("info source"); if (ans == NO_GDB_ANSWER) break; if (ans.contains("Current source file is ")) { file = ans.after("Current source file is "); file = file.before(".\n"); file = unquote(file); } } } else { // Ordinary GDB. ans = gdb_question("info files"); if (ans == NO_GDB_ANSWER) break; file = ""; if (ans.contains("Symbols from ")) { file = ans.after("Symbols from "); file = file.before(".\n"); file = unquote(file); } } core = ""; if (ans.contains("core dump")) { core = ans.after("core dump"); core = core.after('`'); core = core.before("',"); } if (ans.contains("process ")) { string p = ans.after("process "); pid = atoi(p.chars()); } attached = ans.contains("attached process "); ans = gdb_question("info program"); if (ans == NO_GDB_ANSWER) break; if (ans.contains("not being run")) running = false; else if (ans.contains("\nIt stopped ")) { state = ans.from("\nIt stopped "); state = "has " + state.after("\nIt "); state = state.before('.'); running = true; } break; } case DBX: { if (gdb->is_ladebug()) { string ans = gdb_question("show process"); // typical answers: // 1:no process // There are no processes being debugged. // 2: process has been paused. // Current Process: localhost:26177 (a.out) paused. // 3: process terminated // Current Process: localhost:13614 (ddd) terminated. // TODO: treat the terminated case if (ans != NO_GDB_ANSWER && !ans.contains("no processes being debugged")) { if (ans.contains("Current Process: ")) { ans = ans.after(": "); { string p = ans.after(":"); p = p.before(" "); pid = atoi(p.chars()); } ans = ans.after(" ("); file = ans.before(")"); ans = ans.after(") "); running = ans.contains("paused"); // ladebug always creates a process. // It may be "loaded" or attached. attached = true; } } } // AD TODO: shouldn't it be an "else" ? string ans = gdb_question(gdb->debug_command()); if (ans != NO_GDB_ANSWER) { if (ans.contains("Current givenfile is ", 0)) ans = ans.after("Current givenfile is "); else if (ans.contains("Debugging: ", 0)) ans = ans.after(": "); strip_space(ans); if (!ans.contains(' ')) // Sanity check file = ans; } break; } case XDB: break; // FIXME case PERL: // Use the program we were invoked with file = gdb->program(); if (file.matches(rxint)) file = ""; // Invoked with a constant expression if (file.empty()) { // Not invoked with a program? Use the current file, then. file = source_view->file_of_cursor(); file = file.before(":"); } core = ""; break; case BASH: // Use the program we were invoked with file = gdb->program(); if (file.matches(rxint)) file = ""; // Invoked with a constant expression if (file.empty()) { // Not invoked with a program? Use the current file, then. file = source_view->file_of_cursor(); file = file.before(":"); } core = ""; break; case JDB: // Just use the current class. file = source_view->line_of_cursor(); file = file.before(":"); core = ""; // Save whether JDB's VM is running static int last_jdb_pid = -1; static bool jvm_running = false; if (gdb->pid() != last_jdb_pid) { // New JDB: reset info jvm_running = false; last_jdb_pid = gdb->pid(); } // The VM is running iff the prompt contains a backtrace // level ("[n]"). if (!jvm_running && gdb->prompt().contains("[")) jvm_running = true; running = jvm_running; break; } if (file == NO_GDB_ANSWER) { // As a fallback, get core file and executable from argument list. // Works only on local file system and is more a guess. char **argv = saved_argv(); int argc = 0; while (argv[argc] != 0) argc++; for (int i = argc - 1; i > 0 && file == NO_GDB_ANSWER; i--) { // All debuggers supported by DDD have [EXEC [CORE]] as // their last arguments. string arg = argv[i]; if (is_core_file(arg)) core = arg; else if (is_debuggee_file(arg)) file = arg; } } if (file != NO_GDB_ANSWER) add_to_recent(file); }
// Create list of processes static void update_processes(Widget processes, bool keep_selection) { StatusDelay delay("Getting list of processes"); string cmd = sh_command(app_data.ps_command) + " 2>&1"; FILE *fp = popen(cmd.chars(), "r"); if (fp == 0) { delay.outcome = strerror(errno); return; } StringArray all_process_list; int c; string line = ""; bool first_line = true; while ((c = getc(fp)) != EOF) { if (c == '\n') { if (first_line || valid_ps_line(line, app_data.ps_command)) all_process_list += line; #if 0 else std::clog << "Excluded: " << line << "\n"; #endif if (first_line) { // Find first occurrence of `PID' title ps_pid_index = line.index(" PID "); if (ps_pid_index < 0) ps_pid_index = 0; } line = ""; first_line = false; } else { line += c; } } pclose(fp); sortProcesses(all_process_list); DynIntArray pids(all_process_list.size()); // If GDB cannot send a signal to the process, we cannot debug it. // Try a `kill -0' (via GDB, as it may be setuid) and filter out // all processes in the `kill' diagnostic -- that is, all // processes that `kill' could not send a signal. string kill = "kill -0"; if (gdb->has_handler_command()) kill = "/usr/bin/kill -0"; // Bypass built-in SUN DBX command int i; for (i = 0; i < all_process_list.size(); i++) { pids[i] = ps_pid(all_process_list[i]); if (pids[i]) kill += string(" ") + itostring(pids[i]); } #if defined(__sun) // bypass underlying debugger // Fix for Sun: use /usr/bin/kill string kill_result; { std::ostringstream os; kill += " 2>&1"; FILE *fp = popen(kill.chars(), "r"); if (fp != 0) { int c; while ((c = getc(fp)) != EOF) { os << (char)c; } pclose(fp); } kill_result = os; } #else string kill_result = gdb_question(gdb->shell_command(kill)); #endif i = 0; while (i >= 0) { i = kill_result.index(rxint, i); if (i >= 0) { int bad_pid = atoi(kill_result.chars() + i); for (int k = 0; k < all_process_list.size(); k++) { if (pids[k] != 0 && pids[k] == bad_pid) { #if 0 std::clog << "Excluded: " << all_process_list[k] << "\n"; #endif all_process_list[k] = NO_GDB_ANSWER; } } i++; } } StringArray process_list; for (i = 0; i < all_process_list.size(); i++) if (all_process_list[i] != NO_GDB_ANSWER) process_list += all_process_list[i]; // Now set the selection. bool *selected = new bool[process_list.size()]; for (i = 0; i < process_list.size(); i++) selected[i] = false; int pos = -1; if (keep_selection) { // Preserve old selection: each PID selected before will also be // selected after. IntArray selection; getPIDs(processes, selection); for (i = 0; i < selection.size(); i++) { for (int j = 0; j < process_list.size(); j++) if (selection[i] == ps_pid(process_list[j])) { if (pos < 0) pos = j; selected[j] = true; } } } if (pos < 0) { // Create new selection from current file and current pid. ProgramInfo info; // Check for current pid; if found, highlight it. for (i = 0; pos < 0 && i < process_list.size(); i++) { if (info.pid != 0 && ps_pid(process_list[i]) == info.pid) pos = i; } if (pos < 0) { // Not found? Try leftmost occurrence of process base name. string current_base = basename(info.file.chars()); int leftmost = INT_MAX; for (i = 0; i < process_list.size(); i++) { int occurrence = process_list[i].index(current_base); if (occurrence >= 0 && occurrence < leftmost && ps_pid(process_list[i]) > 0) { leftmost = occurrence; pos = i; } } } } if (pos >= 0) selected[pos] = true; setLabelList(processes, process_list.values(), selected, process_list.size(), true, false); if (pos >= 0) ListSetAndSelectPos(processes, pos + 1); delete[] selected; }
string dbx_lookup(const string& func_name, bool silent) { // Protect against `1' or `' being looked up as function names if (!func_name.contains(rxidentifier, 0)) return ""; // Bad function name if (pos_cache.has(func_name)) { string pos = pos_cache[func_name]; if (silent || !pos.empty()) return pos; } string reply; switch (gdb->type()) { case DBG: case DBX: case GDB: case JDB: case PYDB: reply = gdb_question("list " + func_name, 0, true); break; case XDB: reply = gdb_question("v " + func_name, 0, true); break; case PERL: reply = gdb_question("l " + func_name, 0, true); break; case BASH: reply = gdb_question("l " + func_name, 0, true); break; case MAKE: reply = gdb_question("target " + func_name, 0, true); break; } if (reply == NO_GDB_ANSWER) { // post_gdb_busy(); return ""; } string file = ""; int line = 0; switch (gdb->type()) { case GDB: case PYDB: // XXX { file = reply.from('\"'); file = file.before('\"'); const string line_s = reply.after("Line "); line = atoi(line_s.chars()); break; } case DBX: line = line_of_listing(reply, silent); if (line > 0) { file = gdb_question("file"); strip_trailing_space(file); } break; case BASH: case DBG: case JDB: case MAKE: case PERL: line = line_of_listing(reply, silent); file = source_view->line_of_cursor(); file = file.before(':'); break; case XDB: { #if RUNTIME_REGEX static regex rxcolons("[^:]*:[^:]*: *[0-9][0-9]*.*"); #endif if (reply.matches(rxcolons)) { file = reply.before(':'); reply = reply.after(':'); // Skip file reply = reply.after(':'); // Skip function strip_leading_space(reply); const string line_s = reply.before(':'); line = atoi(line_s.chars()); } else { // post_gdb_message(reply); return ""; } break; } } string pos = ""; if (line > 0) pos = file + ":" + itostring(line); pos_cache[func_name] = pos; return pos; }
bool UndoBuffer::process_command(UndoBufferEntry& entry) { // Process command string commands; if (entry.has(UB_EXEC_COMMAND)) commands = entry[UB_EXEC_COMMAND]; else if (entry.has(UB_COMMAND)) commands = entry[UB_COMMAND]; else return true; // Nothing to do entry.remove(UB_COMMAND); entry.remove(UB_EXEC_COMMAND); //string original_commands = commands; int bp_count = 0; undoing = true; bool confirm = false; if (!commands.empty() && gdb->type() == GDB) { gdb_command("show confirm", 0, get_confirm, &confirm); syncCommandQueue(); } if (confirm) { // Turn confirmation off during undo/redo. gdb_question("set confirm off"); } while (!commands.empty()) { string cmd; if (commands.contains('\n')) cmd = commands.before('\n'); else cmd = commands; commands = commands.after('\n'); // Handle breakpoint remappings if (cmd.contains(REMAP_COMMAND, 0)) { int old_bp_nr = atoi(cmd.chars() + strlen(REMAP_COMMAND "@")); int new_bp_nr = source_view->next_breakpoint_number() + bp_count++; remap_breakpoint(old_bp_nr, new_bp_nr); remap_breakpoint(commands, old_bp_nr, new_bp_nr); continue; } // Replace all occurrences of `@N@' by N #if RUNTIME_REGEX static regex rxnum("@[0-9]+@"); #endif int i; while ((i = index(cmd, rxnum, "@")) >= 0) { int num = atoi(cmd.chars() + i + 1); int j = cmd.index('@', i + 1); cmd.at(i, j - i + 1) = itostring(num); } if (cmd.contains("set confirm", 0)) confirm = false; // Don't overwrite // Execute command. This will result in new redo command(s) // being passed to add_command(). Command c(cmd); c.priority = COMMAND_PRIORITY_SYSTEM; gdb_command(c); // Wait until this command is processed syncCommandQueue(); } if (confirm) gdb_question("set confirm on"); if (!entry.has(UB_COMMAND) && !entry.has(UB_EXEC_COMMAND)) { // We had an error during execution return false; } undoing = false; return true; }