try to update source window when breakpoints change

this is not tested yet
This commit is contained in:
Tom Tromey
2015-05-08 13:01:23 -06:00
parent 6b5c4dc9df
commit 7647b97c01
4 changed files with 95 additions and 7 deletions

View File

@@ -25,10 +25,15 @@ breakpoints have been set.""",
13598: """Your gdb doesn't have a "before prompt" event. 13598: """Your gdb doesn't have a "before prompt" event.
This means that various windows won't be able to react to This means that various windows won't be able to react to
commands like "up" or "down".""" commands like "up" or "down".""",
18385: """Your gdb doesn't expose locations on a gdb.Breakpoint.
This can be worked around, but maybe not always reliably.
This means that sometimes breakpoints won't display in source windows."""
} }
_warning = "See https://sourceware.org/bugzilla/show_bug.cgi?id=%s for more information." _warning = """See https://sourceware.org/bugzilla/show_bug.cgi?id=%s
for more information."""
_first_report = True _first_report = True

57
gui/bpcache.py Normal file
View File

@@ -0,0 +1,57 @@
# Copyright (C) 2015 Tom Tromey <tom@trolley.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import gdb
import gui.events
import gui.adapt
# This maps from (FILENAME,LINE) to a set of breakpoints referencing
# that file/line. Then we emit events when entries are created or
# destroyed.
breakpoint_source_map = {}
def _breakpoint_created(bp):
if bp.location is None:
return
gui.adapt.notify_bug(18385)
(rest, locs) = gdb.decode_line(bp.location)
if rest is not None:
# Let's assume we couldn't reparse for some reason.
return
for sal in locs:
if sal.symtab is None:
continue
entry = (sal.symtab.fullname(), sal.line)
if entry not in breakpoint_source_map:
breakpoint_source_map[entry] = set()
if bp.number not in breakpoint_source_map[entry]:
breakpoint_source_map[entry].add(bp.number)
gui.events.location_changed.post(entry, True)
else:
breakpoint_source_map[entry].add(bp.number)
def _breakpoint_deleted(bp):
num = bp.number
for entry in breakpoint_source_map:
if num in breakpoint_source_map[entry]:
breakpoint_source_map[entry].discard(bp.number)
if len(breakpoint_source_map[entry]) == 0:
gui.events.location_changed.post(entry, False)
if not hasattr(gdb.events, 'breakpoint_created'):
gui.adapt.notify_bug(15620)
else:
gdb.events.breakpoint_created.connect(_breakpoint_created)
gdb.events.breakpoint_deleted.connect(_breakpoint_deleted)

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2013 Tom Tromey <tom@trolley.com> # Copyright (C) 2013, 2015 Tom Tromey <tom@trolley.com>
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@@ -25,8 +25,9 @@ class _Event(object):
def disconnect(self, callback): def disconnect(self, callback):
self.funcs.remove(callback) self.funcs.remove(callback)
def post(self): def post(self, *args, **kwargs):
for fun in self.funcs: for fun in self.funcs:
fun() fun(*args, **kwargs)
frame_changed = _Event() frame_changed = _Event()
location_changed = _Event()

View File

@@ -26,6 +26,7 @@ import gui.events
import os.path import os.path
import gui.gdbutil import gui.gdbutil
import gui.params import gui.params
import gui.bpcache
from gi.repository import Gtk, GtkSource, GObject, Gdk, GdkPixbuf, Pango from gi.repository import Gtk, GtkSource, GObject, Gdk, GdkPixbuf, Pango
@@ -34,6 +35,7 @@ class BufferManager:
self.buffers = {} self.buffers = {}
self.lang_manager = None self.lang_manager = None
gui.params.source_theme.set_buffer_manager(self) gui.params.source_theme.set_buffer_manager(self)
gui.events.location_changed.connect(self._location_changed)
def release_buffer(self, buff): def release_buffer(self, buff):
# FIXME: we should be smart about buffer caching. # FIXME: we should be smart about buffer caching.
@@ -41,10 +43,13 @@ class BufferManager:
@in_gtk_thread @in_gtk_thread
def _set_marks(self, buffer, line_set): def _set_marks(self, buffer, line_set):
buffer.all_marks = {}
iter = buffer.get_iter_at_line(0) iter = buffer.get_iter_at_line(0)
while True: while True:
if iter.get_line() + 1 in line_set: line = iter.get_line() + 1
mark = buffer.create_source_mark(None, 'executable', iter) if line in line_set:
all_marks[line] = buffer.create_source_mark(None, 'executable',
iter)
if not iter.forward_line(): if not iter.forward_line():
break break
@@ -91,6 +96,26 @@ class BufferManager:
def change_theme(self): def change_theme(self):
gui.startup.send_to_gtk(self._do_change_theme) gui.startup.send_to_gtk(self._do_change_theme)
@in_gtk_thread
def update_breakpoint_location(self, sal, is_set):
if is_set:
category = 'breakpoint'
else:
category = 'executable'
[fullname, line] = sal
if fullname in self.buffers:
buffer = self.buffers[fullname]
if line in buffer.all_marks:
if buffer.all_marks[line].category is not category:
iter = buffer.get_iter_at_line(line - 1)
buffer.all_marks[line] = buffer.create_source_mark(None,
category,
iter)
@in_gdb_thread
def _location_changed(self, loc, is_set):
gui.startup.send_to_gtk(self.update_breakpoint_location)
buffer_manager = BufferManager() buffer_manager = BufferManager()
# Return (FRAME, SYMTAB, FILE, LINE) for the selected frame, or, if # Return (FRAME, SYMTAB, FILE, LINE) for the selected frame, or, if