def _getPackageName(self): if self.objdir: acname = os.path.join(self.objdir, 'config', 'autoconf.mk') try: acfile = open(acname) for line in acfile: if 'ANDROID_PACKAGE_NAME' not in line: continue acfile.close() pkg = line.partition('=')[2].strip() print 'Using package %s.' % pkg return pkg acfile.close() except OSError: pass pkgs = [x[:x.rindex('-')] for x in \ adb.call(['shell', 'ls', '-1', '/data/app']).splitlines() \ if x.startswith('org.mozilla.')] if pkgs: print 'Found package names:' for pkg in pkgs: print ' ' + pkg else: pkgs = ['org.mozilla.fennec_unofficial', 'org.mozilla.fennec', 'org.mozilla.aurora', 'org.mozilla.firefox'] pkg = None while not pkg: pkg = readinput.call( 'Use package (e.g. org.mozilla.fennec): ', '-l', str(pkgs)) return pkg
def invoke(self, argument, from_tty): self.dont_repeat() interval = (self.update_interval if hasattr(self, 'update_interval') else 90) if argument and argument.strip() == 'force': interval = -1 if not interval: return self.worktree = os.path.abspath( os.path.join(gdb.PYTHONDIR, os.path.pardir)) self.gitdir = os.path.join(self.worktree, '.git') if not os.path.isdir(self.gitdir): return marker = os.path.join(self.worktree, '.update') def touchUpdate(): with open(marker, 'a'): os.utime(marker, None) if interval > 0 and not os.path.isfile(marker): touchUpdate() return elapsed = time.time() - os.path.getmtime(marker) if elapsed >= interval * 24 * 60 * 60: ans = '' if interval > 0 else 'y' while not ans or (ans[0] != 'y' and ans[0] != 'Y' and ans[0] != 'n' and ans[0] != 'N'): print ans = readinput.call( 'Last checked for update %d days ago; ' 'check now? [yes/no]: ' % (elapsed / 60 / 60 / 24), '-l', str(['yes', 'no'])) if ans[0] == 'y' or ans[0] == 'Y': self._checkUpdate() # update timestamp regardless of choice above touchUpdate()
def invoke(self, argument, from_tty): self.dont_repeat() interval = self.update_interval if hasattr(self, "update_interval") else 90 if argument and argument.strip() == "force": interval = -1 if not interval: return self.worktree = os.path.abspath(os.path.join(gdb.PYTHONDIR, os.path.pardir)) self.gitdir = os.path.join(self.worktree, ".git") if not os.path.isdir(self.gitdir): return marker = os.path.join(self.worktree, ".update") def touchUpdate(): with open(marker, "a"): os.utime(marker, None) if interval > 0 and not os.path.isfile(marker): touchUpdate() return elapsed = time.time() - os.path.getmtime(marker) if elapsed >= interval * 24 * 60 * 60: ans = "" if interval > 0 else "y" while not ans or (ans[0] != "y" and ans[0] != "Y" and ans[0] != "n" and ans[0] != "N"): print ans = readinput.call( "Last checked for update %d days ago; " "check now? [yes/no]: " % (elapsed / 60 / 60 / 24), "-l", str(["yes", "no"]), ) if ans[0] == "y" or ans[0] == "Y": self._checkUpdate() # update timestamp regardless of choice above touchUpdate()
def chooseDevice(): # identify device devs = getDevices() # wait for a device if no device is found while not devs: try: print('ADB: waiting for device... (Ctrl+C to stop)') waitForDevice() except gdb.GdbError: raise gdb.GdbError(' ADB: no device') devs = getDevices() # use saved setting if possible; also allows gdbinit to set device dev = str(gdb.parameter('adb-device')) if dev and dev not in devs: print('feninit.default.device (%s) is not connected' % dev) # use only device if len(devs) == 1: dev = devs[0] # otherwise, let user decide while not dev in devs: print('Found multiple devices:') for i in range(len(devs)): print('%d. %s' % (i + 1, devs[i])) dev = readinput.call('Choose device: ', '-l', str(devs)) if dev.isdigit() and int(dev) > 0 and int(dev) <= len(devs): dev = devs[int(dev) - 1] elif len(dev) > 0: matchDev = filter( lambda x: x.lower().startswith(dev.lower()), devs) # if only one match, use it if len(matchDev) == 1: dev = matchDev[0] if str(gdb.parameter('adb-device')) != dev: gdb.execute('set adb-device ' + dev) return dev
raise gdb.GdbError(' ADB: no device') devs = getDevices() # use saved setting if possible; also allows gdbinit to set device dev = str(gdb.parameter('adb-device')) if dev and dev not in devs: print 'feninit.default.device (%s) is not connected' % dev # use only device if len(devs) == 1: dev = devs[0] # otherwise, let user decide while not dev in devs: print 'Found multiple devices:' for i in range(len(devs)): print '%d. %s' % (i + 1, devs[i]) dev = readinput.call('Choose device: ', '-l', str(devs)) if dev.isdigit() and int(dev) > 0 and int(dev) <= len(devs): dev = devs[int(dev) - 1] elif len(dev) > 0: matchDev = filter( lambda x: x.lower().startswith(dev.lower()), devs) # if only one match, use it if len(matchDev) == 1: dev = matchDev[0] if str(gdb.parameter('adb-device')) != dev: gdb.execute('set adb-device ' + dev) return dev def pull(src, dest): params = ['pull'] if isinstance(src, list):
def _chooseObjdir(self): def scanSrcDir(objdirs, path): # look for 'obj*' directories, using 'dist' as a clue abspath = os.path.abspath(os.path.expanduser(path)) if not os.path.isdir(abspath): return if os.path.isdir(os.path.join(abspath, 'dist')): objdirs.append(abspath) return for d in os.listdir(abspath): if not d.startswith('obj'): continue objdir = os.path.join(abspath, d) if os.path.isdir(objdir) and \ os.path.isdir(os.path.join(objdir, 'dist')): objdirs.append(objdir) objdir = '' # None means don't use an objdir objdirs = [] # look for possible locations srcroot = self.srcroot if hasattr(self, 'srcroot') else '~' scanSrcDir(objdirs, os.path.join(srcroot, 'mozilla-central')) scanSrcDir(objdirs, os.path.join(srcroot, 'central')) scanSrcDir(objdirs, os.path.join(srcroot, 'mozilla-aurora')) scanSrcDir(objdirs, os.path.join(srcroot, 'aurora')) scanSrcDir(objdirs, os.path.join(srcroot, 'mozilla-beta')) scanSrcDir(objdirs, os.path.join(srcroot, 'beta')) scanSrcDir(objdirs, os.path.join(srcroot, 'mozilla-release')) scanSrcDir(objdirs, os.path.join(srcroot, 'release')) objdirs.sort() # use saved setting if possible; also allows gdbinit to set objdir if hasattr(self, 'objdir'): objdir = self.objdir if objdir: scanSrcDir(objdirs, objdir) if objdir not in objdirs: print 'feninit.default.objdir (%s) is not found' % objdir else: objdir = None objdirs.append(objdir) # let user choose even if only one objdir found, # because the user might want to not use an objdir while objdir not in objdirs: if objdirs: print 'Choices for object directory to use:' print '0. Do not use object directory' for i in range(len(objdirs)): print '%d. %s' % (i + 1, objdirs[i]) print 'Choose from above or enter alternative' objdir = readinput.call(': ', '-d') if not objdir: continue elif objdir == '0': objdir = None break else: print 'No object directory found. Enter path or leave blank' objdir = readinput.call(': ', '-d') if not objdir: objdir = None break if objdir.isdigit() and int(objdir) > 0 and \ int(objdir) <= len(objdirs): objdir = objdirs[int(objdir) - 1] break objdir = os.path.abspath(os.path.expanduser(objdir)) matchObjdir = filter(lambda x: x.startswith(objdir), objdirs) if len(matchObjdir) == 0: # not on list, verify objdir first scanSrcDir(objdirs, objdir) elif len(matchObjdir) == 1: # only one match, good to go objdir = matchObjdir[0] print 'Using object directory: %s' % str(objdir) self.objdir = objdir
def _launchAndAttach(self): # name of child binary CHILD_EXECUTABLE = 'plugin-container' # 'file' command argument for parent process PARENT_FILE_PATH = os.path.join(self.libdir, 'bin', 'app_process') # 'file' command argument for child process if self.objdir: CHILD_FILE_PATH = os.path.join(self.objdir, 'dist', 'bin', CHILD_EXECUTABLE) else: CHILD_FILE_PATH = None # launch pkg = self._getPackageName() sys.stdout.write('Launching %s... ' % pkg) sys.stdout.flush() out = adb.call(['shell', 'am', 'start', '-a', 'org.mozilla.gecko.DEBUG', '-n', pkg + '/.App']) if 'error' in out.lower(): print '' print out raise gdb.GdbError('Error while launching %s.' % pkg) # FIXME sleep for 1s to allow time to launch time.sleep(1) # wait for launch to complete pkgProcs = [] while not [True for x in pkgProcs if CHILD_EXECUTABLE not in x]: ps = adb.call(['shell', 'ps']).splitlines() # get parent/child processes that are waiting ('S' state) pkgProcs = [x for x in ps if pkg in x and ('S' in x.split() or 'T' in x.split())] print 'Done' # get parent/child(ren) pid's pidParent = next((x.split()[1] for x in pkgProcs if CHILD_EXECUTABLE not in x)) pidChild = [x.split()[1] for x in pkgProcs if CHILD_EXECUTABLE in x] pidChildParent = pidParent # see if any gdbserver instance is running, and discard # the debuggee from our list because it's already taken for proc in [x.split() for x in ps if 'gdbserver' in x]: # get the program being debugged by examine gdbserver cmdline cmdline = adb.call(['shell', 'cat', '/proc/' + proc[1] + '/cmdline']).split('\0') if '--attach' not in cmdline: continue # this should be the pid pid = next((x for x in reversed(cmdline) if x.isdigit())) if pid == pidParent: pidParent = None elif pid in pidChild: pidChild.remove(pid) if pidParent: # the parent is not being debugged, pick the parent pidAttach = pidParent sys.stdout.write('Attaching to parent (pid %s)... ' % pidAttach) sys.stdout.flush() elif not pidChild: # ok, no child is available. assume the user # wants to wait for child to start up pkgProcs = None print 'Waiting for child process...' while not pkgProcs: ps = adb.call(['shell', 'ps']).splitlines() # check for 'S' state, for right parent, and for right child pkgProcs = [x for x in ps if ('S' in x or 'T' in x) and \ pidChildParent in x and CHILD_EXECUTABLE in x] pidChild = [x.split()[1] for x in pkgProcs] # if the parent was not picked, pick the right child if not pidParent and len(pidChild) == 1: # that is easy pidAttach = pidChild[0] sys.stdout.write('Attaching to child (pid %s)... ' % pidAttach) sys.stdout.flush() elif not pidParent: # should not happen for now, because we only use one child pidAttach = None while pidAttach not in pidChild: print 'WTF multiple child processes found:' for i in range(len(pidChild)): print '%d. pid %s' % (i + 1, pidChild[i]) pidAttach = readinput.call('Child pid: ', '-l', str(pidChild)) if pidAttach.isdigit() and int(pidAttach) > 0 \ and int(pidAttach) <= len(pidChild): pidAttach = pidChild[pidAttach] sys.stdout.write('Attaching... ') sys.stdout.flush() self.pid = pidAttach # push gdbserver if it's not there gdbserverPath = '/data/local/tmp/gdbserver' if not adb.pathExists(gdbserverPath): adb.push(os.path.join(self.bindir, 'gdbserver'), gdbserverPath) # run this after fork() and before exec(gdbserver) # so 'adb shell gdbserver' doesn't get gdb's signals def gdbserverPreExec(): os.setpgrp() # can we run as root? if 'uid=0' in adb.call(['shell', 'id']): gdbserverProc = adb.call(['shell', gdbserverPath, '--attach', ':0', pidAttach], stderr=subprocess.PIPE, async=True, preexec_fn=gdbserverPreExec) else: sys.stdout.write('as non-root... ') sys.stdout.flush() gdbserverProc = adb.call(['shell', 'run-as', pkg, gdbserverPath, '--attach', ':0', pidAttach], stderr=subprocess.PIPE, async=True, preexec_fn=gdbserverPreExec) # we passed ':0' to gdbserver so it'll pick a port for us # but that means we have to find the port from stdout # while this complicates things a little, it allows us to # have multiple gdbservers running port = None while not port: if gdbserverProc.poll() is not None: print '' print gdbserverProc.stdout.read() raise gdb.GdbError('gdbserver exited unexpectedly') line = gdbserverProc.stdout.readline().split() # kind of hacky, assume the port number comes after 'port' if 'port' in line: port = line[line.index('port') + 1] self.port = port self.gdbserver = gdbserverProc # collect output from gdbserver in another thread def makeGdbserverWait(obj, proc): def gdbserverWait(): obj.gdbserverOut = proc.communicate(); return gdbserverWait; threading.Thread( target = makeGdbserverWait(self, gdbserverProc)).start() # forward the port that gdbserver gave us adb.forward('tcp:' + port, 'tcp:' + port) print 'Done' sys.stdout.write('Setting up remote debugging... ') sys.stdout.flush() # load the right file gdb.execute('file ' + (PARENT_FILE_PATH if pidParent else CHILD_FILE_PATH), False, True) gdb.execute('target remote :' + port, False, True) print 'Done\n' if pidParent: print 'Run another gdb session to debug child process.\n' print 'Ready. Use "continue" to resume execution.'
raise gdb.GdbError(' ADB: no device') devs = getDevices() # use saved setting if possible; also allows gdbinit to set device dev = str(gdb.parameter('adb-device')) if dev and dev not in devs: print 'feninit.default.device (%s) is not connected' % dev # use only device if len(devs) == 1: dev = devs[0] # otherwise, let user decide while not dev in devs: print 'Found multiple devices:' for i in range(len(devs)): print '%d. %s' % (i + 1, devs[i]) dev = readinput.call('Choose device: ', '-l', str(devs)) if dev.isdigit() and int(dev) > 0 and int(dev) <= len(devs): dev = devs[int(dev) - 1] elif len(dev) > 0: matchDev = filter(lambda x: x.lower().startswith(dev.lower()), devs) # if only one match, use it if len(matchDev) == 1: dev = matchDev[0] if str(gdb.parameter('adb-device')) != dev: gdb.execute('set adb-device ' + dev) return dev def pull(src, dest): params = ['pull']