Home | History | Annotate | Download | only in scripts
      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)
    241