blob: 17d8017634586f4fdb902572402f1d0baaca7869 [file] [log] [blame]
Jarkko Poyry3c827362014-09-02 11:48:52 +03001# -*- coding: utf-8 -*-
2
3import sys
4import os
5import time
6import string
7import shutil
8import subprocess
9import signal
10import argparse
11
12import common
13
14def 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
44def 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
195if __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)