comparison agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java @ 3960:f08d439fab8c

7089790: integrate bsd-port changes Reviewed-by: kvn, twisti, jrose Contributed-by: Kurt Miller <kurt@intricatesoftware.com>, Greg Lewis <glewis@eyesbeyond.com>, Jung-uk Kim <jkim@freebsd.org>, Christos Zoulas <christos@zoulas.com>, Landon Fuller <landonf@plausible.coop>, The FreeBSD Foundation <board@freebsdfoundation.org>, Michael Franz <mvfranz@gmail.com>, Roger Hoover <rhoover@apple.com>, Alexander Strange <astrange@apple.com>
author never
date Sun, 25 Sep 2011 16:03:29 -0700
parents
children 436b4a3231bf
comparison
equal deleted inserted replaced
3959:eda6988c0d81 3960:f08d439fab8c
1 /*
2 * Copyright (c) 2002, 2008, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 package sun.jvm.hotspot.debugger.bsd;
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 BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
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 BsdCDebugger 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 Bsd 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(BsdDebuggerLocal debugger) throws DebuggerException;
109 }
110
111 class BsdDebuggerLocalWorkerThread extends Thread {
112 BsdDebuggerLocal debugger;
113 WorkerThreadTask task;
114 DebuggerException lastException;
115
116 public BsdDebuggerLocalWorkerThread(BsdDebuggerLocal 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 BsdDebuggerLocalWorkerThread 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 BsdDebuggerLocal(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 Bsd/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 Bsd, 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 BsdDebuggerLocalWorkerThread(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(BsdDebuggerLocal 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(BsdDebuggerLocal 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 BsdAddress(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 Bsd");
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 BsdAddress(this, handleGCC32ABI(addr, symbol));
363 } else {
364 class LookupByNameTask implements WorkerThreadTask {
365 String objectName, symbol;
366 Address result;
367
368 public void doit(BsdDebuggerLocal debugger) {
369 long addr = debugger.lookupByName0(objectName, symbol);
370 result = (addr == 0 ? null : new BsdAddress(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 BsdThread(this, addr);
403 }
404
405 /** From the ThreadAccess interface via Debugger and JVMDebugger */
406 public ThreadProxy getThreadForThreadId(long id) {
407 return new BsdThread(this, id);
408 }
409
410 //----------------------------------------------------------------------
411 // Internal routines (for implementation of BsdAddress).
412 // These must not be called until the MachineDescription has been set up.
413 //
414
415 /** From the BsdDebugger interface */
416 public String addressValueToString(long address) {
417 return utils.addressValueToString(address);
418 }
419
420 /** From the BsdDebugger interface */
421 public BsdAddress readAddress(long address)
422 throws UnmappedAddressException, UnalignedAddressException {
423 long value = readAddressValue(address);
424 return (value == 0 ? null : new BsdAddress(this, value));
425 }
426 public BsdAddress readCompOopAddress(long address)
427 throws UnmappedAddressException, UnalignedAddressException {
428 long value = readCompOopAddressValue(address);
429 return (value == 0 ? null : new BsdAddress(this, value));
430 }
431
432 /** From the BsdDebugger interface */
433 public BsdOopHandle readOopHandle(long address)
434 throws UnmappedAddressException, UnalignedAddressException,
435 NotInHeapException {
436 long value = readAddressValue(address);
437 return (value == 0 ? null : new BsdOopHandle(this, value));
438 }
439 public BsdOopHandle readCompOopHandle(long address)
440 throws UnmappedAddressException, UnalignedAddressException,
441 NotInHeapException {
442 long value = readCompOopAddressValue(address);
443 return (value == 0 ? null : new BsdOopHandle(this, value));
444 }
445
446 //----------------------------------------------------------------------
447 // Thread context access
448 //
449
450 public synchronized long[] getThreadIntegerRegisterSet(int lwp_id)
451 throws DebuggerException {
452 requireAttach();
453 if (isCore) {
454 return getThreadIntegerRegisterSet0(lwp_id);
455 } else {
456 class GetThreadIntegerRegisterSetTask implements WorkerThreadTask {
457 int lwp_id;
458 long[] result;
459 public void doit(BsdDebuggerLocal debugger) {
460 result = debugger.getThreadIntegerRegisterSet0(lwp_id);
461 }
462 }
463
464 GetThreadIntegerRegisterSetTask task = new GetThreadIntegerRegisterSetTask();
465 task.lwp_id = lwp_id;
466 workerThread.execute(task);
467 return task.result;
468 }
469 }
470
471 /** Need to override this to relax alignment checks on x86. */
472 public long readCInteger(long address, long numBytes, boolean isUnsigned)
473 throws UnmappedAddressException, UnalignedAddressException {
474 // Only slightly relaxed semantics -- this is a hack, but is
475 // necessary on x86 where it seems the compiler is
476 // putting some global 64-bit data on 32-bit boundaries
477 if (numBytes == 8) {
478 utils.checkAlignment(address, 4);
479 } else {
480 utils.checkAlignment(address, numBytes);
481 }
482 byte[] data = readBytes(address, numBytes);
483 return utils.dataToCInteger(data, isUnsigned);
484 }
485
486 // Overridden from DebuggerBase because we need to relax alignment
487 // constraints on x86
488 public long readJLong(long address)
489 throws UnmappedAddressException, UnalignedAddressException {
490 utils.checkAlignment(address, jintSize);
491 byte[] data = readBytes(address, jlongSize);
492 return utils.dataToJLong(data, jlongSize);
493 }
494
495 //----------------------------------------------------------------------
496 // Address access. Can not be package private, but should only be
497 // accessed by the architecture-specific subpackages.
498
499 /** From the BsdDebugger interface */
500 public long getAddressValue(Address addr) {
501 if (addr == null) return 0;
502 return ((BsdAddress) addr).getValue();
503 }
504
505 /** From the BsdDebugger interface */
506 public Address newAddress(long value) {
507 if (value == 0) return null;
508 return new BsdAddress(this, value);
509 }
510
511 /** From the BsdCDebugger interface */
512 public List/*<ThreadProxy>*/ getThreadList() {
513 requireAttach();
514 return threadList;
515 }
516
517 /** From the BsdCDebugger interface */
518 public List/*<LoadObject>*/ getLoadObjectList() {
519 requireAttach();
520 return loadObjectList;
521 }
522
523 /** From the BsdCDebugger interface */
524 public synchronized ClosestSymbol lookup(long addr) {
525 requireAttach();
526 if (isCore) {
527 return lookupByAddress0(addr);
528 } else {
529 class LookupByAddressTask implements WorkerThreadTask {
530 long addr;
531 ClosestSymbol result;
532
533 public void doit(BsdDebuggerLocal debugger) {
534 result = debugger.lookupByAddress0(addr);
535 }
536 }
537
538 LookupByAddressTask task = new LookupByAddressTask();
539 task.addr = addr;
540 workerThread.execute(task);
541 return task.result;
542 }
543 }
544
545 public CDebugger getCDebugger() {
546 if (cdbg == null) {
547 String cpu = getCPU();
548 if (cpu.equals("ia64") ) {
549 // IA-64 is not supported because of stack-walking issues
550 return null;
551 }
552 cdbg = new BsdCDebugger(this);
553 }
554 return cdbg;
555 }
556
557 /** This reads bytes from the remote process. */
558 public synchronized ReadResult readBytesFromProcess(long address,
559 long numBytes) throws UnmappedAddressException, DebuggerException {
560 requireAttach();
561 if (isCore) {
562 byte[] res = readBytesFromProcess0(address, numBytes);
563 return (res != null)? new ReadResult(res) : new ReadResult(address);
564 } else {
565 class ReadBytesFromProcessTask implements WorkerThreadTask {
566 long address, numBytes;
567 ReadResult result;
568 public void doit(BsdDebuggerLocal debugger) {
569 byte[] res = debugger.readBytesFromProcess0(address, numBytes);
570 if (res != null)
571 result = new ReadResult(res);
572 else
573 result = new ReadResult(address);
574 }
575 }
576
577 ReadBytesFromProcessTask task = new ReadBytesFromProcessTask();
578 task.address = address;
579 task.numBytes = numBytes;
580 workerThread.execute(task);
581 return task.result;
582 }
583 }
584
585 public void writeBytesToProcess(long address, long numBytes, byte[] data)
586 throws UnmappedAddressException, DebuggerException {
587 // FIXME
588 throw new DebuggerException("Unimplemented");
589 }
590
591 static {
592 System.loadLibrary("saproc");
593 init0();
594 }
595 }