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

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

Issue 1241263009: Rename shell runner and debugger -> mojo_run, mojo_debug. (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/README.md ('k') | mojo/devtools/common/mojo_debug » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
5
6 import argparse
7 import codecs
8 import logging
9 import os.path
10 import requests
11 import signal
12 import subprocess
13 import sys
14 import tempfile
15
16
17 from android_gdb.install_remote_file_reader import install
18 from devtoolslib import paths
19
20
21 _MOJO_DEBUGGER_PORT = 7777
22 _DEFAULT_PACKAGE_NAME = 'org.chromium.mojo.shell'
23
24
25 # TODO(etiennej): Refactor with similar methods in subdirectories
26 class DirectoryNotFoundException(Exception):
27 """Directory has not been found."""
28 pass
29
30
31 def _get_dir_above(dirname):
32 """Returns the directory "above" this file containing |dirname|."""
33 path = paths.find_ancestor_with(dirname)
34 if not path:
35 raise DirectoryNotFoundException(dirname)
36 return path
37
38
39 def _send_request(request, payload=None):
40 """Sends a request to mojo:debugger."""
41 try:
42 url = 'http://localhost:%s/%s' % (_MOJO_DEBUGGER_PORT, request)
43 if payload:
44 return requests.post(url, payload)
45 else:
46 return requests.get(url)
47 except requests.exceptions.ConnectionError:
48 print 'Failed to connect to mojo:debugger, make sure the shell is running.'
49 return None
50
51
52 def _tracing_start(_):
53 """Starts tracing."""
54 if not _send_request('start_tracing'):
55 return 1
56 print "Started tracing."
57 return 0
58
59
60 def _tracing_stop(args):
61 """Stops tracing and writes trace to file."""
62 if args.file_name:
63 file_name = args.file_name
64 else:
65 for i in xrange(1000):
66 candidate_file_name = 'mojo_trace_%03d.json' % i
67 if not os.path.exists(candidate_file_name):
68 file_name = candidate_file_name
69 break
70 else:
71 print 'Failed to pick a name for the trace output file.'
72 return 1
73
74 response = _send_request('stop_tracing')
75 if not response:
76 return 1
77
78 # https://github.com/domokit/mojo/issues/253
79 if int(response.headers['content-length']) != len(response.content):
80 print 'Response is truncated.'
81 return 1
82
83 with open(file_name, "wb") as trace_file:
84 trace_file.write('{"traceEvents":[')
85 trace_file.write(response.content)
86 trace_file.write(']}')
87 print "Trace saved in %s" % file_name
88 return 0
89
90
91 def _add_tracing_command(subparsers):
92 """Sets up the command line parser to manage tracing."""
93 tracing_parser = subparsers.add_parser('tracing',
94 help='trace event profiler')
95 tracing_subparser = tracing_parser.add_subparsers(
96 help='the command to run')
97
98 start_tracing_parser = tracing_subparser.add_parser('start',
99 help='start tracing')
100 start_tracing_parser.set_defaults(func=_tracing_start)
101
102 stop_tracing_parser = tracing_subparser.add_parser('stop',
103 help='stop tracing and retrieve the result')
104 stop_tracing_parser.add_argument('file_name', type=str, nargs='?',
105 help='name of the output file (optional)')
106 stop_tracing_parser.set_defaults(func=_tracing_stop)
107
108
109 def _wm_load(args):
110 """Loads (embeds) the given url in the window manager."""
111 if not _send_request('load', args.url):
112 return 1
113 return 0
114
115
116 def _add_wm_command(subparsers):
117 """Sets up the parser for the 'wm' command."""
118 wm_parser = subparsers.add_parser('wm', help='window manager')
119 wm_subparser = wm_parser.add_subparsers(
120 help='the command to run')
121
122 wm_load_parser = wm_subparser.add_parser('load',
123 help='load (embed) the given url')
124 wm_load_parser.add_argument('url', type=str,
125 help='the url to load')
126 wm_load_parser.set_defaults(func=_wm_load)
127
128
129 def _device_stack(args):
130 """Runs the device logcat through android_stack_parser."""
131 adb_path = args.adb_path if args.adb_path else 'adb'
132 logcat_cmd = [adb_path, 'logcat', '-d']
133 try:
134 logcat = subprocess.Popen(logcat_cmd, stdout=subprocess.PIPE)
135 except OSError:
136 print 'failed to call adb, make sure it is in PATH or pass --adb-path'
137 return 1
138
139 devtools_dir = os.path.dirname(os.path.abspath(__file__))
140 stack_command = [os.path.join(devtools_dir, 'android_stack_parser', 'stack')]
141 if args.build_dir:
142 stack_command.append('--build-dir=' + os.path.abspath(args.build_dir))
143 if args.ndk_dir:
144 stack_command.append('--ndk-dir=' + os.path.abspath(args.ndk_dir))
145 stack_command.append('-')
146 stack = subprocess.Popen(stack_command, stdin=logcat.stdout)
147
148 logcat.wait()
149 stack.wait()
150
151 if logcat.returncode:
152 print 'adb logcat failed, make sure the device is connected and available'
153 return logcat.returncode
154 if stack.returncode:
155 return stack.returncode
156 return 0
157
158
159 def _gdb_attach(args):
160 """Run GDB on an instance of Mojo Shell on an android device."""
161 if args.ndk_dir:
162 ndk_dir = args.ndk_dir
163 else:
164 try:
165 ndk_dir = os.path.join(_get_dir_above('third_party'), 'third_party',
166 'android_tools', 'ndk')
167 if not os.path.exists(ndk_dir):
168 raise DirectoryNotFoundException()
169 except DirectoryNotFoundException:
170 logging.fatal("Unable to find the Android NDK, please specify its path "
171 "with --ndk-dir.")
172 return
173
174 install_args = {}
175 if args.gsutil_dir:
176 install_args['gsutil'] = os.path.join(args.gsutil_dir, 'gsutil')
177 else:
178 try:
179 depot_tools_path = paths.find_depot_tools()
180 if not depot_tools_path:
181 raise DirectoryNotFoundException()
182 install_args['gsutil'] = os.path.join(depot_tools_path, 'third_party',
183 'gsutil', 'gsutil')
184 if not os.path.exists(install_args['gsutil']):
185 raise DirectoryNotFoundException()
186 except DirectoryNotFoundException:
187 logging.fatal("Unable to find gsutil, please specify its path with "
188 "--gsutil-dir.")
189 return
190
191 if args.adb_path:
192 install_args['adb'] = args.adb_path
193 install(**install_args)
194
195 gdb_path = os.path.join(
196 ndk_dir,
197 'toolchains',
198 # TODO(etiennej): Always select the most recent toolchain?
199 'arm-linux-androideabi-4.9',
200 'prebuilt',
201 # TODO(etiennej): DEPS mac NDK and use it on macs.
202 'linux-x86_64',
203 'bin',
204 'arm-linux-androideabi-gdb')
205 python_gdb_script_path = os.path.join(os.path.dirname(__file__),
206 'android_gdb', 'session.py')
207 debug_session_arguments = {}
208 if args.build_dir:
209 debug_session_arguments["build_directory"] = args.build_dir
210 else:
211 try:
212 debug_session_arguments["build_directory"] = os.path.join(
213 _get_dir_above('out'), 'out', 'android_Debug')
214 if not os.path.exists(debug_session_arguments["build_directory"]):
215 raise DirectoryNotFoundException()
216 except DirectoryNotFoundException:
217 logging.fatal("Unable to find the build directory, please specify it "
218 "using --build-dir.")
219 return
220
221 if args.package_name:
222 debug_session_arguments["package_name"] = args.package_name
223 else:
224 debug_session_arguments["package_name"] = _DEFAULT_PACKAGE_NAME
225 if args.pyelftools_dir:
226 debug_session_arguments["pyelftools_dir"] = args.pyelftools_dir
227 else:
228 debug_session_arguments["pyelftools_dir"] = os.path.join(
229 _get_dir_above('third_party'), 'third_party', 'pyelftools')
230
231 debug_session_arguments_str = ', '.join(
232 [k + '="' + codecs.encode(v, 'string_escape') + '"'
233 for k, v in debug_session_arguments.items()])
234
235 # We need to pass some commands to GDB at startup.
236 gdb_commands_file = tempfile.NamedTemporaryFile()
237 gdb_commands_file.write('source ' + python_gdb_script_path + '\n')
238 gdb_commands_file.write('py d = DebugSession(' + debug_session_arguments_str
239 + ')\n')
240 gdb_commands_file.write('py d.start()\n')
241 gdb_commands_file.flush()
242
243 gdb_proc = subprocess.Popen([gdb_path, '-x', gdb_commands_file.name],
244 stdin=sys.stdin,
245 stdout=sys.stdout,
246 stderr=sys.stderr)
247
248 # We don't want SIGINT to stop this program. It is automatically propagated by
249 # the system to gdb.
250 signal.signal(signal.SIGINT, signal.SIG_IGN)
251 gdb_proc.wait()
252 signal.signal(signal.SIGINT, signal.SIG_DFL)
253
254
255 def _add_device_command(subparsers):
256 """Sets up the parser for the 'device' command."""
257 device_parser = subparsers.add_parser('device',
258 help='interact with the Android device (requires adb in PATH or passing '
259 '--adb-path)')
260 device_parser.add_argument('--adb-path', type=str,
261 help='path to the adb tool from the Android SDK (optional)')
262 device_subparser = device_parser.add_subparsers(
263 help='the command to run')
264
265 device_stack_parser = device_subparser.add_parser('stack',
266 help='symbolize the crash stacktraces from the device log')
267 device_stack_parser.add_argument('--ndk-dir', type=str,
268 help='path to the directory containing the Android NDK')
269 device_stack_parser.add_argument('--build-dir', type=str,
270 help='path to the build directory')
271 device_stack_parser.set_defaults(func=_device_stack)
272
273
274 def _add_gdb_command(subparsers):
275 gdb_parser = subparsers.add_parser(
276 'gdb', help='Debug Mojo Shell and its apps using GDB')
277 gdb_subparser = gdb_parser.add_subparsers(
278 help='Commands to GDB')
279
280 gdb_attach_parser = gdb_subparser.add_parser(
281 'attach', help='Attach GDB to a running Mojo Shell process')
282 gdb_attach_parser.add_argument('--adb-path', type=str,
283 help='path to the adb tool from the Android SDK (optional)')
284 gdb_attach_parser.add_argument('--ndk-dir', type=str,
285 help='path to the directory containing the Android NDK')
286 gdb_attach_parser.add_argument('--build-dir', type=str,
287 help='path to the build directory')
288 gdb_attach_parser.add_argument('--pyelftools-dir', type=str,
289 help='Path to a directory containing third party libraries')
290 gdb_attach_parser.add_argument('--gsutil-dir', type=str,
291 help='Path to a directory containing gsutil')
292 gdb_attach_parser.add_argument('--package-name', type=str,
293 help='Name of the Mojo Shell android package to debug')
294 gdb_attach_parser.set_defaults(func=_gdb_attach)
295
296
297 def main():
298 parser = argparse.ArgumentParser(description='Command-line interface for '
299 'mojo:debugger')
300 subparsers = parser.add_subparsers(help='the tool to run')
301 _add_device_command(subparsers)
302 _add_tracing_command(subparsers)
303 _add_wm_command(subparsers)
304 _add_gdb_command(subparsers)
305
306 args = parser.parse_args()
307 return args.func(args)
308
309 if __name__ == '__main__':
310 sys.exit(main())
OLDNEW
« no previous file with comments | « mojo/devtools/common/README.md ('k') | mojo/devtools/common/mojo_debug » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698