author | coleenp |
Sun, 13 Apr 2008 17:43:42 -0400 | |
changeset 360 | 21d113ecbf6a |
parent 1 | 489c9b5090e2 |
child 670 | ddf3e9583f2f |
permissions | -rw-r--r-- |
1 | 1 |
/* |
2 |
* Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved. |
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. |
|
8 |
* |
|
9 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
13 |
* accompanied this code). |
|
14 |
* |
|
15 |
* You should have received a copy of the GNU General Public License version |
|
16 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
17 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 |
* |
|
19 |
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
20 |
* CA 95054 USA or visit www.sun.com if you need additional information or |
|
21 |
* have any questions. |
|
22 |
* |
|
23 |
*/ |
|
24 |
||
25 |
package sun.jvm.hotspot.debugger.dbx; |
|
26 |
||
27 |
import java.io.*; |
|
28 |
import java.net.*; |
|
29 |
import java.util.*; |
|
30 |
import sun.jvm.hotspot.debugger.*; |
|
31 |
import sun.jvm.hotspot.debugger.dbx.sparc.*; |
|
32 |
import sun.jvm.hotspot.debugger.dbx.x86.*; |
|
33 |
import sun.jvm.hotspot.debugger.cdbg.CDebugger; |
|
34 |
import sun.jvm.hotspot.utilities.*; |
|
35 |
||
36 |
/** <P> An implementation of the JVMDebugger interface which sits on |
|
37 |
top of dbx and relies on the SA's dbx import module for |
|
38 |
communication with the debugger. </P> |
|
39 |
||
40 |
<P> <B>NOTE</B> that since we have the notion of fetching "Java |
|
41 |
primitive types" from the remote process (which might have |
|
42 |
different sizes than we expect) we have a bootstrapping |
|
43 |
problem. We need to know the sizes of these types before we can |
|
44 |
fetch them. The current implementation solves this problem by |
|
45 |
requiring that it be configured with these type sizes before they |
|
46 |
can be fetched. The readJ(Type) routines here will throw a |
|
47 |
RuntimeException if they are called before the debugger is |
|
48 |
configured with the Java primitive type sizes. </P> |
|
49 |
*/ |
|
50 |
||
51 |
public class DbxDebuggerLocal extends DebuggerBase implements DbxDebugger { |
|
52 |
// These may be set by DbxDebuggerRemote |
|
53 |
protected boolean unalignedAccessesOkay; |
|
54 |
protected DbxThreadFactory threadFactory; |
|
55 |
||
56 |
private String dbxPathName; |
|
57 |
private String[] dbxSvcAgentDSOPathNames; |
|
58 |
private Process dbxProcess; |
|
59 |
private StreamMonitor dbxOutStreamMonitor; |
|
60 |
private StreamMonitor dbxErrStreamMonitor; |
|
61 |
private PrintWriter dbxOstr; |
|
62 |
private PrintWriter out; |
|
63 |
private InputLexer in; |
|
64 |
private Socket importModuleSocket; |
|
65 |
private static final int PORT = 21928; |
|
66 |
private static final int LONG_TIMEOUT = 60000; |
|
67 |
private static final int DBX_MODULE_NOT_FOUND = 101; |
|
68 |
private static final int DBX_MODULE_LOADED = 102; |
|
69 |
||
70 |
//-------------------------------------------------------------------------------- |
|
71 |
// Implementation of Debugger interface |
|
72 |
// |
|
73 |
||
74 |
/** <P> machDesc may be null if it couldn't be determined yet; i.e., |
|
75 |
if we're on SPARC, we need to ask the remote process whether |
|
76 |
we're in 32- or 64-bit mode. </P> |
|
77 |
||
78 |
<P> useCache should be set to true if debugging is being done |
|
79 |
locally, and to false if the debugger is being created for the |
|
80 |
purpose of supporting remote debugging. </P> */ |
|
81 |
public DbxDebuggerLocal(MachineDescription machDesc, |
|
82 |
String dbxPathName, |
|
83 |
String[] dbxSvcAgentDSOPathNames, |
|
84 |
boolean useCache) { |
|
85 |
this.machDesc = machDesc; |
|
86 |
this.dbxPathName = dbxPathName; |
|
87 |
this.dbxSvcAgentDSOPathNames = dbxSvcAgentDSOPathNames; |
|
88 |
int cacheNumPages; |
|
89 |
int cachePageSize; |
|
90 |
if (PlatformInfo.getCPU().equals("sparc")) { |
|
91 |
cacheNumPages = parseCacheNumPagesProperty(2048); |
|
92 |
cachePageSize = 8192; |
|
93 |
threadFactory = new DbxSPARCThreadFactory(this); |
|
94 |
} else if (PlatformInfo.getCPU().equals("x86")) { |
|
95 |
cacheNumPages = 4096; |
|
96 |
cachePageSize = 4096; |
|
97 |
threadFactory = new DbxX86ThreadFactory(this); |
|
98 |
unalignedAccessesOkay = true; |
|
99 |
} else { |
|
100 |
throw new RuntimeException("Thread access for CPU architecture " + PlatformInfo.getCPU() + " not yet supported"); |
|
101 |
} |
|
102 |
if (useCache) { |
|
103 |
// Cache portion of the remote process's address space. |
|
104 |
// Fetching data over the socket connection to dbx is relatively |
|
105 |
// slow. For now, this cache works best if it covers the entire |
|
106 |
// heap of the remote process. FIXME: at least should make this |
|
107 |
// tunable from the outside, i.e., via the UI. This is a 16 MB |
|
108 |
// cache divided on SPARC into 2048 8K pages and on x86 into |
|
109 |
// 4096 4K pages; the page size must be adjusted to be the OS's |
|
110 |
// page size. (FIXME: should pick this up from the debugger.) |
|
111 |
initCache(cachePageSize, cacheNumPages); |
|
112 |
} |
|
113 |
} |
|
114 |
||
115 |
/** Only called by DbxDebuggerRemote */ |
|
116 |
protected DbxDebuggerLocal() { |
|
117 |
} |
|
118 |
||
119 |
/** FIXME: implement this with a Runtime.exec() of ps followed by |
|
120 |
parsing of its output */ |
|
121 |
public boolean hasProcessList() throws DebuggerException { |
|
122 |
return false; |
|
123 |
} |
|
124 |
||
125 |
public List getProcessList() throws DebuggerException { |
|
126 |
throw new DebuggerException("Not yet supported"); |
|
127 |
} |
|
128 |
||
129 |
/** From the Debugger interface via JVMDebugger */ |
|
130 |
public synchronized void attach(int processID) throws DebuggerException { |
|
131 |
try { |
|
132 |
launchProcess(); |
|
133 |
dbxErrStreamMonitor.addTrigger("dbx: no process", 1); |
|
134 |
dbxErrStreamMonitor.addTrigger("dbx: Cannot open", 1); |
|
135 |
dbxErrStreamMonitor.addTrigger("dbx: Cannot find", DBX_MODULE_NOT_FOUND); |
|
136 |
dbxOstr = new PrintWriter(dbxProcess.getOutputStream(), true); |
|
137 |
dbxOstr.println("debug - " + processID); |
|
138 |
dbxOstr.println("kprint -u2 \\(ready\\)"); |
|
139 |
boolean seen = dbxErrStreamMonitor.waitFor("(ready)", LONG_TIMEOUT); |
|
140 |
if (!seen) { |
|
141 |
detach(); |
|
142 |
throw new DebuggerException("Timed out while connecting to process " + processID); |
|
143 |
} |
|
144 |
List retVals = dbxErrStreamMonitor.getTriggersSeen(); |
|
145 |
if (retVals.contains(new Integer(1))) { |
|
146 |
detach(); |
|
147 |
throw new DebuggerException("No such process " + processID); |
|
148 |
} |
|
149 |
||
150 |
// Throws DebuggerException upon failure |
|
151 |
importDbxModule(); |
|
152 |
||
153 |
dbxOstr.println("svc_agent_run"); |
|
154 |
||
155 |
connectToImportModule(); |
|
156 |
||
157 |
// Set "fail fast" mode on process memory reads |
|
158 |
printlnToOutput("peek_fail_fast 1"); |
|
159 |
} |
|
160 |
catch (IOException e) { |
|
161 |
detach(); |
|
162 |
throw new DebuggerException("Error while connecting to dbx process", e); |
|
163 |
} |
|
164 |
} |
|
165 |
||
166 |
/** From the Debugger interface via JVMDebugger */ |
|
167 |
public synchronized void attach(String executableName, String coreFileName) throws DebuggerException { |
|
168 |
try { |
|
169 |
launchProcess(); |
|
170 |
// Missing executable |
|
171 |
dbxErrStreamMonitor.addTrigger("dbx: Cannot open", 1); |
|
172 |
// Missing core file |
|
173 |
dbxErrStreamMonitor.addTrigger("dbx: can't read", 2); |
|
174 |
// Corrupt executable |
|
175 |
dbxErrStreamMonitor.addTrigger("dbx: File", 3); |
|
176 |
// Corrupt core file |
|
177 |
dbxErrStreamMonitor.addTrigger("dbx: Unable to read", 4); |
|
178 |
// Mismatched core and executable |
|
179 |
dbxErrStreamMonitor.addTrigger("dbx: core object name", 5); |
|
180 |
// Missing loadobject |
|
181 |
dbxErrStreamMonitor.addTrigger("dbx: can't stat", 6); |
|
182 |
// Successful load of svc module |
|
183 |
dbxOstr = new PrintWriter(dbxProcess.getOutputStream(), true); |
|
184 |
dbxOstr.println("debug " + executableName + " " + coreFileName); |
|
185 |
dbxOstr.println("kprint -u2 \\(ready\\)"); |
|
186 |
boolean seen = dbxErrStreamMonitor.waitFor("(ready)", LONG_TIMEOUT); |
|
187 |
if (!seen) { |
|
188 |
detach(); |
|
189 |
throw new DebuggerException("Timed out while attaching to core file"); |
|
190 |
} |
|
191 |
List retVals = dbxErrStreamMonitor.getTriggersSeen(); |
|
192 |
if (retVals.size() > 0) { |
|
193 |
detach(); |
|
194 |
||
195 |
if (retVals.contains(new Integer(1))) { |
|
196 |
throw new DebuggerException("Can not find executable \"" + executableName + "\""); |
|
197 |
} else if (retVals.contains(new Integer(2))) { |
|
198 |
throw new DebuggerException("Can not find core file \"" + coreFileName + "\""); |
|
199 |
} else if (retVals.contains(new Integer(3))) { |
|
200 |
throw new DebuggerException("Corrupt executable \"" + executableName + "\""); |
|
201 |
} else if (retVals.contains(new Integer(4))) { |
|
202 |
throw new DebuggerException("Corrupt core file \"" + coreFileName + "\""); |
|
203 |
} else if (retVals.contains(new Integer(5))) { |
|
204 |
throw new DebuggerException("Mismatched core file/executable \"" + coreFileName + "\"/\"" + executableName + "\""); |
|
205 |
} else { |
|
206 |
throw new DebuggerException("Couldn't find all loaded libraries for executable \"" + executableName + "\""); |
|
207 |
} |
|
208 |
} |
|
209 |
||
210 |
// Throws DebuggerException upon failure |
|
211 |
importDbxModule(); |
|
212 |
||
213 |
dbxOstr.println("svc_agent_run"); |
|
214 |
||
215 |
connectToImportModule(); |
|
216 |
||
217 |
// Set "fail fast" mode on process memory reads |
|
218 |
printlnToOutput("peek_fail_fast 1"); |
|
219 |
} |
|
220 |
catch (IOException e) { |
|
221 |
detach(); |
|
222 |
throw new DebuggerException("Error while connecting to dbx process", e); |
|
223 |
} |
|
224 |
} |
|
225 |
||
226 |
/** From the Debugger interface via JVMDebugger */ |
|
227 |
public synchronized boolean detach() { |
|
228 |
try { |
|
229 |
if (dbxProcess == null) { |
|
230 |
return false; |
|
231 |
} |
|
232 |
||
233 |
if (out != null && dbxOstr != null) { |
|
234 |
printlnToOutput("exit"); |
|
235 |
dbxOstr.println("exit"); |
|
236 |
||
237 |
// Wait briefly for the process to exit (FIXME: should make this |
|
238 |
// nicer) |
|
239 |
try { |
|
240 |
Thread.sleep(500); |
|
241 |
} |
|
242 |
catch (InterruptedException e) { |
|
243 |
} |
|
244 |
} |
|
245 |
||
246 |
shutdown(); |
|
247 |
||
248 |
return true; |
|
249 |
} catch (IOException e) { |
|
250 |
e.printStackTrace(); |
|
251 |
return false; |
|
252 |
} |
|
253 |
} |
|
254 |
||
255 |
/** From the Debugger interface via JVMDebugger */ |
|
256 |
public Address parseAddress(String addressString) throws NumberFormatException { |
|
257 |
long addr = utils.scanAddress(addressString); |
|
258 |
if (addr == 0) { |
|
259 |
return null; |
|
260 |
} |
|
261 |
return new DbxAddress(this, addr); |
|
262 |
} |
|
263 |
||
264 |
/** From the Debugger interface via JVMDebugger */ |
|
265 |
public String getOS() { |
|
266 |
return PlatformInfo.getOS(); |
|
267 |
} |
|
268 |
||
269 |
/** From the Debugger interface via JVMDebugger */ |
|
270 |
public String getCPU() { |
|
271 |
return PlatformInfo.getCPU(); |
|
272 |
} |
|
273 |
||
274 |
public boolean hasConsole() throws DebuggerException { |
|
275 |
return true; |
|
276 |
} |
|
277 |
||
278 |
public synchronized String consoleExecuteCommand(String cmd) throws DebuggerException { |
|
279 |
try { |
|
280 |
// A little tricky. We need to cause the dbx import module to |
|
281 |
// exit, then print our command on dbx's stdin along with a |
|
282 |
// command which will allow our StreamMonitors to |
|
283 |
// resynchronize. We need save the output from the StreamMonitors |
|
284 |
// along the way. |
|
285 |
printlnToOutput("exit"); |
|
286 |
importModuleSocket.close(); |
|
287 |
importModuleSocket = null; |
|
288 |
out = null; |
|
289 |
in = null; |
|
290 |
dbxOstr.println("kprint \\(ready\\)"); |
|
291 |
dbxOstr.flush(); |
|
292 |
dbxOutStreamMonitor.waitFor("(ready)", LONG_TIMEOUT); |
|
293 |
||
294 |
dbxOutStreamMonitor.startCapture(); |
|
295 |
dbxErrStreamMonitor.startCapture(); |
|
296 |
dbxOstr.println(cmd); |
|
297 |
dbxOstr.println("kprint \\(ready\\)"); |
|
298 |
dbxOutStreamMonitor.waitFor("(ready)", LONG_TIMEOUT); |
|
299 |
String result = dbxOutStreamMonitor.stopCapture(); |
|
300 |
String result2 = dbxErrStreamMonitor.stopCapture(); |
|
301 |
result = result + result2; |
|
302 |
// Cut out the "(ready)" string |
|
303 |
StringBuffer outBuf = new StringBuffer(result.length()); |
|
304 |
BufferedReader reader = new BufferedReader(new StringReader(result)); |
|
305 |
// FIXME: bug in BufferedReader? readLine returns null when |
|
306 |
// ready() returns true. |
|
307 |
String line = null; |
|
308 |
do { |
|
309 |
line = reader.readLine(); |
|
310 |
if ((line != null) && (!line.equals("(ready)"))) { |
|
311 |
outBuf.append(line); |
|
312 |
outBuf.append("\n"); |
|
313 |
} |
|
314 |
} while (line != null); |
|
315 |
dbxOstr.println("svc_agent_run"); |
|
316 |
dbxOstr.flush(); |
|
317 |
||
318 |
connectToImportModule(); |
|
319 |
||
320 |
return outBuf.toString(); |
|
321 |
} |
|
322 |
catch (IOException e) { |
|
323 |
detach(); |
|
324 |
throw new DebuggerException("Error while executing command on dbx console", e); |
|
325 |
} |
|
326 |
} |
|
327 |
||
328 |
public String getConsolePrompt() throws DebuggerException { |
|
329 |
return "(dbx) "; |
|
330 |
} |
|
331 |
||
332 |
public CDebugger getCDebugger() throws DebuggerException { |
|
333 |
return null; |
|
334 |
} |
|
335 |
||
336 |
/** From the SymbolLookup interface via Debugger and JVMDebugger */ |
|
337 |
public synchronized Address lookup(String objectName, String symbol) { |
|
338 |
long addr = lookupInProcess(objectName, symbol); |
|
339 |
if (addr == 0) { |
|
340 |
return null; |
|
341 |
} |
|
342 |
return new DbxAddress(this, addr); |
|
343 |
} |
|
344 |
||
345 |
/** From the SymbolLookup interface via Debugger and JVMDebugger */ |
|
346 |
public synchronized OopHandle lookupOop(String objectName, String symbol) { |
|
347 |
long addr = lookupInProcess(objectName, symbol); |
|
348 |
if (addr == 0) { |
|
349 |
return null; |
|
350 |
} |
|
351 |
return new DbxOopHandle(this, addr); |
|
352 |
} |
|
353 |
||
354 |
/** From the Debugger interface */ |
|
355 |
public MachineDescription getMachineDescription() { |
|
356 |
return machDesc; |
|
357 |
} |
|
358 |
||
359 |
/** Internal routine supporting lazy setting of MachineDescription, |
|
360 |
since on SPARC we will need to query the remote process to ask |
|
361 |
it what its data model is (32- or 64-bit). NOTE that this is NOT |
|
362 |
present in the DbxDebugger interface because it should not be |
|
363 |
called across the wire (until we support attaching to multiple |
|
364 |
remote processes via RMI -- see the documentation for |
|
365 |
DbxDebuggerRemoteIntf.) */ |
|
366 |
public void setMachineDescription(MachineDescription machDesc) { |
|
367 |
this.machDesc = machDesc; |
|
368 |
setBigEndian(machDesc.isBigEndian()); |
|
369 |
utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian()); |
|
370 |
} |
|
371 |
||
372 |
/** Internal routine which queries the remote process about its data |
|
373 |
model -- i.e., size of addresses. Returns -1 upon error. |
|
374 |
Currently supported return values are 32 and 64. NOTE that this |
|
375 |
is NOT present in the DbxDebugger interface because it should |
|
376 |
not be called across the wire (until we support attaching to |
|
377 |
multiple remote processes via RMI -- see the documentation for |
|
378 |
DbxDebuggerRemoteIntf.) */ |
|
379 |
public int getRemoteProcessAddressSize() { |
|
380 |
if (dbxProcess == null) { |
|
381 |
throw new RuntimeException("Not attached to remote process"); |
|
382 |
} |
|
383 |
||
384 |
try { |
|
385 |
printlnToOutput("address_size"); |
|
386 |
int i = in.parseInt(); |
|
387 |
return i; |
|
388 |
} |
|
389 |
catch (IOException e) { |
|
390 |
return -1; |
|
391 |
} |
|
392 |
} |
|
393 |
||
394 |
//-------------------------------------------------------------------------------- |
|
395 |
// Implementation of ThreadAccess interface |
|
396 |
// |
|
397 |
||
398 |
/** From the ThreadAccess interface via Debugger and JVMDebugger */ |
|
399 |
public ThreadProxy getThreadForIdentifierAddress(Address addr) { |
|
400 |
return threadFactory.createThreadWrapper(addr); |
|
401 |
} |
|
402 |
||
403 |
public ThreadProxy getThreadForThreadId(long id) { |
|
404 |
return threadFactory.createThreadWrapper(id); |
|
405 |
} |
|
406 |
||
407 |
//---------------------------------------------------------------------- |
|
408 |
// Overridden from DebuggerBase because we need to relax alignment |
|
409 |
// constraints on x86 |
|
410 |
||
411 |
public long readJLong(long address) |
|
412 |
throws UnmappedAddressException, UnalignedAddressException { |
|
413 |
checkJavaConfigured(); |
|
414 |
// FIXME: allow this to be configurable. Undesirable to add a |
|
415 |
// dependency on the runtime package here, though, since this |
|
416 |
// package should be strictly underneath it. |
|
417 |
if (unalignedAccessesOkay) { |
|
418 |
utils.checkAlignment(address, jintSize); |
|
419 |
} else { |
|
420 |
utils.checkAlignment(address, jlongSize); |
|
421 |
} |
|
422 |
byte[] data = readBytes(address, jlongSize); |
|
423 |
return utils.dataToJLong(data, jlongSize); |
|
424 |
} |
|
425 |
||
426 |
//-------------------------------------------------------------------------------- |
|
427 |
// Internal routines (for implementation of DbxAddress). |
|
428 |
// These must not be called until the MachineDescription has been set up. |
|
429 |
// |
|
430 |
||
431 |
/** From the DbxDebugger interface */ |
|
432 |
public String addressValueToString(long address) { |
|
433 |
return utils.addressValueToString(address); |
|
434 |
} |
|
435 |
||
436 |
/** Need to override this to relax alignment checks on Solaris/x86. */ |
|
437 |
public long readCInteger(long address, long numBytes, boolean isUnsigned) |
|
438 |
throws UnmappedAddressException, UnalignedAddressException { |
|
439 |
checkConfigured(); |
|
440 |
if (!unalignedAccessesOkay) { |
|
441 |
utils.checkAlignment(address, numBytes); |
|
442 |
} else { |
|
443 |
// Only slightly relaxed semantics -- this is a hack, but is |
|
444 |
// necessary on Solaris/x86 where it seems the compiler is |
|
445 |
// putting some global 64-bit data on 32-bit boundaries |
|
446 |
if (numBytes == 8) { |
|
447 |
utils.checkAlignment(address, 4); |
|
448 |
} else { |
|
449 |
utils.checkAlignment(address, numBytes); |
|
450 |
} |
|
451 |
} |
|
452 |
byte[] data = readBytes(address, numBytes); |
|
453 |
return utils.dataToCInteger(data, isUnsigned); |
|
454 |
} |
|
455 |
||
456 |
/** From the DbxDebugger interface */ |
|
457 |
public DbxAddress readAddress(long address) |
|
458 |
throws UnmappedAddressException, UnalignedAddressException { |
|
459 |
long value = readAddressValue(address); |
|
460 |
return (value == 0 ? null : new DbxAddress(this, value)); |
|
461 |
} |
|
462 |
||
360
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
463 |
public DbxAddress readCompOopAddress(long address) |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
464 |
throws UnmappedAddressException, UnalignedAddressException { |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
465 |
long value = readCompOopAddressValue(address); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
466 |
return (value == 0 ? null : new DbxAddress(this, value)); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
467 |
} |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
468 |
|
1 | 469 |
/** From the DbxDebugger interface */ |
470 |
public DbxOopHandle readOopHandle(long address) |
|
471 |
throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { |
|
472 |
long value = readAddressValue(address); |
|
473 |
return (value == 0 ? null : new DbxOopHandle(this, value)); |
|
474 |
} |
|
360
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
475 |
public DbxOopHandle readCompOopHandle(long address) |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
476 |
throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
477 |
long value = readCompOopAddressValue(address); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
478 |
return (value == 0 ? null : new DbxOopHandle(this, value)); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
479 |
} |
1 | 480 |
|
481 |
//-------------------------------------------------------------------------------- |
|
482 |
// Thread context access. Can not be package private, but should |
|
483 |
// only be accessed by the architecture-specific subpackages. |
|
484 |
||
485 |
/** From the DbxDebugger interface. May have to redefine this later. */ |
|
486 |
public synchronized long[] getThreadIntegerRegisterSet(int tid) { |
|
487 |
try { |
|
488 |
printlnToOutput("thr_gregs " + tid); |
|
489 |
int num = in.parseInt(); |
|
490 |
long[] res = new long[num]; |
|
491 |
for (int i = 0; i < num; i++) { |
|
492 |
res[i] = in.parseAddress(); |
|
493 |
} |
|
494 |
return res; |
|
495 |
} |
|
496 |
catch (Exception e) { |
|
497 |
e.printStackTrace(); |
|
498 |
return null; |
|
499 |
} |
|
500 |
} |
|
501 |
||
502 |
//-------------------------------------------------------------------------------- |
|
503 |
// Address access. Can not be package private, but should only be |
|
504 |
// accessed by the architecture-specific subpackages. |
|
505 |
||
506 |
/** From the Debugger interface */ |
|
507 |
public long getAddressValue(Address addr) { |
|
508 |
if (addr == null) return 0; |
|
509 |
return ((DbxAddress) addr).getValue(); |
|
510 |
} |
|
511 |
||
512 |
/** From the DbxDebugger interface */ |
|
513 |
public Address newAddress(long value) { |
|
514 |
if (value == 0) return null; |
|
515 |
return new DbxAddress(this, value); |
|
516 |
} |
|
517 |
||
518 |
//-------------------------------------------------------------------------------- |
|
519 |
// Internals only below this point |
|
520 |
// |
|
521 |
||
522 |
private void launchProcess() throws IOException { |
|
523 |
dbxProcess = Runtime.getRuntime().exec(dbxPathName); |
|
524 |
// dbxOutStreamMonitor = new StreamMonitor(dbxProcess.getInputStream()); |
|
525 |
// dbxErrStreamMonitor = new StreamMonitor(dbxProcess.getErrorStream()); |
|
526 |
dbxOutStreamMonitor = new StreamMonitor(dbxProcess.getInputStream(), "dbx stdout", true); |
|
527 |
dbxErrStreamMonitor = new StreamMonitor(dbxProcess.getErrorStream(), "dbx stderr", true); |
|
528 |
} |
|
529 |
||
530 |
/** Requires that dbxErrStreamMonitor has a trigger on "dbx: Cannot |
|
531 |
find" with number DBX_MODULE_NOT_FOUND as well as one on "dbx: |
|
532 |
warning:" (plus the serviceability agent's dbx module path name, |
|
533 |
to avoid conflation with inability to load individual object |
|
534 |
files) with number DBX_MODULE_FAILED_TO_LOAD. The former |
|
535 |
indicates an absence of libsvc_agent_dbx.so, while the latter |
|
536 |
indicates that the module failed to load, specifically because |
|
537 |
the architecture was mismatched. (I don't see a way to detect |
|
538 |
from the dbx command prompt whether it's running the v8 or v9 |
|
539 |
executbale, so we try to import both flavors of the import |
|
540 |
module; the "v8" file name convention doesn't actually include |
|
541 |
the v8 prefix, so this code should work for Intel as well.) */ |
|
542 |
private void importDbxModule() throws DebuggerException { |
|
543 |
// Trigger for a successful load |
|
544 |
dbxOutStreamMonitor.addTrigger("Defining svc_agent_run", DBX_MODULE_LOADED); |
|
545 |
for (int i = 0; i < dbxSvcAgentDSOPathNames.length; i++) { |
|
546 |
dbxOstr.println("import " + dbxSvcAgentDSOPathNames[i]); |
|
547 |
dbxOstr.println("kprint -u2 \\(Ready\\)"); |
|
548 |
boolean seen = dbxErrStreamMonitor.waitFor("(Ready)", LONG_TIMEOUT); |
|
549 |
if (!seen) { |
|
550 |
detach(); |
|
551 |
throw new DebuggerException("Timed out while importing dbx module from file\n" + dbxSvcAgentDSOPathNames[i]); |
|
552 |
} |
|
553 |
List retVals = dbxErrStreamMonitor.getTriggersSeen(); |
|
554 |
if (retVals.contains(new Integer(DBX_MODULE_NOT_FOUND))) { |
|
555 |
detach(); |
|
556 |
throw new DebuggerException("Unable to find the Serviceability Agent's dbx import module at pathname \"" + |
|
557 |
dbxSvcAgentDSOPathNames[i] + "\""); |
|
558 |
} else { |
|
559 |
retVals = dbxOutStreamMonitor.getTriggersSeen(); |
|
560 |
if (retVals.contains(new Integer(DBX_MODULE_LOADED))) { |
|
561 |
System.out.println("importDbxModule: imported " + dbxSvcAgentDSOPathNames[i]); |
|
562 |
return; |
|
563 |
} |
|
564 |
} |
|
565 |
} |
|
566 |
||
567 |
// Failed to load all flavors |
|
568 |
detach(); |
|
569 |
String errMsg = ("Unable to find a version of the Serviceability Agent's dbx import module\n" + |
|
570 |
"matching the architecture of dbx at any of the following locations:"); |
|
571 |
for (int i = 0; i < dbxSvcAgentDSOPathNames.length; i++) { |
|
572 |
errMsg = errMsg + "\n" + dbxSvcAgentDSOPathNames[i]; |
|
573 |
} |
|
574 |
throw new DebuggerException(errMsg); |
|
575 |
} |
|
576 |
||
577 |
/** Terminate the debugger forcibly */ |
|
578 |
private void shutdown() { |
|
579 |
||
580 |
if (dbxProcess != null) { |
|
581 |
// See whether the process has exited and, if not, terminate it |
|
582 |
// forcibly |
|
583 |
try { |
|
584 |
dbxProcess.exitValue(); |
|
585 |
} |
|
586 |
catch (IllegalThreadStateException e) { |
|
587 |
dbxProcess.destroy(); |
|
588 |
} |
|
589 |
} |
|
590 |
||
591 |
try { |
|
592 |
if (importModuleSocket != null) { |
|
593 |
importModuleSocket.close(); |
|
594 |
} |
|
595 |
} |
|
596 |
catch (IOException e) { |
|
597 |
} |
|
598 |
||
599 |
// Release references to all objects |
|
600 |
clear(); |
|
601 |
clearCache(); |
|
602 |
} |
|
603 |
||
604 |
/** Looks up an address in the remote process's address space. |
|
605 |
Returns 0 if symbol not found or upon error. Package private to |
|
606 |
allow DbxDebuggerRemoteIntfImpl access. */ |
|
607 |
synchronized long lookupInProcess(String objectName, String symbol) { |
|
608 |
try { |
|
609 |
printlnToOutput("lookup " + objectName + " " + symbol); |
|
610 |
return in.parseAddress(); |
|
611 |
} |
|
612 |
catch (Exception e) { |
|
613 |
return 0; |
|
614 |
} |
|
615 |
} |
|
616 |
||
617 |
/** This reads bytes from the remote process. */ |
|
618 |
public synchronized ReadResult readBytesFromProcess(long address, long numBytes) |
|
619 |
throws DebuggerException { |
|
620 |
if (numBytes < 0) { |
|
621 |
throw new DebuggerException("Can not read negative number (" + numBytes + ") of bytes from process"); |
|
622 |
} |
|
623 |
try { |
|
624 |
String cmd = "peek " + utils.addressValueToString(address) + " " + numBytes; |
|
625 |
printlnToOutput(cmd); |
|
626 |
while (in.readByte() != 'B') { |
|
627 |
} |
|
628 |
byte res = in.readByte(); |
|
629 |
if (res == 0) { |
|
630 |
System.err.println("Failing command: " + cmd); |
|
631 |
throw new DebuggerException("Read of remote process address space failed"); |
|
632 |
} |
|
633 |
// NOTE: must read ALL of the data regardless of whether we need |
|
634 |
// to throw an UnmappedAddressException. Otherwise will corrupt |
|
635 |
// the input stream each time we have a failure. Not good. Do |
|
636 |
// not want to risk "flushing" the input stream in case a huge |
|
637 |
// read has a hangup in the middle and we leave data on the |
|
638 |
// stream. |
|
639 |
byte[] buf = new byte[(int) numBytes]; |
|
640 |
boolean bailOut = false; |
|
641 |
long failureAddress = 0; |
|
642 |
int numReads = 0; |
|
643 |
while (numBytes > 0) { |
|
644 |
long len = in.readUnsignedInt(); |
|
645 |
boolean isMapped = ((in.readByte() == 0) ? false : true); |
|
646 |
if (!isMapped) { |
|
647 |
if (!bailOut) { |
|
648 |
bailOut = true; |
|
649 |
failureAddress = address; |
|
650 |
} |
|
651 |
} else { |
|
652 |
// This won't work if we have unmapped regions, but if we do |
|
653 |
// then we're going to throw an exception anyway |
|
654 |
||
655 |
// NOTE: there is a factor of 20 speed difference between |
|
656 |
// these two ways of doing this read. |
|
657 |
in.readBytes(buf, 0, (int) len); |
|
658 |
} |
|
659 |
||
660 |
// Do NOT do this: |
|
661 |
// for (int i = 0; i < (int) len; i++) { |
|
662 |
// buf[i] = in.readByte(); |
|
663 |
// } |
|
664 |
||
665 |
numBytes -= len; |
|
666 |
address += len; |
|
667 |
++numReads; |
|
668 |
} |
|
669 |
if (Assert.ASSERTS_ENABLED) { |
|
670 |
Assert.that(numBytes == 0, "Bug in debug server's implementation of peek: numBytesLeft == " + |
|
671 |
numBytes + ", should be 0 (did " + numReads + " reads)"); |
|
672 |
} |
|
673 |
if (bailOut) { |
|
674 |
return new ReadResult(failureAddress); |
|
675 |
} |
|
676 |
return new ReadResult(buf); |
|
677 |
} |
|
678 |
catch (IOException e) { |
|
679 |
throw new DebuggerException(e); |
|
680 |
} |
|
681 |
} |
|
682 |
||
683 |
public void writeBytesToProcess(long address, long numBytes, byte[] data) |
|
684 |
throws UnmappedAddressException, DebuggerException { |
|
685 |
// FIXME |
|
686 |
throw new DebuggerException("Unimplemented"); |
|
687 |
} |
|
688 |
||
689 |
/** This provides DbxDebuggerRemoteIntfImpl access to readBytesFromProcess */ |
|
690 |
ReadResult readBytesFromProcessInternal(long address, long numBytes) |
|
691 |
throws DebuggerException { |
|
692 |
return readBytesFromProcess(address, numBytes); |
|
693 |
} |
|
694 |
||
695 |
/** Convenience routine */ |
|
696 |
private void printlnToOutput(String s) throws IOException { |
|
697 |
out.println(s); |
|
698 |
if (out.checkError()) { |
|
699 |
throw new IOException("Error occurred while writing to debug server"); |
|
700 |
} |
|
701 |
} |
|
702 |
||
703 |
private void clear() { |
|
704 |
dbxProcess = null; |
|
705 |
dbxOstr = null; |
|
706 |
out = null; |
|
707 |
in = null; |
|
708 |
importModuleSocket = null; |
|
709 |
} |
|
710 |
||
711 |
/** Connects to the dbx import module, setting up out and in |
|
712 |
streams. Factored out to allow access to the dbx console. */ |
|
713 |
private void connectToImportModule() throws IOException { |
|
714 |
// Try for 20 seconds to connect to dbx import module; time out |
|
715 |
// with failure if didn't succeed |
|
716 |
importModuleSocket = null; |
|
717 |
long endTime = System.currentTimeMillis() + LONG_TIMEOUT; |
|
718 |
||
719 |
while ((importModuleSocket == null) && (System.currentTimeMillis() < endTime)) { |
|
720 |
try { |
|
721 |
importModuleSocket = new Socket(InetAddress.getLocalHost(), PORT); |
|
722 |
importModuleSocket.setTcpNoDelay(true); |
|
723 |
} |
|
724 |
catch (IOException e) { |
|
725 |
// Swallow IO exceptions while attempting connection |
|
726 |
try { |
|
727 |
// Don't swamp the CPU |
|
728 |
Thread.sleep(1000); |
|
729 |
} |
|
730 |
catch (InterruptedException ex) { |
|
731 |
} |
|
732 |
} |
|
733 |
} |
|
734 |
||
735 |
if (importModuleSocket == null) { |
|
736 |
// Failed to connect because of timeout |
|
737 |
detach(); |
|
738 |
throw new DebuggerException("Timed out while attempting to connect to remote dbx process"); |
|
739 |
} |
|
740 |
||
741 |
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(importModuleSocket.getOutputStream(), "US-ASCII")), true); |
|
742 |
in = new InputLexer(new BufferedInputStream(importModuleSocket.getInputStream())); |
|
743 |
} |
|
744 |
} |