am 207522c3: (-s ours) Improvements to standalone Android build scripts automerge...
[platform/upstream/VK-GL-CTS.git] / android / scripts / debug.py
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)