blob: 91dc104c2d767c77d83c48f3a006ef6663905999 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
cmticeb70801a2014-12-11 14:29:34 -08002# Copyright 2014 The Chromium OS 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"""Wrapper for running gdb.
7
8This handles the fun details like running against the right sysroot, via
9qemu, bind mounts, etc...
10"""
11
12from __future__ import print_function
13
14import argparse
15import contextlib
16import errno
17import os
18import sys
19import tempfile
20
21from chromite.lib import commandline
22from chromite.lib import cros_build_lib
cmticef23cb132015-04-10 15:13:00 -070023from chromite.lib import cros_logging as logging
cmticeb70801a2014-12-11 14:29:34 -080024from chromite.lib import namespaces
25from chromite.lib import osutils
cmticef23cb132015-04-10 15:13:00 -070026from chromite.lib import parallel
cmtice932e0aa2015-02-27 11:49:12 -080027from chromite.lib import qemu
cmticef23cb132015-04-10 15:13:00 -070028from chromite.lib import remote_access
cmticeb70801a2014-12-11 14:29:34 -080029from chromite.lib import retry_util
cmticef23cb132015-04-10 15:13:00 -070030from chromite.lib import timeout_util
31from chromite.lib import toolchain
cmticeb70801a2014-12-11 14:29:34 -080032
cmticef23cb132015-04-10 15:13:00 -070033class GdbException(Exception):
34 """Base exception for this module."""
35
36
37class GdbBadRemoteDeviceError(GdbException):
38 """Raised when remote device does not exist or is not responding."""
39
40
41class GdbMissingSysrootError(GdbException):
42 """Raised when path to sysroot cannot be found in chroot."""
43
44
45class GdbMissingInferiorError(GdbException):
46 """Raised when the binary to be debugged cannot be found."""
47
48
49class GdbMissingDebuggerError(GdbException):
50 """Raised when cannot find correct version of debugger."""
51
52
53class GdbCannotFindRemoteProcessError(GdbException):
54 """Raised when cannot find requested executing process on remote device."""
55
56
57class GdbUnableToStartGdbserverError(GdbException):
58 """Raised when error occurs trying to start gdbserver on remote device."""
59
60
61class GdbTooManyPidsError(GdbException):
62 """Raised when more than one matching pid is found running on device."""
63
64
65class GdbEarlyExitError(GdbException):
66 """Raised when user requests to exit early."""
67
68
69class GdbCannotDetectBoardError(GdbException):
70 """Raised when board isn't specified and can't be automatically determined."""
cmticeb70801a2014-12-11 14:29:34 -080071
cmtice932e0aa2015-02-27 11:49:12 -080072
cmticeb70801a2014-12-11 14:29:34 -080073class BoardSpecificGdb(object):
74 """Framework for running gdb."""
75
76 _BIND_MOUNT_PATHS = ('dev', 'dev/pts', 'proc', 'mnt/host/source', 'sys')
cmticef23cb132015-04-10 15:13:00 -070077 _GDB = '/usr/bin/gdb'
78 _EXTRA_SSH_SETTINGS = {'CheckHostIP': 'no',
79 'BatchMode': 'yes'}
80 _MISSING_DEBUG_INFO_MSG = """
81%(inf_cmd)s is stripped and %(debug_file)s does not exist on your local machine.
82 The debug symbols for that package may not be installed. To install the debug
83 symbols for %(package)s only, run:
cmticeb70801a2014-12-11 14:29:34 -080084
cmticef23cb132015-04-10 15:13:00 -070085 cros_install_debug_syms --board=%(board)s %(package)s
86
87To install the debug symbols for all available packages, run:
88
89 cros_install_debug_syms --board=%(board)s --all"""
90
91 def __init__(self, board, gdb_args, inf_cmd, inf_args, remote, pid,
92 remote_process_name, cgdb_flag, ping):
cmticeb70801a2014-12-11 14:29:34 -080093 self.board = board
cmticef23cb132015-04-10 15:13:00 -070094 self.sysroot = None
95 self.prompt = '(gdb) '
cmtice932e0aa2015-02-27 11:49:12 -080096 self.inf_cmd = inf_cmd
cmticef23cb132015-04-10 15:13:00 -070097 self.run_as_root = False
98 self.gdb_args = gdb_args
cmtice932e0aa2015-02-27 11:49:12 -080099 self.inf_args = inf_args
cmticef23cb132015-04-10 15:13:00 -0700100 self.remote = remote.hostname if remote else None
101 self.pid = pid
102 self.remote_process_name = remote_process_name
103 # Port used for sending ssh commands to DUT.
104 self.remote_port = remote.port if remote else None
105 # Port for communicating between gdb & gdbserver.
106 self.gdbserver_port = remote_access.GetUnusedPort()
107 self.ssh_settings = remote_access.CompileSSHConnectSettings(
108 **self._EXTRA_SSH_SETTINGS)
109 self.cgdb = cgdb_flag
cmtice932e0aa2015-02-27 11:49:12 -0800110 self.framework = 'auto'
111 self.qemu = None
cmticef23cb132015-04-10 15:13:00 -0700112 self.device = None
113 self.cross_gdb = None
114 self.ping = ping
cmtice932e0aa2015-02-27 11:49:12 -0800115
cmticef23cb132015-04-10 15:13:00 -0700116 def VerifyAndFinishInitialization(self, device):
117 """Verify files/processes exist and flags are correct."""
118 if not self.board:
119 if self.remote:
120 self.board = cros_build_lib.GetBoard(device_board=device.board,
121 override_board=self.board)
122 else:
123 raise GdbCannotDetectBoardError('Cannot determine which board to use. '
124 'Please specify the with --board flag.')
125
126 self.sysroot = cros_build_lib.GetSysroot(board=self.board)
127 self.prompt = '(%s-gdb) ' % self.board
128 self.inf_cmd = self.RemoveSysrootPrefix(self.inf_cmd)
129 self.cross_gdb = self.GetCrossGdb()
130
131 if self.remote:
132
133 # If given remote process name, find pid & inf_cmd on remote device.
134 if self.remote_process_name or self.pid:
135 self._FindRemoteProcess(device)
136
137 # Verify that sysroot is valid (exists).
138 if not os.path.isdir(self.sysroot):
139 raise GdbMissingSysrootError('Sysroot does not exist: %s' %
140 self.sysroot)
141
142 self.device = device
143 sysroot_inf_cmd = ''
144 if self.inf_cmd:
145 sysroot_inf_cmd = os.path.join(self.sysroot,
146 self.inf_cmd.lstrip('/'))
147
148 # Verify that inf_cmd, if given, exists.
149 if sysroot_inf_cmd and not os.path.exists(sysroot_inf_cmd):
150 raise GdbMissingInferiorError('Cannot find file %s (in sysroot).' %
151 sysroot_inf_cmd)
152
153 # Check to see if inf_cmd is stripped, and if so, check to see if debug file
154 # exists. If not, tell user and give them the option of quitting & getting
155 # the debug info.
156 if sysroot_inf_cmd:
157 stripped_info = cros_build_lib.RunCommand(['file', sysroot_inf_cmd],
158 capture_output=True).output
159 if not ' not stripped' in stripped_info:
160 debug_file = os.path.join(self.sysroot, 'usr/lib/debug',
161 self.inf_cmd.lstrip('/'))
162 debug_file += '.debug'
163 if not os.path.exists(debug_file):
164 equery = 'equery-%s' % self.board
165 package = cros_build_lib.RunCommand([equery, '-q', 'b',
166 self.inf_cmd],
167 capture_output=True).output
168 logging.info(self._MISSING_DEBUG_INFO_MSG % {
169 'board': self.board,
170 'inf_cmd': self.inf_cmd,
171 'package': package,
172 'debug_file': debug_file})
173 answer = cros_build_lib.BooleanPrompt()
174 if not answer:
175 raise GdbEarlyExitError('Exiting early, at user request.')
176
177 # Set up qemu, if appropriate.
178 qemu_arch = qemu.Qemu.DetectArch(self._GDB, self.sysroot)
cmtice932e0aa2015-02-27 11:49:12 -0800179 if qemu_arch is None:
180 self.framework = 'ldso'
181 else:
182 self.framework = 'qemu'
183 self.qemu = qemu.Qemu(self.sysroot, arch=qemu_arch)
cmticeb70801a2014-12-11 14:29:34 -0800184
cmticef23cb132015-04-10 15:13:00 -0700185 if self.remote:
186 # Verify cgdb flag info.
187 if self.cgdb:
188 if osutils.Which('cgdb') is None:
189 raise GdbMissingDebuggerError('Cannot find cgdb. Please install '
190 'cgdb first.')
cmticeb70801a2014-12-11 14:29:34 -0800191
cmticef23cb132015-04-10 15:13:00 -0700192 def RemoveSysrootPrefix(self, path):
cmticeb70801a2014-12-11 14:29:34 -0800193 """Returns the given path with any sysroot prefix removed."""
194 # If the sysroot is /, then the paths are already normalized.
195 if self.sysroot != '/' and path.startswith(self.sysroot):
196 path = path.replace(self.sysroot, '', 1)
cmticeb70801a2014-12-11 14:29:34 -0800197 return path
198
199 @staticmethod
200 def GetNonRootAccount():
201 """Return details about the non-root account we want to use.
202
203 Returns:
204 A tuple of (username, uid, gid, home).
205 """
206 return (
207 os.environ.get('SUDO_USER', 'nobody'),
208 int(os.environ.get('SUDO_UID', '65534')),
209 int(os.environ.get('SUDO_GID', '65534')),
210 # Should we find a better home?
211 '/tmp/portage',
212 )
213
214 @staticmethod
215 @contextlib.contextmanager
216 def LockDb(db):
217 """Lock an account database.
218
219 We use the same algorithm as shadow/user.eclass. This way we don't race
220 and corrupt things in parallel.
221 """
222 lock = '%s.lock' % db
223 _, tmplock = tempfile.mkstemp(prefix='%s.platform.' % lock)
224
225 # First try forever to grab the lock.
226 retry = lambda e: e.errno == errno.EEXIST
227 # Retry quickly at first, but slow down over time.
228 try:
229 retry_util.GenericRetry(retry, 60, os.link, tmplock, lock, sleep=0.1)
cmticef23cb132015-04-10 15:13:00 -0700230 except Exception as e:
231 raise Exception('Could not grab lock %s. %s' % (lock, e))
cmticeb70801a2014-12-11 14:29:34 -0800232
233 # Yield while holding the lock, but try to clean it no matter what.
234 try:
235 os.unlink(tmplock)
236 yield lock
237 finally:
238 os.unlink(lock)
239
240 def SetupUser(self):
241 """Propogate the user name<->id mapping from outside the chroot.
242
243 Some unittests use getpwnam($USER), as does bash. If the account
244 is not registered in the sysroot, they get back errors.
245 """
246 MAGIC_GECOS = 'Added by your friendly platform test helper; do not modify'
247 # This is kept in sync with what sdk_lib/make_chroot.sh generates.
248 SDK_GECOS = 'ChromeOS Developer'
249
250 user, uid, gid, home = self.GetNonRootAccount()
251 if user == 'nobody':
252 return
253
254 passwd_db = os.path.join(self.sysroot, 'etc', 'passwd')
255 with self.LockDb(passwd_db):
256 data = osutils.ReadFile(passwd_db)
257 accts = data.splitlines()
258 for acct in accts:
259 passwd = acct.split(':')
260 if passwd[0] == user:
261 # Did the sdk make this account?
262 if passwd[4] == SDK_GECOS:
263 # Don't modify it (see below) since we didn't create it.
264 return
265
266 # Did we make this account?
267 if passwd[4] != MAGIC_GECOS:
268 raise RuntimeError('your passwd db (%s) has unmanaged acct %s' %
269 (passwd_db, user))
270
271 # Maybe we should see if it needs to be updated? Like if they
272 # changed UIDs? But we don't really check that elsewhere ...
273 return
274
275 acct = '%(name)s:x:%(uid)s:%(gid)s:%(gecos)s:%(homedir)s:%(shell)s' % {
276 'name': user,
277 'uid': uid,
278 'gid': gid,
279 'gecos': MAGIC_GECOS,
280 'homedir': home,
281 'shell': '/bin/bash',
282 }
283 with open(passwd_db, 'a') as f:
284 if data[-1] != '\n':
285 f.write('\n')
286 f.write('%s\n' % acct)
287
cmticef23cb132015-04-10 15:13:00 -0700288 def _FindRemoteProcess(self, device):
289 """Find a named process (or a pid) running on a remote device."""
290 if not self.remote_process_name and not self.pid:
291 return
cmticeb70801a2014-12-11 14:29:34 -0800292
cmticef23cb132015-04-10 15:13:00 -0700293 if self.remote_process_name:
294 # Look for a process with the specified name on the remote device; if
295 # found, get its pid.
296 pname = self.remote_process_name
297 if pname == 'browser':
298 all_chrome_pids = set(device.GetRunningPids(
299 '/opt/google/chrome/chrome'))
300 sandbox_pids = set(device.GetRunningPids(
301 '/opt/google/chrome/chrome-sandbox'))
302 non_main_chrome_pids = set(device.GetRunningPids('type='))
303 pids = list(all_chrome_pids - sandbox_pids - non_main_chrome_pids)
304 elif pname == 'renderer' or pname == 'gpu-process':
305 pids = device.GetRunningPids('type=%s'% pname)
306 else:
307 pids = device.GetRunningPids(pname)
308
309 if pids:
310 if len(pids) == 1:
311 self.pid = pids[0]
312 else:
313 raise GdbTooManyPidsError('Multiple pids found for %s process: %s. '
314 'You must specify the correct pid.'
315 % (pname, repr(pids)))
316 else:
317 raise GdbCannotFindRemoteProcessError('Cannot find pid for "%s" on %s' %
318 (pname, self.remote))
319
320 # Find full path for process, from pid (and verify pid).
321 command = [
322 'readlink',
323 '-e', '/proc/%s/exe' % self.pid,
324 ]
325 try:
326 res = device.RunCommand(command, capture_output=True)
327 if res.returncode == 0:
328 self.inf_cmd = res.output.rstrip('\n')
329 except cros_build_lib.RunCommandError:
330 raise GdbCannotFindRemoteProcessError('Unable to find name of process '
331 'with pid %s on %s' %
332 (self.pid, self.remote))
333
334 def GetCrossGdb(self):
335 """Find the appropriate cross-version of gdb for the board."""
336 toolchains = toolchain.GetToolchainsForBoard(self.board)
337 tc = toolchain.FilterToolchains(toolchains, 'default', True).keys()
338 cross_gdb = tc[0] + '-gdb'
339 if not osutils.Which(cross_gdb):
340 raise GdbMissingDebuggerError('Cannot find %s; do you need to run '
341 'setup_board?' % cross_gdb)
342 return cross_gdb
343
344 def StartGdbserver(self, inf_cmd, device):
345 """Set up and start gdbserver running on remote."""
346
347 # Generate appropriate gdbserver command.
348 command = ['gdbserver']
349 if self.pid:
350 # Attach to an existing process.
351 command += [
352 '--attach',
353 'localhost:%s' % self.gdbserver_port,
354 '%s' % self.pid,
355 ]
356 elif inf_cmd:
357 # Start executing a new process.
358 command += ['localhost:%s' % self.gdbserver_port, inf_cmd] + self.inf_args
359
360 self.ssh_settings.append('-n')
361 self.ssh_settings.append('-L%s:localhost:%s' %
362 (self.gdbserver_port, self.gdbserver_port))
363 return device.RunCommand(command,
364 connect_settings=self.ssh_settings,
365 input=open('/dev/null')).returncode
366
367 def GetGdbInitCommands(self, inferior_cmd):
368 """Generate list of commands with which to initialize the gdb session."""
369 gdb_init_commands = []
370
371 if self.remote:
372 sysroot_var = self.sysroot
373 else:
374 sysroot_var = '/'
375
376 gdb_init_commands = [
377 'set sysroot %s' % sysroot_var,
378 'set solib-absolute-prefix %s' % sysroot_var,
379 'set solib-search-path %s' % sysroot_var,
380 'set debug-file-directory %s/usr/lib/debug' % sysroot_var,
381 'set prompt %s' % self.prompt,
382 ]
383
384 if self.remote:
385 if inferior_cmd and not inferior_cmd.startswith(self.sysroot):
386 inferior_cmd = os.path.join(self.sysroot, inferior_cmd.lstrip('/'))
387
388 if inferior_cmd:
389 gdb_init_commands.append('file %s' % inferior_cmd)
390 gdb_init_commands.append('target remote localhost:%s' %
391 self.gdbserver_port)
392 else:
393 if inferior_cmd:
394 gdb_init_commands.append('file %s ' % inferior_cmd)
395 gdb_init_commands.append('set args %s' % ' '.join(self.inf_args))
396
397 return gdb_init_commands
398
399 def RunRemote(self):
400 """Handle remote debugging, via gdbserver & cross debugger."""
401 device = None
402 try:
403 device = remote_access.ChromiumOSDeviceHandler(
404 self.remote,
405 port=self.remote_port,
406 connect_settings=self.ssh_settings,
407 ping=self.ping).device
408 except remote_access.DeviceNotPingableError:
409 raise GdbBadRemoteDeviceError('Remote device %s is not responding to '
410 'ping.' % self.remote)
411
412 self.VerifyAndFinishInitialization(device)
413 gdb_cmd = self.cross_gdb
414
415 gdb_commands = self.GetGdbInitCommands(self.inf_cmd)
416 gdb_args = [gdb_cmd, '--quiet'] + ['--eval-command=%s' % x
417 for x in gdb_commands]
Raul E Rangelabd74fe2018-04-26 09:17:41 -0600418 gdb_args += self.gdb_args
419
cmticef23cb132015-04-10 15:13:00 -0700420 if self.cgdb:
421 gdb_args = ['cgdb'] + gdb_args
422
423 with parallel.BackgroundTaskRunner(self.StartGdbserver,
424 self.inf_cmd,
425 device) as task:
426 task.put([])
427 # Verify that gdbserver finished launching.
428 try:
429 timeout_util.WaitForSuccess(
430 lambda x: len(x) == 0, self.device.GetRunningPids,
431 4, func_args=('gdbserver',))
432 except timeout_util.TimeoutError:
433 raise GdbUnableToStartGdbserverError('gdbserver did not start on'
434 ' remote device.')
435 cros_build_lib.RunCommand(gdb_args)
436
437 def Run(self):
438 """Runs the debugger in a proper environment (e.g. qemu)."""
439
440 self.VerifyAndFinishInitialization(None)
441 self.SetupUser()
cmtice932e0aa2015-02-27 11:49:12 -0800442 if self.framework == 'qemu':
443 self.qemu.Install(self.sysroot)
444 self.qemu.RegisterBinfmt()
445
cmticeb70801a2014-12-11 14:29:34 -0800446 for mount in self._BIND_MOUNT_PATHS:
447 path = os.path.join(self.sysroot, mount)
448 osutils.SafeMakedirs(path)
449 osutils.Mount('/' + mount, path, 'none', osutils.MS_BIND)
450
cmticef23cb132015-04-10 15:13:00 -0700451 gdb_cmd = self._GDB
452 inferior_cmd = self.inf_cmd
453
cmtice932e0aa2015-02-27 11:49:12 -0800454 gdb_argv = self.gdb_args[:]
455 if gdb_argv:
cmticef23cb132015-04-10 15:13:00 -0700456 gdb_argv[0] = self.RemoveSysrootPrefix(gdb_argv[0])
cmticeb70801a2014-12-11 14:29:34 -0800457 # Some programs expect to find data files via $CWD, so doing a chroot
458 # and dropping them into / would make them fail.
cmticef23cb132015-04-10 15:13:00 -0700459 cwd = self.RemoveSysrootPrefix(os.getcwd())
cmticeb70801a2014-12-11 14:29:34 -0800460
cmticeb70801a2014-12-11 14:29:34 -0800461 os.chroot(self.sysroot)
462 os.chdir(cwd)
463 # The TERM the user is leveraging might not exist in the sysroot.
464 # Force a sane default that supports standard color sequences.
465 os.environ['TERM'] = 'ansi'
466 # Some progs want this like bash else they get super confused.
467 os.environ['PWD'] = cwd
468 if not self.run_as_root:
469 _, uid, gid, home = self.GetNonRootAccount()
470 os.setgid(gid)
471 os.setuid(uid)
472 os.environ['HOME'] = home
473
cmticef23cb132015-04-10 15:13:00 -0700474 gdb_commands = self.GetGdbInitCommands(inferior_cmd)
cmticeb70801a2014-12-11 14:29:34 -0800475
cmticef23cb132015-04-10 15:13:00 -0700476 gdb_args = [gdb_cmd, '--quiet'] + ['--eval-command=%s' % x
477 for x in gdb_commands]
cmtice932e0aa2015-02-27 11:49:12 -0800478 gdb_args += self.gdb_args
479
cmtice932e0aa2015-02-27 11:49:12 -0800480 sys.exit(os.execvp(gdb_cmd, gdb_args))
cmticeb70801a2014-12-11 14:29:34 -0800481
482
cmtice932e0aa2015-02-27 11:49:12 -0800483def _ReExecuteIfNeeded(argv, ns_net=False, ns_pid=False):
cmticeb70801a2014-12-11 14:29:34 -0800484 """Re-execute gdb as root.
485
486 We often need to do things as root, so make sure we're that. Like chroot
487 for proper library environment or do bind mounts.
488
489 Also unshare the mount namespace so as to ensure that doing bind mounts for
490 tests don't leak out to the normal chroot. Also unshare the UTS namespace
491 so changes to `hostname` do not impact the host.
492 """
493 if os.geteuid() != 0:
494 cmd = ['sudo', '-E', '--'] + argv
495 os.execvp(cmd[0], cmd)
496 else:
cmtice932e0aa2015-02-27 11:49:12 -0800497 namespaces.SimpleUnshare(net=ns_net, pid=ns_pid)
498
499
cmticef23cb132015-04-10 15:13:00 -0700500def FindInferior(arg_list):
cmtice932e0aa2015-02-27 11:49:12 -0800501 """Look for the name of the inferior (to be debugged) in arg list."""
502
503 program_name = ''
504 new_list = []
505 for item in arg_list:
506 if item[0] == '-':
507 new_list.append(item)
508 elif not program_name:
509 program_name = item
510 else:
511 raise RuntimeError('Found multiple program names: %s %s'
512 % (program_name, item))
513
514 return program_name, new_list
cmticeb70801a2014-12-11 14:29:34 -0800515
516
517def main(argv):
518
519 parser = commandline.ArgumentParser(description=__doc__)
520
cmticef23cb132015-04-10 15:13:00 -0700521 parser.add_argument('--board', default=None,
cmticeb70801a2014-12-11 14:29:34 -0800522 help='board to debug for')
cmticef23cb132015-04-10 15:13:00 -0700523 parser.add_argument('-g', '--gdb_args', action='append', default=[],
524 help='Arguments to gdb itself. If multiple arguments are'
525 ' passed, each argument needs a separate \'-g\' flag.')
526 parser.add_argument(
527 '--remote', default=None,
528 type=commandline.DeviceParser(commandline.DEVICE_SCHEME_SSH),
529 help='Remote device on which to run the binary. Use'
530 ' "--remote=localhost:9222" to debug in a ChromeOS image in an'
531 ' already running local virtual machine.')
532 parser.add_argument('--pid', default='',
533 help='Process ID of the (already) running process on the'
534 ' remote device to which to attach.')
535 parser.add_argument('--remote_pid', dest='pid', default='',
536 help='Deprecated alias for --pid.')
537 parser.add_argument('--no-ping', dest='ping', default=True,
538 action='store_false',
539 help='Do not ping remote before attempting to connect.')
540 parser.add_argument('--attach', dest='attach_name', default='',
541 help='Name of existing process to which to attach, on'
542 ' remote device (remote debugging only). "--attach'
543 ' browser" will find the main chrome browser process;'
544 ' "--attach renderer" will find a chrome renderer'
545 ' process; "--attach gpu-process" will find the chrome'
546 ' gpu process.')
547 parser.add_argument('--cgdb', default=False,
548 action='store_true',
549 help='Use cgdb curses interface rather than plain gdb.'
550 'This option is only valid for remote debugging.')
551 parser.add_argument('inf_args', nargs=argparse.REMAINDER,
552 help='Arguments for gdb to pass to the program being'
553 ' debugged. These are positional and must come at the end'
554 ' of the command line. This will not work if attaching'
555 ' to an already running program.')
cmticeb70801a2014-12-11 14:29:34 -0800556
557 options = parser.parse_args(argv)
558 options.Freeze()
559
cmtice932e0aa2015-02-27 11:49:12 -0800560 gdb_args = []
561 inf_args = []
562 inf_cmd = ''
563
cmticef23cb132015-04-10 15:13:00 -0700564 if options.inf_args:
565 inf_cmd = options.inf_args[0]
566 inf_args = options.inf_args[1:]
cmtice932e0aa2015-02-27 11:49:12 -0800567
cmticef23cb132015-04-10 15:13:00 -0700568 if options.gdb_args:
569 gdb_args = options.gdb_args
cmtice932e0aa2015-02-27 11:49:12 -0800570
571 if inf_cmd:
572 fname = os.path.join(cros_build_lib.GetSysroot(options.board),
573 inf_cmd.lstrip('/'))
574 if not os.path.exists(fname):
575 cros_build_lib.Die('Cannot find program %s.' % fname)
cmticef23cb132015-04-10 15:13:00 -0700576 else:
577 if inf_args:
578 parser.error('Cannot specify arguments without a program.')
cmtice932e0aa2015-02-27 11:49:12 -0800579
cmticef23cb132015-04-10 15:13:00 -0700580 if inf_args and (options.pid or options.attach_name):
581 parser.error('Cannot pass arguments to an already'
582 ' running process (--remote-pid or --attach).')
583
584 if options.remote:
585 if not options.pid and not inf_cmd and not options.attach_name:
586 parser.error('Must specify a program to start or a pid to attach '
587 'to on the remote device.')
588 if options.attach_name and options.attach_name == 'browser':
589 inf_cmd = '/opt/google/chrome/chrome'
590 else:
591 if options.cgdb:
592 parser.error('--cgdb option can only be used with remote debugging.')
593 if options.pid:
594 parser.error('Must specify a remote device (--remote) if you want '
595 'to attach to a remote pid.')
596 if options.attach_name:
597 parser.error('Must specify remote device (--remote) when using'
598 ' --attach option.')
cmtice932e0aa2015-02-27 11:49:12 -0800599
cmticeb70801a2014-12-11 14:29:34 -0800600 # Once we've finished sanity checking args, make sure we're root.
cmticef23cb132015-04-10 15:13:00 -0700601 if not options.remote:
602 _ReExecuteIfNeeded([sys.argv[0]] + argv)
cmticeb70801a2014-12-11 14:29:34 -0800603
cmticef23cb132015-04-10 15:13:00 -0700604 gdb = BoardSpecificGdb(options.board, gdb_args, inf_cmd, inf_args,
605 options.remote, options.pid, options.attach_name,
606 options.cgdb, options.ping)
cmticeb70801a2014-12-11 14:29:34 -0800607
cmticef23cb132015-04-10 15:13:00 -0700608 try:
609 if options.remote:
610 gdb.RunRemote()
611 else:
612 gdb.Run()
613
614 except GdbException as e:
615 if options.debug:
616 raise
617 else:
618 raise cros_build_lib.Die(str(e))