Jarkko Poyry | 3c82736 | 2014-09-02 11:48:52 +0300 | [diff] [blame^] | 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 libtestercore.so from build dir") |
| 121 | shutil.copyfile(os.path.join(buildDir, "libtestercore.so"), "libtestercore.so") |
| 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) |