Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Unified Diff: sky/tools/shelldb

Issue 1167513003: Make --gdb and gdb_attach mostly work in shelldb (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Fix reverse/forward typo Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/tools/shelldb
diff --git a/sky/tools/shelldb b/sky/tools/shelldb
index 3800670c3b1dbd6171ab9c14fdb1047d537e4d12..369b5efc57bba9c77bda0c9713162f24a58dd775 100755
--- a/sky/tools/shelldb
+++ b/sky/tools/shelldb
@@ -5,22 +5,25 @@
from skypy.skyserver import SkyServer
import argparse
+import hashlib
import json
import logging
import os
+import pipes
+import platform
import re
import signal
import subprocess
import sys
+import tempfile
import time
import urlparse
-import hashlib
-import tempfile
SKY_TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
SKY_ROOT = os.path.dirname(SKY_TOOLS_DIR)
SRC_ROOT = os.path.dirname(SKY_ROOT)
+GDB_PORT = 8888
SKY_SERVER_PORT = 9888
OBSERVATORY_PORT = 8181
DEFAULT_URL = "sky://domokit.github.io/sky_home"
@@ -37,8 +40,13 @@ PID_FILE_KEYS = frozenset([
'sky_server_port',
'sky_server_root',
'build_dir',
+ 'sky_shell_pid',
+ 'remote_gdbserver_port',
])
+# TODO(iansf): Fix undefined behavior when you have more than one device attached.
+SYSTEM_LIBS_ROOT_PATH = '/tmp/device_libs/%s' % (subprocess.check_output(['adb', 'get-serialno']).strip())
+
_IGNORED_PATTERNS = [
# Ignored because they're not indicative of specific errors.
re.compile(r'^$'),
@@ -153,6 +161,7 @@ class StartSky(object):
start_parser = subparsers.add_parser('start',
help='launch SkyShell.apk on the device')
start_parser.add_argument('build_dir', type=str)
+ start_parser.add_argument('--gdb', action="store_true")
start_parser.add_argument('url_or_path', nargs='?', type=str,
default=DEFAULT_URL)
start_parser.add_argument('--no_install', action="store_false",
@@ -179,6 +188,20 @@ class StartSky(object):
sky_server = SkyServer(SKY_SERVER_PORT, configuration, server_root, packages_root)
return sky_server
+ def _find_remote_pid_for_package(self, package):
+ ps_output = subprocess.check_output([ADB_PATH, 'shell', 'ps'])
+ for line in ps_output.split('\n'):
+ fields = line.split()
+ if fields and fields[-1] == package:
+ return fields[1]
+ return None
+
+ def _find_install_location_for_package(self, package):
+ pm_command = [ADB_PATH, 'shell', 'pm', 'path', package]
+ pm_output = subprocess.check_output(pm_command)
+ # e.g. package:/data/app/org.chromium.mojo.shell-1/base.apk
+ return pm_output.split(':')[-1]
+
def run(self, args, pids):
apk_path = os.path.join(args.build_dir, 'apks', APK_NAME)
if not os.path.exists(apk_path):
@@ -236,11 +259,124 @@ class StartSky(object):
])
pids['remote_sky_server_port'] = sky_server.port
+
subprocess.check_call([ADB_PATH, 'shell',
'am', 'start',
'-a', 'android.intent.action.VIEW',
'-d', _url_from_args(args, pids)])
+ if not args.gdb:
+ return
+
+ # TODO(eseidel): am start -W does not seem to work?
+ pid_tries = 0
+ while True:
+ pid = self._find_remote_pid_for_package(ANDROID_PACKAGE)
+ if pid or pid_tries > 3:
+ break
+ logging.debug('No pid for %s yet, waiting' % ANDROID_PACKAGE)
+ time.sleep(5)
+ pid_tries += 1
+
+ if not pid:
+ logging.error('Failed to find pid on device!')
+ return
+
+ pids['sky_shell_pid'] = pid
+
+ # We push our own copy of gdbserver with the package since
+ # the default gdbserver is a different version from our gdb.
+ package_path = \
+ self._find_install_location_for_package(ANDROID_PACKAGE)
+ gdb_server_path = os.path.join(
+ os.path.dirname(package_path), 'lib/arm/gdbserver')
+ gdbserver_cmd = [
+ ADB_PATH, 'shell',
+ gdb_server_path, '--attach',
+ ':%d' % GDB_PORT,
+ str(pid)
+ ]
+ print ' '.join(map(pipes.quote, gdbserver_cmd))
+ subprocess.Popen(gdbserver_cmd)
+
+ port_string = 'tcp:%d' % GDB_PORT
+ subprocess.check_call([
+ ADB_PATH, 'forward', port_string, port_string
+ ])
+ pids['remote_gdbserver_port'] = GDB_PORT
+
+
+class GDBAttach(object):
+ def add_subparser(self, subparsers):
+ start_parser = subparsers.add_parser('gdb_attach',
+ help='attach to gdbserver running on device')
+ start_parser.set_defaults(func=self.run)
+
+ def _pull_system_libraries(self, pids, system_libs_root):
+ # Pull down the system libraries this pid has already mapped in.
+ # TODO(eseidel): This does not handle dynamic loads.
+ library_cacher_path = os.path.join(
+ SKY_TOOLS_DIR, 'android_library_cacher.py')
+ subprocess.call([
+ library_cacher_path, system_libs_root, pids['sky_shell_pid']
+ ])
+
+ # TODO(eseidel): adb_gdb does, this, unclear why solib-absolute-prefix
+ # doesn't make this explicit listing not necessary?
+ return subprocess.check_output([
+ 'find', system_libs_root,
+ '-mindepth', '1',
+ '-maxdepth', '4',
+ '-type', 'd',
+ ]).strip().split('\n')
+
+ def run(self, args, pids):
+ symbol_search_paths = [
+ pids['build_dir'],
+ ]
+ gdb_path = '/usr/bin/gdb'
+
+ eval_commands = [
+ 'directory %s' % SRC_ROOT,
+ # TODO(eseidel): What file do I point it at? The apk?
+ #'file %s' % self.paths.mojo_shell_path,
+ 'target remote localhost:%s' % GDB_PORT,
+ ]
+
+ system_lib_dirs = self._pull_system_libraries(pids,
+ SYSTEM_LIBS_ROOT_PATH)
+ eval_commands.append(
+ 'set solib-absolute-prefix %s' % SYSTEM_LIBS_ROOT_PATH)
+
+ symbol_search_paths = system_lib_dirs + symbol_search_paths
+
+ # TODO(eseidel): We need to look up the toolchain somehow?
+ if platform.system() == 'Darwin':
+ gdb_path = os.path.join(SRC_ROOT, 'third_party/android_tools/ndk/'
+ 'toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/'
+ 'bin/arm-linux-androideabi-gdb')
+ else:
+ gdb_path = os.path.join(SRC_ROOT, 'third_party/android_tools/ndk/'
+ 'toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/'
+ 'bin/arm-linux-androideabi-gdb')
+
+ # Set solib-search-path after letting android modify symbol_search_paths
+ eval_commands.append(
+ 'set solib-search-path %s' % ':'.join(symbol_search_paths))
+
+ exec_command = [gdb_path]
+ for command in eval_commands:
+ exec_command += ['--eval-command', command]
+
+ print " ".join(exec_command)
+
+ # Write out our pid file before we exec ourselves.
+ pids.write_to(PID_FILE_PATH)
+
+ # Exec gdb directly to avoid python intercepting symbols, etc.
+ os.execv(exec_command[0], exec_command)
+
+
class StopSky(object):
def add_subparser(self, subparsers):
@@ -259,12 +395,24 @@ class StopSky(object):
except OSError:
logging.info('%s (%d) already gone.' % (name, pid))
+ def _adb_reverse_remove(self, port):
+ port_string = 'tcp:%s' % port
+ subprocess.call([ADB_PATH, 'reverse', '--remove', port_string])
+
+ def _adb_forward_remove(self, port):
+ port_string = 'tcp:%s' % port
+ subprocess.call([ADB_PATH, 'forward', '--remove', port_string])
+
def run(self, args, pids):
self._kill_if_exists(pids, 'sky_server_pid', 'sky_server')
if 'remote_sky_server_port' in pids:
- port_string = 'tcp:%s' % pids['remote_sky_server_port']
- subprocess.call([ADB_PATH, 'reverse', '--remove', port_string])
+ self._adb_reverse_remove(pids['remote_sky_server_port'])
+
+ if 'remote_gdbserver_port' in pids:
+ self._kill_if_exists('adb_shell_gdbserver_pid',
+ 'adb shell gdbserver')
+ self._adb_forward_remove(pids['remote_gdbserver_port'])
subprocess.call([
ADB_PATH, 'shell', 'am', 'force-stop', ANDROID_PACKAGE])
@@ -373,6 +521,7 @@ class SkyShellRunner(object):
StartSky(),
StopSky(),
Analyze(),
+ GDBAttach(),
StartTracing(),
StopTracing(),
]
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698