[gnome-builder/wip/chergert/debugger: 32/58] gdb: hook up some client signals and plumbing
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/debugger: 32/58] gdb: hook up some client signals and plumbing
- Date: Sun, 26 Mar 2017 07:24:02 +0000 (UTC)
commit d96a1d6b05e693163deeb7dc427d90113f9cc996
Author: Christian Hergert <chergert redhat com>
Date: Fri Mar 24 02:59:39 2017 -0700
gdb: hook up some client signals and plumbing
plugins/gdb/gdb_plugin.py | 96 +++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 93 insertions(+), 3 deletions(-)
---
diff --git a/plugins/gdb/gdb_plugin.py b/plugins/gdb/gdb_plugin.py
index fc79cbb..484fc8a 100644
--- a/plugins/gdb/gdb_plugin.py
+++ b/plugins/gdb/gdb_plugin.py
@@ -19,15 +19,34 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+import os
+
from gi.repository import GLib
from gi.repository import GObject
+from gi.repository import Gio
from gi.repository import Ide
+from gi.repository import Mi2
class GdbDebugger(Ide.Object, Ide.Debugger):
can_step_in = GObject.Property('can-step-in', type=bool, default=False)
can_step_over = GObject.Property('can-step-over', type=bool, default=False)
can_continue = GObject.Property('can-continue', type=bool, default=False)
+ # If we've stolen a PTY from the runner to be used later,
+ # it will be here. This should be close()d if we do not
+ # get a chance to assitn it using gdb.
+ inferior_pty = None
+
+ # Our Mi2.Client is what we use to communicate with the controlling gdb
+ # process over stdin/stdout.
+ client = None
+
+ def __del__(self):
+ if self.inferior_pty is not None:
+ os.close(self.inferior_pty)
+ if self.client:
+ self.client.stop_listening()
+
def do_get_name(self):
return 'GNU Debugger'
@@ -38,8 +57,79 @@ class GdbDebugger(Ide.Object, Ide.Debugger):
return (False, 0)
def do_prepare(self, runner):
- gdb_arguments = ['gdb', '-ex', 'run', '--args']
-
- for arg in reversed(gdb_arguments):
+ # Run the program under gdb so that we can control the debugger
+ # with stdin/stdout.
+ for arg in reversed(['gdb', '--interpreter', 'mi2', '--args']):
runner.prepend_argv(arg)
+ # Connect to signals so we can setup/cleanup properly
+ runner.connect('spawned', self.on_runner_spawned)
+ runner.connect('exited', self.on_runner_exited)
+
+ # We need to steal the TTY from the runner (if there is one) so
+ # that we can tell GDB to use it. But we need our own access to
+ # gdb over a regular stdin/stdout pipe.
+ self.inferior_pty = runner.steal_tty()
+
+ # We need access to stdin/stdout so that we can communicate with
+ # the gdb process.
+ runner.set_flags(Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE)
+
+ def on_runner_spawned(self, runner, identifier):
+ # Create our client to communicate with gdb
+ io_stream = Gio.SimpleIOStream.new(runner.get_stdout(), runner.get_stdin())
+ self.client = Mi2.Client.new(io_stream)
+
+ # Connect to all the signals we need from the client before we ask it to start
+ # processing incoming messages. We don't want to lose anything.
+ self.client.connect('breakpoint-inserted', self.on_client_breakpoint_inserted)
+ self.client.connect('breakpoint-removed', self.on_client_breakpoint_removed)
+ self.client.connect('event', self.on_client_event)
+ self.client.connect('stopped', self.on_client_stopped)
+ self.client.connect('log', self.on_client_log)
+
+ # Start the async read loop for the client to process replies.
+ self.client.start_listening()
+
+ # We stole the pty from the runner so that we could pass it to gdb
+ # instead. This will ensure that gdb re-opens that pty. Since gdb is
+ # in the same sandbox as the application, this should Just Workâ˘.
+ command = '-gdb-set inferior-tty {}'.format(os.ttyname(self.inferior_pty))
+ self.client.exec_async(command, None, self.on_client_exec_cb)
+
+ # Add a breakpoint at main()
+ #breakpoint = Mi2.Breakpoint(function='main')
+ #self.client.insert_breakpoint_async(breakpoint, None)
+
+ # Now ask gdb to start the inferior
+ self.client.run_async(None, self.on_client_run_cb)
+
+ def on_client_run_cb(self, client, result):
+ try:
+ ret = client.run_finish(result)
+ except Exception as ex:
+ print(repr(ex))
+
+ def on_client_exec_cb(self, client, result):
+ try:
+ ret = client.exec_finish(result)
+ except Exception as ex:
+ print(repr(ex))
+
+ def on_runner_exited(self, runner):
+ self.client.stop_listening()
+
+ def on_client_log(self, client, message):
+ print('>>>', message[:-1])
+
+ def on_client_event(self, client, message):
+ print('Event: {}'.format(message.get_name()))
+
+ def on_client_breakpoint_inserted(self, client, breakpoint):
+ print('Breakpoint inserted {}'.format(breakpoint))
+
+ def on_client_breakpoint_removed(self, client, breakpoint_id):
+ print('Breakpoint removed{}'.format(breakpoint_id))
+
+ def on_client_stopped(self, client, reason, message):
+ print('::stopped {}'.format(reason))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]