1 # -*- coding: utf-8 -*- 2 3 import sys 4 import os 5 import time 6 import string 7 import shutil 8 import subprocess 9 import signal 10 import argparse 11 12 import common 13 14 def getADBProgramPID(program): 15 adbCmd = common.shellquote(common.ADB_BIN) 16 pid = -1 17 18 process = subprocess.Popen("%s shell ps" % adbCmd, shell=True, stdout=subprocess.PIPE) 19 20 firstLine = True 21 for line in process.stdout.readlines(): 22 if firstLine: 23 firstLine = False 24 continue 25 26 fields = string.split(line) 27 fields = filter(lambda x: len(x) > 0, fields) 28 29 if len(fields) < 9: 30 continue 31 32 if fields[8] == program: 33 assert pid == -1 34 pid = int(fields[1]) 35 36 process.wait() 37 38 if process.returncode != 0: 39 print("adb shell ps returned %s" % str(process.returncode)) 40 pid = -1 41 42 return pid 43 44 def debug( 45 adbCmd, 46 deqpCmdLine, 47 targetGDBPort, 48 hostGDBPort, 49 jdbPort, 50 jdbCmd, 51 gdbCmd, 52 buildDir, 53 deviceLibs, 54 breakpoints 55 ): 56 57 programPid = -1 58 gdbServerProcess = None 59 gdbProcess = None 60 jdbProcess = None 61 curDir = os.getcwd() 62 debugDir = os.path.join(common.ANDROID_DIR, "debug") 63 64 if os.path.exists(debugDir): 65 shutil.rmtree(debugDir) 66 67 os.makedirs(debugDir) 68 os.chdir(debugDir) 69 70 try: 71 # Start execution 72 print("Starting intent...") 73 common.execute("%s shell am start -W -D -n com.drawelements.deqp/android.app.NativeActivity -e cmdLine \"unused %s\"" % (adbCmd, deqpCmdLine.replace("\"", "\\\""))) 74 print("Intent started") 75 76 # Kill existing gdbservers 77 print("Check and kill existing gdbserver") 78 gdbPid = getADBProgramPID("lib/gdbserver") 79 if gdbPid != -1: 80 print("Found gdbserver with PID %i" % gdbPid) 81 common.execute("%s shell run-as com.drawelements.deqp kill -9 %i" % (adbCmd, gdbPid)) 82 print("Killed gdbserver") 83 else: 84 print("Couldn't find existing gdbserver") 85 86 programPid = getADBProgramPID("com.drawelements.deqp:testercore") 87 88 print("Find process PID") 89 if programPid == -1: 90 common.die("Couldn't get PID of testercore") 91 print("Process running with PID %i" % programPid) 92 93 # Start gdbserver 94 print("Start gdbserver for PID %i redirect stdout to gdbserver-stdout.txt" % programPid) 95 gdbServerProcess = subprocess.Popen("%s shell run-as com.drawelements.deqp lib/gdbserver localhost:%i --attach %i" % (adbCmd, targetGDBPort, programPid), shell=True, stdin=subprocess.PIPE, stdout=open("gdbserver-stdout.txt", "wb"), stderr=open("gdbserver-stderr.txt", "wb")) 96 print("gdbserver started") 97 98 time.sleep(1) 99 100 gdbServerProcess.poll() 101 102 if gdbServerProcess.returncode != None: 103 common.die("gdbserver returned unexpectly with return code %i see gdbserver-stdout.txt for more info" % gdbServerProcess.returncode) 104 105 # Setup port forwarding 106 print("Forwarding local port to gdbserver port") 107 common.execute("%s forward tcp:%i tcp:%i" % (adbCmd, hostGDBPort, targetGDBPort)) 108 109 # Pull some data files for debugger 110 print("Pull /system/bin/app_process from device") 111 common.execute("%s pull /system/bin/app_process" % adbCmd) 112 113 print("Pull /system/bin/linker from device") 114 common.execute("%s pull /system/bin/linker" % adbCmd) 115 116 for lib in deviceLibs: 117 print("Pull library %s from device" % lib) 118 common.execute("%s pull %s" % (adbCmd, lib)) 119 120 print("Copy %s from build dir" % common.NATIVE_LIB_NAME) 121 shutil.copyfile(os.path.join(buildDir, common.NATIVE_LIB_NAME), common.NATIVE_LIB_NAME) 122 123 # Forward local port for jdb 124 print("Forward local port to jdb port") 125 common.execute("%s forward tcp:%i jdwp:%i" % (adbCmd, jdbPort, programPid)) 126 127 # Connect JDB 128 print("Start jdb process redirectd stdout to jdb-stdout.txt") 129 jdbProcess = subprocess.Popen("%s -connect com.sun.jdi.SocketAttach:hostname=localhost,port=%i -sourcepath ../package" % (jdbCmd, jdbPort), shell=True, stdin=subprocess.PIPE, stdout=open("jdb-stdout.txt", "wb"), stderr=open("jdb-stderr.txt", "wb")) 130 print("Started jdb process") 131 132 # Write gdb.setup 133 print("Write gdb.setup") 134 gdbSetup = open("gdb.setup", "wb") 135 gdbSetup.write("file app_process\n") 136 gdbSetup.write("set solib-search-path .\n") 137 gdbSetup.write("target remote :%i\n" % hostGDBPort) 138 gdbSetup.write("set breakpoint pending on\n") 139 140 for breakpoint in breakpoints: 141 print("Set breakpoint at %s" % breakpoint) 142 gdbSetup.write("break %s\n" % breakpoint) 143 144 gdbSetup.write("set breakpoint pending off\n") 145 gdbSetup.close() 146 147 print("Start gdb") 148 gdbProcess = subprocess.Popen("%s -x gdb.setup" % common.shellquote(gdbCmd), shell=True) 149 150 gdbProcess.wait() 151 152 print("gdb returned with %i" % gdbProcess.returncode) 153 gdbProcess=None 154 155 print("Close jdb process with 'quit'") 156 jdbProcess.stdin.write("quit\n") 157 jdbProcess.wait() 158 print("JDB returned %s" % str(jdbProcess.returncode)) 159 jdbProcess=None 160 161 print("Kill gdbserver process") 162 gdbServerProcess.kill() 163 gdbServerProcess=None 164 print("Killed gdbserver process") 165 166 print("Kill program %i" % programPid) 167 common.execute("%s shell run-as com.drawelements.deqp -9 %i" % (adbCmd, programPid)) 168 print("Killed program") 169 170 finally: 171 if jdbProcess and jdbProcess.returncode == None: 172 print("Kill jdb") 173 jdbProcess.kill() 174 elif jdbProcess: 175 print("JDB returned %i" % jdbProcess.returncode) 176 177 if gdbProcess and gdbProcess.returncode == None: 178 print("Kill gdb") 179 gdbProcess.kill() 180 elif gdbProcess: 181 print("GDB returned %i" % gdbProcess.returncode) 182 183 if gdbServerProcess and gdbServerProcess.returncode == None: 184 print("Kill gdbserver") 185 gdbServerProcess.kill() 186 elif gdbServerProcess: 187 print("GDB server returned %i" % gdbServerProcess.returncode) 188 189 print("Kill program %i" % programPid) 190 common.execute("%s shell run-as com.drawelements.deqp kill -9 %i" % (adbCmd, programPid)) 191 print("Killed program") 192 193 os.chdir(curDir) 194 195 if __name__ == "__main__": 196 parser = argparse.ArgumentParser() 197 198 defaultDeviceLibs = { 199 "nexus-4" : [ 200 "/system/lib/libgenlock.so", 201 "/system/lib/libmemalloc.so", 202 "/system/lib/libqdutils.so", 203 "/system/lib/libsc-a3xx.so" 204 ] 205 } 206 207 defaultDevices = [] 208 209 for device in defaultDeviceLibs: 210 defaultDevices += [device] 211 212 parser.add_argument('--adb', dest='adbCmd', default=common.shellquote(common.ADB_BIN), help="Path to adb command. Use absolute paths.") 213 parser.add_argument('--deqp-commandline', dest='deqpCmdLine', default="--deqp-log-filename=/sdcard/TestLog.qpa", help="Command line arguments passed to dEQP test binary.") 214 215 if common.getPlatform() == "linux": 216 parser.add_argument('--gdb', dest='gdbCmd', default=common.shellquote(os.path.join(common.ANDROID_NDK_PATH, "toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb")), help="gdb command used by script. Use absolute paths") 217 else: 218 parser.add_argument('--gdb', dest='gdbCmd', default=common.shellquote(os.path.join(common.ANDROID_NDK_PATH, "toolchains/arm-linux-androideabi-4.8/prebuilt/windows/bin/arm-linux-androideabi-gdb")), help="gdb command used by script. Use absolute paths") 219 220 parser.add_argument('--target-gdb-port', dest='targetGDBPort', default=60001, type=int, help="Port used by gdbserver on target.") 221 parser.add_argument('--host-gdb-port', dest='hostGDBPort', default=60002, type=int, help="Host port that is forwarded to device gdbserver port.") 222 parser.add_argument('--jdb', dest='jdbCmd', default="jdb", help="Path to jdb command. Use absolute paths.") 223 parser.add_argument('--jdb-port', dest='jdbPort', default=60003, type=int, help="Host port used to forward jdb commands to device.") 224 parser.add_argument('--build-dir', dest='buildDir', default="../../../deqp-build-android-9-armeabi-v7a-debug", help="Path to dEQP native build directory.") 225 parser.add_argument('--device-libs', dest='deviceLibs', default=[], nargs='+', help="List of libraries that should be pulled from device for debugging.") 226 parser.add_argument('--breakpoints', dest='breakpoints', default=["tcu::App::App"], nargs='+', help="List of breakpoints that are set by gdb.") 227 parser.add_argument('--device', dest='device', default=None, choices=defaultDevices, help="Pull default libraries for this device.") 228 229 args = parser.parse_args() 230 231 debug(adbCmd=os.path.normpath(args.adbCmd), 232 gdbCmd=os.path.normpath(args.gdbCmd), 233 targetGDBPort=args.targetGDBPort, 234 hostGDBPort=args.hostGDBPort, 235 jdbCmd=os.path.normpath(args.jdbCmd), 236 jdbPort=args.jdbPort, 237 deqpCmdLine=args.deqpCmdLine, 238 buildDir=args.buildDir, 239 deviceLibs=["/system/lib/libc.so", "/system/lib/libdl.so"] + args.deviceLibs + (defaultDeviceLibs[args.device] if args.device else []), 240 breakpoints=args.breakpoints) 241