--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/utilities/debug.cpp Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,936 @@
+/*
+ * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+# include "incls/_precompiled.incl"
+# include "incls/_debug.cpp.incl"
+
+#ifndef ASSERT
+# ifdef _DEBUG
+ // NOTE: don't turn the lines below into a comment -- if you're getting
+ // a compile error here, change the settings to define ASSERT
+ ASSERT should be defined when _DEBUG is defined. It is not intended to be used for debugging
+ functions that do not slow down the system too much and thus can be left in optimized code.
+ On the other hand, the code should not be included in a production version.
+# endif // _DEBUG
+#endif // ASSERT
+
+
+#ifdef _DEBUG
+# ifndef ASSERT
+ configuration error: ASSERT must be defined in debug version
+# endif // ASSERT
+#endif // _DEBUG
+
+
+#ifdef PRODUCT
+# if -defined _DEBUG || -defined ASSERT
+ configuration error: ASSERT et al. must not be defined in PRODUCT version
+# endif
+#endif // PRODUCT
+
+
+void warning(const char* format, ...) {
+ // In case error happens before init or during shutdown
+ if (tty == NULL) ostream_init();
+
+ tty->print("%s warning: ", VM_Version::vm_name());
+ va_list ap;
+ va_start(ap, format);
+ tty->vprint_cr(format, ap);
+ va_end(ap);
+ if (BreakAtWarning) BREAKPOINT;
+}
+
+#ifndef PRODUCT
+
+#define is_token_break(ch) (isspace(ch) || (ch) == ',')
+
+static const char* last_file_name = NULL;
+static int last_line_no = -1;
+
+// assert/guarantee/... may happen very early during VM initialization.
+// Don't rely on anything that is initialized by Threads::create_vm(). For
+// example, don't use tty.
+bool assert_is_suppressed(const char* file_name, int line_no) {
+ // The following 1-element cache requires that passed-in
+ // file names are always only constant literals.
+ if (file_name == last_file_name && line_no == last_line_no) return true;
+
+ int file_name_len = (int)strlen(file_name);
+ char separator = os::file_separator()[0];
+ const char* base_name = strrchr(file_name, separator);
+ if (base_name == NULL)
+ base_name = file_name;
+
+ // scan the SuppressErrorAt option
+ const char* cp = SuppressErrorAt;
+ for (;;) {
+ const char* sfile;
+ int sfile_len;
+ int sline;
+ bool noisy;
+ while ((*cp) != '\0' && is_token_break(*cp)) cp++;
+ if ((*cp) == '\0') break;
+ sfile = cp;
+ while ((*cp) != '\0' && !is_token_break(*cp) && (*cp) != ':') cp++;
+ sfile_len = cp - sfile;
+ if ((*cp) == ':') cp++;
+ sline = 0;
+ while ((*cp) != '\0' && isdigit(*cp)) {
+ sline *= 10;
+ sline += (*cp) - '0';
+ cp++;
+ }
+ // "file:line!" means the assert suppression is not silent
+ noisy = ((*cp) == '!');
+ while ((*cp) != '\0' && !is_token_break(*cp)) cp++;
+ // match the line
+ if (sline != 0) {
+ if (sline != line_no) continue;
+ }
+ // match the file
+ if (sfile_len > 0) {
+ const char* look = file_name;
+ const char* look_max = file_name + file_name_len - sfile_len;
+ const char* foundp;
+ bool match = false;
+ while (!match
+ && (foundp = strchr(look, sfile[0])) != NULL
+ && foundp <= look_max) {
+ match = true;
+ for (int i = 1; i < sfile_len; i++) {
+ if (sfile[i] != foundp[i]) {
+ match = false;
+ break;
+ }
+ }
+ look = foundp + 1;
+ }
+ if (!match) continue;
+ }
+ // got a match!
+ if (noisy) {
+ fdStream out(defaultStream::output_fd());
+ out.print_raw("[error suppressed at ");
+ out.print_raw(base_name);
+ char buf[16];
+ jio_snprintf(buf, sizeof(buf), ":%d]", line_no);
+ out.print_raw_cr(buf);
+ } else {
+ // update 1-element cache for fast silent matches
+ last_file_name = file_name;
+ last_line_no = line_no;
+ }
+ return true;
+ }
+
+ if (!is_error_reported()) {
+ // print a friendly hint:
+ fdStream out(defaultStream::output_fd());
+ out.print_raw_cr("# To suppress the following error report, specify this argument");
+ out.print_raw ("# after -XX: or in .hotspotrc: SuppressErrorAt=");
+ out.print_raw (base_name);
+ char buf[16];
+ jio_snprintf(buf, sizeof(buf), ":%d", line_no);
+ out.print_raw_cr(buf);
+ }
+ return false;
+}
+
+#undef is_token_break
+
+#else
+
+// Place-holder for non-existent suppression check:
+#define assert_is_suppressed(file_name, line_no) (false)
+
+#endif //PRODUCT
+
+void report_assertion_failure(const char* file_name, int line_no, const char* message) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), message, file_name, line_no);
+ err.report_and_die();
+}
+
+void report_fatal(const char* file_name, int line_no, const char* message) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), message, file_name, line_no);
+ err.report_and_die();
+}
+
+void report_fatal_vararg(const char* file_name, int line_no, const char* format, ...) {
+ char buffer[256];
+ va_list ap;
+ va_start(ap, format);
+ jio_vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ report_fatal(file_name, line_no, buffer);
+}
+
+
+// Used by report_vm_out_of_memory to detect recursion.
+static jint _exiting_out_of_mem = 0;
+
+// Just passing the flow to VMError to handle error
+void report_vm_out_of_memory(const char* file_name, int line_no, size_t size, const char* message) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+
+ // We try to gather additional information for the first out of memory
+ // error only; gathering additional data might cause an allocation and a
+ // recursive out_of_memory condition.
+
+ const jint exiting = 1;
+ // If we succeed in changing the value, we're the first one in.
+ bool first_time_here = Atomic::xchg(exiting, &_exiting_out_of_mem) != exiting;
+
+ if (first_time_here) {
+ Thread* thread = ThreadLocalStorage::get_thread_slow();
+ VMError(thread, size, message, file_name, line_no).report_and_die();
+ }
+ vm_abort();
+}
+
+void report_vm_out_of_memory_vararg(const char* file_name, int line_no, size_t size, const char* format, ...) {
+ char buffer[256];
+ va_list ap;
+ va_start(ap, format);
+ jio_vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ report_vm_out_of_memory(file_name, line_no, size, buffer);
+}
+
+void report_should_not_call(const char* file_name, int line_no) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), "ShouldNotCall()", file_name, line_no);
+ err.report_and_die();
+}
+
+
+void report_should_not_reach_here(const char* file_name, int line_no) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), "ShouldNotReachHere()", file_name, line_no);
+ err.report_and_die();
+}
+
+
+void report_unimplemented(const char* file_name, int line_no) {
+ if (Debugging || assert_is_suppressed(file_name, line_no)) return;
+ VMError err(ThreadLocalStorage::get_thread_slow(), "Unimplemented()", file_name, line_no);
+ err.report_and_die();
+}
+
+
+void report_untested(const char* file_name, int line_no, const char* msg) {
+#ifndef PRODUCT
+ warning("Untested: %s in %s: %d\n", msg, file_name, line_no);
+#endif // PRODUCT
+}
+
+void report_java_out_of_memory(const char* message) {
+ static jint out_of_memory_reported = 0;
+
+ // A number of threads may attempt to report OutOfMemoryError at around the
+ // same time. To avoid dumping the heap or executing the data collection
+ // commands multiple times we just do it once when the first threads reports
+ // the error.
+ if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) {
+ // create heap dump before OnOutOfMemoryError commands are executed
+ if (HeapDumpOnOutOfMemoryError) {
+ tty->print_cr("java.lang.OutOfMemoryError: %s", message);
+ HeapDumper::dump_heap();
+ }
+
+ if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
+ VMError err(message);
+ err.report_java_out_of_memory();
+ }
+ }
+}
+
+
+extern "C" void ps();
+
+static bool error_reported = false;
+
+// call this when the VM is dying--it might loosen some asserts
+void set_error_reported() {
+ error_reported = true;
+}
+
+bool is_error_reported() {
+ return error_reported;
+}
+
+// ------ helper functions for debugging go here ------------
+
+#ifndef PRODUCT
+// All debug entries should be wrapped with a stack allocated
+// Command object. It makes sure a resource mark is set and
+// flushes the logfile to prevent file sharing problems.
+
+class Command : public StackObj {
+ private:
+ ResourceMark rm;
+ ResetNoHandleMark rnhm;
+ HandleMark hm;
+ bool debug_save;
+ public:
+ static int level;
+ Command(const char* str) {
+ debug_save = Debugging;
+ Debugging = true;
+ if (level++ > 0) return;
+ tty->cr();
+ tty->print_cr("\"Executing %s\"", str);
+ }
+
+ ~Command() { tty->flush(); Debugging = debug_save; level--; }
+};
+
+int Command::level = 0;
+
+extern "C" void blob(CodeBlob* cb) {
+ Command c("blob");
+ cb->print();
+}
+
+
+extern "C" void dump_vtable(address p) {
+ Command c("dump_vtable");
+ klassOop k = (klassOop)p;
+ instanceKlass::cast(k)->vtable()->print();
+}
+
+
+extern "C" void nm(intptr_t p) {
+ // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatability)
+ Command c("nm");
+ CodeBlob* cb = CodeCache::find_blob((address)p);
+ if (cb == NULL) {
+ tty->print_cr("NULL");
+ } else {
+ cb->print();
+ }
+}
+
+
+extern "C" void disnm(intptr_t p) {
+ Command c("disnm");
+ CodeBlob* cb = CodeCache::find_blob((address) p);
+ cb->print();
+ Disassembler::decode(cb);
+}
+
+
+extern "C" void printnm(intptr_t p) {
+ char buffer[256];
+ sprintf(buffer, "printnm: " INTPTR_FORMAT, p);
+ Command c(buffer);
+ CodeBlob* cb = CodeCache::find_blob((address) p);
+ if (cb->is_nmethod()) {
+ nmethod* nm = (nmethod*)cb;
+ nm->print_nmethod(true);
+ }
+}
+
+
+extern "C" void universe() {
+ Command c("universe");
+ Universe::print();
+}
+
+
+extern "C" void verify() {
+ // try to run a verify on the entire system
+ // note: this may not be safe if we're not at a safepoint; for debugging,
+ // this manipulates the safepoint settings to avoid assertion failures
+ Command c("universe verify");
+ bool safe = SafepointSynchronize::is_at_safepoint();
+ if (!safe) {
+ tty->print_cr("warning: not at safepoint -- verify may fail");
+ SafepointSynchronize::set_is_at_safepoint();
+ }
+ // Ensure Eden top is correct before verification
+ Universe::heap()->prepare_for_verify();
+ Universe::verify(true);
+ if (!safe) SafepointSynchronize::set_is_not_at_safepoint();
+}
+
+
+extern "C" void pp(void* p) {
+ Command c("pp");
+ FlagSetting fl(PrintVMMessages, true);
+ if (Universe::heap()->is_in(p)) {
+ oop obj = oop(p);
+ obj->print();
+ } else {
+ tty->print("%#p", p);
+ }
+}
+
+
+// pv: print vm-printable object
+extern "C" void pa(intptr_t p) { ((AllocatedObj*) p)->print(); }
+extern "C" void findpc(intptr_t x);
+
+extern "C" void ps() { // print stack
+ Command c("ps");
+
+
+ // Prints the stack of the current Java thread
+ JavaThread* p = JavaThread::active();
+ tty->print(" for thread: ");
+ p->print();
+ tty->cr();
+
+ if (p->has_last_Java_frame()) {
+ // If the last_Java_fp is set we are in C land and
+ // can call the standard stack_trace function.
+ p->trace_stack();
+ } else {
+ frame f = os::current_frame();
+ RegisterMap reg_map(p);
+ f = f.sender(®_map);
+ tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id());
+ p->trace_stack_from(vframe::new_vframe(&f, ®_map, p));
+ pd_ps(f);
+ }
+
+}
+
+
+extern "C" void psf() { // print stack frames
+ {
+ Command c("psf");
+ JavaThread* p = JavaThread::active();
+ tty->print(" for thread: ");
+ p->print();
+ tty->cr();
+ if (p->has_last_Java_frame()) {
+ p->trace_frames();
+ }
+ }
+}
+
+
+extern "C" void threads() {
+ Command c("threads");
+ Threads::print(false, true);
+}
+
+
+extern "C" void psd() {
+ Command c("psd");
+ SystemDictionary::print();
+}
+
+
+extern "C" void safepoints() {
+ Command c("safepoints");
+ SafepointSynchronize::print_state();
+}
+
+
+extern "C" void pss() { // print all stacks
+ Command c("pss");
+ Threads::print(true, true);
+}
+
+
+extern "C" void debug() { // to set things up for compiler debugging
+ Command c("debug");
+ WizardMode = true;
+ PrintVMMessages = PrintCompilation = true;
+ PrintInlining = PrintAssembly = true;
+ tty->flush();
+}
+
+
+extern "C" void ndebug() { // undo debug()
+ Command c("ndebug");
+ PrintCompilation = false;
+ PrintInlining = PrintAssembly = false;
+ tty->flush();
+}
+
+
+extern "C" void flush() {
+ Command c("flush");
+ tty->flush();
+}
+
+
+extern "C" void events() {
+ Command c("events");
+ Events::print_last(tty, 50);
+}
+
+
+extern "C" void nevents(int n) {
+ Command c("events");
+ Events::print_last(tty, n);
+}
+
+
+// Given a heap address that was valid before the most recent GC, if
+// the oop that used to contain it is still live, prints the new
+// location of the oop and the address. Useful for tracking down
+// certain kinds of naked oop and oop map bugs.
+extern "C" void pnl(intptr_t old_heap_addr) {
+ // Print New Location of old heap address
+ Command c("pnl");
+#ifndef VALIDATE_MARK_SWEEP
+ tty->print_cr("Requires build with VALIDATE_MARK_SWEEP defined (debug build) and RecordMarkSweepCompaction enabled");
+#else
+ MarkSweep::print_new_location_of_heap_address((HeapWord*) old_heap_addr);
+#endif
+}
+
+
+extern "C" methodOop findm(intptr_t pc) {
+ Command c("findm");
+ nmethod* nm = CodeCache::find_nmethod((address)pc);
+ return (nm == NULL) ? (methodOop)NULL : nm->method();
+}
+
+
+extern "C" nmethod* findnm(intptr_t addr) {
+ Command c("findnm");
+ return CodeCache::find_nmethod((address)addr);
+}
+
+static address same_page(address x, address y) {
+ intptr_t page_bits = -os::vm_page_size();
+ if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) {
+ return x;
+ } else if (x > y) {
+ return (address)(intptr_t(y) | ~page_bits) + 1;
+ } else {
+ return (address)(intptr_t(y) & page_bits);
+ }
+}
+
+
+static void find(intptr_t x, bool print_pc) {
+ address addr = (address)x;
+
+ CodeBlob* b = CodeCache::find_blob_unsafe(addr);
+ if (b != NULL) {
+ if (b->is_buffer_blob()) {
+ // the interpreter is generated into a buffer blob
+ InterpreterCodelet* i = Interpreter::codelet_containing(addr);
+ if (i != NULL) {
+ i->print();
+ return;
+ }
+ if (Interpreter::contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT " is pointing into interpreter code (not bytecode specific)", addr);
+ return;
+ }
+ //
+ if (AdapterHandlerLibrary::contains(b)) {
+ AdapterHandlerLibrary::print_handler(b);
+ }
+ // the stubroutines are generated into a buffer blob
+ StubCodeDesc* d = StubCodeDesc::desc_for(addr);
+ if (d != NULL) {
+ d->print();
+ if (print_pc) tty->cr();
+ return;
+ }
+ if (StubRoutines::contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) stub routine", addr);
+ return;
+ }
+ // the InlineCacheBuffer is using stubs generated into a buffer blob
+ if (InlineCacheBuffer::contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT "is pointing into InlineCacheBuffer", addr);
+ return;
+ }
+ VtableStub* v = VtableStubs::stub_containing(addr);
+ if (v != NULL) {
+ v->print();
+ return;
+ }
+ }
+ if (print_pc && b->is_nmethod()) {
+ ResourceMark rm;
+ tty->print("%#p: Compiled ", addr);
+ ((nmethod*)b)->method()->print_value_on(tty);
+ tty->print(" = (CodeBlob*)" INTPTR_FORMAT, b);
+ tty->cr();
+ return;
+ }
+ if ( b->is_nmethod()) {
+ if (b->is_zombie()) {
+ tty->print_cr(INTPTR_FORMAT " is zombie nmethod", b);
+ } else if (b->is_not_entrant()) {
+ tty->print_cr(INTPTR_FORMAT " is non-entrant nmethod", b);
+ }
+ }
+ b->print();
+ return;
+ }
+
+ if (Universe::heap()->is_in_reserved(addr)) {
+ HeapWord* p = Universe::heap()->block_start(addr);
+ bool print = false;
+ // If we couldn't find it it just may mean that heap wasn't parseable
+ // See if we were just given an oop directly
+ if (p != NULL && Universe::heap()->block_is_obj(p)) {
+ print = true;
+ } else if (p == NULL && ((oopDesc*)addr)->is_oop()) {
+ p = (HeapWord*) addr;
+ print = true;
+ }
+ if (print) {
+ oop(p)->print();
+ if (p != (HeapWord*)x && oop(p)->is_constMethod() &&
+ constMethodOop(p)->contains(addr)) {
+ Thread *thread = Thread::current();
+ HandleMark hm(thread);
+ methodHandle mh (thread, constMethodOop(p)->method());
+ if (!mh->is_native()) {
+ tty->print_cr("bci_from(%p) = %d; print_codes():",
+ addr, mh->bci_from(address(x)));
+ mh->print_codes();
+ }
+ }
+ return;
+ }
+ }
+ if (JNIHandles::is_global_handle((jobject) addr)) {
+ tty->print_cr(INTPTR_FORMAT "is a global jni handle", addr);
+ return;
+ }
+ if (JNIHandles::is_weak_global_handle((jobject) addr)) {
+ tty->print_cr(INTPTR_FORMAT "is a weak global jni handle", addr);
+ return;
+ }
+ if (JNIHandleBlock::any_contains((jobject) addr)) {
+ tty->print_cr(INTPTR_FORMAT "is a local jni handle", addr);
+ return;
+ }
+
+ for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
+ // Check for priviledge stack
+ if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) {
+ tty->print_cr(INTPTR_FORMAT "is pointing into the priviledge stack for thread: " INTPTR_FORMAT, addr, thread);
+ return;
+ }
+ // If the addr is a java thread print information about that.
+ if (addr == (address)thread) {
+ thread->print();
+ return;
+ }
+ }
+
+ // Try an OS specific find
+ if (os::find(addr)) {
+ return;
+ }
+
+ if (print_pc) {
+ tty->print_cr(INTPTR_FORMAT ": probably in C++ code; check debugger", addr);
+ Disassembler::decode(same_page(addr-40,addr),same_page(addr+40,addr));
+ return;
+ }
+
+ tty->print_cr(INTPTR_FORMAT "is pointing to unknown location", addr);
+}
+
+
+class LookForRefInGenClosure : public OopsInGenClosure {
+public:
+ oop target;
+ void do_oop(oop* o) {
+ if (o != NULL && *o == target) {
+ tty->print_cr("0x%08x", o);
+ }
+ }
+};
+
+
+class LookForRefInObjectClosure : public ObjectClosure {
+private:
+ LookForRefInGenClosure look_in_object;
+public:
+ LookForRefInObjectClosure(oop target) { look_in_object.target = target; }
+ void do_object(oop obj) {
+ obj->oop_iterate(&look_in_object);
+ }
+};
+
+
+static void findref(intptr_t x) {
+ GenCollectedHeap *gch = GenCollectedHeap::heap();
+ LookForRefInGenClosure lookFor;
+ lookFor.target = (oop) x;
+ LookForRefInObjectClosure look_in_object((oop) x);
+
+ tty->print_cr("Searching heap:");
+ gch->object_iterate(&look_in_object);
+
+ tty->print_cr("Searching strong roots:");
+ Universe::oops_do(&lookFor, false);
+ JNIHandles::oops_do(&lookFor); // Global (strong) JNI handles
+ Threads::oops_do(&lookFor);
+ ObjectSynchronizer::oops_do(&lookFor);
+ //FlatProfiler::oops_do(&lookFor);
+ SystemDictionary::oops_do(&lookFor);
+
+ tty->print_cr("Done.");
+}
+
+class FindClassObjectClosure: public ObjectClosure {
+ private:
+ const char* _target;
+ public:
+ FindClassObjectClosure(const char name[]) { _target = name; }
+
+ virtual void do_object(oop obj) {
+ if (obj->is_klass()) {
+ Klass* k = klassOop(obj)->klass_part();
+ if (k->name() != NULL) {
+ ResourceMark rm;
+ const char* ext = k->external_name();
+ if ( strcmp(_target, ext) == 0 ) {
+ tty->print_cr("Found " INTPTR_FORMAT, obj);
+ obj->print();
+ }
+ }
+ }
+ }
+};
+
+//
+extern "C" void findclass(const char name[]) {
+ Command c("findclass");
+ if (name != NULL) {
+ tty->print_cr("Finding class %s -> ", name);
+ FindClassObjectClosure srch(name);
+ Universe::heap()->permanent_object_iterate(&srch);
+ }
+}
+
+// Another interface that isn't ambiguous in dbx.
+// Can we someday rename the other find to hsfind?
+extern "C" void hsfind(intptr_t x) {
+ Command c("hsfind");
+ find(x, false);
+}
+
+
+extern "C" void hsfindref(intptr_t x) {
+ Command c("hsfindref");
+ findref(x);
+}
+
+extern "C" void find(intptr_t x) {
+ Command c("find");
+ find(x, false);
+}
+
+
+extern "C" void findpc(intptr_t x) {
+ Command c("findpc");
+ find(x, true);
+}
+
+
+// int versions of all methods to avoid having to type type casts in the debugger
+
+void pp(intptr_t p) { pp((void*)p); }
+void pp(oop p) { pp((void*)p); }
+
+void help() {
+ Command c("help");
+ tty->print_cr("basic");
+ tty->print_cr(" pp(void* p) - try to make sense of p");
+ tty->print_cr(" pv(intptr_t p)- ((PrintableResourceObj*) p)->print()");
+ tty->print_cr(" ps() - print current thread stack");
+ tty->print_cr(" pss() - print all thread stacks");
+ tty->print_cr(" pm(int pc) - print methodOop given compiled PC");
+ tty->print_cr(" findm(intptr_t pc) - finds methodOop");
+ tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
+
+ tty->print_cr("misc.");
+ tty->print_cr(" flush() - flushes the log file");
+ tty->print_cr(" events() - dump last 50 events");
+
+
+ tty->print_cr("compiler debugging");
+ tty->print_cr(" debug() - to set things up for compiler debugging");
+ tty->print_cr(" ndebug() - undo debug");
+}
+
+#if 0
+
+// BobV's command parser for debugging on windows when nothing else works.
+
+enum CommandID {
+ CMDID_HELP,
+ CMDID_QUIT,
+ CMDID_HSFIND,
+ CMDID_PSS,
+ CMDID_PS,
+ CMDID_PSF,
+ CMDID_FINDM,
+ CMDID_FINDNM,
+ CMDID_PP,
+ CMDID_BPT,
+ CMDID_EXIT,
+ CMDID_VERIFY,
+ CMDID_THREADS,
+ CMDID_ILLEGAL = 99
+};
+
+struct CommandParser {
+ char *name;
+ CommandID code;
+ char *description;
+};
+
+struct CommandParser CommandList[] = {
+ (char *)"help", CMDID_HELP, " Dump this list",
+ (char *)"quit", CMDID_QUIT, " Return from this routine",
+ (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address",
+ (char *)"ps", CMDID_PS, " Print Current Thread Stack Trace",
+ (char *)"pss", CMDID_PSS, " Print All Thread Stack Trace",
+ (char *)"psf", CMDID_PSF, " Print All Stack Frames",
+ (char *)"findm", CMDID_FINDM, " Find a methodOop from a PC",
+ (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC",
+ (char *)"pp", CMDID_PP, " Find out something about a pointer",
+ (char *)"break", CMDID_BPT, " Execute a breakpoint",
+ (char *)"exitvm", CMDID_EXIT, "Exit the VM",
+ (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify",
+ (char *)"thread", CMDID_THREADS, "Dump Info on all Threads",
+ (char *)0, CMDID_ILLEGAL
+};
+
+
+// get_debug_command()
+//
+// Read a command from standard input.
+// This is useful when you have a debugger
+// which doesn't support calling into functions.
+//
+void get_debug_command()
+{
+ ssize_t count;
+ int i,j;
+ bool gotcommand;
+ intptr_t addr;
+ char buffer[256];
+ nmethod *nm;
+ methodOop m;
+
+ tty->print_cr("You have entered the diagnostic command interpreter");
+ tty->print("The supported commands are:\n");
+ for ( i=0; ; i++ ) {
+ if ( CommandList[i].code == CMDID_ILLEGAL )
+ break;
+ tty->print_cr(" %s \n", CommandList[i].name );
+ }
+
+ while ( 1 ) {
+ gotcommand = false;
+ tty->print("Please enter a command: ");
+ count = scanf("%s", buffer) ;
+ if ( count >=0 ) {
+ for ( i=0; ; i++ ) {
+ if ( CommandList[i].code == CMDID_ILLEGAL ) {
+ if (!gotcommand) tty->print("Invalid command, please try again\n");
+ break;
+ }
+ if ( strcmp(buffer, CommandList[i].name) == 0 ) {
+ gotcommand = true;
+ switch ( CommandList[i].code ) {
+ case CMDID_PS:
+ ps();
+ break;
+ case CMDID_PSS:
+ pss();
+ break;
+ case CMDID_PSF:
+ psf();
+ break;
+ case CMDID_FINDM:
+ tty->print("Please enter the hex addr to pass to findm: ");
+ scanf("%I64X", &addr);
+ m = (methodOop)findm(addr);
+ tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m);
+ break;
+ case CMDID_FINDNM:
+ tty->print("Please enter the hex addr to pass to findnm: ");
+ scanf("%I64X", &addr);
+ nm = (nmethod*)findnm(addr);
+ tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm);
+ break;
+ case CMDID_PP:
+ tty->print("Please enter the hex addr to pass to pp: ");
+ scanf("%I64X", &addr);
+ pp((void*)addr);
+ break;
+ case CMDID_EXIT:
+ exit(0);
+ case CMDID_HELP:
+ tty->print("Here are the supported commands: ");
+ for ( j=0; ; j++ ) {
+ if ( CommandList[j].code == CMDID_ILLEGAL )
+ break;
+ tty->print_cr(" %s -- %s\n", CommandList[j].name,
+ CommandList[j].description );
+ }
+ break;
+ case CMDID_QUIT:
+ return;
+ break;
+ case CMDID_BPT:
+ BREAKPOINT;
+ break;
+ case CMDID_VERIFY:
+ verify();;
+ break;
+ case CMDID_THREADS:
+ threads();;
+ break;
+ case CMDID_HSFIND:
+ tty->print("Please enter the hex addr to pass to hsfind: ");
+ scanf("%I64X", &addr);
+ tty->print("Calling hsfind(0x%I64X)\n", addr);
+ hsfind(addr);
+ break;
+ default:
+ case CMDID_ILLEGAL:
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+#endif // PRODUCT