comparison agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.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-2005 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.windbg;
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.amd64.*;
32 import sun.jvm.hotspot.debugger.x86.*;
33 import sun.jvm.hotspot.debugger.ia64.*;
34 import sun.jvm.hotspot.debugger.windbg.amd64.*;
35 import sun.jvm.hotspot.debugger.windbg.x86.*;
36 import sun.jvm.hotspot.debugger.windbg.ia64.*;
37 import sun.jvm.hotspot.debugger.win32.coff.*;
38 import sun.jvm.hotspot.debugger.cdbg.*;
39 import sun.jvm.hotspot.debugger.cdbg.basic.BasicDebugEvent;
40 import sun.jvm.hotspot.utilities.*;
41 import sun.jvm.hotspot.utilities.memo.*;
42
43 /** <P> An implementation of the JVMDebugger interface which talks to
44 windbg and symbol table management is done in Java. </P>
45
46 <P> <B>NOTE</B> that since we have the notion of fetching "Java
47 primitive types" from the remote process (which might have
48 different sizes than we expect) we have a bootstrapping
49 problem. We need to know the sizes of these types before we can
50 fetch them. The current implementation solves this problem by
51 requiring that it be configured with these type sizes before they
52 can be fetched. The readJ(Type) routines here will throw a
53 RuntimeException if they are called before the debugger is
54 configured with the Java primitive type sizes. </P> */
55
56 public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger {
57 private PageCache cache;
58 private boolean attached;
59 private boolean isCore;
60
61 // Symbol lookup support
62 // This is a map of library names to DLLs
63 private Map nameToDllMap;
64
65 // C/C++ debugging support
66 private List/*<LoadObject>*/ loadObjects;
67 private CDebugger cdbg;
68
69 // thread access
70 private Map threadIntegerRegisterSet;
71 private List threadList;
72
73 // windbg native interface pointers
74
75 private long ptrIDebugClient;
76 private long ptrIDebugControl;
77 private long ptrIDebugDataSpaces;
78 private long ptrIDebugOutputCallbacks;
79 private long ptrIDebugAdvanced;
80 private long ptrIDebugSymbols;
81 private long ptrIDebugSystemObjects;
82
83 private WindbgThreadFactory threadFactory;
84
85 //--------------------------------------------------------------------------------
86 // Implementation of Debugger interface
87 //
88
89 /** <P> machDesc may not be null. </P>
90
91 <P> useCache should be set to true if debugging is being done
92 locally, and to false if the debugger is being created for the
93 purpose of supporting remote debugging. </P> */
94 public WindbgDebuggerLocal(MachineDescription machDesc,
95 boolean useCache) throws DebuggerException {
96 this.machDesc = machDesc;
97 utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian()) {
98 public void checkAlignment(long address, long alignment) {
99 // Need to override default checkAlignment because we need to
100 // relax alignment constraints on Windows/x86
101 if ( (address % alignment != 0)
102 &&(alignment != 8 || address % 4 != 0)) {
103 throw new UnalignedAddressException(
104 "Trying to read at address: "
105 + addressValueToString(address)
106 + " with alignment: " + alignment,
107 address);
108 }
109 }
110 };
111
112 String cpu = PlatformInfo.getCPU();
113 if (cpu.equals("x86")) {
114 threadFactory = new WindbgX86ThreadFactory(this);
115 } else if (cpu.equals("amd64")) {
116 threadFactory = new WindbgAMD64ThreadFactory(this);
117 } else if (cpu.equals("ia64")) {
118 threadFactory = new WindbgIA64ThreadFactory(this);
119 }
120
121 if (useCache) {
122 // Cache portion of the remote process's address space.
123 // Fetching data over the socket connection to dbx is slow.
124 // Might be faster if we were using a binary protocol to talk to
125 // dbx, but would have to test. For now, this cache works best
126 // if it covers the entire heap of the remote process. FIXME: at
127 // least should make this tunable from the outside, i.e., via
128 // the UI. This is a cache of 4096 4K pages, or 16 MB. The page
129 // size must be adjusted to be the hardware's page size.
130 // (FIXME: should pick this up from the debugger.)
131 initCache(4096, 4096);
132 }
133 // FIXME: add instantiation of thread factory
134
135 }
136
137 /** From the Debugger interface via JVMDebugger */
138 public boolean hasProcessList() throws DebuggerException {
139 return false;
140 }
141
142 /** From the Debugger interface via JVMDebugger */
143 public List getProcessList() throws DebuggerException {
144 return null;
145 }
146
147
148 /** From the Debugger interface via JVMDebugger */
149 public synchronized void attach(int processID) throws DebuggerException {
150 attachInit();
151 attach0(processID);
152 attached = true;
153 isCore = false;
154 }
155
156 /** From the Debugger interface via JVMDebugger */
157 public synchronized void attach(String executableName, String coreFileName) throws DebuggerException {
158 attachInit();
159 attach0(executableName, coreFileName);
160 attached = true;
161 isCore = true;
162 }
163
164 public List getLoadObjectList() {
165 requireAttach();
166 return loadObjects;
167 }
168
169 /** From the Debugger interface via JVMDebugger */
170 public synchronized boolean detach() {
171 if ( ! attached)
172 return false;
173
174 // Close all open DLLs
175 if (nameToDllMap != null) {
176 for (Iterator iter = nameToDllMap.values().iterator(); iter.hasNext(); ) {
177 DLL dll = (DLL) iter.next();
178 dll.close();
179 }
180 nameToDllMap = null;
181 loadObjects = null;
182 }
183
184 cdbg = null;
185 clearCache();
186
187 threadIntegerRegisterSet = null;
188 threadList = null;
189 try {
190 detach0();
191 } finally {
192 attached = false;
193 resetNativePointers();
194 }
195 return true;
196 }
197
198
199 /** From the Debugger interface via JVMDebugger */
200 public Address parseAddress(String addressString) throws NumberFormatException {
201 return newAddress(utils.scanAddress(addressString));
202 }
203
204 /** From the Debugger interface via JVMDebugger */
205 public String getOS() {
206 return PlatformInfo.getOS();
207 }
208
209 /** From the Debugger interface via JVMDebugger */
210 public String getCPU() {
211 return PlatformInfo.getCPU();
212 }
213
214 public boolean hasConsole() throws DebuggerException {
215 return true;
216 }
217
218 public synchronized String consoleExecuteCommand(String cmd) throws DebuggerException {
219 requireAttach();
220 if (! attached) {
221 throw new DebuggerException("debugger not yet attached to a Dr. Watson dump!");
222 }
223
224 return consoleExecuteCommand0(cmd);
225 }
226
227 public String getConsolePrompt() throws DebuggerException {
228 return "(windbg)";
229 }
230
231 public CDebugger getCDebugger() throws DebuggerException {
232 if (cdbg == null) {
233 // FIXME: CDebugger is not yet supported for IA64 because
234 // of native stack walking issues.
235 if (! getCPU().equals("ia64")) {
236 cdbg = new WindbgCDebugger(this);
237 }
238 }
239 return cdbg;
240 }
241
242 /** From the SymbolLookup interface via Debugger and JVMDebugger */
243 public synchronized Address lookup(String objectName, String symbol) {
244 requireAttach();
245 return newAddress(lookupByName(objectName, symbol));
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 public synchronized ClosestSymbol lookup(long address) {
258 return lookupByAddress0(address);
259 }
260
261 /** From the Debugger interface */
262 public MachineDescription getMachineDescription() {
263 return machDesc;
264 }
265
266 //--------------------------------------------------------------------------------
267 // Implementation of ThreadAccess interface
268 //
269
270
271 /** From the ThreadAccess interface via Debugger and JVMDebugger */
272 public ThreadProxy getThreadForIdentifierAddress(Address addr) {
273 return threadFactory.createThreadWrapper(addr);
274 }
275
276 public ThreadProxy getThreadForThreadId(long handle) {
277 // with windbg we can't make out using handle
278 throw new DebuggerException("Unimplemented!");
279 }
280
281 public long getThreadIdFromSysId(long sysId) throws DebuggerException {
282 requireAttach();
283 return getThreadIdFromSysId0(sysId);
284 }
285
286 //----------------------------------------------------------------------
287 // Overridden from DebuggerBase because we need to relax alignment
288 // constraints on x86
289
290 public long readJLong(long address)
291 throws UnmappedAddressException, UnalignedAddressException {
292 checkJavaConfigured();
293 // FIXME: allow this to be configurable. Undesirable to add a
294 // dependency on the runtime package here, though, since this
295 // package should be strictly underneath it.
296 // utils.checkAlignment(address, jlongSize);
297 utils.checkAlignment(address, jintSize);
298 byte[] data = readBytes(address, jlongSize);
299 return utils.dataToJLong(data, jlongSize);
300 }
301
302 //--------------------------------------------------------------------------------
303 // Internal routines (for implementation of WindbgAddress).
304 // These must not be called until the MachineDescription has been set up.
305 //
306
307 /** From the WindbgDebugger interface */
308 public String addressValueToString(long address) {
309 return utils.addressValueToString(address);
310 }
311
312 /** From the WindbgDebugger interface */
313 public WindbgAddress readAddress(long address)
314 throws UnmappedAddressException, UnalignedAddressException {
315 return (WindbgAddress) newAddress(readAddressValue(address));
316 }
317
318 /** From the WindbgDebugger interface */
319 public WindbgOopHandle readOopHandle(long address)
320 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
321 long value = readAddressValue(address);
322 return (value == 0 ? null : new WindbgOopHandle(this, value));
323 }
324
325 /** From the WindbgDebugger interface */
326 public int getAddressSize() {
327 return (int) machDesc.getAddressSize();
328 }
329
330 //--------------------------------------------------------------------------------
331 // Thread context access
332 //
333
334 private synchronized void setThreadIntegerRegisterSet(long threadId,
335 long[] regs) {
336 threadIntegerRegisterSet.put(new Long(threadId), regs);
337 }
338
339 private synchronized void addThread(long sysId) {
340 threadList.add(threadFactory.createThreadWrapper(sysId));
341 }
342
343 public synchronized long[] getThreadIntegerRegisterSet(long threadId)
344 throws DebuggerException {
345 requireAttach();
346 return (long[]) threadIntegerRegisterSet.get(new Long(threadId));
347 }
348
349 public synchronized List getThreadList() throws DebuggerException {
350 requireAttach();
351 return threadList;
352 }
353
354 private String findFullPath(String file) {
355 File f = new File(file);
356 if (f.exists()) {
357 return file;
358 } else {
359 // remove path part, if any.
360 file = f.getName();
361 StringTokenizer st = new StringTokenizer(imagePath, File.pathSeparator);
362 while (st.hasMoreTokens()) {
363 f = new File(st.nextToken(), file);
364 if (f.exists()) {
365 return f.getPath();
366 }
367 }
368 }
369 return null;
370 }
371
372 private synchronized void addLoadObject(String file, long size, long base) {
373 String path = findFullPath(file);
374 if (path != null) {
375 DLL dll = null;
376 if (useNativeLookup) {
377 dll = new DLL(this, path, size,newAddress(base)) {
378 public ClosestSymbol closestSymbolToPC(Address pcAsAddr) {
379 long pc = getAddressValue(pcAsAddr);
380 ClosestSymbol sym = lookupByAddress0(pc);
381 if (sym == null) {
382 return super.closestSymbolToPC(pcAsAddr);
383 } else {
384 return sym;
385 }
386 }
387 };
388 } else {
389 dll = new DLL(this, path, size, newAddress(base));
390 }
391 loadObjects.add(dll);
392 nameToDllMap.put(new File(file).getName(), dll);
393 }
394 }
395
396 //--------------------------------------------------------------------------------
397 // Address access
398 //
399
400 /** From the Debugger interface */
401 public long getAddressValue(Address addr) {
402 if (addr == null) return 0;
403 return ((WindbgAddress) addr).getValue();
404 }
405
406 /** From the WindbgDebugger interface */
407 public Address newAddress(long value) {
408 if (value == 0) return null;
409 return new WindbgAddress(this, value);
410 }
411
412 //--------------------------------------------------------------------------------
413 // Internals only below this point
414 //
415
416 // attach/detach helpers
417 private void checkAttached() {
418 if (attached) {
419 String msg = (isCore)? "already attached to a Dr. Watson dump!" :
420 "already attached to a process!";
421 throw new DebuggerException(msg);
422 }
423 }
424
425 private void requireAttach() {
426 if (!attached) {
427 throw new RuntimeException("not attached to a process or Dr Watson dump");
428 }
429 }
430
431 private void attachInit() {
432 checkAttached();
433 loadObjects = new ArrayList();
434 nameToDllMap = new HashMap();
435 threadIntegerRegisterSet = new HashMap();
436 threadList = new ArrayList();
437 }
438
439 private void resetNativePointers() {
440 ptrIDebugClient = 0L;
441 ptrIDebugControl = 0L;
442 ptrIDebugDataSpaces = 0L;
443 ptrIDebugOutputCallbacks = 0L;
444 ptrIDebugAdvanced = 0L;
445 ptrIDebugSymbols = 0L;
446 ptrIDebugSystemObjects = 0L;
447 }
448
449 synchronized long lookupByName(String objectName, String symbol) {
450 long res = 0L;
451 if (useNativeLookup) {
452 res = lookupByName0(objectName, symbol);
453 if (res != 0L) {
454 return res;
455 } // else fallthru...
456 }
457
458 DLL dll = (DLL) nameToDllMap.get(objectName);
459 // The DLL can be null because we use this to search through known
460 // DLLs in HotSpotTypeDataBase (for example)
461 if (dll != null) {
462 WindbgAddress addr = (WindbgAddress) dll.lookupSymbol(symbol);
463 if (addr != null) {
464 return addr.getValue();
465 }
466 }
467 return 0L;
468 }
469
470 /** This reads bytes from the remote process. */
471 public synchronized ReadResult readBytesFromProcess(long address, long numBytes)
472 throws UnmappedAddressException, DebuggerException {
473 requireAttach();
474 byte[] res = readBytesFromProcess0(address, numBytes);
475 if(res != null)
476 return new ReadResult(res);
477 else
478 return new ReadResult(address);
479 }
480
481
482 private DLL findDLLByName(String fullPathName) {
483 for (Iterator iter = loadObjects.iterator(); iter.hasNext(); ) {
484 DLL dll = (DLL) iter.next();
485 if (dll.getName().equals(fullPathName)) {
486 return dll;
487 }
488 }
489 return null;
490 }
491
492 public void writeBytesToProcess(long address, long numBytes, byte[] data)
493 throws UnmappedAddressException, DebuggerException {
494 // FIXME
495 throw new DebuggerException("Unimplemented");
496 }
497
498 private static String DTFWHome;
499 private static String imagePath;
500 private static String symbolPath;
501 private static boolean useNativeLookup;
502
503 static {
504
505 /*
506 * sawindbg.dll depends on dbgeng.dll which
507 * itself depends on dbghelp.dll. dbgeng.dll and dbghelp.dll.
508 * On systems newer than Windows 2000, these two .dlls are
509 * in the standard system directory so we will find them there.
510 * On Windows 2000 and earlier, these files do not exist.
511 * The user must download Debugging Tools For Windows (DTFW)
512 * and install it in order to use SA.
513 *
514 * We have to make sure we use the two files from the same directory
515 * in case there are more than one copy on the system because
516 * one version of dbgeng.dll might not be compatible with a
517 * different version of dbghelp.dll.
518 * We first look for them in the directory pointed at by
519 * env. var. DEBUGGINGTOOLSFORWINDOWS, next in the default
520 * installation dir for DTFW, and lastly in the standard
521 * system directory. We expect that that we will find
522 * them in the standard system directory on all systems
523 * newer than Windows 2000.
524 */
525 String dirName = null;
526 DTFWHome = System.getenv("DEBUGGINGTOOLSFORWINDOWS");
527
528 if (DTFWHome == null) {
529 // See if we have the files in the default location.
530 String sysRoot = System.getenv("SYSTEMROOT");
531 DTFWHome = sysRoot + File.separator +
532 ".." + File.separator + "Program Files" +
533 File.separator + "Debugging Tools For Windows";
534 }
535
536 {
537 String dbghelp = DTFWHome + File.separator + "dbghelp.dll";
538 String dbgeng = DTFWHome + File.separator + "dbgeng.dll";
539 File fhelp = new File(dbghelp);
540 File feng = new File(dbgeng);
541 if (fhelp.exists() && feng.exists()) {
542 // found both, we are happy.
543 // NOTE: The order of loads is important! If we load dbgeng.dll
544 // first, then the dependency - dbghelp.dll - will be loaded
545 // from usual DLL search thereby defeating the purpose!
546 System.load(dbghelp);
547 System.load(dbgeng);
548 } else if (! fhelp.exists() && ! feng.exists()) {
549 // neither exist. We will ignore this dir and assume
550 // they are in the system dir.
551 DTFWHome = null;
552 } else {
553 // one exists but not the other
554 //System.err.println("Error: Both files dbghelp.dll and dbgeng.dll "
555 // "must exist in directory " + DTFWHome);
556 throw new UnsatisfiedLinkError("Both files dbghelp.dll and " +
557 "dbgeng.dll must exist in " +
558 "directory " + DTFWHome);
559 }
560 }
561 if (DTFWHome == null) {
562 // The files better be in the system dir.
563 String sysDir = System.getenv("SYSTEMROOT") +
564 File.separator + "system32";
565
566 File feng = new File(sysDir + File.separator + "dbgeng.dll");
567 if (!feng.exists()) {
568 throw new UnsatisfiedLinkError("File dbgeng.dll does not exist in " +
569 sysDir + ". Please search microsoft.com " +
570 "for Debugging Tools For Windows, and " +
571 "either download it to the default " +
572 "location, or download it to a custom " +
573 "location and set environment variable " +
574 " DEBUGGINGTOOLSFORWINDOWS " +
575 "to the pathname of that location.");
576 }
577 }
578
579 // Now, load sawindbg.dll
580 System.loadLibrary("sawindbg");
581 // where do I find '.exe', '.dll' files?
582 imagePath = System.getProperty("sun.jvm.hotspot.debugger.windbg.imagePath");
583 if (imagePath == null) {
584 imagePath = System.getenv("PATH");
585 }
586
587 // where do I find '.pdb', '.dbg' files?
588 symbolPath = System.getProperty("sun.jvm.hotspot.debugger.windbg.symbolPath");
589
590 // mostly, debug files would be find where .dll's, .exe's are found.
591 if (symbolPath == null) {
592 symbolPath = imagePath;
593 }
594
595 // should we parse DLL symbol table in Java code or use
596 // Windbg's native lookup facility? By default, we use
597 // native lookup so that we can take advantage of '.pdb'
598 // files, if available.
599 useNativeLookup = true;
600 String str = System.getProperty("sun.jvm.hotspot.debugger.windbg.disableNativeLookup");
601 if (str != null) {
602 useNativeLookup = false;
603 }
604
605 initIDs();
606 }
607
608 // native methods
609 private static native void initIDs();
610 private native void attach0(String executableName, String coreFileName);
611 private native void attach0(int processID);
612 private native void detach0();
613 private native byte[] readBytesFromProcess0(long address, long numBytes)
614 throws UnmappedAddressException, DebuggerException;
615 private native long getThreadIdFromSysId0(long sysId);
616 private native String consoleExecuteCommand0(String cmd);
617 private native long lookupByName0(String objName, String symName);
618 private native ClosestSymbol lookupByAddress0(long address);
619
620 // helper called lookupByAddress0
621 private ClosestSymbol createClosestSymbol(String symbol, long diff) {
622 return new ClosestSymbol(symbol, diff);
623 }
624 }