1094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# 2094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Copyright (C) 2012 The Android Open Source Project 3094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# 4094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Licensed under the Apache License, Version 2.0 (the "License"); 5094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# you may not use this file except in compliance with the License. 6094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# You may obtain a copy of the License at 7094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# 8094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# http://www.apache.org/licenses/LICENSE-2.0 9094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# 10094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Unless required by applicable law or agreed to in writing, software 11094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# distributed under the License is distributed on an "AS IS" BASIS, 12094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# See the License for the specific language governing permissions and 14094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# limitations under the License. 15094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# 16094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 17094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# 18094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# GDB plugin to allow debugging of apps on remote Android systems using gdbserver. 19094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# 20094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# To use this plugin, source this file from a Python-enabled GDB client, then use: 21094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# load-android-app <app-source-dir> to tell GDB about the app you are debugging 22094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# run-android-app to start the app in a running state 23094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# start-android-app to start the app in a paused state 24094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# attach-android-ap to attach to an existing (running) instance of app 25094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# set-android-device to select a target (only if multiple devices are attached) 26094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 27094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaimport fnmatch 28094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaimport gdb 29094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaimport os 30094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaimport shutil 31094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaimport subprocess 32094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaimport tempfile 33094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaimport time 34094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 35094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleabe_verbose = False 36094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaenable_renderscript_dumps = True 37094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malealocal_symbols_library_directory = os.path.join(os.getenv('ANDROID_PRODUCT_OUT', 'out'), 38094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 'symbols', 'system', 'lib') 39094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malealocal_library_directory = os.path.join(os.getenv('ANDROID_PRODUCT_OUT', 'out'), 40094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 'system', 'lib') 41094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 42094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# ADB - Basic ADB wrapper, far from complete 43094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# DebugAppInfo - App configuration struct, as far as GDB cares 44094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# StartAndroidApp - Implementation of GDB start (for android apps) 45094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# RunAndroidApp - Implementation of GDB run (for android apps) 46094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# AttachAndroidApp - GDB command to attach to an existing android app process 47094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# AndroidStatus - app status query command (not needed, mostly harmless) 48094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# LoadAndroidApp - Sets the package and intent names for an app 49094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 50094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleadef _interesting_libs(): 51094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return ['libc', 'libbcc', 'libRS', 'libandroid_runtime', 'libdvm'] 52094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 53094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# In python 2.6, subprocess.check_output does not exist, so it is implemented here 54094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleadef check_output(*popenargs, **kwargs): 55094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea p = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *popenargs, **kwargs) 56094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea out, err = p.communicate() 57094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea retcode = p.poll() 58094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if retcode != 0: 59094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea c = kwargs.get("args") 60094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if c is None: 61094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea c = popenargs[0] 62094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea e = subprocess.CalledProcessError(retcode, c) 63094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea e.output = str(out) + str(err) 64094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise e 65094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return out 66094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 67094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass DebugAppInfo: 68094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """Stores information from an app manifest""" 69094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 70094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__(self): 71094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.name = None 72094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.intent = None 73094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 74094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def get_name(self): 75094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return self.name 76094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 77094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def get_intent(self): 78094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return self.intent 79094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 80094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def get_data_directory(self): 81094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return self.data_directory 82094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 83094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def get_gdbserver_path(self): 84094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return os.path.join(self.data_directory, "lib", "gdbserver") 85094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 86094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def set_info(self, name, intent, data_directory): 87094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.name = name 88094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.intent = intent 89094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.data_directory = data_directory 90094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 91094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def unset_info(): 92094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.name = None 93094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.intent = None 94094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.data_directory = None 95094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 96094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass ADB: 97094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """ 98094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea Python class implementing a basic ADB wrapper for useful commands. 99094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea Uses subprocess to invoke adb. 100094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """ 101094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 102094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__(self, device=None, verbose=False): 103094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.verbose = verbose 104094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.current_device = device 105094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.temp_libdir = None 106094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.background_processes = [] 107094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.android_build_top = os.getenv('ANDROID_BUILD_TOP', None) 108094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not self.android_build_top: 109094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Unable to read ANDROID_BUILD_TOP. " \ 110094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + "Is your environment setup correct?") 111094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 112094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb_path = os.path.join(self.android_build_top, 113094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 'out', 'host', 'linux-x86', 'bin', 'adb') 114094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 115094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not self.current_device: 116094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea devices = self.devices() 117094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if len(devices) == 1: 118094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.set_current_device(devices[0]) 119094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return 120094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 121094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea msg = "" 122094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if len(devices) == 0: 123094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea msg = "No devices detected. Please connect a device and " 124094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 125094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea msg = "Too many devices (" + ", ".join(devices) + ") detected. " \ 126094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + "Please " 127094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 128094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "Warning: " + msg + " use the set-android-device command." 129094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 130094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 131094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _prepare_adb_args(self, args): 132094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea largs = list(args) 133094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 134094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Prepare serial number option from current_device 135094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.current_device and len(self.current_device) > 0: 136094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea largs.insert(0, self.current_device) 137094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea largs.insert(0, "-s") 138094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 139094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea largs.insert(0, self.adb_path) 140094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return largs 141094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 142094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 143094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _background_adb(self, *args): 144094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea largs = self._prepare_adb_args(args) 145094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea p = None 146094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea try: 147094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 148094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "### " + str(largs) 149094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea p = subprocess.Popen(largs) 150094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.background_processes.append(p) 151094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except CalledProcessError, e: 152094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Error starting background adb " + str(largs)) 153094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except: 154094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Unknown error starting background adb " + str(largs)) 155094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 156094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return p 157094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 158094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _call_adb(self, *args): 159094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea output = "" 160094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea largs = self._prepare_adb_args(args) 161094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea try: 162094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 163094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "### " + str(largs) 164094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea output = check_output(largs) 165094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except subprocess.CalledProcessError, e: 166094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Error starting adb " + str(largs)) 167094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except Exception as e: 168094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Unknown error starting adb " + str(largs)) 169094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 170094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return output 171094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 172094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _shell(self, *args): 173094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args = ["shell"] + list(args) 174094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return self._call_adb(*args) 175094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 176094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _background_shell(self, *args): 177094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args = ["shell"] + list(args) 178094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return self._background_adb(*args) 179094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 180094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _cleanup_background_processes(self): 181094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for handle in self.background_processes: 182094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea try: 183094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea handle.terminate() 184094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except OSError, e: 185094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Background process died already 186094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea pass 187094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 188094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _cleanup_temp(self): 189094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.temp_libdir: 190094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea shutil.rmtree(self.temp_libdir) 191094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.temp_libdir = None 192094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 193094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __del__(self): 194094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_temp() 195094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_background_processes() 196094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 197094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _get_local_libs(self): 198094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ret = [] 199094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for lib in _interesting_libs(): 200094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea lib_path = os.path.join(local_library_directory, lib + ".so") 201094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not os.path.exists(lib_path) and self.verbose: 202094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "Warning: unable to find expected library " \ 203094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + lib_path + "." 204094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ret.append(lib_path) 205094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 206094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return ret 207094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 208094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _check_remote_libs_match_local_libs(self): 209094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ret = [] 210094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea all_remote_libs = self._shell("ls", "/system/lib/*.so").split() 211094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea local_libs = self._get_local_libs() 212094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 213094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.temp_libdir = tempfile.mkdtemp() 214094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 215094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for lib in _interesting_libs(): 216094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea lib += ".so" 217094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for remote_lib in all_remote_libs: 218094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if lib in remote_lib: 219094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Pull lib from device and compute hash 220094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea tmp_path = os.path.join(self.temp_libdir, lib) 221094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.pull(remote_lib, tmp_path) 222094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea remote_hash = self._md5sum(tmp_path) 223094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 224094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Find local lib and compute hash 225094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea built_library = filter(lambda l: lib in l, local_libs)[0] 226094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea built_hash = self._md5sum(built_library) 227094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 228094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Alert user if library mismatch is detected 229094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if built_hash != remote_hash: 230094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_temp() 231094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Library mismatch between:\n" \ 232094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + "\t(" + remote_hash + ") " + tmp_path + " (from target) and\n " \ 233094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + "\t(" + built_hash + ") " + built_library + " (on host)\n" \ 234094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + "The target is running a different build than the host." \ 235094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + " This situation is not debuggable.") 236094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 237094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_temp() 238094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 239094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _md5sum(self, file): 240094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea try: 241094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return check_output(["md5sum", file]).strip().split()[0] 242094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except subprocess.CalledProcessError, e: 243094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Error invoking md5sum commandline utility") 244094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 245094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Returns the list of serial numbers of connected devices 246094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def devices(self): 247094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ret = [] 248094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raw_output = self._call_adb("devices").split() 249094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if len(raw_output) < 5: 250094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return None 251094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 252094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for serial_num_index in range(4, len(raw_output), 2): 253094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ret.append(raw_output[serial_num_index]) 254094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return ret 255094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 256094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def set_current_device(self, serial): 257094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.current_device == str(serial): 258094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "Current device already is: " + str(serial) 259094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return 260094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 261094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # TODO: this function should probably check the serial is valid. 262094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.current_device = str(serial) 263094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 264094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea api_version = self.getprop("ro.build.version.sdk") 265094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if api_version < 15: 266094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "Warning: untested API version. Upgrade to 15 or higher" 267094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 268094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Verify the local libraries loaded by GDB are identical to those 269094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # sitting on the device actually executing. Alert the user if 270094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # this is happening 271094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._check_remote_libs_match_local_libs() 272094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 273094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # adb getprop [property] 274094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # if property is not None, returns the given property, otherwise 275094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # returns all properties. 276094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def getprop(self, property=None): 277094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if property == None: 278094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # get all the props 279094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return self._call_adb(*["shell", "getprop"]).split('\n') 280094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 281094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return str(self._call_adb(*["shell", "getprop", 282094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea str(property)]).split('\n')[0]) 283094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 284094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # adb push 285094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def push(self, source, destination): 286094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._call_adb(*["push", source, destination]) 287094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 288094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # adb forward <source> <destination> 289094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def forward(self, source, destination): 290094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._call_adb(*["forward", source, destination]) 291094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 292094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Returns true if filename exists on Android fs, false otherwise 293094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def exists(self, filename): 294094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raw_listing = self._shell(*["ls", filename]) 295094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return "No such file or directory" not in raw_listing 296094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 297094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # adb pull <remote_path> <local_path> 298094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def pull(self, remote_path, local_path): 299094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._call_adb(*["pull", remote_path, local_path]) 300094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 301094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea #wrapper for adb shell ps. leave process_name=None for list of all processes 302094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea #Otherwise, returns triple with process name, pid and owner, 303094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def get_process_info(self, process_name=None): 304094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ret = [] 305094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raw_output = self._shell("ps") 306094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for raw_line in raw_output.splitlines()[1:]: 307094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea line = raw_line.split() 308094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea name = line[-1] 309094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 310094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if process_name == None or name == process_name: 311094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea user = line[0] 312094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea pid = line[1] 313094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 314094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if process_name != None: 315094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return (pid, user) 316094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 317094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ret.append((pid, user)) 318094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 319094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # No match in target process 320094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if process_name != None: 321094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return (None, None) 322094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 323094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return ret 324094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 325094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def kill_by_pid(self, pid): 326094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._shell(*["kill", "-9", pid]) 327094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 328094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def kill_by_name(self, process_name): 329094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea (pid, user) = self.get_process_info(process_name) 330094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea while pid != None: 331094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.kill_by_pid(pid) 332094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea (pid, user) = self.get_process_info(process_name) 333094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 334094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass AndroidStatus(gdb.Command): 335094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """Implements the android-status gdb command.""" 336094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 337094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__(self, adb, name="android-status", cat=gdb.COMMAND_OBSCURE, verbose=False): 338094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea super (AndroidStatus, self).__init__(name, cat) 339094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.verbose = verbose 340094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb = adb 341094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 342094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _update_status(self, process_name, gdbserver_process_name): 343094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._check_app_is_loaded() 344094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 345094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Update app status 346094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea (self.pid, self.owner_user) = \ 347094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.get_process_info(process_name) 348094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.running = self.pid != None 349094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 350094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Update gdbserver status 351094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea (self.gdbserver_pid, self.gdbserver_user) = \ 352094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.get_process_info(gdbserver_process_name) 353094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.gdbserver_running = self.gdbserver_pid != None 354094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 355094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Print results 356094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 357094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==Android GDB Plugin Status Update==--" 358094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\tinferior name: " + process_name 359094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\trunning: " + str(self.running) 360094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\tpid: " + str(self.pid) 361094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\tgdbserver running: " + str(self.gdbserver_running) 362094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\tgdbserver pid: " + str(self.gdbserver_pid) 363094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\tgdbserver user: " + str(self.gdbserver_user) 364094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 365094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _check_app_is_loaded(self): 366094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not currentAppInfo.get_name(): 367094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Error: no app loaded. Try load-android-app.") 368094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 369094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def invoke(self, arg, from_tty): 370094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._check_app_is_loaded() 371094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._update_status(currentAppInfo.get_name(), 372094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea currentAppInfo.get_gdbserver_path()) 373094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # TODO: maybe print something if verbose is off 374094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 375094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass StartAndroidApp (AndroidStatus): 376094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """Implements the 'start-android-app' gdb command.""" 377094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 378094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _update_status(self): 379094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea AndroidStatus._update_status(self, self.process_name, \ 380094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.gdbserver_path) 381094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 382094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Calls adb shell ps every retry_delay seconds and returns 383094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # the pid when process_name show up in output, or return 0 384094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # after num_retries attempts. num_retries=0 means retry 385094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # indefinitely. 386094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _wait_for_process(self, process_name, retry_delay=1, num_retries=10): 387094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """ This function is a hack and should not be required""" 388094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea (pid, user) = self.adb.get_process_info(process_name) 389094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea retries_left = num_retries 390094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea while pid == None and retries_left != 0: 391094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea (pid, user) = self.adb.get_process_info(process_name) 392094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea time.sleep(retry_delay) 393094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea retries_left -= 1 394094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 395094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return pid 396094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 397094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _gdbcmd(self, cmd, from_tty=False): 398094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 399094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print '### GDB Command: ' + str(cmd) 400094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 401094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea gdb.execute(cmd, from_tty) 402094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 403094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Remove scratch directory if any 404094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _cleanup_temp(self): 405094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.temp_dir: 406094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea shutil.rmtree(self.temp_dir) 407094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.temp_dir = None 408094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 409094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _cleanup_jdb(self): 410094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.jdb_handle: 411094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea try: 412094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.jdb_handle.terminate() 413094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except OSError, e: 414094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # JDB process has likely died 415094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea pass 416094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 417094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.jdb_handle = None 418094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 419094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _load_local_libs(self): 420094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for lib in _interesting_libs(): 421094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._gdbcmd("shar " + lib) 422094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 423094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __del__(self): 424094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_temp() 425094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_jdb() 426094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 427094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__ (self, adb, name="start-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): 428094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea super (StartAndroidApp, self).__init__(adb, name, cat, verbose) 429094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb = adb 430094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 431094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.jdb_handle = None 432094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # TODO: handle possibility that port 8700 is in use (may help with 433094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Eclipse problems) 434094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.jdwp_port = 8700 435094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 436094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Port for gdbserver 437094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.gdbserver_port = 5039 438094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 439094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.temp_dir = None 440094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 441094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def start_process(self, start_running=False): 442094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea #TODO: implement libbcc cache removal if needed 443094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 444094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args = ["am", "start"] 445094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 446094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # If we are to start running, we can take advantage of am's -W flag to wait 447094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # for the process to start before returning. That way, we don't have to 448094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # emulate the behaviour (poorly) through the sleep-loop below. 449094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not start_running: 450094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args.append("-D") 451094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 452094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args.append("-W") 453094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 454094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args.append(self.process_name + "/" + self.intent) 455094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea am_output = self.adb._shell(*args) 456094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if "Error:" in am_output: 457094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Cannot start app. Activity Manager returned:\n"\ 458094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + am_output) 459094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 460094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Gotta wait until the process starts if we can't use -W 461094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not start_running: 462094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.pid = self._wait_for_process(self.process_name) 463094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 464094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not self.pid: 465094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Unable to detect running app remotely." \ 466094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + "Is " + self.process_name + " installed correctly?") 467094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 468094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 469094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==Android App Started: " + self.process_name \ 470094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + " (pid=" + self.pid + ")==--" 471094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 472094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Forward port for java debugger to Dalvik 473094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.forward("tcp:" + str(self.jdwp_port), \ 474094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea "jdwp:" + str(self.pid)) 475094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 476094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def start_gdbserver(self): 477094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # TODO: adjust for architecture... 478094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea gdbserver_local_path = os.path.join(os.getenv('ANDROID_BUILD_TOP'), 479a663b778625f3de523e251ca810f4dc722c706beStephen Hines 'prebuilt', 'android-arm', 'gdbserver', 'gdbserver') 480094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 481094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not self.adb.exists(self.gdbserver_path): 482094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Install gdbserver 483094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea try: 484094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.push(gdbserver_local_path, self.gdbserver_path) 485094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except gdb.GdbError, e: 486094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "Unable to push gdbserver to device. Try re-installing app." 487094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise e 488094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 489094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb._background_shell(*[self.gdbserver_path, "--attach", 490094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea ":" + str(self.gdbserver_port), self.pid]) 491094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 492094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._wait_for_process(self.gdbserver_path) 493094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._update_status() 494094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 495094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 496094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==Remote gdbserver Started " \ 497094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + " (pid=" + str(self.gdbserver_pid) \ 498094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + " port=" + str(self.gdbserver_port) + ") ==--" 499094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 500094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Forward port for gdbserver 501094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.forward("tcp:" + str(self.gdbserver_port), \ 502094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea "tcp:" + str(5039)) 503094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 504094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def attach_gdb(self, from_tty): 505094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._gdbcmd("target remote :" + str(self.gdbserver_port), False) 506094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 507094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==GDB Plugin requested attach (port=" \ 508094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + str(self.gdbserver_port) + ")==-" 509094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 510094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # If GDB has no file set, things start breaking...so grab the same 511094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # binary the NDK grabs from the filesystem and continue 512094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_temp() 513094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.temp_dir = tempfile.mkdtemp() 514094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.gdb_inferior = os.path.join(self.temp_dir, 'app_process') 515094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.pull("/system/bin/app_process", self.gdb_inferior) 516094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._gdbcmd('file ' + self.gdb_inferior) 517094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 518094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def start_jdb(self, port): 519094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Kill if running 520094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._cleanup_jdb() 521094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 522094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Start the java debugger 523094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args = ["jdb", "-connect", 524094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea "com.sun.jdi.SocketAttach:hostname=localhost,port=" + str(port)] 525094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 526094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.jdb_handle = subprocess.Popen(args, \ 527094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea stdin=subprocess.PIPE) 528094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 529094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Unix-only bit here.. 530094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.jdb_handle = subprocess.Popen(args, \ 531094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea stdin=subprocess.PIPE, 532094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea stderr=subprocess.STDOUT, 533094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea stdout=open('/dev/null', 'w')) 534094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 535094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def invoke (self, arg, from_tty): 536094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # TODO: self._check_app_is_installed() 537094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._check_app_is_loaded() 538094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 539094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.intent = currentAppInfo.get_intent() 540094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.process_name = currentAppInfo.get_name() 541094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.data_directory = currentAppInfo.get_data_directory() 542094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.gdbserver_path = currentAppInfo.get_gdbserver_path() 543094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 544094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._update_status() 545094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 546094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.gdbserver_running: 547094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.kill_by_name(self.gdbserver_path) 548094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 549094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==Killed gdbserver process (pid=" \ 550094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + str(self.gdbserver_pid) + ")==--" 551094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._update_status() 552094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 553094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.running: 554094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.kill_by_name(self.process_name) 555094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 556094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==Killed app process (pid=" + str(self.pid) + ")==--" 557094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._update_status() 558094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 559094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.start_process() 560094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 561094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Start remote gdbserver 562094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.start_gdbserver() 563094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 564094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Attach the gdb 565094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.attach_gdb(from_tty) 566094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 567094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Load symbolic libraries 568094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._load_local_libs() 569094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 570094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Set the debug output directory (for JIT debugging) 571094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if enable_renderscript_dumps: 572094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._gdbcmd('set gDebugDumpDirectory="' + self.data_directory + '"') 573094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 574094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Start app 575094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # unblock the gdb by connecting with jdb 576094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.start_jdb(self.jdwp_port) 577094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 578094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass RunAndroidApp(StartAndroidApp): 579094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """Implements the run-android-app gdb command.""" 580094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 581094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__(self, adb, name="run-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): 582094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea super (RunAndroidApp, self).__init__(adb, name, cat, verbose) 583094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 584094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def invoke(self, arg, from_tty): 585094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea StartAndroidApp.invoke(self, arg, from_tty) 586094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._gdbcmd("continue") 587094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 588094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass AttachAndroidApp(StartAndroidApp): 589094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """Implements the attach-android-app gdb command.""" 590094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 591094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__(self, adb, name="attach-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): 592094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea super (AttachAndroidApp, self).__init__(adb, name, cat, verbose) 593094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 594094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def invoke(self, arg, from_tty): 595094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # TODO: self._check_app_is_installed() 596094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._check_app_is_loaded() 597094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 598094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.intent = currentAppInfo.get_intent() 599094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.process_name = currentAppInfo.get_name() 600094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.data_directory = currentAppInfo.get_data_directory() 601094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.gdbserver_path = currentAppInfo.get_gdbserver_path() 602094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 603094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._update_status() 604094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 605094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.gdbserver_running: 606094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb.kill_by_name(self.gdbserver_path) 607094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 608094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==Killed gdbserver process (pid=" \ 609094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + str(self.gdbserver_pid) + ")==--" 610094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._update_status() 611094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 612094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Start remote gdbserver 613094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.start_gdbserver() 614094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 615094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Attach the gdb 616094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.attach_gdb(from_tty) 617094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 618094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Load symbolic libraries 619094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._load_local_libs() 620094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 621094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Set the debug output directory (for JIT debugging) 622094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if enable_renderscript_dumps: 623094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self._gdbcmd('set gDebugDumpDirectory="' + self.data_directory + '"') 624094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 625094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass LoadApp(AndroidStatus): 626094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """ Implements the load-android-app gbd command. 627094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea """ 628094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _awk_script_path(self, script_name): 629094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if os.path.exists(script_name): 630094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return script_name 631094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 632094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea script_root = os.path.join(os.getenv('ANDROID_BUILD_TOP'), \ 633094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 'ndk', 'build', 'awk') 634094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 635094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea path_in_root = os.path.join(script_root, script_name) 636094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if os.path.exists(path_in_root): 637094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return path_in_root 638094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 639094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Unable to find awk script " \ 640094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + str(script_name) + " in " + path_in_root) 641094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 642094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _awk(self, script, command): 643094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args = ["awk", "-f", self._awk_script_path(script), str(command)] 644094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 645094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 646094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "### awk command: " + str(args) 647094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 648094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea awk_output = "" 649094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea try: 650094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea awk_output = check_output(args) 651094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except subprocess.CalledProcessError, e: 652094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("### Error in subprocess awk " + str(args)) 653094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea except: 654094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "### Random error calling awk " + str(args) 655094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 656094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return awk_output.rstrip() 657094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 658094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__(self, adb, name="load-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): 659094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea super (LoadApp, self).__init__(adb, name, cat, verbose) 660094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.manifest_name = "AndroidManifest.xml" 661094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.verbose = verbose 662094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb = adb 663094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.temp_libdir = None 664094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 665094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _find_manifests(self, path): 666094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea manifests = [] 667094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for root, dirnames, filenames in os.walk(path): 668094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea for filename in fnmatch.filter(filenames, self.manifest_name): 669094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea manifests.append(os.path.join(root, filename)) 670094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return manifests 671094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 672094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _usage(self): 673094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return "Usage: load-android-app [<path-to-AndroidManifest.xml>" \ 674094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + " | <package-name> <intent-name>]" 675094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 676094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def invoke(self, arg, from_tty): 677094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 678094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea package_name = '' 679094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea launchable = '' 680094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea args = arg.strip('"').split() 681094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if len(args) == 2: 682094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea package_name = args[0] 683094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea launchable = args[1] 684094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea elif len(args) == 1: 685094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if os.path.isfile(args[0]) and os.path.basename(args[0]) == self.manifest_name: 686094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.manifest_path = args[0] 687094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea elif os.path.isdir(args[0]): 688094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea manifests = self._find_manifests(args[0]) 689094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if len(manifests) == 0: 690094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError(self.manifest_name + " not found in: " \ 691094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + args[0] + "\n" + self._usage()) 692094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea elif len(manifests) > 1: 693094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Ambiguous argument! Found too many " \ 694094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + self.manifest_name + " files found:\n" + "\n".join(manifests)) 695094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 696094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.manifest_path = manifests[0] 697094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 698094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Invalid path: " + args[0] + "\n" + self._usage()) 699094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 700094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea package_name = self._awk("extract-package-name.awk", 701094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.manifest_path) 702094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea launchable = self._awk("extract-launchable.awk", 703094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.manifest_path) 704094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 705094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError(self._usage()) 706094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 707094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 708094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea data_directory = self.adb._shell("run-as", package_name, 709094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea "/system/bin/sh", "-c", "pwd").rstrip() 710094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 711094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not data_directory \ 712094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea or len(data_directory) == 0 \ 713094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea or not self.adb.exists(data_directory): 714094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea data_directory = os.path.join('/data', 'data', package_name) 715094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "Warning: unable to read data directory for package " \ 716094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + package_name + ". Meh, defaulting to " + data_directory 717094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 718094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea currentAppInfo.set_info(package_name, launchable, data_directory) 719094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 720094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if self.verbose: 721094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "--==Android App Loaded==--" 722094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\tname=" + currentAppInfo.get_name() 723094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea print "\tintent=" + currentAppInfo.get_intent() 724094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 725094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # TODO: Check status of app on device 726094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 727094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaclass SetAndroidDevice (gdb.Command): 728094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def __init__(self, adb, name="set-android-device", cat=gdb.COMMAND_RUNNING, verbose=False): 729094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea super (SetAndroidDevice, self).__init__(name, cat) 730094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.verbose = verbose 731094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea self.adb = adb 732094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 733094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def _usage(self): 734094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea return "Usage: set-android-device <serial>" 735094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 736094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea def invoke(self, arg, from_tty): 737094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if not arg or len(arg) == 0: 738094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError(self._usage) 739094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 740094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea serial = str(arg) 741094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea devices = adb.devices() 742094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea if serial in devices: 743094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea adb.set_current_device(serial) 744094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea else: 745094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea raise gdb.GdbError("Invalid serial. Serial numbers of connected " \ 746094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea + "device(s): \n" + "\n".join(devices)) 747094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 748094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Global initialization 749094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleadef initOnce(adb): 750094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Try to speed up startup by skipping most android shared objects 751094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea gdb.execute("set auto-solib-add 0", False); 752094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 753094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea # Set shared object search path 754094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea gdb.execute("set solib-search-path " + local_symbols_library_directory, False) 755094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 756094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Global instance of the object containing the info for current app 757094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleacurrentAppInfo = DebugAppInfo () 758094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 759094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Global instance of ADB helper 760094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Maleaadb = ADB(verbose=be_verbose) 761094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 762094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Perform global initialization 763094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleainitOnce(adb) 764094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea 765094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel Malea# Command registration 766094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleaStartAndroidApp (adb, "start-android-app", gdb.COMMAND_RUNNING, be_verbose) 767094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleaRunAndroidApp (adb, "run-android-app", gdb.COMMAND_RUNNING, be_verbose) 768094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleaAndroidStatus (adb, "android-status", gdb.COMMAND_OBSCURE, be_verbose) 769094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleaLoadApp (adb, "load-android-app", gdb.COMMAND_RUNNING, be_verbose) 770094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleaSetAndroidDevice (adb, "set-android-device", gdb.COMMAND_RUNNING, be_verbose) 771094881f513ab366f7ffd0b2c7778ab50281ca59eDaniel MaleaAttachAndroidApp (adb, "attach-android-app", gdb.COMMAND_RUNNING, be_verbose) 772