Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 os.path | 7 import os.path |
| 8 import requests | 8 import requests |
| 9 import subprocess | 9 import subprocess |
| 10 import sys | 10 import sys |
| 11 import tempfile | |
| 12 import codecs | |
| 13 | |
| 14 from android_gdb.install_remote_file_reader import install_binary | |
| 11 | 15 |
| 12 _MOJO_DEBUGGER_PORT = 7777 | 16 _MOJO_DEBUGGER_PORT = 7777 |
| 13 | 17 |
| 14 | 18 |
| 19 # TODO(etiennej): Refactor with similar methods in subdirectories | |
| 20 def _GetDirAbove(dirname): | |
|
ppi
2015/07/09 13:12:40
_get_dir_above, let's make it not loop infinitely
etiennej
2015/07/15 07:13:21
Done.
| |
| 21 """Returns the directory "above" this file containing |dirname|.""" | |
| 22 path = os.path.abspath(__file__) | |
| 23 while True: | |
| 24 path, _ = os.path.split(path) | |
| 25 assert path | |
| 26 if dirname in os.listdir(path): | |
| 27 return path | |
| 28 | |
| 29 | |
| 15 def _send_request(request, payload=None): | 30 def _send_request(request, payload=None): |
| 16 """Sends a request to mojo:debugger.""" | 31 """Sends a request to mojo:debugger.""" |
| 17 try: | 32 try: |
| 18 url = 'http://localhost:%s/%s' % (_MOJO_DEBUGGER_PORT, request) | 33 url = 'http://localhost:%s/%s' % (_MOJO_DEBUGGER_PORT, request) |
| 19 if payload: | 34 if payload: |
| 20 return requests.post(url, payload) | 35 return requests.post(url, payload) |
| 21 else: | 36 else: |
| 22 return requests.get(url) | 37 return requests.get(url) |
| 23 except requests.exceptions.ConnectionError: | 38 except requests.exceptions.ConnectionError: |
| 24 print 'Failed to connect to mojo:debugger, make sure the shell is running.' | 39 print 'Failed to connect to mojo:debugger, make sure the shell is running.' |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 125 stack.wait() | 140 stack.wait() |
| 126 | 141 |
| 127 if logcat.returncode: | 142 if logcat.returncode: |
| 128 print 'adb logcat failed, make sure the device is connected and available' | 143 print 'adb logcat failed, make sure the device is connected and available' |
| 129 return logcat.returncode | 144 return logcat.returncode |
| 130 if stack.returncode: | 145 if stack.returncode: |
| 131 return stack.returncode | 146 return stack.returncode |
| 132 return 0 | 147 return 0 |
| 133 | 148 |
| 134 | 149 |
| 150 def _gdb_attach(args): | |
| 151 """Run GDB on an instance of Mojo Shell on an android device.""" | |
| 152 if args.ndk_dir: | |
| 153 ndk_dir = args.ndk_dir | |
| 154 else: | |
| 155 ndk_dir = os.path.join(_GetDirAbove('third_party'), 'third_party', | |
| 156 'android_tools', 'ndk') | |
| 157 install_args = {} | |
| 158 if args.gsutil_dir: | |
| 159 install_args['gsutil'] = os.path.join(args.gsutil_dir, 'gsutil') | |
| 160 else: | |
| 161 install_args['gsutil'] = os.path.join( | |
| 162 _GetDirAbove('depot_tools'), 'depot_tools', 'third_party', 'gsutil', | |
| 163 'gsutil') | |
| 164 if args.adb_path: | |
| 165 install_args['adb'] = args.adb_path | |
| 166 install_binary(**install_args) | |
| 167 | |
| 168 gdb_path = os.path.join( | |
| 169 ndk_dir, | |
| 170 'toolchains', | |
| 171 # TODO(etiennej): Always select the most recent toolchain? | |
| 172 'arm-linux-androideabi-4.9', | |
| 173 'prebuilt', | |
| 174 # TODO(etiennej): DEPS mac NDK and use it on macs. | |
| 175 'linux-x86_64', | |
| 176 'bin', | |
| 177 'arm-linux-androideabi-gdb') | |
| 178 python_gdb_script_path = os.path.join(os.path.dirname(__file__), | |
| 179 'android_gdb', 'session.py') | |
| 180 # We need to pass some commands to GDB at startup. | |
| 181 gdb_setup_commands = tempfile.NamedTemporaryFile() | |
|
ppi
2015/07/09 13:12:40
maybe 'gdb_commands_file'?
etiennej
2015/07/15 07:13:21
Done.
| |
| 182 gdb_setup_commands.write('source ' + python_gdb_script_path + '\n') | |
| 183 debug_session_arguments = {} | |
| 184 if args.build_dir: | |
| 185 debug_session_arguments["build_directory"] = args.build_dir | |
| 186 if args.package_name: | |
| 187 debug_session_arguments["package_name"] = args.package_name | |
| 188 if args.pyelftools_dir: | |
| 189 debug_session_arguments["pyelftools_dir"] = args.pyelftools_dir | |
| 190 debug_session_arguments = ', '.join( | |
|
ppi
2015/07/09 13:12:40
Maybe compute this string before gdb command file
ppi
2015/07/09 13:12:40
Better to use a new variable / not to change the t
etiennej
2015/07/15 07:13:21
Done.
etiennej
2015/07/15 07:13:21
If one cannot redefine its variable types in Pytho
| |
| 191 [k + '="' + codecs.encode(v, 'string_escape') + '"' | |
| 192 for k, v in debug_session_arguments.items()]) | |
| 193 gdb_setup_commands.write('py d = DebugSession(' + debug_session_arguments + | |
| 194 ')\n') | |
| 195 gdb_setup_commands.write('py d.start_debug()\n') | |
| 196 gdb_setup_commands.flush() | |
| 197 gdb_proc = subprocess.Popen([gdb_path, '-x', gdb_setup_commands.name], | |
| 198 stdin=sys.stdin, | |
| 199 stdout=sys.stdout, | |
| 200 stderr=sys.stderr) | |
| 201 gdb_proc.wait() | |
| 202 | |
| 203 | |
| 135 def _add_device_command(subparsers): | 204 def _add_device_command(subparsers): |
| 136 """Sets up the parser for the 'device' command.""" | 205 """Sets up the parser for the 'device' command.""" |
| 137 device_parser = subparsers.add_parser('device', | 206 device_parser = subparsers.add_parser('device', |
| 138 help='interact with the Android device (requires adb in PATH or passing ' | 207 help='interact with the Android device (requires adb in PATH or passing ' |
| 139 '--adb-path)') | 208 '--adb-path)') |
| 140 device_parser.add_argument('--adb-path', type=str, | 209 device_parser.add_argument('--adb-path', type=str, |
| 141 help='path to the adb tool from the Android SDK') | 210 help='path to the adb tool from the Android SDK (optional)') |
| 142 device_subparser = device_parser.add_subparsers( | 211 device_subparser = device_parser.add_subparsers( |
| 143 help='the command to run') | 212 help='the command to run') |
| 144 | 213 |
| 145 device_stack_parser = device_subparser.add_parser('stack', | 214 device_stack_parser = device_subparser.add_parser('stack', |
| 146 help='symbolize the crash stacktraces from the device log') | 215 help='symbolize the crash stacktraces from the device log') |
| 216 device_stack_parser.add_argument('--ndk-dir', type=str, | |
| 217 help='path to the directory containing the Android NDK') | |
| 147 device_stack_parser.add_argument('--build-dir', type=str, | 218 device_stack_parser.add_argument('--build-dir', type=str, |
| 148 help='path to the build directory') | 219 help='path to the build directory') |
| 149 device_stack_parser.add_argument('--ndk-dir', type=str, | 220 device_stack_parser.set_defaults(func=_device_stack) |
| 221 | |
| 222 | |
| 223 def _add_gdb_command(subparsers): | |
| 224 gdb_parser = subparsers.add_parser( | |
| 225 'gdb', help='Debug Mojo Shell and its apps using GDB') | |
| 226 gdb_subparser = gdb_parser.add_subparsers( | |
| 227 help='Commands to GDB') | |
| 228 | |
| 229 gdb_attach_parser = gdb_subparser.add_parser( | |
| 230 'attach', help='Attach GDB to a running Mojo Shell process') | |
| 231 gdb_attach_parser.add_argument('--adb-path', type=str, | |
| 232 help='path to the adb tool from the Android SDK (optional)') | |
| 233 gdb_attach_parser.add_argument('--ndk-dir', type=str, | |
| 150 help='path to the directory containing the Android NDK') | 234 help='path to the directory containing the Android NDK') |
| 151 device_stack_parser.set_defaults(func=_device_stack) | 235 gdb_attach_parser.add_argument('--build-dir', type=str, |
| 236 help='path to the build directory') | |
| 237 gdb_attach_parser.add_argument('--pyelftools-dir', type=str, | |
| 238 help='Path to a directory containing third party libraries') | |
| 239 gdb_attach_parser.add_argument('--gsutil-dir', type=str, | |
| 240 help='Path to a directory containing gsutil') | |
| 241 gdb_attach_parser.add_argument('--package-name', type=str, | |
| 242 help='Name of the Mojo Shell android package to debug') | |
| 243 gdb_attach_parser.set_defaults(func=_gdb_attach) | |
| 152 | 244 |
| 153 | 245 |
| 154 def main(): | 246 def main(): |
| 155 parser = argparse.ArgumentParser(description='Command-line interface for ' | 247 parser = argparse.ArgumentParser(description='Command-line interface for ' |
| 156 'mojo:debugger') | 248 'mojo:debugger') |
| 157 subparsers = parser.add_subparsers(help='the tool to run') | 249 subparsers = parser.add_subparsers(help='the tool to run') |
| 158 _add_device_command(subparsers) | 250 _add_device_command(subparsers) |
| 159 _add_tracing_command(subparsers) | 251 _add_tracing_command(subparsers) |
| 160 _add_wm_command(subparsers) | 252 _add_wm_command(subparsers) |
| 253 _add_gdb_command(subparsers) | |
| 161 | 254 |
| 162 args = parser.parse_args() | 255 args = parser.parse_args() |
| 163 return args.func(args) | 256 return args.func(args) |
| 164 | 257 |
| 165 if __name__ == '__main__': | 258 if __name__ == '__main__': |
| 166 sys.exit(main()) | 259 sys.exit(main()) |
| OLD | NEW |