Index: ddd/SourceView.C =================================================================== --- ddd/SourceView.C (revision 8026) +++ ddd/SourceView.C (working copy) @@ -967,6 +967,10 @@ { if (address.contains('*', 0)) { + if (bp->n_locations() > 1) { + post_warning("Cannot move multiple BP in code window"); + return false; + } if (compare_address(address.after('*'), bp->address()) == 0) return false; // Breakpoint already at address } @@ -1194,7 +1198,8 @@ { BreakPoint *bp = bp_map.get(nrs[i]); if (bp != 0) - gdb_command(clear_command(bp->pos())); + for (int j = 0; j < bp->n_locations(); j++) + gdb_command(clear_command(bp->get_location(j).pos())); } } else if (gdb->has_delete_command()) @@ -1203,26 +1208,31 @@ } else { - for (int i = 0; i < nrs.size(); i++) - gdb_command(delete_command(nrs[i])); + for (int i = 0; i < nrs.size(); i++) { + std::vector delcmds = delete_commands(nrs[i]); + for (unsigned j = 0; j < delcmds.size(); j++) + gdb_command(delcmds[j]); + } } } // A generic deletion command for breakpoint BP_NR - either `clear' or `delete' -string SourceView::delete_command(int bp_nr) +std::vector SourceView::delete_commands(int bp_nr) { + std::vector cmds; if (gdb->has_delete_command()) { - return gdb->delete_command(itostring(bp_nr)); + cmds.push_back(gdb->delete_command(itostring(bp_nr))); } else if (gdb->has_clear_command()) { BreakPoint *bp = bp_map.get(bp_nr); - if (bp != 0) - return clear_command(bp->pos()); + if (bp != 0) { + for (int j = 0; j < bp->n_locations(); j++) + cmds.push_back(clear_command(bp->get_location(j).pos())); + } } - - return ""; // No way to delete a breakpoint (*sigh*) + return cmds; } // Return `clear ARG' command. If CLEAR_NEXT is set, attempt to guess @@ -1366,10 +1376,19 @@ { int bp_nr = *((int *)client_data); BreakPoint *bp = bp_map.get(bp_nr); - if (bp != 0 && !bp->address().empty()) + if (bp != 0) { - string address = string('*') + bp->address(); - line_popup_set_pcCB(w, XtPointer(&address), call_data); + if (bp->n_locations() > 1) + { + post_warning("BP has multiple locations, PC is ambiguous"); + return; + } + string addr = bp->address(); + if (!addr.empty()) + { + string address = string('*') + addr; + line_popup_set_pcCB(w, XtPointer(&address), call_data); + } } } @@ -1581,14 +1600,17 @@ bool SourceView::bp_matches(BreakPoint *bp, const string& file, int line) { + int i; switch (bp->type()) { case BREAKPOINT: case ACTIONPOINT: case TRACEPOINT: - return (line == 0 || bp->line_nr() == line) && - (bp->file_name().empty() || file_matches(bp->file_name(), file)); - + for (i = 0; i < bp->n_locations(); i++) { + BreakPointLocn &locn = bp->get_location(i); + if (bp_matches(locn, file, line)) return true; + } + return false; case WATCHPOINT: return false; } @@ -1596,6 +1618,19 @@ return false; // Never reached } +// Check if BP occurs in the current source text +bool SourceView::bp_matches(BreakPointLocn &locn, int line) +{ + return bp_matches(locn, current_source_name(), line) || + bp_matches(locn, current_file_name, line); +} + +bool SourceView::bp_matches(BreakPointLocn &locn, const string& file, int line) +{ + return ((line == 0 || locn.line_nr() == line) && + (locn.file_name().empty() || file_matches(locn.file_name(), file))); +} + // *************************************************************************** // @@ -1747,9 +1782,16 @@ bp != 0; bp = bp_map.next(ref)) { - bp->selected() = - (bp->type() == BREAKPOINT && - compare_address(pos, bp->address()) == 0); + int i; + bp->selected() = false; + for (i = 0; i < bp->n_locations(); i++) { + BreakPointLocn &locn = bp->get_location(i); + if (bp->type() == BREAKPOINT && + compare_address(pos, locn.address()) == 0) { + bp->selected() = true; + break; + } + } } } } @@ -2844,6 +2886,7 @@ if ((bp->type() == BREAKPOINT || bp->type() == TRACEPOINT) && bp_matches(bp)) { + // ASSUME: multi-location breakpoints all have same source line bps_in_line[bp->line_nr()] += bp->number(); } } @@ -2931,7 +2974,8 @@ if (bp->type() != BREAKPOINT) continue; - bp_addresses += bp->address(); + for (i = 0; i < bp->n_locations(); i++) + bp_addresses += bp->get_location(i).address(); } // Process all bp_addresses @@ -2948,8 +2992,9 @@ bp != 0; bp = bp_map.next(ref)) { - if (bp->address() == address) - insert_string += bp->symbol(); + for (int j = 0; j < bp->n_locations(); j++) + if (bp->get_location(j).address() == address) + insert_string += bp->symbol(); } int indent = indent_amount(code_text_w, pos); @@ -3005,14 +3050,17 @@ bp != 0; bp = bp_map.next(ref)) { - if (w == bp->source_glyph() || w == bp->code_glyph()) - { - // Breakpoint glyph found - line_nr = bp->line_nr(); - address = bp->address(); - in_text = false; - bp_nr = bp->number(); - return true; + for (int i = 0; i < bp->n_locations(); i++) { + BreakPointLocn &locn = bp->get_location(i); + if (w == locn.source_glyph() || w == locn.code_glyph()) + { + // Breakpoint glyph found + line_nr = locn.line_nr(); + address = locn.address(); + in_text = false; + bp_nr = bp->number(); + return true; + } } } } @@ -3127,8 +3175,9 @@ bp != 0; bp = bp_map.next(ref)) { - if (compare_address(address, bp->address()) == 0) - bps += bp->number(); + for (int i = 0; i < bp->n_locations(); i++) + if (compare_address(address, bp->get_location(i).address()) == 0) + bps += bp->number(); } if (bps.size() == 1) { @@ -4185,8 +4234,10 @@ { // To undo this change, we must delete the old // breakpoint and create a new one. - undo_commands << delete_command(bp->number()) << "\n" - << string(old_state); + std::vector delcmds = delete_commands(bp->number()); + for (unsigned i = 0; i < delcmds.size(); i++) + undo_commands << delcmds[i] << "\n"; + undo_commands << string(old_state); } else { @@ -4210,7 +4261,9 @@ } else { - undo_commands << delete_command(bp_nr) << '\n'; + std::vector delcmds = delete_commands(bp_nr); + for (unsigned i = 0; i < delcmds.size(); i++) + undo_commands << delcmds[i] << '\n'; } if (!added) @@ -5487,9 +5540,12 @@ bp != 0; bp = bp_map.next(ref)) { - if (bp->type() == BREAKPOINT && - compare_address(address, bp->address()) == 0) - bps += bp->number(); + for (int i = 0; i < bp->n_locations(); i++) { + BreakPointLocn &locn = bp->get_location(i); + if (bp->type() == BREAKPOINT && + compare_address(address, locn.address()) == 0) + bps += bp->number(); + } } } @@ -6594,7 +6650,8 @@ { // Replace breakpoint by new one with command. const string cmd = "b " + - bp->file_name() + ":" + itostring(bp->line_nr()) + + bp->file_name() + ":" + + itostring(bp->line_nr()) + " {" + action + "}"; gdb_command(cmd, origin); delete_bp(bp->number(), origin); @@ -6847,6 +6904,7 @@ return; strip_space(info_breakpoints_output); + info_breakpoints_output.gsub("\t", " "); if (info_breakpoints_output.empty()) { if (gdb->has_watch_command()) @@ -8815,60 +8873,63 @@ bp != 0; bp = bp_map.next(ref)) { - if (bp->type() != BREAKPOINT) - continue; - - Widget& bp_glyph = k ? bp->code_glyph() : bp->source_glyph(); - Widget text_w = k ? code_text_w : source_text_w; - bp_glyph = 0; - - XmTextPosition pos; - if (k == 0) - { - // Find source position - if (!bp_matches(bp) - || line_count <= 0 - || bp->line_nr() <= 0 - || bp->line_nr() > line_count) + for (int i = 0; i < bp->n_locations(); i++) { + BreakPointLocn &locn = bp->get_location(i); + if (bp->type() != BREAKPOINT) continue; - pos = pos_of_line(bp->line_nr()); - } - else - { - // Find code position - pos = find_pc(bp->address()); - } + Widget& bp_glyph = k ? locn.code_glyph() : locn.source_glyph(); + Widget text_w = k ? code_text_w : source_text_w; + bp_glyph = 0; - if (bp->dispo() != BPKEEP) - { - // Temporary breakpoint - if (bp->enabled()) - bp_glyph = map_stop_at(text_w, pos, plain_temps[k], - plain_temps_count, positions); - else - bp_glyph = map_stop_at(text_w, pos, grey_temps[k], - grey_temps_count, positions); - } - else if (!bp->condition().empty() || bp->ignore_count() != 0) - { - // Conditional breakpoint - if (bp->enabled()) - bp_glyph = map_stop_at(text_w, pos, plain_conds[k], - plain_conds_count, positions); + XmTextPosition pos; + if (k == 0) + { + // Find source position + if (!bp_matches(bp) + || line_count <= 0 + || locn.line_nr() <= 0 + || locn.line_nr() > line_count) + continue; + + pos = pos_of_line(locn.line_nr()); + } else - bp_glyph = map_stop_at(text_w, pos, grey_conds[k], - grey_conds_count, positions); - } - else - { - // Ordinary breakpoint - if (bp->enabled()) - bp_glyph = map_stop_at(text_w, pos, plain_stops[k], - plain_stops_count, positions); + { + // Find code position + pos = find_pc(locn.address()); + } + + if (bp->dispo() != BPKEEP) + { + // Temporary breakpoint + if (bp->enabled()) + bp_glyph = map_stop_at(text_w, pos, plain_temps[k], + plain_temps_count, positions); + else + bp_glyph = map_stop_at(text_w, pos, grey_temps[k], + grey_temps_count, positions); + } + else if (!bp->condition().empty() || bp->ignore_count() != 0) + { + // Conditional breakpoint + if (bp->enabled()) + bp_glyph = map_stop_at(text_w, pos, plain_conds[k], + plain_conds_count, positions); + else + bp_glyph = map_stop_at(text_w, pos, grey_conds[k], + grey_conds_count, positions); + } else - bp_glyph = map_stop_at(text_w, pos, grey_stops[k], - grey_stops_count, positions); + { + // Ordinary breakpoint + if (bp->enabled()) + bp_glyph = map_stop_at(text_w, pos, plain_stops[k], + plain_stops_count, positions); + else + bp_glyph = map_stop_at(text_w, pos, grey_stops[k], + grey_stops_count, positions); + } } } } @@ -9167,19 +9228,30 @@ unmap_drag_stop(text_w); unmap_drag_arrow(text_w); - current_drag_origin = glyph; - current_drag_breakpoint = 0; - // Check for breakpoint MapRef ref; for (BreakPoint *bp = bp_map.first(ref); bp != 0; bp = bp_map.next(ref)) { - if (glyph == bp->source_glyph() || glyph == bp->code_glyph()) - { - current_drag_breakpoint = bp->number(); - break; + for (int i = 0; i < bp->n_locations(); i++) { + BreakPointLocn &locn = bp->get_location(i); + if (glyph == locn.source_glyph() || glyph == locn.code_glyph()) + { + if (glyph == locn.code_glyph() && bp->n_locations() > 1) { + // Cannot drag a breakpoint in code window if it has + // multiple locations. FIXME: such glyphs should be + // visually distinguished. + current_drag_origin = NULL; + current_drag_breakpoint = 0; + return; + } + current_drag_origin = glyph; + current_drag_breakpoint = bp->number(); + return; + } } } + current_drag_origin = glyph; + current_drag_breakpoint = 0; } void SourceView::followGlyphAct(Widget glyph, XEvent *e, String *, Cardinal *) @@ -9421,9 +9493,15 @@ MapRef ref; for (BreakPoint *bp = bp_map.first(ref); bp != 0; bp = bp_map.next(ref)) { - if (glyph == bp->source_glyph() || glyph == bp->code_glyph()) - { - bps += bp->number(); + for (int i = 0; i < bp->n_locations(); i++) { + BreakPointLocn &locn = bp->get_location(i); + if (glyph == locn.source_glyph() || glyph == locn.code_glyph()) + { + // Cannot delete individual locations. + if (glyph == locn.code_glyph() && bp->n_locations() > 1) + continue; + bps += bp->number(); + } } } @@ -9874,8 +9952,10 @@ BreakPoint *bp = bp_map.get(num); if (bp == 0) return ""; - else + else { + std::cerr << "FIXME: SourceView::bp_pos: only returns first pos\n"; return bp->pos(); + } } @@ -10017,6 +10097,8 @@ for (BreakPoint *bp = bp_map.first(ref); bp != 0; bp = bp_map.next(ref)) { + // For gdb we use the delete command. + // So if we get here this is a simple breakpoint. Command c(clear_command(bp->pos())); c.verbose = false; c.prompt = false; Index: ddd/SourceView.h =================================================================== --- ddd/SourceView.h (revision 8026) +++ ddd/SourceView.h (working copy) @@ -46,6 +47,8 @@ #ifndef _DDD_SourceView_h #define _DDD_SourceView_h +#include + // Motif includes #include @@ -328,6 +331,12 @@ // True iff breakpoint BP is in FILE (at LINE, if given) static bool bp_matches(BreakPoint *bp, const string& file, int line = 0); + // True iff breakpoint location locn is in current file (at LINE, if given) + static bool bp_matches(BreakPointLocn &locn, int line = 0); + + // True iff breakpoint location locn is in FILE (at LINE, if given) + static bool bp_matches(BreakPointLocn &locn, const string& file, int line = 0); + // True iff FILE1 is equal to FILE2 static bool file_matches(const string& file1, const string& file2); @@ -829,7 +838,7 @@ static string clear_command(string arg, bool clear_next = false, int first_bp = 0); // Return `delete N' command. - static string delete_command(int bp_nr); + static std::vector delete_commands(int bp_nr); // Return `{ COMMAND; }' static string command_list(const string& cmd); Index: ddd/BreakPoint.C =================================================================== --- ddd/BreakPoint.C (revision 8026) +++ ddd/BreakPoint.C (working copy) @@ -51,10 +52,12 @@ #include "regexps.h" #include "index.h" #include "value-read.h" +#include "post.h" #if RUNTIME_REGEX static regex rxnl_int ("\n[1-9]"); static regex rxname_colon_int_nl ("[^ ]+:[0-9]+\n"); +static regex rxint_dot_int ("[0-9]+\.[0-9]+"); #endif // Create new breakpoint from INFO_OUTPUT @@ -64,10 +67,6 @@ mytype(BREAKPOINT), mydispo(BPKEEP), myenabled(true), - myfile_name(file), - myline_nr(0), - myaddress(""), - myfunc(""), myexpr(""), myinfos(""), myignore_count(0), @@ -79,10 +78,9 @@ myfile_changed(true), myposition_changed(true), myaddress_changed(true), - myselected(false), - mysource_glyph(0), - mycode_glyph(0) + myselected(false) { + locn.resize(1); if (gdb->has_numbered_breakpoints()) { // Read leading breakpoint number @@ -199,15 +197,23 @@ } info_output = info_output.after(rxblanks_or_tabs); - string new_info = ""; - if (mytype == BREAKPOINT) + // Check for multiple breakpoints + + bool multiple = false; + if (info_output.contains("", 0)) { + info_output = info_output.after('\n'); + multiple = true; + } + + if (mytype == BREAKPOINT && !multiple) { + locn.resize(1); if (MAKE != gdb->type() && BASH != gdb->type()) { // Read address - myaddress = info_output.through(rxalphanum); + locn[0].myaddress = info_output.through(rxalphanum); - info_output = info_output.after(myaddress); + info_output = info_output.after(locn[0].myaddress); strip_leading_space(info_output); } @@ -223,7 +229,7 @@ func = func.before(" at "); strip_space(func); - myfunc = func; + locn[0].myfunc = func; } } @@ -240,11 +246,11 @@ } remainder = remainder.from(rxname_colon_int_nl); - myfile_name = remainder.before(":"); + locn[0].myfile_name = remainder.before(":"); remainder = remainder.after(":"); if (!remainder.empty() && isdigit(remainder[0])) - myline_nr = get_positive_nr(remainder); + locn[0].myline_nr = get_positive_nr(remainder); } else if (mytype == WATCHPOINT) { @@ -256,6 +262,7 @@ int ignore_count = 0; string cond = ""; StringArray commands; + string new_info = ""; if (!info_output.empty() && !isdigit(info_output[0])) { @@ -324,6 +331,72 @@ delete[] lines; } + if (mytype == BREAKPOINT && multiple) + { + if (GDB != gdb->type()) { + post_warning("Detected multiple breakpoint, but this is not GDB"); + return; + } + int numlocs = 0; + while (!info_output.empty() && info_output.contains(rxint_dot_int, 0)) { + locn.resize(numlocs+1); + + // Read address + info_output = info_output.after(rxint_dot_int); + strip_leading_space(info_output); + + // Read enabled flag (`y' or `n') + // We discard this: I don't think GDB allows these flags to + // be set individually. + bool myenabled2; + if (info_output.contains('y', 0)) + myenabled2 = true; + else if (info_output.contains('n', 0)) + myenabled2 = false; + info_output = info_output.after(rxblanks_or_tabs); + + // Read address + locn[numlocs].myaddress = info_output.through(rxalphanum); + info_output = info_output.after(locn[numlocs].myaddress); + strip_leading_space(info_output); + + // Read function name + if (info_output.contains("in ", 0)) + { + // Function name + string func2 = info_output.after("in "); + if (func2.contains('\n')) + func2 = func2.before('\n'); + if (func2.contains(" at ")) + func2 = func2.before(" at "); + strip_space(func2); + locn[numlocs].myfunc = func2; + } + + // Read 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); + locn[numlocs].myfile_name = remainder.before(":"); + + remainder = remainder.after(":"); + if (!remainder.empty() && isdigit(remainder[0])) + locn[numlocs].myline_nr = get_positive_nr(remainder); + + numlocs++; + } + } + + myinfos = new_info; myignore_count = ignore_count; mycondition = cond; @@ -381,13 +454,13 @@ new_line_nr = get_positive_nr(info_output); if (!file_name.empty()) - myfile_name = file_name; + locn[0].myfile_name = file_name; if (new_line_nr != 0) - myline_nr = new_line_nr; + locn[0].myline_nr = new_line_nr; // DBX issues either locations or functions - myfunc = ""; + locn[0].myfunc = ""; } else if (info_output.contains ("in ", 0)) { @@ -400,37 +473,37 @@ // 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); + locn[0].myfile_name = line.after("\""); + locn[0].myfile_name = locn[0].myfile_name.before("\""); + locn[0].myline_nr = get_positive_nr(line.after("\":")); + locn[0].myfunc = line.before("\""); + strip_space(locn[0].myfunc); // Be sure to remove TYPE - while (myfunc.contains(" ")) - myfunc = myfunc.after(" "); + while (locn[0].myfunc.contains(" ")) + locn[0].myfunc = locn[0].myfunc.after(" "); } else { // DBX output: // `stop in FUNC' - myfunc = line.before(rxblanks_or_tabs); - strip_space(myfunc); + locn[0].myfunc = line.before(rxblanks_or_tabs); + strip_space(locn[0].myfunc); - myfile_name = ""; - myline_nr = 0; + locn[0].myfile_name = ""; + locn[0].myline_nr = 0; // Attempt to get exact position of FUNC - const string pos = dbx_lookup(myfunc); + const string pos = dbx_lookup(locn[0].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; + locn[0].myfile_name = file_name; if (new_line_nr != 0) - myline_nr = new_line_nr; + locn[0].myline_nr = new_line_nr; } } } @@ -523,16 +596,16 @@ // Get function name and position info_output = info_output.after(rxblanks_or_tabs); - myfunc = info_output.before(": "); + locn[0].myfunc = info_output.before(": "); - const string pos = dbx_lookup(myfunc); + const string pos = dbx_lookup(locn[0].myfunc); if (!pos.empty()) { - myfile_name = pos.before(":"); + locn[0].myfile_name = pos.before(":"); } info_output = info_output.after(": "); - myline_nr = get_positive_nr(info_output); + locn[0].myline_nr = get_positive_nr(info_output); info_output = info_output.after('\n'); @@ -570,8 +643,8 @@ if (last_space > 0) class_name = class_name.after(last_space); - myfile_name = class_name; - myline_nr = line_no; + locn[0].myfile_name = class_name; + locn[0].myline_nr = line_no; // Kill this line int beginning_of_line = colon; @@ -603,14 +676,14 @@ if (first_line.contains(':', -1)) { // Get leading file name - myfile_name = first_line.before(':'); + locn[0].myfile_name = first_line.before(':'); info_output = info_output.after('\n'); } } static const StringArray empty; mycommands = empty; - myline_nr = atoi(info_output.chars()); + locn[0].myline_nr = atoi(info_output.chars()); info_output = info_output.after('\n'); bool break_seen = false; while (info_output.contains(" ", 0)) @@ -740,28 +813,35 @@ if (type() == BREAKPOINT) { - if (new_bp.address() != address()) + // FIXME: I don't believe any of these can be reached for GDB. + // If I'm wrong then we will need to be more careful because + // the breakpoint could have multiple locations. + if (new_bp.locn[0].address() != locn[0].address()) { + std::cerr << "\007**** BREAKPOINT ADDRESS CHANGED\007\n"; changed = myaddress_changed = true; - myaddress = new_bp.address(); + locn[0].myaddress = new_bp.locn[0].address(); } - if (new_bp.func() != func()) + if (new_bp.locn[0].func() != locn[0].func()) { + std::cerr << "\007**** BREAKPOINT FUNCTION CHANGED\007\n"; changed = myposition_changed = true; - myfunc = new_bp.func(); + locn[0].myfunc = new_bp.locn[0].func(); } - if (new_bp.file_name() != file_name()) + if (new_bp.locn[0].file_name() != locn[0].file_name()) { + std::cerr << "\007**** BREAKPOINT FILENAME CHANGED\007\n"; changed = myposition_changed = myfile_changed = true; - myfile_name = new_bp.file_name(); + locn[0].myfile_name = new_bp.locn[0].file_name(); } - if (new_bp.line_nr() != line_nr()) + if (new_bp.locn[0].line_nr() != locn[0].line_nr()) { + std::cerr << "\007**** BREAKPOINT LINE CHANGED\007\n"; changed = myposition_changed = true; - myline_nr = new_bp.line_nr(); + locn[0].myline_nr = new_bp.locn[0].line_nr(); } } else if (type() == WATCHPOINT) @@ -823,7 +903,7 @@ // Resources //----------------------------------------------------------------------------- -string BreakPoint::pos() const +string BreakPointLocn::pos() const { if (line_nr() == 0) return "*" + address(); @@ -833,6 +913,11 @@ return file_name() + ":" + itostring(line_nr()); } +string BreakPoint::pos() const +{ + return locn[0].pos(); +} + string BreakPoint::symbol() const { char c; @@ -1032,10 +1117,10 @@ { if (pos.empty()) { - if (line_nr() > 0) - pos = file_name() + ":" + itostring(line_nr()); + if (locn[0].line_nr() > 0) + pos = locn[0].file_name() + ":" + itostring(locn[0].line_nr()); else - pos = string('*') + address(); + pos = string('*') + locn[0].address(); } if (cond == char(-1)) @@ -1118,9 +1203,9 @@ switch (type()) { case BREAKPOINT: - if (!func().empty()) + if (!locn[0].func().empty()) { - os << "stop in " << func() << "\n"; + os << "stop in " << locn[0].func() << "\n"; } else if (pos.contains('*', 0)) { Index: ddd/BreakPoint.h =================================================================== --- ddd/BreakPoint.h (revision 8026) +++ ddd/BreakPoint.h (working copy) @@ -32,6 +33,8 @@ // A `BreakPoint' stores information about an existing debugger breakpoint. //----------------------------------------------------------------------------- +#include + #include // Misc includes @@ -70,15 +73,43 @@ BPDIS // Disable (`enable once' in GDB) }; +class BreakPoint; + +class BreakPointLocn { + string myfile_name; // File name + int myline_nr; // Line number + string myaddress; // Address in memory + string myfunc; // Function name + Widget mysource_glyph; // Associated glyph in source + Widget mycode_glyph; // Associated glyph in code +public: + BreakPointLocn(): + myfile_name(""), + myline_nr(0), + myaddress(""), + myfunc(""), + mysource_glyph(0), + mycode_glyph(0) + { + } + // Breakpoint position + const string& file_name() const { return myfile_name; } + int line_nr() const { return myline_nr; } + const string& address() const { return myaddress; } + string pos() const; + const string& func() const { return myfunc; } + // Associated glyphs in source and machine code + Widget& source_glyph() { return mysource_glyph; } + Widget& code_glyph() { return mycode_glyph; } + friend class BreakPoint; +}; + class BreakPoint { int mynumber; // Breakpoint number BPType mytype; // Type, as above BPDispo mydispo; // Disposition, as above bool myenabled; // Is breakpoint enabled? - string myfile_name; // File name - int myline_nr; // Line number - string myaddress; // Address in memory - string myfunc; // Function name + std::vector locn; string myexpr; // Expression to watch (for watchpoints) string myinfos; // Additional information (human-readable) int myignore_count; // Ignore count @@ -93,9 +124,6 @@ bool myaddress_changed; // True if address changed bool myselected; // True if selected - Widget mysource_glyph; // Associated glyph in source - Widget mycode_glyph; // Associated glyph in code - private: BreakPoint(const BreakPoint&); BreakPoint& operator = (const BreakPoint&); @@ -140,15 +168,21 @@ // What to do when breakpoint is reached. BPDispo dispo() const { return mydispo; } + // Number of items (GDB has breakpoints at multiple locations) + int n_locations() const { return locn.size(); } + + // Get numbered locn + BreakPointLocn &get_location(int i) { return locn[i]; } + // Whether breakpoint is enabled bool enabled() const; - // Breakpoint position - const string& file_name() const { return myfile_name; } - int line_nr() const { return myline_nr; } - const string& address() const { return myaddress; } + // Breakpoint position (for simple breakpoints) + const string& file_name() const { return locn[0].myfile_name; } + int line_nr() const { return locn[0].myline_nr; } + const string& address() const { return locn[0].myaddress; } string pos() const; - const string& func() const { return myfunc; } + const string& func() const { return locn[0].myfunc; } // Watchpoint info const string& expr() const { return myexpr; } @@ -167,10 +201,6 @@ // Selection state bool& selected() { return myselected; } - // Associated glyphs in source and machine code - Widget& source_glyph() { return mysource_glyph; } - Widget& code_glyph() { return mycode_glyph; } - // True iff `enabled' status changed bool enabled_changed () const { return myenabled_changed; }