hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java
changeset 1 489c9b5090e2
child 360 21d113ecbf6a
equal deleted inserted replaced
0:fd16c54261b3 1:489c9b5090e2
       
     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 }