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

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