public Object[] getIds() { Object[] superIds = super.getIds(); Object[] tmp = fields.keySet().toArray(); Object[] res = new Object[superIds.length + tmp.length]; System.arraycopy(tmp, 0, res, 0, tmp.length); System.arraycopy(superIds, 0, res, tmp.length, superIds.length); return res; }
private void usage() { System.out.println("usage: java " + getClass().getName() + " <pid> [server id]"); System.out.println(" or: java " + getClass().getName() + " <executable> <core> [server id]"); System.out.println("\"pid\" must be the process ID of a HotSpot process."); System.out.println("If reading a core file, \"executable\" must (currently) be the"); System.out.println("full path name to the precise java executable which generated"); System.out.println("the core file (not, on Solaris, the \"java\" wrapper script in"); System.out.println("the \"bin\" subdirectory of the JDK.)"); System.out.println("The \"server id\" is a unique name for a specific remote debuggee."); System.exit(1); }
private void run(String[] args) { if ((args.length < 1) || (args.length > 3)) { usage(); } // Attempt to handle "-h" or "-help" if (args[0].startsWith("-")) { usage(); } int pid = 0; boolean usePid = false; String coreFileName = null; // FIXME: would be nice to pick this up from the core file // somehow, but that doesn't look possible. Should at least figure // it out from a path to the JDK. String javaExecutableName = null; String serverID = null; switch (args.length) { case 1: try { pid = Integer.parseInt(args[0]); usePid = true; } catch (NumberFormatException e) { usage(); } break; case 2: // either we have pid and server id or exec file and core file try { pid = Integer.parseInt(args[0]); usePid = true; serverID = args[1]; } catch (NumberFormatException e) { pid = -1; usePid = false; javaExecutableName = args[0]; coreFileName = args[1]; } break; case 3: javaExecutableName = args[0]; coreFileName = args[1]; serverID = args[2]; break; default: // should not happend, taken care already. break; } final HotSpotAgent agent = new HotSpotAgent(); try { if (usePid) { System.err.println( "Attaching to process ID " + pid + " and starting RMI services, please wait..."); agent.startServer(pid, serverID); } else { System.err.println( "Attaching to core " + coreFileName + " from executable " + javaExecutableName + " and starting RMI services, please wait..."); agent.startServer(javaExecutableName, coreFileName, serverID); } } catch (DebuggerException e) { if (usePid) { System.err.print("Error attaching to process or starting server: "); } else { System.err.print("Error attaching to core file or starting server: "); } e.printStackTrace(); System.exit(1); } // shutdown hook to clean-up the server in case of forced exit. Runtime.getRuntime() .addShutdownHook( new java.lang.Thread( new Runnable() { public void run() { agent.shutdownServer(); } })); System.err.println("Debugger attached and RMI services started."); }
/** * Should be able to be used on all amd64 platforms we support (Linux/amd64) to implement * JavaThread's "currentFrameGuess()" functionality. Input is an AMD64ThreadContext; output is SP, * FP, and PC for an AMD64Frame. Instantiation of the AMD64Frame is left to the caller, since we may * need to subclass AMD64Frame to support signal handler frames on Unix platforms. * * <p>Algorithm is to walk up the stack within a given range (say, 512K at most) looking for a * plausible PC and SP for a Java frame, also considering those coming in from the context. If we * find a PC that belongs to the VM (i.e., in generated code like the interpreter or CodeCache) then * we try to find an associated EBP. We repeat this until we either find a complete frame or run out * of stack to look at. */ public class AMD64CurrentFrameGuess { private AMD64ThreadContext context; private JavaThread thread; private Address spFound; private Address fpFound; private Address pcFound; private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.amd64.AMD64Frame.DEBUG") != null; public AMD64CurrentFrameGuess(AMD64ThreadContext context, JavaThread thread) { this.context = context; this.thread = thread; } /** Returns false if not able to find a frame within a reasonable range. */ public boolean run(long regionInBytesToSearch) { Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); Address fp = context.getRegisterAsAddress(AMD64ThreadContext.RBP); if (sp == null) { // Bail out if no last java frame either if (thread.getLastJavaSP() != null) { setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null); return true; } return false; } Address end = sp.addOffsetTo(regionInBytesToSearch); VM vm = VM.getVM(); setValues(null, null, null); // Assume we're not going to find anything if (vm.isJavaPCDbg(pc)) { if (vm.isClientCompiler()) { // If the topmost frame is a Java frame, we are (pretty much) // guaranteed to have a viable EBP. We should be more robust // than this (we have the potential for losing entire threads' // stack traces) but need to see how much work we really have // to do here. Searching the stack for an (SP, FP) pair is // hard since it's easy to misinterpret inter-frame stack // pointers as base-of-frame pointers; we also don't know the // sizes of C1 frames (not registered in the nmethod) so can't // derive them from ESP. setValues(sp, fp, pc); return true; } else { if (vm.getInterpreter().contains(pc)) { if (DEBUG) { System.out.println( "CurrentFrameGuess: choosing interpreter frame: sp = " + sp + ", fp = " + fp + ", pc = " + pc); } setValues(sp, fp, pc); return true; } // For the server compiler, EBP is not guaranteed to be valid // for compiled code. In addition, an earlier attempt at a // non-searching algorithm (see below) failed because the // stack pointer from the thread context was pointing // (considerably) beyond the ostensible end of the stack, into // garbage; walking from the topmost frame back caused a crash. // // This algorithm takes the current PC as a given and tries to // find the correct corresponding SP by walking up the stack // and repeatedly performing stackwalks (very inefficient). // // FIXME: there is something wrong with stackwalking across // adapter frames...this is likely to be the root cause of the // failure with the simpler algorithm below. for (long offset = 0; offset < regionInBytesToSearch; offset += vm.getAddressSize()) { try { Address curSP = sp.addOffsetTo(offset); Frame frame = new X86Frame(curSP, null, pc); RegisterMap map = thread.newRegisterMap(false); while (frame != null) { if (frame.isEntryFrame() && frame.entryFrameIsFirst()) { // We were able to traverse all the way to the // bottommost Java frame. // This sp looks good. Keep it. if (DEBUG) { System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc); } setValues(curSP, null, pc); return true; } frame = frame.sender(map); } } catch (Exception e) { if (DEBUG) { System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset); } // Bad SP. Try another. } } // Were not able to find a plausible SP to go with this PC. // Bail out. return false; /* // Original algorithm which does not work because SP was // pointing beyond where it should have: // For the server compiler, EBP is not guaranteed to be valid // for compiled code. We see whether the PC is in the // interpreter and take care of that, otherwise we run code // (unfortunately) duplicated from AMD64Frame.senderForCompiledFrame. CodeCache cc = vm.getCodeCache(); if (cc.contains(pc)) { CodeBlob cb = cc.findBlob(pc); // See if we can derive a frame pointer from SP and PC // NOTE: This is the code duplicated from AMD64Frame Address saved_fp = null; int llink_offset = cb.getLinkOffset(); if (llink_offset >= 0) { // Restore base-pointer, since next frame might be an interpreter frame. Address fp_addr = sp.addOffsetTo(VM.getVM().getAddressSize() * llink_offset); saved_fp = fp_addr.getAddressAt(0); } setValues(sp, saved_fp, pc); return true; } */ } } else { // If the current program counter was not known to us as a Java // PC, we currently assume that we are in the run-time system // and attempt to look to thread-local storage for saved ESP and // EBP. Note that if these are null (because we were, in fact, // in Java code, i.e., vtable stubs or similar, and the SA // didn't have enough insight into the target VM to understand // that) then we are going to lose the entire stack trace for // the thread, which is sub-optimal. FIXME. if (DEBUG) { System.out.println( "CurrentFrameGuess: choosing last Java frame: sp = " + thread.getLastJavaSP() + ", fp = " + thread.getLastJavaFP()); } if (thread.getLastJavaSP() == null) { return false; // No known Java frames on stack } setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null); return true; } } public Address getSP() { return spFound; } public Address getFP() { return fpFound; } /** * May be null if getting values from thread-local storage; take care to call the correct * AMD64Frame constructor to recover this if necessary */ public Address getPC() { return pcFound; } private void setValues(Address sp, Address fp, Address pc) { spFound = sp; fpFound = fp; pcFound = pc; } }