View Javadoc
1   /*
2    * Copyright (c) 2002, 2012, 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.remote;
26  
27  import java.rmi.*;
28  import java.util.*;
29  import java.lang.reflect.*;
30  
31  import sun.jvm.hotspot.debugger.*;
32  import sun.jvm.hotspot.debugger.cdbg.*;
33  import sun.jvm.hotspot.debugger.remote.sparc.*;
34  import sun.jvm.hotspot.debugger.remote.x86.*;
35  import sun.jvm.hotspot.debugger.remote.amd64.*;
36  
37  /** An implementation of Debugger which wraps a
38      RemoteDebugger, providing remote debugging via RMI.
39      This implementation provides caching of the remote process's
40      address space on the local machine where the user interface is
41      running. */
42  
43  public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger {
44    private RemoteDebugger remoteDebugger;
45    private RemoteThreadFactory threadFactory;
46    private boolean unalignedAccessesOkay = false;
47    private static final int cacheSize = 16 * 1024 * 1024; // 16 MB
48  
49    public RemoteDebuggerClient(RemoteDebugger remoteDebugger) throws DebuggerException {
50      super();
51      try {
52        this.remoteDebugger = remoteDebugger;
53        machDesc = remoteDebugger.getMachineDescription();
54        utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
55        int cacheNumPages;
56        int cachePageSize;
57        String cpu = remoteDebugger.getCPU();
58        // page size. (FIXME: should pick this up from the remoteDebugger.)
59        if (cpu.equals("sparc")) {
60          threadFactory = new RemoteSPARCThreadFactory(this);
61          cachePageSize = 8192;
62          cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
63        } else if (cpu.equals("x86")) {
64          threadFactory = new RemoteX86ThreadFactory(this);
65          cachePageSize = 4096;
66          cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
67          unalignedAccessesOkay = true;
68        } else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
69          threadFactory = new RemoteAMD64ThreadFactory(this);
70          cachePageSize = 4096;
71          cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
72          unalignedAccessesOkay = true;
73        } else {
74          try {
75            Class tf = Class.forName("sun.jvm.hotspot.debugger.remote." +
76              cpu.toLowerCase() + ".Remote" + cpu.toUpperCase() +
77              "ThreadFactory");
78            Constructor[] ctf = tf.getConstructors();
79            threadFactory = (RemoteThreadFactory)ctf[0].newInstance(this);
80          } catch (Exception e) {
81            throw new DebuggerException("Thread access for CPU architecture " + cpu + " not yet supported");
82          }
83          cachePageSize = 4096;
84          cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
85          unalignedAccessesOkay = false;
86        }
87  
88        // Cache portion of the remote process's address space.
89        initCache(cachePageSize, cacheNumPages);
90  
91        jbooleanSize = remoteDebugger.getJBooleanSize();
92        jbyteSize    = remoteDebugger.getJByteSize();
93        jcharSize    = remoteDebugger.getJCharSize();
94        jdoubleSize  = remoteDebugger.getJDoubleSize();
95        jfloatSize   = remoteDebugger.getJFloatSize();
96        jintSize     = remoteDebugger.getJIntSize();
97        jlongSize    = remoteDebugger.getJLongSize();
98        jshortSize   = remoteDebugger.getJShortSize();
99        javaPrimitiveTypesConfigured = true;
100       narrowOopBase  = remoteDebugger.getNarrowOopBase();
101       narrowOopShift = remoteDebugger.getNarrowOopShift();
102       narrowKlassBase  = remoteDebugger.getNarrowKlassBase();
103       narrowKlassShift = remoteDebugger.getNarrowKlassShift();
104       heapOopSize  = remoteDebugger.getHeapOopSize();
105       klassPtrSize  = remoteDebugger.getKlassPtrSize();
106     }
107     catch (RemoteException e) {
108       throw new DebuggerException(e);
109     }
110   }
111 
112   public long[] getThreadIntegerRegisterSet(Address addr) {
113     try {
114       return remoteDebugger.getThreadIntegerRegisterSet(getAddressValue(addr), true);
115     }
116     catch (RemoteException e) {
117       throw new DebuggerException(e);
118     }
119   }
120 
121   public long[] getThreadIntegerRegisterSet(long id) {
122     try {
123       return remoteDebugger.getThreadIntegerRegisterSet(id, false);
124     }
125     catch (RemoteException e) {
126       throw new DebuggerException(e);
127     }
128   }
129 
130   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
131   public boolean hasProcessList() throws DebuggerException {
132     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
133   }
134 
135   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
136   public List getProcessList() throws DebuggerException {
137     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
138   }
139 
140   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
141   public void attach(int processID) throws DebuggerException {
142     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
143   }
144 
145   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
146   public void attach(String executableName, String coreFileName) throws DebuggerException {
147     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
148   }
149 
150   /** Unimplemented in this class (remote remoteDebugger can not be detached) */
151   public boolean detach() {
152     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
153   }
154 
155   public Address parseAddress(String addressString) throws NumberFormatException {
156     long addr = utils.scanAddress(addressString);
157     if (addr == 0) {
158       return null;
159     }
160     return new RemoteAddress(this, addr);
161   }
162 
163   public String getOS() throws DebuggerException {
164     try {
165       return remoteDebugger.getOS();
166     }
167     catch (RemoteException e) {
168       throw new DebuggerException(e);
169     }
170   }
171 
172   public String getCPU() {
173     try {
174       return remoteDebugger.getCPU();
175     }
176     catch (RemoteException e) {
177       throw new DebuggerException(e);
178     }
179   }
180 
181   public boolean hasConsole() throws DebuggerException {
182     try {
183        return remoteDebugger.hasConsole();
184     } catch (RemoteException e) {
185        throw new DebuggerException(e);
186     }
187   }
188 
189   public String consoleExecuteCommand(String cmd) throws DebuggerException {
190     try {
191       return remoteDebugger.consoleExecuteCommand(cmd);
192     }
193     catch (RemoteException e) {
194       throw new DebuggerException(e);
195     }
196   }
197 
198   public String getConsolePrompt() throws DebuggerException {
199     try {
200       return remoteDebugger.getConsolePrompt();
201     } catch (RemoteException e) {
202       throw new DebuggerException(e);
203     }
204   }
205 
206   public CDebugger getCDebugger() throws DebuggerException {
207     return null;
208   }
209 
210   //--------------------------------------------------------------------------------
211   // Implementation of SymbolLookup interface
212 
213   public Address lookup(String objectName, String symbol) {
214     try {
215       long addr = remoteDebugger.lookupInProcess(objectName, symbol);
216       if (addr == 0) {
217         return null;
218       }
219       return new RemoteAddress(this, addr);
220     }
221     catch (RemoteException e) {
222       throw new DebuggerException(e);
223     }
224   }
225 
226   public OopHandle lookupOop(String objectName, String symbol) {
227     try {
228       long addr = remoteDebugger.lookupInProcess(objectName, symbol);
229       if (addr == 0) {
230         return null;
231       }
232       return new RemoteOopHandle(this, addr);
233     }
234     catch (RemoteException e) {
235       throw new DebuggerException(e);
236     }
237   }
238 
239   /** Need to override this to relax alignment checks on x86. */
240   public long readCInteger(long address, long numBytes, boolean isUnsigned)
241     throws UnmappedAddressException, UnalignedAddressException {
242     if (!unalignedAccessesOkay) {
243       utils.checkAlignment(address, numBytes);
244     } else {
245       // Only slightly relaxed semantics -- this is a hack, but is
246       // necessary on x86 where it seems the compiler is
247       // putting some global 64-bit data on 32-bit boundaries
248       if (numBytes == 8) {
249         utils.checkAlignment(address, 4);
250       } else {
251         utils.checkAlignment(address, numBytes);
252       }
253     }
254     byte[] data = readBytes(address, numBytes);
255     return utils.dataToCInteger(data, isUnsigned);
256   }
257 
258   // Overridden from DebuggerBase because we need to relax alignment
259   // constraints on x86
260   public long readJLong(long address)
261     throws UnmappedAddressException, UnalignedAddressException {
262     // FIXME: allow this to be configurable. Undesirable to add a
263     // dependency on the runtime package here, though, since this
264     // package should be strictly underneath it.
265     if (unalignedAccessesOkay) {
266       utils.checkAlignment(address, jintSize);
267     } else {
268       utils.checkAlignment(address, jlongSize);
269     }
270     byte[] data = readBytes(address, jlongSize);
271     return utils.dataToJLong(data, jlongSize);
272   }
273 
274 
275   //--------------------------------------------------------------------------------
276   // Implementation of JVMDebugger interface
277   //
278 
279   /** Unimplemented in this class (remote remoteDebugger should already be configured) */
280   public void configureJavaPrimitiveTypeSizes(long jbooleanSize,
281                                               long jbyteSize,
282                                               long jcharSize,
283                                               long jdoubleSize,
284                                               long jfloatSize,
285                                               long jintSize,
286                                               long jlongSize,
287                                               long jshortSize) {
288     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
289   }
290 
291   public void setMachineDescription(MachineDescription machDesc) {
292     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
293   }
294 
295   public int getRemoteProcessAddressSize() {
296     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
297   }
298 
299   public String addressValueToString(long addr) {
300     return utils.addressValueToString(addr);
301   }
302 
303   public long getAddressValue(Address addr) throws DebuggerException {
304     if (addr == null) return 0;
305     return ((RemoteAddress) addr).getValue();
306   }
307 
308   public Address newAddress(long value) {
309     if (value == 0) return null;
310     return new RemoteAddress(this, value);
311   }
312 
313   RemoteAddress readAddress(long address)
314     throws UnmappedAddressException, UnalignedAddressException {
315     long value = readAddressValue(address);
316     return (value == 0 ? null : new RemoteAddress(this, value));
317   }
318 
319   RemoteAddress readCompOopAddress(long address)
320     throws UnmappedAddressException, UnalignedAddressException {
321     long value = readCompOopAddressValue(address);
322     return (value == 0 ? null : new RemoteAddress(this, value));
323   }
324 
325   RemoteAddress readCompKlassAddress(long address)
326     throws UnmappedAddressException, UnalignedAddressException {
327     long value = readCompKlassAddressValue(address);
328     return (value == 0 ? null : new RemoteAddress(this, value));
329   }
330 
331   RemoteOopHandle readOopHandle(long address)
332     throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
333     long value = readAddressValue(address);
334     return (value == 0 ? null : new RemoteOopHandle(this, value));
335   }
336 
337   RemoteOopHandle readCompOopHandle(long address)
338     throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
339     long value = readCompOopAddressValue(address);
340     return (value == 0 ? null : new RemoteOopHandle(this, value));
341   }
342 
343   boolean areThreadsEqual(Address addr1, Address addr2) {
344     try {
345        return remoteDebugger.areThreadsEqual(getAddressValue(addr1), true,
346                                              getAddressValue(addr2), true);
347     } catch (RemoteException e) {
348     }
349     return false;
350   }
351 
352   boolean areThreadsEqual(long id1, long id2) {
353     try {
354        return remoteDebugger.areThreadsEqual(id1, false, id2, false);
355     } catch (RemoteException e) {
356     }
357     return false;
358   }
359 
360   boolean areThreadsEqual(Address addr1, long id2) {
361     try {
362        return remoteDebugger.areThreadsEqual(getAddressValue(addr1), true, id2, false);
363     } catch (RemoteException e) {
364     }
365     return false;
366   }
367 
368   boolean areThreadsEqual(long id1, Address addr2) {
369     try {
370        return remoteDebugger.areThreadsEqual(id1, false, getAddressValue(addr2), true);
371     } catch (RemoteException e) {
372     }
373     return false;
374   }
375 
376   int getThreadHashCode(Address a) {
377     try {
378        return remoteDebugger.getThreadHashCode(getAddressValue(a), true);
379     } catch (RemoteException e) {
380     }
381     return a.hashCode();
382   }
383 
384   int getThreadHashCode(long id) {
385     try {
386        return remoteDebugger.getThreadHashCode(id, false);
387     } catch (RemoteException e) {
388     }
389     return (int) id;
390   }
391 
392   public ThreadProxy getThreadForIdentifierAddress(Address addr) {
393      return threadFactory.createThreadWrapper(addr);
394   }
395 
396   public ThreadProxy getThreadForThreadId(long id) {
397      return threadFactory.createThreadWrapper(id);
398   }
399 
400   public MachineDescription getMachineDescription() throws DebuggerException {
401      return machDesc;
402   }
403 
404   /** This reads bytes from the remote process. */
405   public ReadResult readBytesFromProcess(long address, long numBytes) {
406     try {
407       return remoteDebugger.readBytesFromProcess(address, numBytes);
408     }
409     catch (RemoteException e) {
410       throw new DebuggerException(e);
411     }
412   }
413 
414   public void writeBytesToProcess(long a, long b, byte[] c) {
415      throw new DebuggerException("Unimplemented!");
416   }
417 }