comparison agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children ba764ed4b6f2
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2002-2006 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.linux;
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.x86.*;
32 import sun.jvm.hotspot.debugger.cdbg.*;
33 import sun.jvm.hotspot.utilities.*;
34 import java.lang.reflect.*;
35
36 /** <P> An implementation of the JVMDebugger interface. The basic debug
37 facilities are implemented through ptrace interface in the JNI code
38 (libsaproc.so). Library maps and symbol table management are done in
39 JNI. </P>
40
41 <P> <B>NOTE</B> that since we have the notion of fetching "Java
42 primitive types" from the remote process (which might have
43 different sizes than we expect) we have a bootstrapping
44 problem. We need to know the sizes of these types before we can
45 fetch them. The current implementation solves this problem by
46 requiring that it be configured with these type sizes before they
47 can be fetched. The readJ(Type) routines here will throw a
48 RuntimeException if they are called before the debugger is
49 configured with the Java primitive type sizes. </P> */
50
51 public class LinuxDebuggerLocal extends DebuggerBase implements LinuxDebugger {
52 private boolean useGCC32ABI;
53 private boolean attached;
54 private long p_ps_prochandle; // native debugger handle
55 private boolean isCore;
56
57 // CDebugger support
58 private LinuxCDebugger cdbg;
59
60 // threadList and loadObjectList are filled by attach0 method
61 private List threadList;
62 private List loadObjectList;
63
64 // called by native method lookupByAddress0
65 private ClosestSymbol createClosestSymbol(String name, long offset) {
66 return new ClosestSymbol(name, offset);
67 }
68
69 // called by native method attach0
70 private LoadObject createLoadObject(String fileName, long textsize,
71 long base) {
72 File f = new File(fileName);
73 Address baseAddr = newAddress(base);
74 return new SharedObject(this, fileName, f.length(), baseAddr);
75 }
76
77 // native methods
78
79 private native static void init0()
80 throws DebuggerException;
81 private native void attach0(int pid)
82 throws DebuggerException;
83 private native void attach0(String execName, String coreName)
84 throws DebuggerException;
85 private native void detach0()
86 throws DebuggerException;
87 private native long lookupByName0(String objectName, String symbol)
88 throws DebuggerException;
89 private native ClosestSymbol lookupByAddress0(long address)
90 throws DebuggerException;
91 private native long[] getThreadIntegerRegisterSet0(int lwp_id)
92 throws DebuggerException;
93 private native byte[] readBytesFromProcess0(long address, long numBytes)
94 throws DebuggerException;
95 public native static int getAddressSize() ;
96
97 // Note on Linux threads are really processes. When target process is
98 // attached by a serviceability agent thread, only that thread can do
99 // ptrace operations on the target. This is because from kernel's point
100 // view, other threads are just separate processes and they are not
101 // attached to the target. When they attempt to make ptrace calls,
102 // an ESRCH error will be returned as kernel believes target is not
103 // being traced by the caller.
104 // To work around the problem, we use a worker thread here to handle
105 // all JNI functions that are making ptrace calls.
106
107 interface WorkerThreadTask {
108 public void doit(LinuxDebuggerLocal debugger) throws DebuggerException;
109 }
110
111 class LinuxDebuggerLocalWorkerThread extends Thread {
112 LinuxDebuggerLocal debugger;
113 WorkerThreadTask task;
114 DebuggerException lastException;
115
116 public LinuxDebuggerLocalWorkerThread(LinuxDebuggerLocal debugger) {
117 this.debugger = debugger;
118 setDaemon(true);
119 }
120
121 public void run() {
122 synchronized (workerThread) {
123 for (;;) {
124 if (task != null) {
125 lastException = null;
126 try {
127 task.doit(debugger);
128 } catch (DebuggerException exp) {
129 lastException = exp;
130 }
131 task = null;
132 workerThread.notifyAll();
133 }
134
135 try {
136 workerThread.wait();
137 } catch (InterruptedException x) {}
138 }
139 }
140 }
141
142 public WorkerThreadTask execute(WorkerThreadTask task) throws DebuggerException {
143 synchronized (workerThread) {
144 this.task = task;
145 workerThread.notifyAll();
146 while (this.task != null) {
147 try {
148 workerThread.wait();
149 } catch (InterruptedException x) {}
150 }
151 if (lastException != null) {
152 throw new DebuggerException(lastException);
153 } else {
154 return task;
155 }
156 }
157 }
158 }
159
160 private LinuxDebuggerLocalWorkerThread workerThread = null;
161
162 //----------------------------------------------------------------------
163 // Implementation of Debugger interface
164 //
165
166 /** <P> machDesc may not be null. </P>
167
168 <P> useCache should be set to true if debugging is being done
169 locally, and to false if the debugger is being created for the
170 purpose of supporting remote debugging. </P> */
171 public LinuxDebuggerLocal(MachineDescription machDesc,
172 boolean useCache) throws DebuggerException {
173 this.machDesc = machDesc;
174 utils = new DebuggerUtilities(machDesc.getAddressSize(),
175 machDesc.isBigEndian()) {
176 public void checkAlignment(long address, long alignment) {
177 // Need to override default checkAlignment because we need to
178 // relax alignment constraints on Linux/x86
179 if ( (address % alignment != 0)
180 &&(alignment != 8 || address % 4 != 0)) {
181 throw new UnalignedAddressException(
182 "Trying to read at address: "
183 + addressValueToString(address)
184 + " with alignment: " + alignment,
185 address);
186 }
187 }
188 };
189
190 if (useCache) {
191 // FIXME: re-test necessity of cache on Linux, where data
192 // fetching is faster
193 // Cache portion of the remote process's address space.
194 // Fetching data over the socket connection to dbx is slow.
195 // Might be faster if we were using a binary protocol to talk to
196 // dbx, but would have to test. For now, this cache works best
197 // if it covers the entire heap of the remote process. FIXME: at
198 // least should make this tunable from the outside, i.e., via
199 // the UI. This is a cache of 4096 4K pages, or 16 MB. The page
200 // size must be adjusted to be the hardware's page size.
201 // (FIXME: should pick this up from the debugger.)
202 if (getCPU().equals("ia64")) {
203 initCache(16384, parseCacheNumPagesProperty(1024));
204 } else {
205 initCache(4096, parseCacheNumPagesProperty(4096));
206 }
207 }
208
209 workerThread = new LinuxDebuggerLocalWorkerThread(this);
210 workerThread.start();
211 }
212
213 /** From the Debugger interface via JVMDebugger */
214 public boolean hasProcessList() throws DebuggerException {
215 return false;
216 }
217
218 /** From the Debugger interface via JVMDebugger */
219 public List getProcessList() throws DebuggerException {
220 throw new DebuggerException("getProcessList not implemented yet");
221 }
222
223 private void checkAttached() throws DebuggerException {
224 if (attached) {
225 if (isCore) {
226 throw new DebuggerException("attached to a core dump already");
227 } else {
228 throw new DebuggerException("attached to a process already");
229 }
230 }
231 }
232
233 private void requireAttach() {
234 if (! attached) {
235 throw new RuntimeException("not attached to a process or a core!");
236 }
237 }
238
239 /* called from attach methods */
240 private void findABIVersion() throws DebuggerException {
241 if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 ||
242 lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) {
243 // old C++ ABI
244 useGCC32ABI = false;
245 } else {
246 // new C++ ABI
247 useGCC32ABI = true;
248 }
249 }
250
251 /** From the Debugger interface via JVMDebugger */
252 public synchronized void attach(int processID) throws DebuggerException {
253 checkAttached();
254 threadList = new ArrayList();
255 loadObjectList = new ArrayList();
256 class AttachTask implements WorkerThreadTask {
257 int pid;
258 public void doit(LinuxDebuggerLocal debugger) {
259 debugger.attach0(pid);
260 debugger.attached = true;
261 debugger.isCore = false;
262 findABIVersion();
263 }
264 }
265
266 AttachTask task = new AttachTask();
267 task.pid = processID;
268 workerThread.execute(task);
269 }
270
271 /** From the Debugger interface via JVMDebugger */
272 public synchronized void attach(String execName, String coreName) {
273 checkAttached();
274 threadList = new ArrayList();
275 loadObjectList = new ArrayList();
276 attach0(execName, coreName);
277 attached = true;
278 isCore = true;
279 findABIVersion();
280 }
281
282 /** From the Debugger interface via JVMDebugger */
283 public synchronized boolean detach() {
284 if (!attached) {
285 return false;
286 }
287
288 threadList = null;
289 loadObjectList = null;
290
291 if (isCore) {
292 detach0();
293 attached = false;
294 return true;
295 } else {
296 class DetachTask implements WorkerThreadTask {
297 boolean result = false;
298
299 public void doit(LinuxDebuggerLocal debugger) {
300 debugger.detach0();
301 debugger.attached = false;
302 result = true;
303 }
304 }
305
306 DetachTask task = new DetachTask();
307 workerThread.execute(task);
308 return task.result;
309 }
310 }
311
312 /** From the Debugger interface via JVMDebugger */
313 public Address parseAddress(String addressString)
314 throws NumberFormatException {
315 long addr = utils.scanAddress(addressString);
316 if (addr == 0) {
317 return null;
318 }
319 return new LinuxAddress(this, addr);
320 }
321
322 /** From the Debugger interface via JVMDebugger */
323 public String getOS() {
324 return PlatformInfo.getOS();
325 }
326
327 /** From the Debugger interface via JVMDebugger */
328 public String getCPU() {
329 return PlatformInfo.getCPU();
330 }
331
332 public boolean hasConsole() throws DebuggerException {
333 return false;
334 }
335
336 public String consoleExecuteCommand(String cmd) throws DebuggerException {
337 throw new DebuggerException("No debugger console available on Linux");
338 }
339
340 public String getConsolePrompt() throws DebuggerException {
341 return null;
342 }
343
344 /* called from lookup */
345 private long handleGCC32ABI(long addr, String symbol) throws DebuggerException {
346 if (useGCC32ABI && symbol.startsWith("_ZTV")) {
347 return addr + (2 * machDesc.getAddressSize());
348 } else {
349 return addr;
350 }
351 }
352
353 /** From the SymbolLookup interface via Debugger and JVMDebugger */
354 public synchronized Address lookup(String objectName, String symbol) {
355 requireAttach();
356 if (!attached) {
357 return null;
358 }
359
360 if (isCore) {
361 long addr = lookupByName0(objectName, symbol);
362 return (addr == 0)? null : new LinuxAddress(this, handleGCC32ABI(addr, symbol));
363 } else {
364 class LookupByNameTask implements WorkerThreadTask {
365 String objectName, symbol;
366 Address result;
367
368 public void doit(LinuxDebuggerLocal debugger) {
369 long addr = debugger.lookupByName0(objectName, symbol);
370 result = (addr == 0 ? null : new LinuxAddress(debugger, handleGCC32ABI(addr, symbol)));
371 }
372 }
373
374 LookupByNameTask task = new LookupByNameTask();
375 task.objectName = objectName;
376 task.symbol = symbol;
377 workerThread.execute(task);
378 return task.result;
379 }
380 }
381
382 /** From the SymbolLookup interface via Debugger and JVMDebugger */
383 public synchronized OopHandle lookupOop(String objectName, String symbol) {
384 Address addr = lookup(objectName, symbol);
385 if (addr == null) {
386 return null;
387 }
388 return addr.addOffsetToAsOopHandle(0);
389 }
390
391 /** From the Debugger interface */
392 public MachineDescription getMachineDescription() {
393 return machDesc;
394 }
395
396 //----------------------------------------------------------------------
397 // Implementation of ThreadAccess interface
398 //
399
400 /** From the ThreadAccess interface via Debugger and JVMDebugger */
401 public ThreadProxy getThreadForIdentifierAddress(Address addr) {
402 return new LinuxThread(this, addr);
403 }
404
405 /** From the ThreadAccess interface via Debugger and JVMDebugger */
406 public ThreadProxy getThreadForThreadId(long id) {
407 return new LinuxThread(this, id);
408 }
409
410 //----------------------------------------------------------------------
411 // Internal routines (for implementation of LinuxAddress).
412 // These must not be called until the MachineDescription has been set up.
413 //
414
415 /** From the LinuxDebugger interface */
416 public String addressValueToString(long address) {
417 return utils.addressValueToString(address);
418 }
419
420 /** From the LinuxDebugger interface */
421 public LinuxAddress readAddress(long address)
422 throws UnmappedAddressException, UnalignedAddressException {
423 long value = readAddressValue(address);
424 return (value == 0 ? null : new LinuxAddress(this, value));
425 }
426
427 /** From the LinuxDebugger interface */
428 public LinuxOopHandle readOopHandle(long address)
429 throws UnmappedAddressException, UnalignedAddressException,
430 NotInHeapException {
431 long value = readAddressValue(address);
432 return (value == 0 ? null : new LinuxOopHandle(this, value));
433 }
434
435 //----------------------------------------------------------------------
436 // Thread context access
437 //
438
439 public synchronized long[] getThreadIntegerRegisterSet(int lwp_id)
440 throws DebuggerException {
441 requireAttach();
442 if (isCore) {
443 return getThreadIntegerRegisterSet0(lwp_id);
444 } else {
445 class GetThreadIntegerRegisterSetTask implements WorkerThreadTask {
446 int lwp_id;
447 long[] result;
448 public void doit(LinuxDebuggerLocal debugger) {
449 result = debugger.getThreadIntegerRegisterSet0(lwp_id);
450 }
451 }
452
453 GetThreadIntegerRegisterSetTask task = new GetThreadIntegerRegisterSetTask();
454 task.lwp_id = lwp_id;
455 workerThread.execute(task);
456 return task.result;
457 }
458 }
459
460 /** Need to override this to relax alignment checks on x86. */
461 public long readCInteger(long address, long numBytes, boolean isUnsigned)
462 throws UnmappedAddressException, UnalignedAddressException {
463 // Only slightly relaxed semantics -- this is a hack, but is
464 // necessary on x86 where it seems the compiler is
465 // putting some global 64-bit data on 32-bit boundaries
466 if (numBytes == 8) {
467 utils.checkAlignment(address, 4);
468 } else {
469 utils.checkAlignment(address, numBytes);
470 }
471 byte[] data = readBytes(address, numBytes);
472 return utils.dataToCInteger(data, isUnsigned);
473 }
474
475 // Overridden from DebuggerBase because we need to relax alignment
476 // constraints on x86
477 public long readJLong(long address)
478 throws UnmappedAddressException, UnalignedAddressException {
479 utils.checkAlignment(address, jintSize);
480 byte[] data = readBytes(address, jlongSize);
481 return utils.dataToJLong(data, jlongSize);
482 }
483
484 //----------------------------------------------------------------------
485 // Address access. Can not be package private, but should only be
486 // accessed by the architecture-specific subpackages.
487
488 /** From the LinuxDebugger interface */
489 public long getAddressValue(Address addr) {
490 if (addr == null) return 0;
491 return ((LinuxAddress) addr).getValue();
492 }
493
494 /** From the LinuxDebugger interface */
495 public Address newAddress(long value) {
496 if (value == 0) return null;
497 return new LinuxAddress(this, value);
498 }
499
500 /** From the LinuxCDebugger interface */
501 public List/*<ThreadProxy>*/ getThreadList() {
502 requireAttach();
503 return threadList;
504 }
505
506 /** From the LinuxCDebugger interface */
507 public List/*<LoadObject>*/ getLoadObjectList() {
508 requireAttach();
509 return loadObjectList;
510 }
511
512 /** From the LinuxCDebugger interface */
513 public synchronized ClosestSymbol lookup(long addr) {
514 requireAttach();
515 if (isCore) {
516 return lookupByAddress0(addr);
517 } else {
518 class LookupByAddressTask implements WorkerThreadTask {
519 long addr;
520 ClosestSymbol result;
521
522 public void doit(LinuxDebuggerLocal debugger) {
523 result = debugger.lookupByAddress0(addr);
524 }
525 }
526
527 LookupByAddressTask task = new LookupByAddressTask();
528 task.addr = addr;
529 workerThread.execute(task);
530 return task.result;
531 }
532 }
533
534 public CDebugger getCDebugger() {
535 if (cdbg == null) {
536 String cpu = getCPU();
537 if (cpu.equals("ia64") ) {
538 // IA-64 is not supported because of stack-walking issues
539 return null;
540 }
541 cdbg = new LinuxCDebugger(this);
542 }
543 return cdbg;
544 }
545
546 /** This reads bytes from the remote process. */
547 public synchronized ReadResult readBytesFromProcess(long address,
548 long numBytes) throws UnmappedAddressException, DebuggerException {
549 requireAttach();
550 if (isCore) {
551 byte[] res = readBytesFromProcess0(address, numBytes);
552 return (res != null)? new ReadResult(res) : new ReadResult(address);
553 } else {
554 class ReadBytesFromProcessTask implements WorkerThreadTask {
555 long address, numBytes;
556 ReadResult result;
557 public void doit(LinuxDebuggerLocal debugger) {
558 byte[] res = debugger.readBytesFromProcess0(address, numBytes);
559 if (res != null)
560 result = new ReadResult(res);
561 else
562 result = new ReadResult(address);
563 }
564 }
565
566 ReadBytesFromProcessTask task = new ReadBytesFromProcessTask();
567 task.address = address;
568 task.numBytes = numBytes;
569 workerThread.execute(task);
570 return task.result;
571 }
572 }
573
574 public void writeBytesToProcess(long address, long numBytes, byte[] data)
575 throws UnmappedAddressException, DebuggerException {
576 // FIXME
577 throw new DebuggerException("Unimplemented");
578 }
579
580 static {
581 System.loadLibrary("saproc");
582 init0();
583 }
584 }