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