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