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 2002-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.proc; |
|
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.cdbg.*; |
|
32 |
import sun.jvm.hotspot.debugger.proc.amd64.*; |
|
33 |
import sun.jvm.hotspot.debugger.proc.sparc.*; |
|
34 |
import sun.jvm.hotspot.debugger.proc.x86.*; |
|
35 |
import sun.jvm.hotspot.debugger.amd64.*; |
|
36 |
import sun.jvm.hotspot.debugger.sparc.*; |
|
37 |
import sun.jvm.hotspot.debugger.x86.*; |
|
38 |
import sun.jvm.hotspot.utilities.*; |
|
39 |
||
40 |
/** <P> An implementation of the JVMDebugger interface which sits on |
|
41 |
* top of proc and relies on the SA's proc import module for |
|
42 |
* communication with the debugger. </P> |
|
43 |
* |
|
44 |
* <P> <B>NOTE</B> that since we have the notion of fetching "Java |
|
45 |
* primitive types" from the remote process (which might have |
|
46 |
* different sizes than we expect) we have a bootstrapping |
|
47 |
* problem. We need to know the sizes of these types before we can |
|
48 |
* fetch them. The current implementation solves this problem by |
|
49 |
* requiring that it be configured with these type sizes before they |
|
50 |
* can be fetched. The readJ(Type) routines here will throw a |
|
51 |
* RuntimeException if they are called before the debugger is |
|
52 |
* configured with the Java primitive type sizes. </P> |
|
53 |
*/ |
|
54 |
||
55 |
public class ProcDebuggerLocal extends DebuggerBase implements ProcDebugger { |
|
56 |
protected static final int cacheSize = 16 * 1024 * 1024; // 16 MB |
|
57 |
||
58 |
//------------------------------------------------------------------------ |
|
59 |
// Implementation of Debugger interface |
|
60 |
// |
|
61 |
||
62 |
/** <P> machDesc may be null if it couldn't be determined yet; i.e., |
|
63 |
* if we're on SPARC, we need to ask the remote process whether |
|
64 |
* we're in 32- or 64-bit mode. </P> |
|
65 |
* |
|
66 |
* <P> useCache should be set to true if debugging is being done |
|
67 |
* locally, and to false if the debugger is being created for the |
|
68 |
* purpose of supporting remote debugging. </P> */ |
|
69 |
public ProcDebuggerLocal(MachineDescription machDesc, boolean useCache) { |
|
70 |
this.machDesc = machDesc; |
|
71 |
int cacheNumPages; |
|
72 |
int cachePageSize; |
|
73 |
||
74 |
final String cpu = PlatformInfo.getCPU(); |
|
75 |
if (cpu.equals("sparc")) { |
|
76 |
threadFactory = new ProcSPARCThreadFactory(this); |
|
77 |
pcRegIndex = SPARCThreadContext.R_PC; |
|
78 |
fpRegIndex = SPARCThreadContext.R_I6; |
|
79 |
} else if (cpu.equals("x86")) { |
|
80 |
threadFactory = new ProcX86ThreadFactory(this); |
|
81 |
pcRegIndex = X86ThreadContext.EIP; |
|
82 |
fpRegIndex = X86ThreadContext.EBP; |
|
83 |
unalignedAccessesOkay = true; |
|
84 |
} else if (cpu.equals("amd64")) { |
|
85 |
threadFactory = new ProcAMD64ThreadFactory(this); |
|
86 |
pcRegIndex = AMD64ThreadContext.RIP; |
|
87 |
fpRegIndex = AMD64ThreadContext.RBP; |
|
88 |
} else { |
|
89 |
throw new RuntimeException("Thread access for CPU architecture " + PlatformInfo.getCPU() + " not yet supported"); |
|
90 |
} |
|
91 |
if (useCache) { |
|
92 |
// Cache portion of the remote process's address space. |
|
93 |
// For now, this cache works best if it covers the entire |
|
94 |
// heap of the remote process. FIXME: at least should make this |
|
95 |
// tunable from the outside, i.e., via the UI. This is a 16 MB |
|
96 |
// cache divided on SPARC into 2048 8K pages and on x86 into |
|
97 |
// 4096 4K pages; the page size must be adjusted to be the OS's |
|
98 |
// page size. |
|
99 |
||
100 |
cachePageSize = getPageSize(); |
|
101 |
cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize); |
|
102 |
initCache(cachePageSize, cacheNumPages); |
|
103 |
} |
|
104 |
||
105 |
resetNativePointers(); |
|
106 |
clearCacheFields(); |
|
107 |
} |
|
108 |
||
109 |
/** FIXME: implement this with a Runtime.exec() of ps followed by |
|
110 |
* parsing of its output */ |
|
111 |
public boolean hasProcessList() throws DebuggerException { |
|
112 |
return false; |
|
113 |
} |
|
114 |
||
115 |
public List getProcessList() throws DebuggerException { |
|
116 |
throw new DebuggerException("Not yet supported"); |
|
117 |
} |
|
118 |
||
119 |
||
120 |
/** From the Debugger interface via JVMDebugger */ |
|
121 |
public synchronized void attach(int processID) throws DebuggerException { |
|
122 |
checkAttached(); |
|
123 |
isCore = false; |
|
124 |
attach0(new Integer(processID).toString()); |
|
125 |
attached = true; |
|
126 |
suspended = true; |
|
127 |
} |
|
128 |
||
129 |
/** From the Debugger interface via JVMDebugger */ |
|
130 |
public synchronized void attach |
|
131 |
(String executableName, String coreFileName) throws DebuggerException { |
|
132 |
checkAttached(); |
|
133 |
isCore = true; |
|
134 |
topFrameCache = new HashMap(); |
|
135 |
attach0(executableName, coreFileName); |
|
136 |
attached = true; |
|
137 |
suspended = true; |
|
138 |
} |
|
139 |
||
140 |
/** From the Debugger interface via JVMDebugger */ |
|
141 |
public synchronized boolean detach() { |
|
142 |
if (! attached) { |
|
143 |
return false; |
|
144 |
} |
|
145 |
||
146 |
try { |
|
147 |
if (p_ps_prochandle == 0L) { |
|
148 |
return false; |
|
149 |
} |
|
150 |
detach0(); |
|
151 |
clearCache(); |
|
152 |
return true; |
|
153 |
} catch (Exception e) { |
|
154 |
e.printStackTrace(); |
|
155 |
return false; |
|
156 |
} finally { |
|
157 |
resetNativePointers(); |
|
158 |
clearCacheFields(); |
|
159 |
suspended = false; |
|
160 |
attached = false; |
|
161 |
} |
|
162 |
} |
|
163 |
||
164 |
public synchronized void suspend() throws DebuggerException { |
|
165 |
requireAttach(); |
|
166 |
if (suspended) { |
|
167 |
throw new DebuggerException("Process already suspended"); |
|
168 |
} |
|
169 |
suspend0(); |
|
170 |
suspended = true; |
|
171 |
enableCache(); |
|
172 |
reresolveLoadObjects(); |
|
173 |
} |
|
174 |
||
175 |
public synchronized void resume() throws DebuggerException { |
|
176 |
requireAttach(); |
|
177 |
if (!suspended) { |
|
178 |
throw new DebuggerException("Process not suspended"); |
|
179 |
} |
|
180 |
resume0(); |
|
181 |
disableCache(); |
|
182 |
suspended = false; |
|
183 |
} |
|
184 |
||
185 |
public synchronized boolean isSuspended() throws DebuggerException { |
|
186 |
requireAttach(); |
|
187 |
return suspended; |
|
188 |
} |
|
189 |
||
190 |
/** From the Debugger interface via JVMDebugger */ |
|
191 |
public Address parseAddress(String addressString) throws NumberFormatException { |
|
192 |
long addr = utils.scanAddress(addressString); |
|
193 |
if (addr == 0) { |
|
194 |
return null; |
|
195 |
} |
|
196 |
return new ProcAddress(this, addr); |
|
197 |
} |
|
198 |
||
199 |
/** From the Debugger interface via JVMDebugger */ |
|
200 |
public String getOS() { |
|
201 |
return PlatformInfo.getOS(); |
|
202 |
} |
|
203 |
||
204 |
/** From the Debugger interface via JVMDebugger */ |
|
205 |
public String getCPU() { |
|
206 |
return PlatformInfo.getCPU(); |
|
207 |
} |
|
208 |
||
209 |
public boolean hasConsole() throws DebuggerException { |
|
210 |
return false; |
|
211 |
} |
|
212 |
||
213 |
public String consoleExecuteCommand(String cmd) throws DebuggerException { |
|
214 |
throw new DebuggerException("Can't execute console commands"); |
|
215 |
} |
|
216 |
||
217 |
public String getConsolePrompt() throws DebuggerException { |
|
218 |
return ""; |
|
219 |
} |
|
220 |
||
221 |
public CDebugger getCDebugger() throws DebuggerException { |
|
222 |
if (cdbg == null) { |
|
223 |
cdbg = new ProcCDebugger(this); |
|
224 |
} |
|
225 |
return cdbg; |
|
226 |
} |
|
227 |
||
228 |
/** From the SymbolLookup interface via Debugger and JVMDebugger */ |
|
229 |
public synchronized Address lookup(String objectName, String symbol) { |
|
230 |
requireAttach(); |
|
231 |
long addr = lookupByName0(objectName, symbol); |
|
232 |
if (addr == 0) { |
|
233 |
return null; |
|
234 |
} |
|
235 |
return new ProcAddress(this, addr); |
|
236 |
} |
|
237 |
||
238 |
/** From the SymbolLookup interface via Debugger and JVMDebugger */ |
|
239 |
public synchronized OopHandle lookupOop(String objectName, String symbol) { |
|
240 |
Address addr = lookup(objectName, symbol); |
|
241 |
if (addr == null) { |
|
242 |
return null; |
|
243 |
} |
|
244 |
return addr.addOffsetToAsOopHandle(0); |
|
245 |
} |
|
246 |
||
247 |
/** From the ProcDebugger interface */ |
|
248 |
public MachineDescription getMachineDescription() { |
|
249 |
return machDesc; |
|
250 |
} |
|
251 |
||
252 |
/** Internal routine supporting lazy setting of MachineDescription, |
|
253 |
* since on SPARC we will need to query the remote process to ask |
|
254 |
* it what its data model is (32- or 64-bit). |
|
255 |
*/ |
|
256 |
||
257 |
public void setMachineDescription(MachineDescription machDesc) { |
|
258 |
this.machDesc = machDesc; |
|
259 |
setBigEndian(machDesc.isBigEndian()); |
|
260 |
utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian()); |
|
261 |
} |
|
262 |
||
263 |
public synchronized int getRemoteProcessAddressSize() |
|
264 |
throws DebuggerException { |
|
265 |
requireAttach(); |
|
266 |
return getRemoteProcessAddressSize0(); |
|
267 |
} |
|
268 |
||
269 |
//-------------------------------------------------------------------------------- |
|
270 |
// Implementation of ThreadAccess interface |
|
271 |
// |
|
272 |
||
273 |
/** From the ThreadAccess interface via Debugger and JVMDebugger */ |
|
274 |
public ThreadProxy getThreadForIdentifierAddress(Address addr) { |
|
275 |
return threadFactory.createThreadWrapper(addr); |
|
276 |
} |
|
277 |
||
278 |
public ThreadProxy getThreadForThreadId(long id) { |
|
279 |
return threadFactory.createThreadWrapper(id); |
|
280 |
} |
|
281 |
||
282 |
//---------------------------------------------------------------------- |
|
283 |
// Overridden from DebuggerBase because we need to relax alignment |
|
284 |
// constraints on x86 |
|
285 |
||
286 |
public long readJLong(long address) |
|
287 |
throws UnmappedAddressException, UnalignedAddressException { |
|
288 |
checkJavaConfigured(); |
|
289 |
// FIXME: allow this to be configurable. Undesirable to add a |
|
290 |
// dependency on the runtime package here, though, since this |
|
291 |
// package should be strictly underneath it. |
|
292 |
if (unalignedAccessesOkay) { |
|
293 |
utils.checkAlignment(address, jintSize); |
|
294 |
} else { |
|
295 |
utils.checkAlignment(address, jlongSize); |
|
296 |
} |
|
297 |
byte[] data = readBytes(address, jlongSize); |
|
298 |
return utils.dataToJLong(data, jlongSize); |
|
299 |
} |
|
300 |
||
301 |
//-------------------------------------------------------------------------------- |
|
302 |
// Internal routines (for implementation of ProcAddress). |
|
303 |
// These must not be called until the MachineDescription has been set up. |
|
304 |
// |
|
305 |
||
306 |
/** From the ProcDebugger interface */ |
|
307 |
public String addressValueToString(long address) { |
|
308 |
return utils.addressValueToString(address); |
|
309 |
} |
|
310 |
||
311 |
/** Need to override this to relax alignment checks on Solaris/x86. */ |
|
312 |
public long readCInteger(long address, long numBytes, boolean isUnsigned) |
|
313 |
throws UnmappedAddressException, UnalignedAddressException { |
|
314 |
checkConfigured(); |
|
315 |
if (!unalignedAccessesOkay) { |
|
316 |
utils.checkAlignment(address, numBytes); |
|
317 |
} else { |
|
318 |
// Only slightly relaxed semantics -- this is a hack, but is |
|
319 |
// necessary on Solaris/x86 where it seems the compiler is |
|
320 |
// putting some global 64-bit data on 32-bit boundaries |
|
321 |
if (numBytes == 8) { |
|
322 |
utils.checkAlignment(address, 4); |
|
323 |
} else { |
|
324 |
utils.checkAlignment(address, numBytes); |
|
325 |
} |
|
326 |
} |
|
327 |
byte[] data = readBytes(address, numBytes); |
|
328 |
return utils.dataToCInteger(data, isUnsigned); |
|
329 |
} |
|
330 |
||
331 |
/** From the ProcDebugger interface */ |
|
332 |
public ProcAddress readAddress(long address) |
|
333 |
throws UnmappedAddressException, UnalignedAddressException { |
|
334 |
long value = readAddressValue(address); |
|
335 |
return (value == 0 ? null : new ProcAddress(this, value)); |
|
336 |
} |
|
337 |
||
360
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
338 |
public ProcAddress readCompOopAddress(long address) |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
339 |
throws UnmappedAddressException, UnalignedAddressException { |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
340 |
long value = readCompOopAddressValue(address); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
341 |
return (value == 0 ? null : new ProcAddress(this, value)); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
342 |
} |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
343 |
|
1 | 344 |
/** From the ProcDebugger interface */ |
345 |
public ProcOopHandle readOopHandle(long address) |
|
346 |
throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { |
|
360
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
347 |
long value = readAddressValue(address); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
348 |
return (value == 0 ? null : new ProcOopHandle(this, value)); |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
349 |
} |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
350 |
|
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
351 |
public ProcOopHandle readCompOopHandle(long address) { |
21d113ecbf6a
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
1
diff
changeset
|
352 |
long value = readCompOopAddressValue(address); |
1 | 353 |
return (value == 0 ? null : new ProcOopHandle(this, value)); |
354 |
} |
|
355 |
||
356 |
public void writeBytesToProcess(long address, long numBytes, byte[] data) |
|
357 |
throws UnmappedAddressException, DebuggerException { |
|
358 |
if (isCore) { |
|
359 |
throw new DebuggerException("Attached to a core file!"); |
|
360 |
} |
|
361 |
writeBytesToProcess0(address, numBytes, data); |
|
362 |
} |
|
363 |
||
364 |
public synchronized ReadResult readBytesFromProcess(long address, long numBytes) |
|
365 |
throws DebuggerException { |
|
366 |
requireAttach(); |
|
367 |
byte[] res = readBytesFromProcess0(address, numBytes); |
|
368 |
if(res != null) |
|
369 |
return new ReadResult(res); |
|
370 |
else |
|
371 |
return new ReadResult(address); |
|
372 |
} |
|
373 |
||
374 |
protected int getPageSize() { |
|
375 |
int pagesize = getPageSize0(); |
|
376 |
if (pagesize == -1) { |
|
377 |
// return the hard coded default value. |
|
378 |
pagesize = (PlatformInfo.getCPU().equals("x86"))? 4096 : 8192; |
|
379 |
} |
|
380 |
return pagesize; |
|
381 |
} |
|
382 |
||
383 |
//-------------------------------------------------------------------------------- |
|
384 |
// Thread context access. Can not be package private, but should |
|
385 |
// only be accessed by the architecture-specific subpackages. |
|
386 |
||
387 |
/** From the ProcDebugger interface. May have to redefine this later. */ |
|
388 |
public synchronized long[] getThreadIntegerRegisterSet(int tid) { |
|
389 |
requireAttach(); |
|
390 |
return getThreadIntegerRegisterSet0(tid); |
|
391 |
} |
|
392 |
||
393 |
//-------------------------------------------------------------------------------- |
|
394 |
// Address access. Can not be package private, but should only be |
|
395 |
// accessed by the architecture-specific subpackages. |
|
396 |
||
397 |
/** From the ProcDebugger interface */ |
|
398 |
public long getAddressValue(Address addr) { |
|
399 |
if (addr == null) return 0; |
|
400 |
return ((ProcAddress) addr).getValue(); |
|
401 |
} |
|
402 |
||
403 |
/** From the ProcDebugger interface */ |
|
404 |
public Address newAddress(long value) { |
|
405 |
if (value == 0) return null; |
|
406 |
return new ProcAddress(this, value); |
|
407 |
} |
|
408 |
||
409 |
/** From the ProcDebugger interface */ |
|
410 |
public synchronized List getThreadList() throws DebuggerException { |
|
411 |
requireAttach(); |
|
412 |
List res = null; |
|
413 |
if (isCore && (threadListCache != null)) { |
|
414 |
res = threadListCache; |
|
415 |
} else { |
|
416 |
res = new ArrayList(); |
|
417 |
fillThreadList0(res); |
|
418 |
if (isCore) { |
|
419 |
threadListCache = res; |
|
420 |
} |
|
421 |
} |
|
422 |
return res; |
|
423 |
} |
|
424 |
||
425 |
/** From the ProcDebugger interface */ |
|
426 |
public synchronized List getLoadObjectList() throws DebuggerException { |
|
427 |
requireAttach(); |
|
428 |
if (!suspended) { |
|
429 |
throw new DebuggerException("Process not suspended"); |
|
430 |
} |
|
431 |
||
432 |
if (loadObjectCache == null) { |
|
433 |
updateLoadObjectCache(); |
|
434 |
} |
|
435 |
return loadObjectCache; |
|
436 |
} |
|
437 |
||
438 |
/** From the ProcDebugger interface */ |
|
439 |
public synchronized CFrame topFrameForThread(ThreadProxy thread) |
|
440 |
throws DebuggerException { |
|
441 |
requireAttach(); |
|
442 |
CFrame res = null; |
|
443 |
if (isCore && ((res = (CFrame) topFrameCache.get(thread)) != null)) { |
|
444 |
return res; |
|
445 |
} else { |
|
446 |
ThreadContext context = thread.getContext(); |
|
447 |
int numRegs = context.getNumRegisters(); |
|
448 |
long[] regs = new long[numRegs]; |
|
449 |
for (int i = 0; i < numRegs; i++) { |
|
450 |
regs[i] = context.getRegister(i); |
|
451 |
} |
|
452 |
res = fillCFrameList0(regs); |
|
453 |
if (isCore) { |
|
454 |
topFrameCache.put(thread, res); |
|
455 |
} |
|
456 |
return res; |
|
457 |
} |
|
458 |
} |
|
459 |
||
460 |
/** From the ProcDebugger interface */ |
|
461 |
public synchronized ClosestSymbol lookup(long address) { |
|
462 |
requireAttach(); |
|
463 |
return lookupByAddress0(address); |
|
464 |
} |
|
465 |
||
466 |
/** From the ProcDebugger interface */ |
|
467 |
public String demangle(String name) { |
|
468 |
return demangle0(name); |
|
469 |
} |
|
470 |
||
471 |
//------------- Internals only below this point -------------------- |
|
472 |
// |
|
473 |
// |
|
474 |
||
475 |
private void updateLoadObjectCache() { |
|
476 |
List res = new ArrayList(); |
|
477 |
nameToDsoMap = new HashMap(); |
|
478 |
fillLoadObjectList0(res); |
|
479 |
loadObjectCache = sortLoadObjects(res); |
|
480 |
} |
|
481 |
||
482 |
// sort load objects by base address |
|
483 |
private static List sortLoadObjects(List in) { |
|
484 |
// sort the list by base address |
|
485 |
Object[] arr = in.toArray(); |
|
486 |
Arrays.sort(arr, loadObjectComparator); |
|
487 |
return Arrays.asList(arr); |
|
488 |
} |
|
489 |
||
490 |
private long lookupByName(String objectName, String symbolName) |
|
491 |
throws DebuggerException { |
|
492 |
// NOTE: this assumes that process is suspended (which is probably |
|
493 |
// necessary assumption given that DSOs can be loaded/unloaded as |
|
494 |
// process runs). Should update documentation. |
|
495 |
if (nameToDsoMap == null) { |
|
496 |
getLoadObjectList(); |
|
497 |
} |
|
498 |
SharedObject dso = (SharedObject) nameToDsoMap.get(objectName); |
|
499 |
// The DSO can be null because we use this to search through known |
|
500 |
// DSOs in HotSpotTypeDataBase (for example) |
|
501 |
if (dso != null) { |
|
502 |
ProcAddress addr = (ProcAddress) dso.lookupSymbol(symbolName); |
|
503 |
if (addr != null) { |
|
504 |
return addr.getValue(); |
|
505 |
} |
|
506 |
} |
|
507 |
return 0; |
|
508 |
} |
|
509 |
||
510 |
private SharedObject findDSOByName(String fullPathName) { |
|
511 |
if (loadObjectCache == null) |
|
512 |
return null; |
|
513 |
for (Iterator iter = loadObjectCache.iterator(); iter.hasNext(); ) { |
|
514 |
SharedObject dso = (SharedObject) iter.next(); |
|
515 |
if (dso.getName().equals(fullPathName)) { |
|
516 |
return dso; |
|
517 |
} |
|
518 |
} |
|
519 |
return null; |
|
520 |
} |
|
521 |
||
522 |
private void reresolveLoadObjects() throws DebuggerException { |
|
523 |
if (loadObjectCache == null) { |
|
524 |
return; |
|
525 |
} |
|
526 |
updateLoadObjectCache(); |
|
527 |
} |
|
528 |
||
529 |
||
530 |
private void checkAttached() { |
|
531 |
if (attached) { |
|
532 |
if (isCore) { |
|
533 |
throw new DebuggerException("already attached to a core file!"); |
|
534 |
} else { |
|
535 |
throw new DebuggerException("already attached to a process!"); |
|
536 |
} |
|
537 |
} |
|
538 |
} |
|
539 |
||
540 |
private void requireAttach() { |
|
541 |
if (! attached) { |
|
542 |
throw new RuntimeException("not attached to a process or core file!"); |
|
543 |
} |
|
544 |
} |
|
545 |
||
546 |
private void clearCacheFields() { |
|
547 |
loadObjectCache = null; |
|
548 |
nameToDsoMap = null; |
|
549 |
threadListCache = null; |
|
550 |
topFrameCache = null; |
|
551 |
} |
|
552 |
||
553 |
private void resetNativePointers() { |
|
554 |
p_ps_prochandle = 0L; |
|
555 |
||
556 |
// reset thread_db pointers |
|
557 |
libthread_db_handle = 0L; |
|
558 |
p_td_thragent_t = 0L; |
|
559 |
p_td_init = 0L; |
|
560 |
p_td_ta_new = 0L; |
|
561 |
p_td_ta_delete = 0L; |
|
562 |
p_td_ta_thr_iter = 0L; |
|
563 |
p_td_thr_get_info = 0L; |
|
564 |
p_td_ta_map_id2thr = 0L; |
|
565 |
p_td_thr_getgregs = 0L; |
|
566 |
||
567 |
// part of class sharing workaround |
|
568 |
classes_jsa_fd = -1; |
|
569 |
p_file_map_header = 0L; |
|
570 |
} |
|
571 |
||
572 |
// native methods and native helpers |
|
573 |
||
574 |
// attach, detach |
|
575 |
private native void attach0(String pid) throws DebuggerException; |
|
576 |
private native void attach0(String executableFile, String coreFileName) throws DebuggerException; |
|
577 |
private native void detach0() throws DebuggerException; |
|
578 |
||
579 |
// address size, page size |
|
580 |
private native int getRemoteProcessAddressSize0() throws DebuggerException; |
|
581 |
private native int getPageSize0() throws DebuggerException; |
|
582 |
||
583 |
// threads, stacks |
|
584 |
private native long[] getThreadIntegerRegisterSet0(long tid) throws DebuggerException; |
|
585 |
private native void fillThreadList0(List l) throws DebuggerException; |
|
586 |
||
587 |
// fills stack frame list given reg set of the top frame and top frame |
|
588 |
private native ProcCFrame fillCFrameList0(long[] regs) throws DebuggerException; |
|
589 |
||
590 |
// helper called by fillCFrameList0 |
|
591 |
private ProcCFrame createSenderFrame(ProcCFrame f, long pc, long fp) { |
|
592 |
ProcCFrame sender = new ProcCFrame(this, newAddress(pc), newAddress(fp)); |
|
593 |
if (f != null) { |
|
594 |
f.setSender(sender); |
|
595 |
} |
|
596 |
return sender; |
|
597 |
} |
|
598 |
||
599 |
// shared objects |
|
600 |
private native void fillLoadObjectList0(List l) throws DebuggerException; |
|
601 |
||
602 |
// helper called by fillLoadObjectList0 |
|
603 |
private LoadObject createLoadObject(String fileName, long textsize, long base) { |
|
604 |
File f = new File(fileName); |
|
605 |
Address baseAddr = newAddress(base); |
|
606 |
SharedObject res = findDSOByName(fileName); |
|
607 |
if (res != null) { |
|
608 |
// already in cache. just change the base, if needed |
|
609 |
Address oldBase = res.getBase(); |
|
610 |
if (! baseAddr.equals(oldBase)) { |
|
611 |
res.setBase(baseAddr); |
|
612 |
} |
|
613 |
} else { |
|
614 |
// new shared object. |
|
615 |
res = new SharedObject(this, fileName, f.length(), baseAddr); |
|
616 |
} |
|
617 |
nameToDsoMap.put(f.getName(), res); |
|
618 |
return res; |
|
619 |
} |
|
620 |
||
621 |
// symbol-to-pc |
|
622 |
private native long lookupByName0(String objectName, String symbolName) throws DebuggerException; |
|
623 |
private native ClosestSymbol lookupByAddress0(long address) throws DebuggerException; |
|
624 |
||
625 |
// helper called by lookupByAddress0 |
|
626 |
private ClosestSymbol createClosestSymbol(String name, long offset) { |
|
627 |
return new ClosestSymbol(name, offset); |
|
628 |
} |
|
629 |
||
630 |
// process read/write |
|
631 |
private native byte[] readBytesFromProcess0(long address, long numBytes) throws DebuggerException; |
|
632 |
private native void writeBytesToProcess0(long address, long numBytes, byte[] data) throws DebuggerException; |
|
633 |
||
634 |
// process control |
|
635 |
private native void suspend0() throws DebuggerException; |
|
636 |
private native void resume0() throws DebuggerException; |
|
637 |
||
638 |
// demangle a C++ name |
|
639 |
private native String demangle0(String name); |
|
640 |
||
641 |
// init JNI ids to fields, methods |
|
642 |
private native static void initIDs() throws DebuggerException; |
|
643 |
private static LoadObjectComparator loadObjectComparator; |
|
644 |
||
645 |
static { |
|
646 |
System.loadLibrary("saproc"); |
|
647 |
initIDs(); |
|
648 |
loadObjectComparator = new LoadObjectComparator(); |
|
649 |
} |
|
650 |
||
651 |
private boolean unalignedAccessesOkay; |
|
652 |
private ProcThreadFactory threadFactory; |
|
653 |
||
654 |
// indices of PC and FP registers in gregset |
|
655 |
private int pcRegIndex; |
|
656 |
private int fpRegIndex; |
|
657 |
||
658 |
// Symbol lookup support |
|
659 |
// This is a map of library names to DSOs |
|
660 |
private Map nameToDsoMap; // Map<String, SharedObject> |
|
661 |
||
662 |
// C/C++ debugging support |
|
663 |
private List/*<LoadObject>*/ loadObjects; |
|
664 |
private CDebugger cdbg; |
|
665 |
||
666 |
// ProcessControl support |
|
667 |
private boolean suspended; |
|
668 |
||
669 |
// libproc handle |
|
670 |
private long p_ps_prochandle; |
|
671 |
||
672 |
// libthread.so's dlopen handle, thread agent |
|
673 |
// and function pointers |
|
674 |
private long libthread_db_handle; |
|
675 |
private long p_td_thragent_t; |
|
676 |
private long p_td_init; |
|
677 |
private long p_td_ta_new; |
|
678 |
private long p_td_ta_delete; |
|
679 |
private long p_td_ta_thr_iter; |
|
680 |
private long p_td_thr_get_info; |
|
681 |
private long p_td_ta_map_id2thr; |
|
682 |
private long p_td_thr_getgregs; |
|
683 |
||
684 |
// part of class sharing workaround |
|
685 |
private int classes_jsa_fd; |
|
686 |
private long p_file_map_header; |
|
687 |
||
688 |
private boolean attached = false; |
|
689 |
private boolean isCore; |
|
690 |
||
691 |
// for core files, we cache load object list, thread list, top frames etc. |
|
692 |
// for processes we cache load object list and sync. it during suspend. |
|
693 |
private List threadListCache; |
|
694 |
private List loadObjectCache; |
|
695 |
private Map topFrameCache; // Map<ThreadProxy, CFrame> |
|
696 |
} |