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

Side by Side Diff: mojo/devtools/common/debugger

Issue 1209593002: GDB support for Android in devtools' debugger. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 5 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 unified diff | Download patch
« no previous file with comments | « mojo/devtools/common/android_gdb/session.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import argparse 6 import argparse
7 import codecs
8 import logging
7 import os.path 9 import os.path
8 import requests 10 import requests
11 import signal
9 import subprocess 12 import subprocess
10 import sys 13 import sys
14 import tempfile
15
16
17 from android_gdb.install_remote_file_reader import install
18
11 19
12 _MOJO_DEBUGGER_PORT = 7777 20 _MOJO_DEBUGGER_PORT = 7777
21 _DEFAULT_PACKAGE_NAME = 'org.chromium.mojo.shell'
22
23
24 # TODO(etiennej): Refactor with similar methods in subdirectories
25 class DirectoryNotFoundException(Exception):
26 """Directory has not been found."""
27 pass
28
29
30 def _get_dir_above(dirname):
31 """Returns the directory "above" this file containing |dirname|."""
32 path = os.path.abspath(__file__)
33 while True:
34 path, tail = os.path.split(path)
35 if not tail:
36 raise DirectoryNotFoundException(dirname)
37 if dirname in os.listdir(path):
38 return path
39
40
41 # The two methods below are taken from //tools/find_depot_tools.py.
42 def _is_real_depot_tools(path):
43 return os.path.isfile(os.path.join(path, 'gclient.py'))
44
45
46 def _get_depot_tools_path():
47 """Searches for depot_tools."""
48 # First look if depot_tools is already in PYTHONPATH.
49 for i in sys.path:
50 if i.rstrip(os.sep).endswith('depot_tools') and _is_real_depot_tools(i):
51 return i
52 # Then look if depot_tools is in PATH, common case.
53 for i in os.environ['PATH'].split(os.pathsep):
54 if _is_real_depot_tools(i):
55 return i
56 # Rare case, it's not even in PATH, look upward up to root.
57 root_dir = os.path.dirname(os.path.abspath(__file__))
58 previous_dir = os.path.abspath(__file__)
59 while root_dir and root_dir != previous_dir:
60 i = os.path.join(root_dir, 'depot_tools')
61 if _is_real_depot_tools(i):
62 return i
63 previous_dir = root_dir
64 root_dir = os.path.dirname(root_dir)
65 return None
13 66
14 67
15 def _send_request(request, payload=None): 68 def _send_request(request, payload=None):
16 """Sends a request to mojo:debugger.""" 69 """Sends a request to mojo:debugger."""
17 try: 70 try:
18 url = 'http://localhost:%s/%s' % (_MOJO_DEBUGGER_PORT, request) 71 url = 'http://localhost:%s/%s' % (_MOJO_DEBUGGER_PORT, request)
19 if payload: 72 if payload:
20 return requests.post(url, payload) 73 return requests.post(url, payload)
21 else: 74 else:
22 return requests.get(url) 75 return requests.get(url)
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 stack.wait() 178 stack.wait()
126 179
127 if logcat.returncode: 180 if logcat.returncode:
128 print 'adb logcat failed, make sure the device is connected and available' 181 print 'adb logcat failed, make sure the device is connected and available'
129 return logcat.returncode 182 return logcat.returncode
130 if stack.returncode: 183 if stack.returncode:
131 return stack.returncode 184 return stack.returncode
132 return 0 185 return 0
133 186
134 187
188 def _gdb_attach(args):
189 """Run GDB on an instance of Mojo Shell on an android device."""
190 if args.ndk_dir:
191 ndk_dir = args.ndk_dir
192 else:
193 try:
194 ndk_dir = os.path.join(_get_dir_above('third_party'), 'third_party',
195 'android_tools', 'ndk')
196 if not os.path.exists(ndk_dir):
197 raise DirectoryNotFoundException()
198 except DirectoryNotFoundException:
199 logging.fatal("Unable to find the Android NDK, please specify its path "
200 "with --ndk-dir.")
201 return
202
203 install_args = {}
204 if args.gsutil_dir:
205 install_args['gsutil'] = os.path.join(args.gsutil_dir, 'gsutil')
206 else:
207 try:
208 install_args['gsutil'] = os.path.join(
209 _get_depot_tools_path(), 'third_party', 'gsutil',
210 'gsutil')
211 if not os.path.exists(install_args['gsutil']):
212 raise DirectoryNotFoundException()
213 except DirectoryNotFoundException:
214 logging.fatal("Unable to find gsutil, please specify its path with " "--gs util-dir.")
215 return
216
217 if args.adb_path:
218 install_args['adb'] = args.adb_path
219 install(**install_args)
220
221 gdb_path = os.path.join(
222 ndk_dir,
223 'toolchains',
224 # TODO(etiennej): Always select the most recent toolchain?
225 'arm-linux-androideabi-4.9',
226 'prebuilt',
227 # TODO(etiennej): DEPS mac NDK and use it on macs.
228 'linux-x86_64',
229 'bin',
230 'arm-linux-androideabi-gdb')
231 python_gdb_script_path = os.path.join(os.path.dirname(__file__),
232 'android_gdb', 'session.py')
233 debug_session_arguments = {}
234 if args.build_dir:
235 debug_session_arguments["build_directory"] = args.build_dir
236 else:
237 try:
238 debug_session_arguments["build_directory"] = os.path.join(
239 _get_dir_above('out'), 'out', 'android_Debug')
240 if not os.path.exists(debug_session_arguments["build_directory"]):
241 raise DirectoryNotFoundException()
242 except DirectoryNotFoundException:
243 logging.fatal("Unable to find the build directory, please specify it "
244 "using --build-dir.")
245 return
246
247 if args.package_name:
248 debug_session_arguments["package_name"] = args.package_name
249 else:
250 debug_session_arguments["package_name"] = _DEFAULT_PACKAGE_NAME
251 if args.pyelftools_dir:
252 debug_session_arguments["pyelftools_dir"] = args.pyelftools_dir
253 else:
254 debug_session_arguments["pyelftools_dir"] = os.path.join(
255 _get_dir_above('third_party'), 'third_party', 'pyelftools')
256
257 debug_session_arguments_str = ', '.join(
258 [k + '="' + codecs.encode(v, 'string_escape') + '"'
259 for k, v in debug_session_arguments.items()])
260
261 # We need to pass some commands to GDB at startup.
262 gdb_commands_file = tempfile.NamedTemporaryFile()
263 gdb_commands_file.write('source ' + python_gdb_script_path + '\n')
264 gdb_commands_file.write('py d = DebugSession(' + debug_session_arguments_str
265 + ')\n')
266 gdb_commands_file.write('py d.start()\n')
267 gdb_commands_file.flush()
268
269 gdb_proc = subprocess.Popen([gdb_path, '-x', gdb_commands_file.name],
270 stdin=sys.stdin,
271 stdout=sys.stdout,
272 stderr=sys.stderr)
273
274 # We don't want SIGINT to stop this program. It is automatically propagated by
275 # the system to gdb.
276 signal.signal(signal.SIGINT, signal.SIG_IGN)
277 gdb_proc.wait()
278 signal.signal(signal.SIGINT, signal.SIG_DFL)
279
280
135 def _add_device_command(subparsers): 281 def _add_device_command(subparsers):
136 """Sets up the parser for the 'device' command.""" 282 """Sets up the parser for the 'device' command."""
137 device_parser = subparsers.add_parser('device', 283 device_parser = subparsers.add_parser('device',
138 help='interact with the Android device (requires adb in PATH or passing ' 284 help='interact with the Android device (requires adb in PATH or passing '
139 '--adb-path)') 285 '--adb-path)')
140 device_parser.add_argument('--adb-path', type=str, 286 device_parser.add_argument('--adb-path', type=str,
141 help='path to the adb tool from the Android SDK') 287 help='path to the adb tool from the Android SDK (optional)')
142 device_subparser = device_parser.add_subparsers( 288 device_subparser = device_parser.add_subparsers(
143 help='the command to run') 289 help='the command to run')
144 290
145 device_stack_parser = device_subparser.add_parser('stack', 291 device_stack_parser = device_subparser.add_parser('stack',
146 help='symbolize the crash stacktraces from the device log') 292 help='symbolize the crash stacktraces from the device log')
293 device_stack_parser.add_argument('--ndk-dir', type=str,
294 help='path to the directory containing the Android NDK')
147 device_stack_parser.add_argument('--build-dir', type=str, 295 device_stack_parser.add_argument('--build-dir', type=str,
148 help='path to the build directory') 296 help='path to the build directory')
149 device_stack_parser.add_argument('--ndk-dir', type=str, 297 device_stack_parser.set_defaults(func=_device_stack)
298
299
300 def _add_gdb_command(subparsers):
301 gdb_parser = subparsers.add_parser(
302 'gdb', help='Debug Mojo Shell and its apps using GDB')
303 gdb_subparser = gdb_parser.add_subparsers(
304 help='Commands to GDB')
305
306 gdb_attach_parser = gdb_subparser.add_parser(
307 'attach', help='Attach GDB to a running Mojo Shell process')
308 gdb_attach_parser.add_argument('--adb-path', type=str,
309 help='path to the adb tool from the Android SDK (optional)')
310 gdb_attach_parser.add_argument('--ndk-dir', type=str,
150 help='path to the directory containing the Android NDK') 311 help='path to the directory containing the Android NDK')
151 device_stack_parser.set_defaults(func=_device_stack) 312 gdb_attach_parser.add_argument('--build-dir', type=str,
313 help='path to the build directory')
314 gdb_attach_parser.add_argument('--pyelftools-dir', type=str,
315 help='Path to a directory containing third party libraries')
316 gdb_attach_parser.add_argument('--gsutil-dir', type=str,
317 help='Path to a directory containing gsutil')
318 gdb_attach_parser.add_argument('--package-name', type=str,
319 help='Name of the Mojo Shell android package to debug')
320 gdb_attach_parser.set_defaults(func=_gdb_attach)
152 321
153 322
154 def main(): 323 def main():
155 parser = argparse.ArgumentParser(description='Command-line interface for ' 324 parser = argparse.ArgumentParser(description='Command-line interface for '
156 'mojo:debugger') 325 'mojo:debugger')
157 subparsers = parser.add_subparsers(help='the tool to run') 326 subparsers = parser.add_subparsers(help='the tool to run')
158 _add_device_command(subparsers) 327 _add_device_command(subparsers)
159 _add_tracing_command(subparsers) 328 _add_tracing_command(subparsers)
160 _add_wm_command(subparsers) 329 _add_wm_command(subparsers)
330 _add_gdb_command(subparsers)
161 331
162 args = parser.parse_args() 332 args = parser.parse_args()
163 return args.func(args) 333 return args.func(args)
164 334
165 if __name__ == '__main__': 335 if __name__ == '__main__':
166 sys.exit(main()) 336 sys.exit(main())
OLDNEW
« no previous file with comments | « mojo/devtools/common/android_gdb/session.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698