string BreakPoint::pos() const { if (line_nr() == 0) return "*" + address(); else if (file_name().empty()) return itostring(line_nr()); else return file_name() + ":" + itostring(line_nr()); }
static void SetViewCB(Widget, XtPointer client_data, XtPointer) { PlotWindowInfo *plot = (PlotWindowInfo *)client_data; int rot_x = 60; int rot_z = 30; XtVaGetValues(plot->vsb, XmNvalue, &rot_x, XtPointer(0)); XtVaGetValues(plot->hsb, XmNvalue, &rot_z, XtPointer(0)); string cmd = "set view " + itostring(rot_x) + ", " + itostring(rot_z); send_and_replot(plot, cmd); }
// Fetch a component static string component(const AppData& ad, DDDFont font, FontComponent n) { if (n == PointSize) { int sz = 0; switch(font) { case DefaultDDDFont: sz = ad.default_font_size; break; case VariableWidthDDDFont: case SymbolDDDFont: sz = ad.variable_width_font_size; break; case FixedWidthDDDFont: sz = ad.fixed_width_font_size; break; case DataDDDFont: sz = ad.data_font_size; break; } return itostring(sz); } string w = component(userfont(ad, font), n); if (w.empty()) // nothing specified w = component(fallbackfont(font), n); return w; }
static bool refresh_tip_dialog(Widget w) { MString tip = get_tip_of_the_day(w, app_data.startup_tip_count); if (!is_tip(tip)) { // Restart from first tip app_data.startup_tip_count = 0; tip = get_tip_of_the_day(w, app_data.startup_tip_count); } if (!is_tip(tip)) return false; XtVaSetValues(w, XmNmessageString, tip.xmstring(), XtPointer(0)); MString next_tip = get_tip_of_the_day(w, app_data.startup_tip_count + 1); MString prev_tip = get_tip_of_the_day(w, app_data.startup_tip_count - 1); set_sensitive(XmMessageBoxGetChild(w, XmDIALOG_CANCEL_BUTTON), is_tip(prev_tip)); set_sensitive(XmMessageBoxGetChild(w, XmDIALOG_HELP_BUTTON), is_tip(next_tip)); string title = DDD_NAME " Tip of the Day #" + itostring(app_data.startup_tip_count); XtVaSetValues(XtParent(w), XmNtitle, title.chars(), XtPointer(0)); return true; }
// OK pressed in `Open Process' static void openProcessDone(Widget w, XtPointer client_data, XtPointer call_data) { int pid = get_pid(w, client_data, call_data); if (pid <= 0) { gdbUpdateProcessesCB(w, client_data, call_data); return; } XtUnmanageChild(w); ProgramInfo info; if (pid == info.pid) { set_status("Already attached to process " + itostring(pid) + "."); return; } if (info.file == NO_GDB_ANSWER || info.file.empty()) { post_error("No program.", "no_program", w); return; } // GDB does not always detach processes upon opening new // files, so we do it explicitly if (info.attached) gdb_command(gdb->detach_command(info.pid)); // Attach to new process gdb_command(gdb->attach_command(pid, info.file)); }
static void SelectCB(Widget, XtPointer client_data, XtPointer) { string& reply = *((string *)client_data); IntArray numbers; getItemNumbers(gdb_selection_list_w, numbers); if (numbers.size() > 0) reply = itostring(numbers[0]) + "\n"; }
string BreakPoint::symbol() const { char c; if (!enabled()) c = '_'; else if (!condition().empty() || ignore_count() != 0) c = '?'; else c = '#'; return c + itostring(number()) + c; }
// Select a process static void SelectProcessCB(Widget w, XtPointer client_data, XtPointer call_data) { XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data; int pos = cbs->item_position; if (pos == 1) XmListDeselectAllItems(w); // Title selected else ListSetAndSelectPos(w, pos); int pid = get_pid(w, client_data, call_data); if (pid <= 0) set_status(""); else set_status("Process " + itostring(pid)); }
static void update_recent_menu(const MMDesc *items) { StringArray recent_files; { StringArray r; get_recent(r); for (int i = 0; i < r.size() && items[i].widget != 0; i++) recent_files += r[i]; } // Uniquify labels char sep = '/'; if (gdb->type() == JDB) sep = '.'; StringArray labels; uniquify(recent_files, labels, sep); // Set labels int i; for (i = 0; i < labels.size(); i++) { MString label(itostring(i + 1) + " "); label += tt(labels[i]); Widget w = items[i].widget; set_label(w, label); const string& file = recent_files[i]; bool sens = true; if (!remote_gdb()) { if (gdb->has_exec_files() && !is_debuggee_file(file)) sens = false; // File not accessible else if (!gdb->has_classes() && !is_regular_file(file)) sens = false; // File not accessible } set_sensitive(w, sens); XtManageChild(w); } // Unmanage remaining items for (; items[i].widget != 0; i++) XtUnmanageChild(items[i].widget); }
static void SaveTipCountCB(Widget, XtPointer = 0, XtPointer = 0) { create_session_dir(DEFAULT_SESSION); const string file = session_tips_file(); std::ofstream os(file.chars()); os << "! " DDD_NAME " tips file\n" "\n" << app_value(XtNstartupTipCount, itostring(++app_data.startup_tip_count)) << "\n"; os.close(); if (os.bad()) { post_error("Cannot save tip count in " + quote(file), "options_save_error"); } }
static MString get_tip_of_the_day(Widget w, int n) { struct tip_of_the_day_resource_values { XmString tip; }; const string tip_name = "tip" + itostring(n); XtResource r; r.resource_name = XTRESSTR(tip_name.chars()); r.resource_class = XTRESSTR("Tip"); r.resource_type = XmRXmString; r.resource_size = sizeof(XmString); r.resource_offset = XtOffsetOf(tip_of_the_day_resource_values, tip); r.default_type = XtRImmediate; r.default_addr = XtPointer(0); tip_of_the_day_resource_values values; XtGetApplicationResources(w, &values, &r, 1, ArgList(0), 0); return MString(values.tip, true); }
bool lock_session_dir(Display *display, const string& session, LockInfo& info) { info.pid = 0; string lock_file = session_lock_file(session); { std::ifstream is(lock_file.chars()); if (!is.bad()) { string version; is >> version; if (version.contains(DDD_NAME, 0)) { // Lock already exists -- use contents as diagnostics is >> info.hostname >> info.pid >> info.display >> info.uid >> info.username; if (info.username.empty()) { // DDD 3.0.90 and earlier do not save the user name info.username = itostring(info.uid); } if (info.hostname != fullhostname()) return false; // Process running on remote host if (info.pid > 0 && kill(info.pid, 0) == 0) return false; // Process running on host } }
// 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; }
// 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; }
void UndoBuffer::remap_breakpoint(string& cmd, int old_bp, int new_bp) { const string old_num = "@" + itostring(old_bp) + "@"; const string new_num = "@" + itostring(new_bp) + "@"; cmd.gsub(old_num, new_num); }
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; }
// ctor from int ... StrInt(int s) : snum(itostring(s)) {}
// Update breakpoint information bool BreakPoint::update(string& info_output, std::ostream& undo_commands, bool& need_total_undo) { string file = file_name(); BreakPoint new_bp(info_output, arg(), number(), file); bool changed = false; myenabled_changed = false; myposition_changed = false; myfile_changed = false; myaddress_changed = false; need_total_undo = false; const string num = "@" + itostring(number()) + "@"; if (new_bp.number() != number()) { mynumber = new_bp.number(); need_total_undo = changed = true; } if (new_bp.type() != type()) { mytype = new_bp.type(); need_total_undo = changed = myenabled_changed = true; } if (new_bp.dispo() != dispo()) { need_total_undo = changed = myenabled_changed = true; mydispo = new_bp.dispo(); } if (new_bp.watch_mode() != watch_mode()) { need_total_undo = changed = myenabled_changed = true; mywatch_mode = new_bp.watch_mode(); } if (new_bp.myenabled != myenabled) { changed = myenabled_changed = true; myenabled = new_bp.myenabled; if (myenabled) { if (gdb->has_disable_command()) undo_commands << gdb->disable_command(num) << "\n"; else need_total_undo = true; } else { if (gdb->has_enable_command()) undo_commands << gdb->enable_command(num) << "\n"; else need_total_undo = true; } } if (type() == BREAKPOINT) { if (new_bp.address() != address()) { changed = myaddress_changed = true; myaddress = new_bp.address(); } if (new_bp.func() != func()) { changed = myposition_changed = true; myfunc = new_bp.func(); } if (new_bp.file_name() != file_name()) { changed = myposition_changed = myfile_changed = true; myfile_name = new_bp.file_name(); } if (new_bp.line_nr() != line_nr()) { changed = myposition_changed = true; myline_nr = new_bp.line_nr(); } } else if (type() == WATCHPOINT) { if (new_bp.expr() != expr()) { changed = true; myexpr = new_bp.expr(); } } if (new_bp.infos() != infos()) { changed = true; myinfos = new_bp.infos(); } if (new_bp.ignore_count() != ignore_count()) { if (gdb->has_ignore_command()) undo_commands << gdb->ignore_command(num, myignore_count) << "\n"; else need_total_undo = true; changed = myenabled_changed = true; myignore_count = new_bp.ignore_count(); } if (new_bp.mycondition != mycondition) { if (gdb->has_condition_command()) undo_commands << gdb->condition_command(num, condition()) << "\n"; else need_total_undo = true; changed = myenabled_changed = true; mycondition = new_bp.mycondition; } if (!equal(new_bp.commands(), commands())) { if (gdb->type() == GDB || gdb->type() == PYDB || gdb->type() == BASH) { undo_commands << "commands " << num << '\n'; for (int i = 0; i < commands().size(); i++) undo_commands << commands()[i] << '\n'; undo_commands << "end\n"; } changed = myenabled_changed = true; mycommands = new_bp.commands(); } return changed; }
// Create a new plot window PlotAgent *new_plotter(const string& name, DispValue *source) { static int tics = 1; string cmd = app_data.plot_command; cmd.gsub("@FONT@", make_font(app_data, FixedWidthDDDFont)); string window_name = ddd_NAME "plot" + itostring(tics++); if (cmd.contains("@NAME@")) cmd.gsub("@NAME@", window_name); else cmd += " -name " + window_name; // Create shell PlotWindowInfo *plot = new_decoration(name); if (plot == 0) return 0; plot->source = source; plot->window_name = window_name; XtVaSetValues(plot->shell, XmNuserData, XtPointer(True), XtPointer(0)); // Pop up a working dialog static Widget dialog = 0; if (dialog == 0) { Arg args[10]; Cardinal arg = 0; dialog = verify(XmCreateWorkingDialog(find_shell(), XMST("launch_plot_dialog"), args, arg)); XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); } XtRemoveAllCallbacks(dialog, XmNcancelCallback); XtAddCallback(dialog, XmNcancelCallback, CancelPlotCB, XtPointer(plot)); plot->working_dialog = dialog; string base = cmd; if (base.contains(' ')) base = cmd.before(' '); MString msg = rm("Starting ") + tt(base) + rm("..."); XtVaSetValues(dialog, XmNmessageString, msg.xmstring(), XtPointer(0)); manage_and_raise(dialog); wait_until_mapped(dialog); // Invoke plot process PlotAgent *plotter = new PlotAgent(XtWidgetToApplicationContext(plot->shell), cmd); XtAddCallback(plot->shell, XtNpopdownCallback, CancelPlotCB, XtPointer(plot)); if (plot->area != 0) { XtAddCallback(plot->area->widget(), XmNexposeCallback, ExposePlotAreaCB, XtPointer(plot)); XtAddCallback(plot->area->widget(), XmNresizeCallback, ResizePlotAreaCB, XtPointer(plot)); } string init = app_data.plot_init_commands; init.prepend("set term " + string(app_data.plot_term_type) + "\n"); if (!init.empty() && !init.contains('\n', -1)) init += '\n'; // Add trace handlers plotter->addHandler(Input, TraceInputHP); // Gnuplot => DDD plotter->addHandler(Output, TraceOutputHP); // DDD => Gnuplot plotter->addHandler(Error, TraceErrorHP); // Gnuplot Errors => DDD // Show Gnuplot Errors in status line plotter->addHandler(Error, SetStatusHP, (void *)plot); // Handle death plotter->addHandler(Died, PlotterNotFoundHP, (void *)plot); plotter->addHandler(Died, DeletePlotterHP, (void *)plot); if (plot->area != 0) plotter->addHandler(Plot, GetPlotHP, (void *)plot); plotter->start_with(init); plot->plotter = plotter; return plotter; }
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; }
// 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; }
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; }
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; }
// Answer GDB question static void select_from_gdb(const string& question, string& reply) { int count = question.freq('\n') + 1; string *choices = new string[count]; bool *selected = new bool[count]; split(question, choices, count, '\n'); // Highlight choice #1 by default for (int i = 0; i < count; i++) { if (!has_nr(choices[i])) { // Choice has no number (prompt) - remove it for (int j = i; j < count - 1; j++) choices[j] = choices[j + 1]; count--; i--; } else { selected[i] = (get_positive_nr(choices[i]) == 1); } } if (count < 2) { // Nothing to choose from if (count == 1) { // Take the first choice. reply = itostring(atoi(choices[0].chars())) + "\n"; } delete[] choices; delete[] selected; return; } // Popup selection dialog static string selection_reply; if (gdb_selection_dialog == 0) { Arg args[10]; Cardinal arg = 0; XtSetArg(args[arg], XmNautoUnmanage, False); arg++; gdb_selection_dialog = verify(XmCreateSelectionDialog(find_shell(gdb_w), XMST("gdb_selection_dialog"), args, arg)); Delay::register_shell(gdb_selection_dialog); XtUnmanageChild(XmSelectionBoxGetChild(gdb_selection_dialog, XmDIALOG_TEXT)); XtUnmanageChild(XmSelectionBoxGetChild(gdb_selection_dialog, XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(gdb_selection_dialog, XmDIALOG_APPLY_BUTTON)); gdb_selection_list_w = XmSelectionBoxGetChild(gdb_selection_dialog, XmDIALOG_LIST); XtVaSetValues(gdb_selection_list_w, XmNselectionPolicy, XmSINGLE_SELECT, XtPointer(0)); XtAddCallback(gdb_selection_dialog, XmNokCallback, SelectCB, &selection_reply); XtAddCallback(gdb_selection_dialog, XmNcancelCallback, CancelCB, &selection_reply); XtAddCallback(gdb_selection_dialog, XmNhelpCallback, ImmediateHelpCB, 0); } setLabelList(gdb_selection_list_w, choices, selected, count, false, false); delete[] choices; delete[] selected; manage_and_raise(gdb_selection_dialog); selection_reply = ""; while (selection_reply.empty() && gdb->running() && !gdb->isReadyWithPrompt()) XtAppProcessEvent(XtWidgetToApplicationContext(gdb_w), XtIMAll); // Found a reply - return reply = selection_reply; }