DDD and GDB breakpoints having multiple locations (C++ constructors, templates etc.)
Peter Wainwright <[email protected]> Sat, 14 Feb 2009 20:06:12 +0000
| Newsgroups | gmane.comp.debugging.ddd.bugs |
|---|---|
| Message-ID | <[email protected]> |
I noticed that recent versions of GDB have a modified "info breakpoints" display which can display multiple addresses for one breakpoint. This occurs, for example, in constructors, templates, inline functions (since I use a lot of C++ this is an itch I have to scratch). https://savannah.gnu.org/bugs/?25510 I've produced a patch which addresses some of these issues. If anyone can improve it, I'd like to hear from you. Peter _______________________________________________ bug-ddd mailing list [email protected] http://lists.gnu.org/mailman/listinfo/bug-ddd
ddd-multi-bp.patch
(text/x-patch, 28.9 KB)
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<string> 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<string> SourceView::delete_commands(int bp_nr)
{
+ std::vector<string> 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<string> 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<string> 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 <vector>
+
// Motif includes
#include <Xm/Xm.h>
@@ -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<string> 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("<MULTIPLE>", 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 <vector>
+
#include <X11/Intrinsic.h>
// 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<BreakPointLocn> 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; }