0
|
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 }
|