Skip to content
Snippets Groups Projects
Commit 1cd591de authored by Louis-Francis Ratté-Boulianne's avatar Louis-Francis Ratté-Boulianne Committed by Sjoerd Simons
Browse files

Add support start a remote application under a debugger


Start the gdbserver on device and start gdb client locally in interactive
mode. Default port is not configurable as of now (1234) and other targets
(e.g. simulator, SDK) are not supported.

Signed-off-by: default avatarLouis-Francis Ratté-Boulianne <lfrb@collabora.com>
Reviewed-by: default avatarSjoerd Simons <sjoerd.simons@collabora.co.uk>
Differential Revision: https://phabricator.apertis.org/D5299
parent fdff21f1
No related branches found
Tags apertis/0.1703.1 v0.1703.1
No related merge requests found
.TH ADE\-DEBUG 1 14/12/2016 0.1612.0 Apertis\ Development\ Tools\ Manual
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.SH NAME
ade-debug \- Start an application in debug mode
.SH SYNOPSIS
.sp
.nf
\fIade debug\fR --app=<app> --device [<user>[:<pass>]@]<hostname>[:<port>] \fBARGS\fR
.fi
.sp
.SH DESCRIPTION
.sp
Start an application on given device in debug mode and connect GDB to it\&.
The tool should be run with the target project directory as the current one\&.
Ideally, the project should have been configured with the \-\-debug option so
the debug symbols are available\&.
.sp
.SH OPTIONS
.sp
.PP
\fI\-\-app\fR
.RS 4
Absolute path to application to start\&.
.sp
.RE
.PP
\fI\-\-device\fR
.RS 4
Use device as target (e.g. user@apertis)\&.
.sp
.RE
.SH SEE ALSO
ade(1)
.SH COPYRIGHT
Copyright (c) 2016 Collabora Ltd.
...@@ -101,6 +101,14 @@ Start application in simulator or on device\&. ...@@ -101,6 +101,14 @@ Start application in simulator or on device\&.
See \fBade-run(1)\fR See \fBade-run(1)\fR
.sp .sp
.RE .RE
.PP
\fIdebug\fR
.RS 4
Start application in debug mode\&.
.sp
See \fBade-debug(1)\fR
.sp
.RE
.SH SEE ALSO .SH SEE ALSO
ade-sysroot(1) ade-sysroot(1)
......
...@@ -27,6 +27,8 @@ import subprocess ...@@ -27,6 +27,8 @@ import subprocess
import sys import sys
import tarfile import tarfile
import tempfile import tempfile
import time
import threading
import urllib import urllib
import xdg.BaseDirectory import xdg.BaseDirectory
...@@ -37,6 +39,7 @@ from urllib.parse import urlparse ...@@ -37,6 +39,7 @@ from urllib.parse import urlparse
from urllib.request import urlopen, urlretrieve from urllib.request import urlopen, urlretrieve
HARD_FLOAT_FLAG = 0x00000400 HARD_FLOAT_FLAG = 0x00000400
DEFAULT_GDBSERVER_PORT = 1234
def print_progress(count, blockSize, total): def print_progress(count, blockSize, total):
...@@ -171,6 +174,72 @@ class TargetTriplet: ...@@ -171,6 +174,72 @@ class TargetTriplet:
raise NotSupportedError raise NotSupportedError
class DebuggerServerThread(threading.Thread):
def __init__(self, target, port, app, *args):
super().__init__()
self.target = target
self.port = port
self.app = app
self.args = args
def run(self):
self._data = self.target.start_gdbserver(self.port, self.app, *self.args)
def stop(self):
self.target.stop_gdbserver(self._data)
class DebuggerServer:
def __init__(self, target, app, *args):
self.target = target
self.app = app
self.args = args
self.port = DEFAULT_GDBSERVER_PORT
self._thread = None
def __enter__(self):
self._thread = DebuggerServerThread(self.target, self.port, self.app, *self.args)
self._thread.start()
return self
def __exit__(self, et, ev, tb):
self._thread.stop()
self._thread.join()
def get_info(self):
return "tcp:{}:{}".format(self.target.host, self.port)
class Debugger:
def __init__(self, target, project):
self.target = target
self.project = project
def _get_commands(self, server, debugdir, libdir):
cmds = []
if isinstance(self.target, Sysroot):
cmds.append("set sysroot {}".format(self.target.path))
cmds.append("set solib-search-path {}".format(libdir))
cmds.append("file {}{}".format(debugdir, server.app))
cmds.append("target remote {}".format(server.get_info()))
return cmds
def connect(self, server):
debugdir = os.path.join(self.project.root, 'debug')
libdir = os.path.join(self.project.root, 'debug', 'Applications', self.project.bundle_id, 'lib')
self.project.install(debugdir)
cmds = self._get_commands(server, debugdir, libdir)
args = ['gdb']
for cmd in cmds:
args.append('-ex')
args.append(cmd)
os.execv('/usr/bin/gdb', args)
class Simulator: class Simulator:
def __init__(self): def __init__(self):
...@@ -249,6 +318,11 @@ class Device: ...@@ -249,6 +318,11 @@ class Device:
return out return out
def _run(self, *args):
ssh = self._connect()
stdin, stdout, stderr = ssh.exec_command(' '.join(args))
return ssh, stdout.channel
def load_sysroot_version(self): def load_sysroot_version(self):
try: try:
v = self._exec('cat', '/etc/image_version') v = self._exec('cat', '/etc/image_version')
...@@ -280,6 +354,29 @@ class Device: ...@@ -280,6 +354,29 @@ class Device:
def run(self, app, *args): def run(self, app, *args):
self._exec('canterbury-exec', app, *args) self._exec('canterbury-exec', app, *args)
def _wait_gdbserver(self, channel):
data = b''
while True:
if channel.exit_status_ready():
status = channel.recv_exit_status()
if status != 0:
raise CommandFailedError('', data.decode().strip(), status)
while channel.recv_stderr_ready():
data += channel.recv_stderr(1024)
if 'Listening on port' in data.decode():
return
time.sleep(1)
def start_gdbserver(self, port, app, *args):
host = self.host
conn = "{}:{}".format(host, port)
ssh, chan = self._run('gdbserver', '--wrapper', 'canterbury-exec', '--', conn, app, *args)
self._wait_gdbserver(chan)
return (ssh, chan)
def stop_gdbserver(self, data):
pass
class SysrootVersion: class SysrootVersion:
...@@ -1263,6 +1360,14 @@ class Ade: ...@@ -1263,6 +1360,14 @@ class Ade:
target = self.get_target() target = self.get_target()
target.run(self.app, *self.args) target.run(self.app, *self.args)
def do_debug(self):
target = self.get_target()
project = Project()
with DebuggerServer(target, self.app, *self.args) as server:
gdb = Debugger(self.unpack_sysroot(target), project)
gdb.connect(server)
def info(self, message): def info(self, message):
if self.format == 'friendly': if self.format == 'friendly':
print(message) print(message)
...@@ -1379,6 +1484,13 @@ if __name__ == '__main__': ...@@ -1379,6 +1484,13 @@ if __name__ == '__main__':
group.add_argument('--device', help="Use device as target (e.g. user@apertis)") group.add_argument('--device', help="Use device as target (e.g. user@apertis)")
run_parser.add_argument('args', help="Arguments to pass to application", nargs=argparse.REMAINDER) run_parser.add_argument('args', help="Arguments to pass to application", nargs=argparse.REMAINDER)
# Debug parser
debug_parser = subparsers.add_parser('debug', help="Debug application")
debug_parser.add_argument('--app', help="Remote path to application to debug")
group = debug_parser.add_mutually_exclusive_group()
group.add_argument('--device', help="Use device as target (e.g. user@apertis)")
debug_parser.add_argument('args', help="Arguments to pass to application", nargs=argparse.REMAINDER)
argcomplete.autocomplete(root_parser) argcomplete.autocomplete(root_parser)
obj = Ade() obj = Ade()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment