// Return next display info from GDB_ANSWER; "" if none. string read_next_disp_info (string& gdb_answer, GDBAgent *gdb) { switch (gdb->type()) { case GDB: case PYDB: { int startpos = gdb_answer.index (": "); int i = startpos + 2; for (;;) { while (i < int(gdb_answer.length()) && gdb_answer[i] != '\n') i++; if (i >= int(gdb_answer.length())) { // Take entire remaining output as display string next_disp_info = gdb_answer; gdb_answer = ""; return next_disp_info; } assert(gdb_answer[i] == '\n'); if (gdb_answer.contains(rxgdb_begin_of_display_info, i + 1)) { // Use output up to `\n[0-9]' as display string next_disp_info = gdb_answer.before(i); gdb_answer = gdb_answer.after(i); return next_disp_info; } i++; } } case DBX: { string next_disp_info; int i = gdb_answer.index('\n'); if (i > 0) { next_disp_info = gdb_answer.before(i); gdb_answer = gdb_answer.after(i); } else { next_disp_info = gdb_answer; gdb_answer = ""; } return next_disp_info; } case XDB: case JDB: case PERL: break; // FIXME } return ""; }
void PosBuffer::filter_pydb(string& answer) { if (already_read != PosComplete && !answer.contains('\n')) { // Position info is incomplete answer_buffer = answer; answer = ""; already_read = PosPart; return; } // `Breakpoint N, FUNCTION (ARGS...) at file:line_no' // rxstopped_func defined for GDB...if it changes, change here int fn_index = index(answer, rxstopped_func, "Breakpoint"); if (fn_index >= 0) { fetch_function(answer, fn_index, func_buffer); } else { // `#FRAME FUNCTION(args) at file:line_no' // Likewise rxframe_func defined for GDB int frame_index = index(answer, rxframe_addr, "#"); if (frame_index == 0 || frame_index > 0 && answer[frame_index - 1] == '\n') { fetch_function(answer, frame_index, func_buffer); } } int lineinfo = answer.index("Lineinfo"); // Lineinfo <function> at file:lineno if (lineinfo == 0 || (lineinfo > 0 && answer[lineinfo - 1] == '\n')) { answer = answer.after('<'); func_buffer = answer.before('>'); } string result = answer.after(" at "); result = result.before('\n'); if (result.contains(':')) { pos_buffer = result; already_read = PosComplete; } // Don't need the answer anymore when line matches 'Lineinfo' if (lineinfo >= 0) { answer = ""; } }
// Add ARG to the list of arguments static void add_argument(string arg, StringArray& arguments, string& last, bool& updated) { strip_trailing_space(arg); while (arg.length() > 0 && isspace(arg[0])) arg = arg.after(0); last = arg; // Insertion sort int i; for (i = 0; i < arguments.size(); i++) { int cmp = compare(arguments[i], arg); if (cmp == 0) return; // Already present if (cmp > 0) break; } arguments += "<dummy>"; for (int j = arguments.size() - 1; j > i; j--) arguments[j] = arguments[j - 1]; arguments[i] = arg; updated = false; }
// Remove and return display number from DISPLAY string read_disp_nr_str (string& display, GDBAgent *gdb) { switch (gdb->type()) { case GDB: case PYDB: case DBG: { #if RUNTIME_REGEX static regex rxgdb_disp_nr("[1-9][0-9]*"); #endif string disp_nr = display.through (rxgdb_disp_nr); display = display.after (": "); return disp_nr; } case DBX: return read_disp_name(display, gdb); case XDB: case JDB: case PERL: case BASH: return ""; // FIXME } return ""; }
void BreakPoint::process_jdb(string& info_output) { int colon = info_output.index(':'); if (colon >= 0) { string class_name = info_output.before(colon); int line_no = get_positive_nr(info_output.after(colon)); if (line_no >= 0 && !class_name.empty()) { // Strip JDB 1.2 info like `breakpoint', etc. strip_space(class_name); int last_space = class_name.index(" ", -1); if (last_space > 0) class_name = class_name.after(last_space); myfile_name = class_name; myline_nr = line_no; // Kill this line int beginning_of_line = colon; while (beginning_of_line >= 0 && info_output[beginning_of_line] != '\n') beginning_of_line--; beginning_of_line++; int next_nl = info_output.index('\n', colon); if (next_nl >= 0) info_output = info_output.before(beginning_of_line) + info_output.from(next_nl); else info_output = info_output.before(beginning_of_line); } } }
// 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; }
string set_history_filter(const string& cmd) { string arg; if (cmd.contains(" = ")) arg = cmd.after(" = "); else if (cmd.contains(" := ")) arg = cmd.after(" := "); if (!arg.empty()) { strip_space(arg); return arg; } return ""; }
static bool try_arg(const string& cmd, const string& prefix_, string& arg) { if (prefix_.empty()) return false; // No such command string prefix( prefix_ ); if (!prefix.contains(" ", -1)) prefix += " "; if (cmd.contains(prefix, 0)) { arg = cmd.after(prefix); strip_space(arg); // Strip format stuff while (arg.contains('/', 0)) arg = arg.after(' '); if (arg.contains("'", 0)) { // Quoted arg -- add as unquoted arg = unquote(arg); return true; } else if (is_file_pos(arg)) { // FILE:LINE arg -- ignore return false; } else if (arg.matches(rxint)) { // LINE arg -- ignore return false; } else { // Other arg -- add unchanged return true; } } // Bad prefix -- ignore return false; }
// Remove and return "NR: " from DISPLAY. string get_info_disp_str (string& display_info, GDBAgent *gdb) { switch (gdb->type()) { case GDB: case PYDB: return display_info.after (": "); case DBX: return display_info.after (") "); case XDB: case JDB: case PERL: return ""; // FIXME } return ""; }
static void gdbEditOutputHP(Agent *, void *, void *call_data) { DataLength *input = (DataLength *)call_data; output_buffer += string(input->data, input->length); while (output_buffer.contains('\n')) { set_status(output_buffer.before('\n')); output_buffer = output_buffer.after('\n'); } if (output_buffer != "") set_status(output_buffer); }
// In FORTRAN mode, GDB issues last dimensions first. Insert new // dimension before first dimension and convert to FORTRAN // multi-dimension syntax. string DispValue::add_member_name(const string& base, const string& member_name) { if (gdb->program_language() == LANGUAGE_FORTRAN && member_name.contains('(', 0) && base.contains('(')) { return base.before('(') + member_name.before(')') + ", " + base.after('('); } return base + member_name; }
bool add_running_arguments(string& cmd, Widget origin) { if (cmd == "run") cmd = gdb->rerun_command(); if (gdb->type() != JDB) return true; // Ok, perform the command if (!is_run_cmd(cmd)) return true; // Ok, perform the command strip_leading_space(cmd); string args = cmd.after(rxwhite); ProgramInfo info; if (args.empty() && gdb->has_debug_command()) { // JDB 1.1 requires at least a class name after the `run' command. cmd += " " + info.file; } if (info.running && !gdb->has_debug_command()) { // JDB 1.2 cannot rerun a program after it has been started. // Offer to restart JDB instead. static Widget restart_jdb = 0; static string saved_run_command; if (restart_jdb == 0) { restart_jdb = verify(XmCreateQuestionDialog(find_shell(origin), XMST("confirm_restart_gdb_dialog"), ArgList(0), 0)); Delay::register_shell(restart_jdb); XtAddCallback(restart_jdb, XmNhelpCallback, ImmediateHelpCB, XtPointer(0)); XtAddCallback(restart_jdb, XmNokCallback, RestartAndRunCB, (XtPointer)&saved_run_command); } saved_run_command = cmd; XtManageChild(restart_jdb); return false; // Don't perform the command yet } return true; }
// Return next display from DISPLAYS ("" if none); remove it from // DISPLAYS string read_next_display (string& displays, GDBAgent *gdb) { string next_display; strip_leading_space(displays); // string old_displays = displays; // std::clog << "read_next_display(" << quote(old_displays) << ")...\n"; if (is_disabling(displays, gdb)) { // After a `disabling' message, `display' output finishes next_display = displays; displays = ""; } else { for (;;) { next_display += read_token(displays); if (displays.empty()) break; // All done if (next_display.contains(":()", -1)) { // AIX DBX gives weird `members' like // "pcg = OM_PCGDownCasters:()\n(_root = 0x2004c248 ..." // Be sure to continue such displays. continue; } if (next_is_nl(displays)) break; // At end of display } } displays = displays.after('\n'); strip_leading_space(displays); // std::clog << "read_next_display(" << quote(old_displays) << ") = " // << quote(next_display) << "\n"; return next_display; }
// Return the Nth component from NAME, or DEFAULT_VALUE if none static string component(string name, FontComponent n) { // If name does not begin with `-', assume it's a font family if (!name.contains('-', 0)) name.prepend("-*-"); // Let I point to the Nth occurrence of `-' int i = -1; while (n >= Foundry && (i = name.index('-', i + 1)) >= 0) n--; string w; if (i >= 0) { w = name.after(i); if (w.contains('-')) w = w.before('-'); } return w; }
// Filter all lines from ANSWER beginning with LINE. This is required // to suppress the line number output after a `stopping in' message. void PosBuffer::filter_line(string& answer) const { if (already_read != PosComplete) return; string line_s = pos_buffer; if (line_s.contains(':')) line_s = line_s.after(':'); int line = atoi(line_s.chars()); if (line <= 0) return; int pos = 0; do { if (atoi(answer.chars() + pos) == line) { answer = answer.before(pos) + answer.after('\n', pos); break; } pos = answer.index('\n', pos) + 1; } while (pos > 0); }
string display_history_filter(const string& cmd) { if (cmd.contains("graph display ", 0)) { string arg = cmd.after("graph display "); if (arg.contains("dependent on")) arg = arg.before("dependent on"); if (arg.contains("now or")) arg = arg.before("now or"); if (arg.contains("when in")) arg = arg.before("when in"); strip_space(arg); // Strip format stuff while (arg.contains('/', 0)) arg = arg.after(' '); strip_space(arg); return arg; } return ""; }
// Handle incremental searches; return true if processed static bool do_isearch(Widget, XmTextVerifyCallbackStruct *change) { if (isearch_state == ISEARCH_NONE) return false; string saved_isearch_string = isearch_string; bool processed = false; if (change->startPos == change->endPos) { // Character insertion string input = string(change->text->ptr, change->text->length); if (!input.contains('\n', -1)) { // Add to current search string isearch_string += input; processed = true; } } else if (change->endPos - change->startPos == 1) { // Backspace - remove last character from search string if (!isearch_string.empty()) isearch_string.after(int(isearch_string.length()) - 2) = ""; else clear_isearch(true, false); processed = true; } if (processed) { int history = -1; if (isearch_string.empty() || current_line().contains(isearch_string)) { // Search string found in current line history = -1; } else { history = search_history(isearch_string, int(isearch_state)); if (history < 0) { // Search string not found in history if (change->event != 0) XtCallActionProc(gdb_w, "beep", change->event, 0, 0); isearch_string = saved_isearch_string; } } // Make this a no-op if (!have_isearch_line) { isearch_line = current_line(); have_isearch_line = true; } // Redraw current line with appropriate prompt. XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, isearch_done, XtPointer(history)); // Upon the next call to gdbMotionCB(), clear ISearch mode, // unless it immediately follows this one. isearch_motion_ok = true; XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 10, set_isearch_motion_ok, XtPointer(false)); } return processed; }
// Set history file name void process_history_filename(string answer) { answer = answer.after('"'); answer = answer.before('"'); set_gdb_history_file(answer); }
void BreakPoint::process_perl(string& info_output) { // Format: [FILE:] // LINE_NO: LINE // INFO 1 // INFO 2 ... if (!info_output.contains(' ', 0)) { const string first_line = info_output.before('\n'); if (first_line.contains(':', -1)) { // Get leading file name myfile_name = first_line.before(':'); info_output = info_output.after('\n'); } } static const StringArray empty; mycommands = empty; myline_nr = atoi(info_output.chars()); info_output = info_output.after('\n'); bool break_seen = false; while (info_output.contains(" ", 0)) { string info = info_output.before('\n'); info_output = info_output.after('\n'); strip_space(info); if (info.contains("break if ", 0)) { string cond = info.after(" if "); while (cond.contains('(', 0) && cond.contains(')', -1)) cond = unquote(cond); if (cond == "1") cond = ""; mycondition = cond; break_seen = true; } else if (info.contains("action: ", 0)) { string commands = info.after(':'); strip_space(commands); if (commands.contains("d " + itostring(line_nr()))) mydispo = BPDEL; // Temporary breakpoint string command = ""; while (!commands.empty()) { const string token = read_token(commands); if (token != ";") command += token; if (token == ";" || commands.empty()) { strip_space(command); if (!command.empty()) { mycommands += command; command = ""; } } } } else { myinfos += info + '\n'; } } if (!break_seen) mytype = ACTIONPOINT; }
void BreakPoint::process_dbx(string& info_output) { if (info_output.contains("PC==", 0) || info_output.contains("stop ", 0) || info_output.contains("stopped ", 0)) { // Breakpoint info_output = info_output.after(rxblanks_or_tabs); strip_leading_space (info_output); if (info_output.contains ("at ", 0)) { info_output = info_output.after(rxblanks_or_tabs); string file_name; if (info_output.contains('"', 0)) { // `stop at "FILE":LINE' file_name = unquote(info_output.before(":")); info_output = info_output.after (":"); } else if (info_output.contains('[', 0)) { // `stop at [file:line ...]' file_name = info_output.before(":"); file_name = file_name.after('['); info_output = info_output.after (":"); } else { // `stop at LINE' file_name = ""; } int new_line_nr = 0; if (!info_output.empty() && isdigit(info_output[0])) new_line_nr = get_positive_nr(info_output); if (!file_name.empty()) myfile_name = file_name; if (new_line_nr != 0) myline_nr = new_line_nr; // DBX issues either locations or functions myfunc = ""; } else if (info_output.contains ("in ", 0)) { string line = info_output.after("in "); if (line.contains('\n')) line = line.before('\n'); if (line.contains("\":")) { // Ladebug output: // `PC==x in TYPE FUNC(ARGS...) "FILE":LINE { COMMANDS } myfile_name = line.after("\""); myfile_name = myfile_name.before("\""); myline_nr = get_positive_nr(line.after("\":")); myfunc = line.before("\""); strip_space(myfunc); // Be sure to remove TYPE while (myfunc.contains(" ")) myfunc = myfunc.after(" "); } else { // DBX output: // `stop in FUNC' myfunc = line.before(rxblanks_or_tabs); strip_space(myfunc); myfile_name = ""; myline_nr = 0; // Attempt to get exact position of FUNC const string pos = dbx_lookup(myfunc); if (!pos.empty()) { const string file_name = pos.before(":"); const string line_s = pos.after(":"); int new_line_nr = get_positive_nr(line_s); myfile_name = file_name; if (new_line_nr != 0) myline_nr = new_line_nr; } } } else { // `stop VAR' mytype = WATCHPOINT; mywatch_mode = WATCH_CHANGE; string expr = info_output; if (expr.contains('\n')) expr = expr.before('\n'); if (expr.contains(rxblanks_or_tabs)) expr = expr.before(rxblanks_or_tabs); myexpr = expr; } // Sun DBX 3.0 issues extra characters like // (2) stop in main -count 0/10 // [3] stop in main -disable string options; if (info_output.contains('\n')) options = info_output.before('\n'); else options = info_output; bool new_enabled = !options.contains(" -disable"); myenabled = new_enabled; myinfos = ""; if (options.contains(" -count ")) { string count = options.after(" -count "); strip_leading_space(count); if (count.contains(' ')) count = count.before(' '); myinfos = "count " + count; if (count.contains('/')) count = count.after('/'); myignore_count = atoi(count.chars()); } if (options.contains(" if ") || options.contains(" -if ")) { string cond = options.after("if "); if (!myinfos.empty()) myinfos += '\n'; myinfos += "stop only if " + cond; mycondition = cond; } } info_output = info_output.after('\n'); }
void BreakPoint::process_xdb(string& info_output) { // Strip leading `:'. // Bob Wiegand <*****@*****.**> if (info_output.contains(':', 0)) info_output = info_output.after(0); strip_leading_space(info_output); // Skip `count: N' if (info_output.contains("count:", 0)) { info_output = info_output.after("count:"); strip_leading_space(info_output); string count = info_output.before(rxblanks_or_tabs); info_output = info_output.after(rxblanks_or_tabs); myignore_count = atoi(count.chars()); } // Check for `Active' or `Suspended' and strip them // Bob Wiegand <*****@*****.**> if (info_output.contains("Active", 0)) { info_output = info_output.after("Active"); myenabled = true; } else if (info_output.contains("Suspended", 0)) { info_output = info_output.after("Suspended"); myenabled = false; } // Get function name and position info_output = info_output.after(rxblanks_or_tabs); myfunc = info_output.before(": "); const string pos = dbx_lookup(myfunc); if (!pos.empty()) { myfile_name = pos.before(":"); } info_output = info_output.after(": "); myline_nr = get_positive_nr(info_output); info_output = info_output.after('\n'); // Examine commands for condition string commands = info_output; strip_leading_space(commands); if (commands.contains('{', 0)) { // A condition has the form `{if COND {} {Q; c}}'. if (commands.contains("{if ", 0)) { string cond = commands.after("{if "); cond = cond.before('{'); strip_space(cond); mycondition = cond; } // Skip this line, too info_output = info_output.after('\n'); } }
// Return commands to restore this breakpoint, using the dummy number // NR. If AS_DUMMY is set, delete the breakpoint immediately in order // to increase the breakpoint number. If ADDR is set, use ADDR as // (fake) address. If COND is set, use COND as (fake) condition. // Return true iff successful. bool BreakPoint::get_state(std::ostream& os, int nr, bool as_dummy, string pos, string cond) { if (pos.empty()) { if (line_nr() > 0) pos = file_name() + ":" + itostring(line_nr()); else pos = string('*') + address(); } if (cond == char(-1)) cond = real_condition(); const string num = "@" + itostring(nr) + "@"; switch (gdb->type()) { case BASH: case GDB: case MAKE: case PYDB: case DBG: { switch (type()) { case BREAKPOINT: { switch (dispo()) { case BPKEEP: case BPDIS: os << "break " << pos << "\n"; break; case BPDEL: os << "tbreak " << pos << "\n"; break; } break; } case WATCHPOINT: { os << gdb->watch_command(expr(), watch_mode()) << "\n"; break; } case TRACEPOINT: case ACTIONPOINT: { // Not handled - FIXME break; } } if (!as_dummy) { // Extra infos if (!enabled() && gdb->has_disable_command()) os << gdb->disable_command(num) << "\n"; int ignore = ignore_count(); if (ignore > 0 && gdb->has_ignore_command()) os << gdb->ignore_command(num, ignore) << "\n"; if (!cond.empty() && gdb->has_condition_command()) os << gdb->condition_command(num, cond) << "\n"; if (commands().size() != 0) { os << "commands " << num << "\n"; for (int i = 0; i < commands().size(); i++) os << commands()[i] << "\n"; os << "end\n"; } } break; } case DBX: { string cond_suffix = ""; if (!cond.empty()) { if (gdb->has_handler_command()) cond_suffix = " -if " + cond; else cond_suffix = " if " + cond; } switch (type()) { case BREAKPOINT: if (!func().empty()) { os << "stop in " << func() << "\n"; } else if (pos.contains('*', 0)) { os << "stop at " << pos.after('*') << cond_suffix << '\n'; } else { os << "file " << pos.before(':') << "\n"; os << "stop at " << pos.after(':') << cond_suffix << "\n"; } break; case WATCHPOINT: os << "stop " << expr() << cond_suffix << '\n'; break; case TRACEPOINT: case ACTIONPOINT: { // Not handled - FIXME break; } } if (!as_dummy) { // Extra infos if (!enabled() && gdb->has_disable_command()) os << gdb->disable_command(num) << "\n"; int ignore = ignore_count(); if (ignore > 0 && gdb->has_ignore_command()) os << gdb->ignore_command(num, ignore) << "\n"; } break; } case JDB: { os << "stop at " << pos << "\n"; break; } case XDB: { string cond_suffix; if (!cond.empty() && !gdb->has_condition_command()) cond_suffix = " {if " + cond + " {} {Q;c}}"; if (pos.contains('*', 0)) os << "ba " << pos.after('*') << cond_suffix << '\n'; else os << "b " << pos << cond_suffix << "\n"; if (!as_dummy) { // Extra infos if (!enabled() && gdb->has_disable_command()) os << gdb->disable_command(num) << "\n"; int ignore = ignore_count(); if (ignore > 0 && gdb->has_ignore_command()) os << gdb->ignore_command(num, ignore) << "\n"; } break; } case PERL: { string cond_suffix; if (!cond.empty()) cond_suffix = " " + cond; os << "f " << pos.before(':') << "\n"; if (type() == BREAKPOINT) os << "b " << pos.after(':') << cond_suffix << "\n"; if (commands().size() != 0) { os << "a " << pos.after(':') << " "; for (int i = 0; i < commands().size(); i++) os << commands()[i] << ";"; os << "\n"; } break; } } if (as_dummy && gdb->has_delete_command()) { // Delete the breakpoint just created os << gdb->delete_command(num) << "\n"; } return true; }
void BreakPoint::process_gdb(string& info_output) { // Read type (`breakpoint' or `watchpoint') // The type may be prefixed by `hw ' or other details. const string word1 = info_output.before('\n'); const string word2 = word1.after(rxblanks_or_tabs); if (word1.contains("watchpoint", 0) || word2.contains("watchpoint", 0)) { mytype = WATCHPOINT; // Fetch breakpoint mode detail (`acc' or `read') if (word1.contains("acc ", 0)) mywatch_mode = WATCH_ACCESS; else if (word1.contains("read ", 0)) mywatch_mode = WATCH_READ; else mywatch_mode = WATCH_CHANGE; } else if (word1.contains("breakpoint", 0) || word2.contains("breakpoint", 0)) { mytype = BREAKPOINT; } info_output = info_output.after("point"); info_output = info_output.after(rxblanks_or_tabs); // Read disposition (`dis', `del', or `keep') if (info_output.contains("dis", 0)) { mydispo = BPDIS; } else if (info_output.contains("del", 0)) { mydispo = BPDEL; } else if (info_output.contains("keep", 0)) { mydispo = BPKEEP; } info_output = info_output.after(rxblanks_or_tabs); // Read enabled flag (`y' or `n') if (info_output.contains('y', 0)) { myenabled = true; } else if (info_output.contains('n', 0)) { myenabled = false; } info_output = info_output.after(rxblanks_or_tabs); string new_info = ""; if (mytype == BREAKPOINT) { if (MAKE != gdb->type() && BASH != gdb->type()) { // Read address myaddress = info_output.through(rxalphanum); info_output = info_output.after(myaddress); strip_leading_space(info_output); } if (BASH != gdb->type()) { if (info_output.contains("in ", 0)) { // Function name string func = info_output.after("in "); if (func.contains('\n')) func = func.before('\n'); if (func.contains(" at ")) func = func.before(" at "); strip_space(func); myfunc = func; } } // Location string remainder = info_output.through('\n'); info_output = info_output.after('\n'); // GDB 5.0 may issue an (indented) file name in the following line if (!remainder.contains(rxname_colon_int_nl)) { remainder += info_output.through('\n'); if (remainder.contains(rxname_colon_int_nl)) info_output = info_output.after('\n'); } remainder = remainder.from(rxname_colon_int_nl); myfile_name = remainder.before(":"); remainder = remainder.after(":"); if (!remainder.empty() && isdigit(remainder[0])) myline_nr = get_positive_nr(remainder); } else if (mytype == WATCHPOINT) { // Read watched expression myexpr = info_output.before('\n'); info_output = info_output.after('\n'); } int ignore_count = 0; string cond = ""; StringArray commands; if (!info_output.empty() && !isdigit(info_output[0])) { // Extra info follows int next_nl = index(info_output, rxnl_int, "\n"); if (next_nl == -1) { new_info += info_output; info_output = ""; } else { new_info += info_output.through(next_nl); info_output = info_output.after(next_nl); } int n = new_info.freq('\n'); string *lines = new string[n + 1]; split(new_info, lines, n + 1, '\n'); string newer_info = ""; for (int i = 0; i < n; i++) { bool save_info = true; string line = lines[i]; bool starts_with_space = (!line.empty() && isspace(line[0])); strip_leading_space(line); if (line.contains("ignore next ", 0)) { // Fetch ignore count string count = line.after("ignore next "); count = count.before(" hits"); ignore_count = atoi(count.chars()); } else if (line.contains("stop only if ", 0)) { // Fetch condition cond = line.after("stop only if "); } else if (line.contains("stop ", 0)) { // Any info (no GDB command starts with `stop') } else if (line.contains("breakpoint ", 0)) { // Any info (no GDB command starts with `breakpoint') } else if (starts_with_space) { // A command (GDB indents all commands) commands += line; save_info = false; } else { // Some other info } if (save_info) newer_info += line + '\n'; } new_info = newer_info; delete[] lines; } myinfos = new_info; myignore_count = ignore_count; mycondition = cond; mycommands = commands; }
void PosBuffer::filter_dbx(string& answer) { string file; // File name found string line; // Line number found // When reaching a breakpoint, DBX issues the breakpoint // number before the status line. Check for this and // initialize defaults from breakpoint position. strip_leading_space(answer); if (answer.contains('(', 0) || answer.contains('[', 0)) { // Get breakpoint position string ans = answer; int num = read_positive_nr(ans); string pos = source_view->bp_pos(num); if (!pos.empty()) { file = pos.before(':'); line = pos.after(':'); } } // DEC DBX way issue warnings like // `warning: "./cxxtest.C":157 has no code associated with it' // right within the position info. int start_of_warning = answer.index("\nwarning"); if (start_of_warning >= 0) { int open_bracket = answer.index('['); int close_bracket = answer.index(']'); if (open_bracket >= 0 && open_bracket < start_of_warning && close_bracket >= 0 && close_bracket > start_of_warning) { // Remove warning int end_of_warning = answer.index('\n', start_of_warning + 1); while (end_of_warning < int(answer.length()) && answer[end_of_warning] == '\n') end_of_warning++; while (start_of_warning > 0 && answer[start_of_warning - 1] == '\n') start_of_warning--; int warning_length = end_of_warning - start_of_warning; answer.at(start_of_warning, warning_length) = ""; } } #if RUNTIME_REGEX static regex rxdbxfunc2( ".*line *[1-9][0-9]* *in *(file *)?\"[^\"]*\"\n.*"); #endif if (already_read != PosComplete && answer.matches(rxdbxfunc2)) { // AIX DBX issues `up', `down' and `func' output // in the format `FUNCTION(ARGS), line LINE in "FILE"'. // SUN DBX uses `line LINE in file "FILE"' instead. // We check for the `line LINE' part. line = answer.after(" line "); line = line.through(rxint); file = answer.after('\"'); file = file.before('\"'); if (!line.empty()) { already_read = PosComplete; // answer = answer.after("\n"); } } #if RUNTIME_REGEX static regex rxdbxpos("[[][^]]*:[1-9][0-9]*[^]]*[]].*"); #endif int dbxpos_index = -1; if (already_read != PosComplete && (dbxpos_index = index(answer, rxdbxpos, "[")) >= 0) { // DEC DBX issues breakpoint lines in the format // "[new_tree:113 ,0x400858] \ttree->right = NULL;" line = answer.from(dbxpos_index); if (line.contains("[#", 0)) { // This is a Ladebug breakpoint, no position info. } else { // Note that the function name may contain "::" sequences. while (line.contains("::")) line = line.after("::"); line = line.after(":"); line = line.through(rxint); if (!line.empty()) { if (answer.index('\n', dbxpos_index) >= 0) { already_read = PosComplete; // Strip position info and line strip_leading_space(answer); if (answer.contains('[', 0)) answer = answer.after("\n"); } else { // Wait for `\n' such that we can delete the line answer_buffer = answer; answer = ""; already_read = PosPart; return; } } } } if (already_read != PosComplete && (answer.contains("stopped in ") || answer.contains("stopped at "))) { int stopped_index = answer.index("stopped"); assert(stopped_index >= 0); // Stop reached // AIX DBX issues lines like // `[4] stopped in unnamed block $b382 at line 4259 in file // "/msdev/sms/ms7/riosqa/src/tffi/fi2tofu.c" ($t1)' int in_file_index = answer.index("in file ", stopped_index); int bracket_index = answer.index("[", stopped_index); if (in_file_index >= 0) { // File name given file = answer.from(in_file_index); file = file.after("in file "); if (file.contains('\n')) file = file.before('\n'); if (file.contains('"', 0)) { file = file.after('"'); file = file.before('"'); } } else if (bracket_index >= 0) { // DEC DBX and SGI DBX output format: // `[3] Process 1852 (cxxtest) // stopped at [::main:266 ,0x1000a028]' line = answer.after(bracket_index); func_buffer = line; while (line.contains("::")) line = line.after("::"); line = line.from(":"); func_buffer = func_buffer.before(line); line = line.after(":"); line = line.through(rxint); // answer = answer.after("\n"); } else { // Function name given string func = answer.after(stopped_index); func = func.after("stopped"); if (func.contains(" at ")) func = func.before(" at "); func_buffer = func; } if (!func_buffer.empty()) { // With DEC's `ladebug', the function name is fully qualified, // as in `stopped at [void tree_test(void):277 0x120003f44]' // We use only the base name (`tree_test' in this case). // (We could avoid this if `ladebug' offered a way to look // up fully qualified names. Does it? - AZ) if (func_buffer.contains('(')) func_buffer = func_buffer.before('('); while (func_buffer.contains(' ')) func_buffer = func_buffer.after(' '); } if (line.empty()) { line = answer.after("at line ", stopped_index); line = line.through(rxint); if ((!file.empty() || !func_buffer.empty()) && !answer.contains("at line ")) line = "0"; } if (!line.empty()) already_read = PosComplete; } #if RUNTIME_REGEX static regex rxdbxfunc("[a-zA-Z_][^[]*: *[1-9][0-9]* *.*"); #endif if (already_read != PosComplete && answer.matches(rxdbxfunc)) { // DEC DBX issues `up', `down' and `func' output // in the format `FUNCTION: LINE TEXT' // Note that the function name may contain "::" sequences. line = answer; while (line.contains("::")) line = line.after("::"); line = line.after(":"); strip_leading_space(line); if (line.contains(rxint, 0)) { line = line.through(rxint); if (!line.empty()) { if (answer.contains('\n')) { // Got it! already_read = PosComplete; answer = answer.after("\n"); } else { // Wait for `\n' such that we can delete the line answer_buffer = answer; answer = ""; already_read = PosPart; return; } } } } if (already_read != PosComplete && answer.contains("Current function is ")) { // Up/Down command entered string nr = answer.after("\n"); if (!nr.empty()) { line = itostring(atoi(nr.chars())); already_read = PosComplete; // Show current function only answer = answer.from("Current function is "); answer = answer.through("\n"); func_buffer = answer.after("function is "); func_buffer = func_buffer.before("\n"); } else { answer_buffer = answer; answer = ""; already_read = PosPart; return; } } if (already_read != PosComplete && (!answer.contains('\n') || (answer.contains('[') && !answer.contains(']')))) { // Position info is incomplete answer_buffer = answer; answer = ""; already_read = PosPart; return; } if (already_read == PosComplete && !line.empty()) { if (!file.empty()) pos_buffer = file + ":" + line; else pos_buffer = line; } if (already_read == PosComplete && pos_buffer.empty()) already_read = Null; }
void PosBuffer::filter_gdb(string& answer) { // Try to find out current PC even for non-existent source if (check_pc && pc_buffer.empty()) { // `$pc = ADDRESS' #if RUNTIME_REGEX static regex rxpc("\\$pc *= *" RXADDRESS); #endif int pc_index = index(answer, rxpc, "$pc "); if (pc_index >= 0) { int addr_index = answer.index('='); fetch_address(answer, addr_index, pc_buffer); // Strip this line from ANSWER int end_line = answer.index('\n', pc_index); int start_line = pc_index; while (start_line > 0 && answer[start_line - 1] != '\n') start_line--; if (end_line < 0) answer.from(start_line) = ""; else answer.at(start_line, end_line - start_line + 1) = ""; } } if (check_pc && pc_buffer.empty() || check_func && func_buffer.empty()) { // `Breakpoint N, ADDRESS in FUNCTION (ARGS...)' #if RUNTIME_REGEX static regex rxstopped_addr("Breakpoint *[1-9][0-9]*, *" RXADDRESS); #endif int pc_index = index(answer, rxstopped_addr, "Breakpoint"); if (pc_index >= 0) { annotate("stopped"); pc_index = answer.index(','); fetch_address(answer, pc_index, pc_buffer); fetch_in_function(answer, pc_index, func_buffer); } } if (check_pc && pc_buffer.empty() || check_func && func_buffer.empty()) { // `#FRAME ADDRESS in FUNCTION (ARGS...)' #if RUNTIME_REGEX static regex rxframe_addr("#[0-9][0-9]* *" RXADDRESS); #endif int pc_index = index(answer, rxframe_addr, "#"); if (pc_index == 0 || pc_index > 0 && answer[pc_index - 1] == '\n') { pc_index = answer.index(' '); fetch_address(answer, pc_index, pc_buffer); fetch_in_function(answer, pc_index, func_buffer); } } if (check_pc && pc_buffer.empty() || check_func && func_buffer.empty()) { // `No line number available for // address ADDRESS <FUNCTION>' #if RUNTIME_REGEX static regex rxaddr("address *" RXADDRESS); #endif int pc_index = index(answer, rxaddr, "address "); if (pc_index >= 0) { pc_index = answer.index(' '); fetch_address(answer, pc_index, pc_buffer); if (func_buffer.empty()) { string line = answer.from(pc_index); line = line.after('<'); line = line.before('>'); if (!line.empty()) func_buffer = line; } } } if (check_pc && pc_buffer.empty() && !answer.empty()) { // `ADDRESS in FUNCTION' #if RUNTIME_REGEX static regex rxaddress_in(RXADDRESS " in "); #endif int pc_index = -1; if (is_address_start(answer[0]) && answer.contains(rxaddress_in, 0)) { pc_index = 0; } else { #if RUNTIME_REGEX static regex rxnladdress_in("\n" RXADDRESS " in "); #endif pc_index = index(answer, rxnladdress_in, "\n"); } if (pc_index >= 0) { fetch_address(answer, pc_index, pc_buffer); fetch_in_function(answer, pc_index, func_buffer); } } // Try to find out current function name, even for // non-existing addresses if (check_func && func_buffer.empty()) { // `Breakpoint N, FUNCTION (ARGS...)' // This regex used for PYDB as well. #if RUNTIME_REGEX static regex rxstopped_func("Breakpoint *[1-9][0-9]*, *"); #endif int bp_index = index(answer, rxstopped_func, "Breakpoint"); if (bp_index >= 0) fetch_function(answer, bp_index, func_buffer); } if (check_func && func_buffer.empty()) { // `#FRAME FUNCTION' #if RUNTIME_REGEX static regex rxframe_func("#[0-9][0-9]* *[a-zA-Z_].*[(]"); #endif int frame_index = index(answer, rxframe_addr, "#"); if (frame_index == 0 || frame_index > 0 && answer[frame_index - 1] == '\n') { fetch_function(answer, frame_index, func_buffer); } } if (check_func && func_buffer.empty()) { // FUNCTION (ARGS...) at FILE:POS int at_index = answer.index(" at "); if (at_index > 0) { int nl_index = answer.index('\n', at_index - answer.length() - 1) + 1; fetch_function(answer, nl_index, func_buffer); // Try to construct position from `at FILE:POS' (vxworks) string file = answer.after(" at "); file = file.before('\n'); if (file.contains(rxaddress, 0)) { // This is `at ADDRESS' (GDB output) } else if (file.contains(":") && !file.contains(": ")) { pos_buffer = file; already_read = PosComplete; return; } } } // Look for regular source info // (GDB's annotations are prefixed with "^Z^Z") int index1 = answer.index ("\032\032"); if (index1 < 0) { int index_p = answer.index ("\032"); if (index_p >= 0 && index_p == int(answer.length()) - 1) { // Possible begin of position info at end of ANSWER answer_buffer = "\032"; answer = answer.before (index_p); already_read = PosPart; return; } // Handle erroneous `info line' output like // `Line number 10 is out of range for "t1.f".' // At least get the file name. #if RUNTIME_REGEX static regex rxout_of_range( "Line number [0-9]+ is out of range for "); #endif index_p = index(answer, rxout_of_range, "Line number"); if (index_p >= 0) { string file = answer.after('\"', index_p); file = file.before('\"'); pos_buffer = file + ":1"; already_read = PosComplete; return; } // Try to construct position from `Line xxxx of "filename"' (vxworks) // which is the output of an 'info line' command string line = answer.after("Line "); string file = answer.after('\"'); if (!line.empty() && !file.empty()) { line = line.before(" of"); file = file.before('\"') + ":" + line; if (!line.empty() && !file.empty()) { pos_buffer = file; already_read = PosComplete; return; } } // Try FUNCTION (ARGS...) at FILE:POS // here to properly handle up/down commands int at_index = answer.index(" at "); int br_index = answer.index("Break"); if ( (at_index > 0) && (br_index < 0) ) { int nl_index = answer.index('\n', at_index - answer.length() - 1) + 1; fetch_function(answer, nl_index, func_buffer); // Try to construct position from `at FILE:POS' (vxworks) string file = answer.after(" at "); file = file.before('\n'); if (!file.empty()) { pos_buffer = file; already_read = PosComplete; return; } } // Nothing found return; } // ANSWER contains position info int index2 = answer.index ("\n", index1); if (index2 == -1) { // Position info is incomplete answer_buffer = answer.from (index1); answer = answer.before (index1); already_read = PosPart; return; } assert (index1 < index2); // Position info is complete pos_buffer = answer.at(index1 + 2, index2 - (index1 + 2)); if (pos_buffer.contains("source ", 0)) { // This happens with GDB in annotation level 2 pos_buffer = pos_buffer.after("source "); } int last_colon = pos_buffer.index(':', -1); pc_buffer = pos_buffer.after(last_colon); if (!pc_buffer.contains(rxaddress_start, 0)) pc_buffer = "0x" + pc_buffer; pc_buffer = pc_buffer.through(rxaddress); answer.at(index1, index2 - index1 + 1) = ""; if (!pos_buffer.empty()) already_read = PosComplete; }
int line_of_listing(string& listing, bool silent) { string message; while (!listing.empty() && !listing.contains('>', 0) && !listing.contains('*', 1) && atoi(listing.chars()) == 0) { message += listing.through('\n'); listing = listing.after('\n'); } if (!silent) post_gdb_message(message); int idx = -1; if (idx < 0 && gdb->type() == JDB) { // JDB issues `=>' in the listed line int idx = listing.index("\t=> \t"); while (idx > 0 && listing[idx - 1] != '\n') idx--; } if (idx < 0 && gdb->type() == DBX) { // SGI DBX issues `*' in column 2 before the `list'ed line. // Quite useful. #if RUNTIME_REGEX static regex rxnlstar("\n.[*]"); #endif int idx = index(listing, rxnlstar, "\n"); if (idx < 0 && listing.contains('*', 1)) idx = 1; } if (idx < 0 && gdb->type() == DBX) { // DEC and SGI DBX issue `>' in column 1 before the current // execution line. Quite useful. int idx = listing.index("\n>"); if (idx < 0 && listing.contains('>', 0)) idx = 0; } // Use the first number found. int num_idx = listing.index(rxint, max(idx, 0)); int line = 0; if (num_idx >= 0) line = atoi(listing.chars() + num_idx); if (line == 0) { // Weird. No source? } else if (idx < 0) { // No indicator found - // the position we are looking for is in the middle line += (listing.freq('\n') + 1) / 2 - 1; } return line; }
// Fetch position from GDB output ANSWER. void PosBuffer::filter (string& answer) { if (answer.length() == 0) return; // Check program state switch (gdb->type()) { case BASH: { if (has_prefix(answer, "Reading ")) started = true; break; } case GDB: { // If GDB prints a "Current function" line, it overrides whatever // came before (e.g. "stopped in"). if (has_prefix(answer, "Current function is ")) already_read= Null; // Check program state if (has_prefix(answer, "Starting program: ")) started = true; if (has_prefix(answer, "The program no longer exists")) terminated = true; if (has_prefix(answer, "Program received signal")) signaled = true; if (has_prefix(answer, "Program terminated with signal")) signaled = terminated = true; if (answer.contains("has changed; re-reading symbols")) recompiled = true; if (has_prefix(answer, "Current language: ")) gdb->program_language(answer); if (has_prefix(answer, "The current source language is ")) gdb->program_language(answer); if (terminated) annotate("exited"); if (signaled) annotate("signalled"); } break; case DBG: { // Check program state if (has_prefix(answer, "Starting program: ")) started = true; } break; case DBX: { if (has_prefix(answer, "Running: ")) started = true; if (answer.contains("has been recompiled")) recompiled = true; if (has_prefix(answer, "signal ")) signaled = true; } break; case MAKE: { if (has_prefix(answer, "Reading makefiles...")) started = true; break; } case PERL: { if (has_prefix(answer, "Loading DB routines from perl5db.pl")) recompiled = true; } break; case XDB: case JDB: case PYDB: break; // Nothing special } // Check for terminated program int i = -1; while ((i = answer.index("rogram", i + 1)) > 0) { int j = i; while (j > 0 && answer[j - 1] != '\n') j--; #if RUNTIME_REGEX static regex rxterminated("([Tt]he )?[Pp]rogram " "(exited|terminated" "|is not being run|no longer exists).*"); #endif if (answer.matches(rxterminated, j)) terminated = true; } if (answer.contains("no active process") || answer.contains("execution completed") || answer.contains("application exited")) terminated = true; // Check for auto command if (app_data.auto_commands) { answer.prepend(auto_cmd_part); auto_cmd_part = ""; string pfx = app_data.auto_command_prefix; if (!auto_cmd_buffer.empty() && !auto_cmd_buffer.contains('\n', -1)) { // Complete pending auto command if (answer.contains('\n')) { auto_cmd_buffer += answer.through('\n'); answer = answer.after('\n'); } else { auto_cmd_buffer += answer; answer = ""; } } int index; while ((index = answer.index(pfx)) >= 0) { string cmd = answer.from(index); if (cmd.contains('\n')) cmd = cmd.through('\n'); answer = answer.before(index) + answer.from(int(index + cmd.length())); cmd = cmd.after(pfx); auto_cmd_buffer += cmd; } if (pfx.contains(answer, 0)) { auto_cmd_part = answer; answer = ""; } } // Fetch and store position info, return remainder switch (already_read) { case PosComplete: if (gdb->type() == GDB) filter_gdb(answer); // Slurp in the source annotation // Nothing more to filter - skip possible line number info filter_line(answer); break; case PosPart: answer.prepend (answer_buffer); answer_buffer = ""; already_read = Null; // FALL THROUGH case Null: { // Now go for the actual position. switch (gdb->type()) { case BASH: filter_bash(answer); break; case DBG: filter_dbg(answer); break; case DBX: filter_dbx(answer); break; case GDB: filter_gdb(answer); break; case JDB: filter_jdb(answer); break; case MAKE: filter_make(answer); break; case PERL: filter_perl(answer); break; case PYDB: filter_pydb(answer); break; case XDB: filter_xdb(answer); break; } filter_line(answer); } break; } }
// Simulate a debugger via the DDD log LOGNAME. If a command matches // a DDD command in LOGNAME, issue the appropriate answer. void logplayer(const string& logname) { // All this is really ugly. Works well as a hack for debugging DDD, // but not really worth anything else. static std::ifstream log(logname.chars()); if (log.bad()) { (void) fopen(logname.chars(), "r"); perror(logname.chars()); exit(EXIT_FAILURE); } put("[Playing " + quote(logname) + ". Use `?' for help]\n"); static string out; static string ddd_line; static string last_prompt; static bool initializing = true; static bool scanning = false; static bool out_seen = false; static bool wrapped = false; static bool echoing = false; static STREAMPOS scan_start, last_input; static string expecting; static int command_no = 0; static int command_no_start = 0; static bool ignore_next_input = false; signal(SIGINT, (SignalProc)intr); if (setjmp(main_loop_env) != 0) { put("Quit\n"); scanning = false; wrapped = false; log.clear(); log.seekg(last_input); command_no = command_no_start; out = ""; ddd_line = ""; ignore_next_input = true; } for (;;) { STREAMPOS current = log.tellg(); if (!scanning) { scan_start = current; command_no_start = command_no; } // Read line from log char buffer[65536]; log.getline(buffer, sizeof buffer); if (!log.fail()) { string log_line(buffer); if (out_seen && log_line.contains(" ", 0)) { // Continuation line out += unquote(log_line.from('"')); } else if (!out.empty()) { // Send out accumulated output if (!scanning) { if (out.contains(ddd_line, 0)) echoing = true; put(out); } out = ""; } if (log_line.contains("<- ", 0)) { assert(out.empty()); // Output line out = unquote(log_line.from('"')); out_seen = true; } if (out_seen && log_line.contains("-> ", 0)) { // Handle input string in = unquote(log_line.from('"')); if (in.contains('\n', -1)) in = in.before('\n', -1); command_no++; if (ddd_line.contains('/', 0) || ddd_line.contains(':', 0)) { static string pattern; char c = ddd_line[0]; string p = ddd_line.after(0); if (!p.empty() || c == ':') pattern = p; if (pattern.empty() || (c == ':' && command_no == atoi(pattern.chars())) || (c == '/' && (pattern.empty() || in.contains(pattern)))) { // Report line char buffer[256]; sprintf(buffer, "%4d", command_no); std::ostringstream os; os << buffer << " " << in << "\n"; put(os); if (c == '/' || !pattern.empty()) { // Stop here scanning = false; scan_start = current; command_no_start = command_no - 1; } } } if (!scanning) { last_input = scan_start; initializing = false; // Read command from DDD if (last_output.contains('\n')) { string prompt = last_output.after('\n', -1); if (!prompt.empty() && !prompt.contains('\\', 0)) { if (prompt.contains('(')) prompt = prompt.from('(', -1); last_prompt = prompt; } } if (!last_output.contains(last_prompt, -1)) put(last_prompt); last_output = ""; char *s = fgets(buffer, sizeof buffer, stdin); if (ignore_next_input) { s = fgets(buffer, sizeof buffer, stdin); ignore_next_input = false; } if (s == 0) exit(EXIT_SUCCESS); ddd_line = buffer; if (ddd_line.contains('\n', -1)) ddd_line = ddd_line.before('\n', -1); if (echoing && !ddd_line.empty() && !isalpha(ddd_line[0])) put(ddd_line + "\r\n"); if (ddd_line.contains('q', 0)) exit(EXIT_SUCCESS); if ((ddd_line.contains("list ", 0) || ddd_line.contains("l ", 0)) && (ddd_line.contains(" 1,") || ddd_line.contains(":1,") || ddd_line.contains(" 1-"))) { // Send the log file instead of a source if (echoing) put(ddd_line + "\r\n"); std::ifstream is(logname.chars()); int line = 1; bool at_start_of_line = true; std::ostringstream os; for (;;) { char c; is.get(c); if (is.eof()) break; if (at_start_of_line) { os << line << '\t'; at_start_of_line = false; } os << c; if (c == '\n') { line++; at_start_of_line = true; } } put(string(os)); scanning = false; } } if (!scanning && ddd_line == ".") { std::ostringstream os; os << "Expecting " << command_no << " " << quote(in) << "\n"; put(os); log.seekg(scan_start); command_no = command_no_start; } else if (!scanning && ddd_line == "?") { put(usage); log.seekg(scan_start); command_no = command_no_start; } else if (ddd_line == in || ddd_line == "!" || ddd_line.empty()) { // Okay, got it scanning = false; } else if (!scanning) { // Bad match: try to find this command in the log expecting = in; scanning = true; wrapped = false; } } } if (log.eof() || log.fail()) { if (scanning && wrapped) { // Nothing found. Don't reply. if (echoing && (ddd_line.empty() || isalpha(ddd_line[0]))) put(ddd_line + "\r\n"); scanning = false; log.clear(); log.seekg(scan_start); out = ""; command_no = command_no_start; } else if (initializing) { // No prompt found std::cerr << logname << ": invalid or incomplete log\n"; exit(EXIT_FAILURE); } else { // Try from the start wrapped = true; out_seen = false; log.clear(); log.seekg(0); command_no = 0; } } } }
// If LINE is an argument-setting command, add it to the list of arguments void add_to_arguments(const string& line) { if (is_set_args_cmd(line)) { string args = line.after("args"); args = args.after(rxwhite); add_argument(args, run_arguments, last_run_argument, run_arguments_updated); } else if (gdb->type() == PERL && line.contains("@ARGV = ", 0)) { // @ARGV = ('arg1', 'arg2', ) string args = line.after("('"); args.gsub("', '", " "); args = args.before("', )"); add_argument(args, run_arguments, last_run_argument, run_arguments_updated); } else if (is_run_cmd(line)) { string args; if (gdb->type() == JDB) { // `run CLASS ARGS...' args = line.after(rxwhite); args = args.after(rxwhite); } else if (gdb->type() == PERL && line.contains("exec ", 0)) { // `exec "perl -d PROGRAM ARGS..."' args = line.after("exec "); strip_leading_space(args); if (args.contains('\"', 0) || args.contains('\'', 0)) args = unquote(args); args = args.after("-d "); strip_leading_space(args); args = args.after(rxwhite); } else { // `run ARGS...' args = line.after(rxwhite); } add_argument(args, run_arguments, last_run_argument, run_arguments_updated); } else if (is_make_cmd(line)) { string args = line.after("make"); args = args.after(rxwhite); add_argument(args, make_arguments, last_make_argument, make_arguments_updated); } else if (gdb->type() == PERL && line.contains("system 'make", 0)) { string args = line.after("make"); args = args.after(rxwhite); args = args.before("'"); add_argument(args, make_arguments, last_make_argument, make_arguments_updated); } else if (is_cd_cmd(line)) { string dir = line.after("cd"); dir = dir.after(rxwhite); dir = source_view->full_path(dir); if (dir.contains('/', 0)) add_argument(dir, cd_arguments, last_cd_argument, cd_arguments_updated); } else if (gdb->type() == PERL && line.contains("chdir '", 0)) { string dir = line.after("'"); dir = dir.before("'"); add_argument(dir, cd_arguments, last_cd_argument, cd_arguments_updated); } else if (gdb->type() == PERL && is_file_cmd(line, gdb)) { string args = line.after(" -d "); args = args.after(rxwhite); // Skip file name args = args.before('\"'); add_argument(args, run_arguments, last_run_argument, run_arguments_updated); } }
// Initialization void DispValue::init(DispValue *parent, int depth, string& value, DispValueType given_type) { #if LOG_CREATE_VALUES std::clog << "Building value from " << quote(value) << "\n"; #endif // Be sure the value is not changed in memory value.consuming(true); const char *initial_value = value.chars(); static const DispValueArray empty(0); _children = empty; if (background(value.length())) { clear(); mytype = Simple; _value = "(Aborted)"; value = "Aborted\n"; return; } mytype = given_type; if (mytype == UnknownType && (parent == 0 || parent->type() == List) && print_name.empty()) mytype = Text; if (mytype == UnknownType && parent == 0 && is_user_command(print_name)) mytype = List; if (mytype == UnknownType) mytype = determine_type(value); bool ignore_repeats = (parent != 0 && parent->type() == Array); char perl_type = '\0'; switch (mytype) { case Simple: { _value = read_simple_value(value, depth, ignore_repeats); #if LOG_CREATE_VALUES std::clog << mytype << ": " << quote(_value) << "\n"; #endif perl_type = '$'; break; } case Text: { // Read in a line of text if (value.contains('\n')) _value = value.through('\n'); else _value = value; value = value.after('\n'); #if LOG_CREATE_VALUES std::clog << mytype << ": " << quote(_value) << "\n"; #endif perl_type = '$'; break; } case Pointer: { _value = read_pointer_value(value, ignore_repeats); _dereferenced = false; #if LOG_CREATE_VALUES std::clog << mytype << ": " << quote(_value) << "\n"; #endif // Hide vtable pointers. if (_value.contains("virtual table") || _value.contains("vtable")) myexpanded = false; perl_type = '$'; // In Perl, pointers may be followed by indented `pointed to' // info. Skip this. if (gdb->type() == PERL) { while (value.contains("\n ", 0)) { value = value.after("\n "); value = value.from("\n"); } } break; } case Array: { string base = normalize_base(myfull_name); _orientation = app_data.array_orientation; #if LOG_CREATE_VALUES std::clog << mytype << ": " << "\n"; #endif read_array_begin(value, myaddr); // Check for `vtable entries' prefix. string vtable_entries = read_vtable_entries(value); if (!vtable_entries.empty()) { _children += parse_child(depth, vtable_entries, myfull_name); } // Read the array elements. Assume that the type is the // same across all elements. DispValueType member_type = UnknownType; if (!_have_index_base) { _index_base = index_base(base, depth); _have_index_base = true; } int array_index = _index_base; // The array has at least one element. Otherwise, GDB // would treat it as a pointer. do { const char *repeated_value = value.chars(); string member_name = gdb->index_expr("", itostring(array_index++)); DispValue *dv = parse_child(depth, value, add_member_name(base, member_name), member_name, member_type); member_type = dv->type(); _children += dv; int repeats = read_repeats(value); if (expand_repeated_values) { // Create one value per repeat while (--repeats > 0) { member_name = gdb->index_expr("", itostring(array_index++)); string val = repeated_value; DispValue *repeated_dv = parse_child(depth, val, add_member_name(base, member_name), member_name, member_type); _children += repeated_dv; } } else { // Show repetition in member if (repeats > 1) { array_index--; #if 0 // We use the GDB `artificial array' notation here, // since repeat recognition is supported in GDB only. member_name += "@" + itostring(repeats); dv->full_name() = add_member_name(base, member_name); dv->name() = member_name; #endif dv->repeats() = repeats; array_index += repeats; } } if (background(value.length())) { init(parent, depth, value); return; } } while (read_array_next(value)); read_array_end(value); // Expand only if at top-level. myexpanded = (depth == 0 || nchildren() <= 1); #if LOG_CREATE_VALUES std::clog << mytype << " has " << nchildren() << " members\n"; #endif perl_type = '@'; break; } case List: // Some DBXes issue the local variables via a frame line, just // like `set_date(d = 0x10003060, day_of_week = Sat, day = 24, // month = 12, year = 1994)'. Make this more readable. munch_dump_line(value); // FALL THROUGH case Struct: { _orientation = app_data.struct_orientation; _member_names = app_data.show_member_names; bool found_struct_begin = false; bool read_multiple_values = false; #if LOG_CREATE_VALUES std::clog << mytype << " " << quote(myfull_name) << "\n"; #endif string member_prefix = myfull_name; string member_suffix = ""; if (mytype == List) { member_prefix = ""; read_multiple_values = true; } else { // In C and Java, `*' binds tighter than `.' if (member_prefix.contains('*', 0)) { if (gdb->program_language() == LANGUAGE_C) { // Use the C `->' operator instead member_prefix.del("*"); if (member_prefix.contains('(', 0) && member_prefix.contains(')', -1)) member_prefix = unquote(member_prefix); #if RUNTIME_REGEX static regex rxchain("[-a-zA-Z0-9::_>.`]+"); #endif if (member_prefix.matches(rxchain)) { // Simple chain of identifiers - prepend `->' member_prefix += "->"; } else { member_prefix.prepend("("); member_prefix += ")->"; } } else { member_prefix.prepend("("); member_prefix += ")."; } } else if (gdb->program_language() == LANGUAGE_PERL) { // In Perl, members of A are accessed as A{'MEMBER_NAME'} member_prefix = normalize_base(member_prefix) + "{'"; member_suffix = "'}"; } else if (gdb->program_language() == LANGUAGE_PHP) { // In PHP, members of $A are accessed as $A['MEMBER_NAME'] member_prefix = normalize_base(member_prefix) + "['"; member_suffix = "']"; } else if (gdb->program_language() == LANGUAGE_FORTRAN) { // In Fortran, members of A are accessed as A%B member_prefix = normalize_base(member_prefix) + "%"; } else { // In all other languages, members are accessed as A.B member_prefix = normalize_base(member_prefix) + "."; } // In case we do not find a struct beginning, read only one value found_struct_begin = read_struct_begin(value, myaddr); read_multiple_values = found_struct_begin; } // Prepend base class in case of multiple inheritance // FIXME: This should be passed as an argument static string baseclass_prefix; member_prefix += baseclass_prefix; int base_classes = 0; bool more_values = true; while (more_values) { // In a List, we may have `member' names like `(a + b)'. // Don't be picky about this. bool picky = (mytype == Struct); string member_name = read_member_name(value, picky); if (member_name.empty()) { // Some struct stuff that is not a member DispValue *dv = parse_child(depth, value, myfull_name, ""); if (dv->type() == Struct) { // What's this - a struct within a struct? Just // adopt the members. // (This happens when we finally found the struct // after having read all the AIX DBX base classes.) for (int i = 0; i < dv->nchildren(); i++) { DispValue *dv2 = dv->child(i)->link(); _children += dv2; } dv->unlink(); } else { _children += dv; } more_values = read_multiple_values && read_struct_next(value); } else if (is_BaseClass_name(member_name)) { // Base class member string saved_baseclass_prefix = baseclass_prefix; base_classes++; if (base_classes > 1) { // Multiple inheritance. Be sure to // reference further members unambiguously. // // Note: we don't do that for the first base class, // because this might turn ambiguous again. // // Example: // // Base // | | // I1 I2 // \ / // C // // Members of I1::Base are not prefixed, members // of I2::Base get `I2::' as base class prefix. // If we did this already for the first base class, // members of both I1 and I2 would get `Base::' as // base class prefix. switch (gdb->program_language()) { case LANGUAGE_C: // C++ baseclass_prefix = unquote(member_name) + "::"; break; default: // Do nothing (yet) break; } } DispValue *dv = parse_child(depth, value, myfull_name, member_name); _children += dv; baseclass_prefix = saved_baseclass_prefix; more_values = read_multiple_values && read_struct_next(value); // Skip a possible `members of CLASS:' prefix read_members_prefix(value); // AIX DBX does not place a separator between base // classes and the other members, so we always // continue reading after having found a base // class. After all, the own class members are // still missing. if (mytype == Struct && !found_struct_begin) more_values = true; } else { // Ordinary member string full_name = ""; if (member_name == " ") { // Anonymous union full_name = myfull_name; } if (member_name.contains('.')) { if (gdb->has_quotes()) { // The member name contains `.' => quote it. This // happens with vtable pointers on Linux (`_vptr.'). full_name = member_prefix + quote(member_name, '\'') + member_suffix; } else { // JDB (and others?) prepend the class name // to inherited members. Omit this. full_name = member_prefix + member_name.after('.', -1) + member_suffix; } } if (full_name.empty()) { // Ordinary member full_name = member_prefix + member_name + member_suffix; } DispValue *child = parse_child(depth, value, full_name, member_name); if (child->type() == Text) { // Found a text as child - child value must be empty string empty = ""; _children += parse_child(depth, empty, full_name, member_name); string v = child->value(); strip_space(v); if (!v.empty()) _children += child; } else { _children += child; } more_values = read_multiple_values && read_struct_next(value); } if (background(value.length())) { init(parent, depth, value); return; } } if (mytype == List && !value.empty()) { // Add remaining value as text _children += parse_child(depth, value, ""); } if (found_struct_begin) { // Skip the remainder read_struct_end(value); } // Expand only if at top-level. myexpanded = (depth == 0 || nchildren() <= 1); #if LOG_CREATE_VALUES std::clog << mytype << " " << quote(myfull_name) << " has " << nchildren() << " members\n"; #endif perl_type = '%'; break; } case Reference: { myexpanded = true; int sep = value.index('@'); sep = value.index(':', sep); string ref = value.before(sep); value = value.after(sep); string addr = gdb->address_expr(myfull_name); _children += parse_child(depth, ref, addr, myfull_name, Pointer); _children += parse_child(depth, value, myfull_name); if (background(value.length())) { init(parent, depth, value); return; } perl_type = '$'; // No such thing in Perl... break; } case Sequence: case UnknownType: assert(0); abort(); } // Handle trailing stuff (`sequences') if (parent == 0 || parent->type() != Sequence) { bool need_clear = true; while (sequence_pending(value, parent)) { if (need_clear) { #if LOG_CREATE_VALUES std::clog << "Sequence detected at " << quote(value) << "\n"; #endif clear(); value = initial_value; mytype = Sequence; #if LOG_CREATE_VALUES std::clog << mytype << " " << quote(myfull_name) << "\n"; #endif need_clear = false; } const char *old_value = value.chars(); DispValue *dv = parse_child(depth, value, myfull_name); if (value == old_value) { // Nothing consumed - stop here dv->unlink(); break; } else if (dv->type() == Simple && dv->value().empty()) { // Empty value - ignore dv->unlink(); } else { _children += dv; } } #if LOG_CREATE_VALUES if (!need_clear) { std::clog << mytype << " " << quote(myfull_name) << " has " << nchildren() << " members\n"; } #endif } if (gdb->program_language() == LANGUAGE_PERL && is_perl_prefix(perl_type)) { // Set new type if (!myfull_name.empty() && is_perl_prefix(myfull_name[0])) myfull_name[0] = perl_type; } background(value.length()); changed = true; }