duke@435: /* bobv@2036: * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #include "precompiled.hpp" stefank@2314: #include "classfile/systemDictionary.hpp" stefank@2314: #include "code/codeCache.hpp" stefank@2314: #include "code/icBuffer.hpp" stefank@2314: #include "code/nmethod.hpp" stefank@2314: #include "code/vtableStubs.hpp" stefank@2314: #include "compiler/compileBroker.hpp" stefank@2314: #include "compiler/disassembler.hpp" stefank@2314: #include "gc_implementation/shared/markSweep.hpp" stefank@2314: #include "gc_interface/collectedHeap.hpp" stefank@2314: #include "interpreter/bytecodeHistogram.hpp" stefank@2314: #include "interpreter/interpreter.hpp" stefank@2314: #include "memory/resourceArea.hpp" stefank@2314: #include "memory/universe.hpp" stefank@2314: #include "oops/oop.inline.hpp" stefank@2314: #include "prims/privilegedStack.hpp" stefank@2314: #include "runtime/arguments.hpp" stefank@2314: #include "runtime/frame.hpp" stefank@2314: #include "runtime/java.hpp" stefank@2314: #include "runtime/sharedRuntime.hpp" stefank@2314: #include "runtime/stubCodeGenerator.hpp" stefank@2314: #include "runtime/stubRoutines.hpp" stefank@2314: #include "runtime/vframe.hpp" stefank@2314: #include "services/heapDumper.hpp" stefank@2314: #include "utilities/defaultStream.hpp" stefank@2314: #include "utilities/events.hpp" stefank@2314: #include "utilities/top.hpp" stefank@2314: #include "utilities/vmError.hpp" stefank@2314: #ifdef TARGET_OS_FAMILY_linux stefank@2314: # include "os_linux.inline.hpp" stefank@2314: # include "thread_linux.inline.hpp" stefank@2314: #endif stefank@2314: #ifdef TARGET_OS_FAMILY_solaris stefank@2314: # include "os_solaris.inline.hpp" stefank@2314: # include "thread_solaris.inline.hpp" stefank@2314: #endif stefank@2314: #ifdef TARGET_OS_FAMILY_windows stefank@2314: # include "os_windows.inline.hpp" stefank@2314: # include "thread_windows.inline.hpp" stefank@2314: #endif duke@435: duke@435: #ifndef ASSERT duke@435: # ifdef _DEBUG duke@435: // NOTE: don't turn the lines below into a comment -- if you're getting duke@435: // a compile error here, change the settings to define ASSERT duke@435: ASSERT should be defined when _DEBUG is defined. It is not intended to be used for debugging duke@435: functions that do not slow down the system too much and thus can be left in optimized code. duke@435: On the other hand, the code should not be included in a production version. duke@435: # endif // _DEBUG duke@435: #endif // ASSERT duke@435: duke@435: duke@435: #ifdef _DEBUG duke@435: # ifndef ASSERT duke@435: configuration error: ASSERT must be defined in debug version duke@435: # endif // ASSERT duke@435: #endif // _DEBUG duke@435: duke@435: duke@435: #ifdef PRODUCT duke@435: # if -defined _DEBUG || -defined ASSERT duke@435: configuration error: ASSERT et al. must not be defined in PRODUCT version duke@435: # endif duke@435: #endif // PRODUCT duke@435: duke@435: duke@435: void warning(const char* format, ...) { kamg@2225: if (PrintWarnings) { kamg@2225: // In case error happens before init or during shutdown kamg@2225: if (tty == NULL) ostream_init(); duke@435: kamg@2225: tty->print("%s warning: ", VM_Version::vm_name()); kamg@2225: va_list ap; kamg@2225: va_start(ap, format); kamg@2225: tty->vprint_cr(format, ap); kamg@2225: va_end(ap); kamg@2225: } duke@435: if (BreakAtWarning) BREAKPOINT; duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: duke@435: #define is_token_break(ch) (isspace(ch) || (ch) == ',') duke@435: duke@435: static const char* last_file_name = NULL; duke@435: static int last_line_no = -1; duke@435: duke@435: // assert/guarantee/... may happen very early during VM initialization. duke@435: // Don't rely on anything that is initialized by Threads::create_vm(). For duke@435: // example, don't use tty. jcoomes@1845: bool error_is_suppressed(const char* file_name, int line_no) { duke@435: // The following 1-element cache requires that passed-in duke@435: // file names are always only constant literals. duke@435: if (file_name == last_file_name && line_no == last_line_no) return true; duke@435: duke@435: int file_name_len = (int)strlen(file_name); duke@435: char separator = os::file_separator()[0]; duke@435: const char* base_name = strrchr(file_name, separator); duke@435: if (base_name == NULL) duke@435: base_name = file_name; duke@435: duke@435: // scan the SuppressErrorAt option duke@435: const char* cp = SuppressErrorAt; duke@435: for (;;) { duke@435: const char* sfile; duke@435: int sfile_len; duke@435: int sline; duke@435: bool noisy; duke@435: while ((*cp) != '\0' && is_token_break(*cp)) cp++; duke@435: if ((*cp) == '\0') break; duke@435: sfile = cp; duke@435: while ((*cp) != '\0' && !is_token_break(*cp) && (*cp) != ':') cp++; duke@435: sfile_len = cp - sfile; duke@435: if ((*cp) == ':') cp++; duke@435: sline = 0; duke@435: while ((*cp) != '\0' && isdigit(*cp)) { duke@435: sline *= 10; duke@435: sline += (*cp) - '0'; duke@435: cp++; duke@435: } duke@435: // "file:line!" means the assert suppression is not silent duke@435: noisy = ((*cp) == '!'); duke@435: while ((*cp) != '\0' && !is_token_break(*cp)) cp++; duke@435: // match the line duke@435: if (sline != 0) { duke@435: if (sline != line_no) continue; duke@435: } duke@435: // match the file duke@435: if (sfile_len > 0) { duke@435: const char* look = file_name; duke@435: const char* look_max = file_name + file_name_len - sfile_len; duke@435: const char* foundp; duke@435: bool match = false; duke@435: while (!match duke@435: && (foundp = strchr(look, sfile[0])) != NULL duke@435: && foundp <= look_max) { duke@435: match = true; duke@435: for (int i = 1; i < sfile_len; i++) { duke@435: if (sfile[i] != foundp[i]) { duke@435: match = false; duke@435: break; duke@435: } duke@435: } duke@435: look = foundp + 1; duke@435: } duke@435: if (!match) continue; duke@435: } duke@435: // got a match! duke@435: if (noisy) { duke@435: fdStream out(defaultStream::output_fd()); duke@435: out.print_raw("[error suppressed at "); duke@435: out.print_raw(base_name); duke@435: char buf[16]; duke@435: jio_snprintf(buf, sizeof(buf), ":%d]", line_no); duke@435: out.print_raw_cr(buf); duke@435: } else { duke@435: // update 1-element cache for fast silent matches duke@435: last_file_name = file_name; duke@435: last_line_no = line_no; duke@435: } duke@435: return true; duke@435: } duke@435: duke@435: if (!is_error_reported()) { duke@435: // print a friendly hint: duke@435: fdStream out(defaultStream::output_fd()); duke@435: out.print_raw_cr("# To suppress the following error report, specify this argument"); duke@435: out.print_raw ("# after -XX: or in .hotspotrc: SuppressErrorAt="); duke@435: out.print_raw (base_name); duke@435: char buf[16]; duke@435: jio_snprintf(buf, sizeof(buf), ":%d", line_no); duke@435: out.print_raw_cr(buf); duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: #undef is_token_break duke@435: duke@435: #else duke@435: duke@435: // Place-holder for non-existent suppression check: jcoomes@1845: #define error_is_suppressed(file_name, line_no) (false) duke@435: duke@435: #endif //PRODUCT duke@435: jcoomes@1845: void report_vm_error(const char* file, int line, const char* error_msg, jcoomes@1845: const char* detail_msg) jcoomes@1845: { jcoomes@1845: if (Debugging || error_is_suppressed(file, line)) return; jcoomes@1845: Thread* const thread = ThreadLocalStorage::get_thread_slow(); jcoomes@1845: VMError err(thread, file, line, error_msg, detail_msg); duke@435: err.report_and_die(); duke@435: } duke@435: jcoomes@1845: void report_fatal(const char* file, int line, const char* message) jcoomes@1845: { jcoomes@1845: report_vm_error(file, line, "fatal error", message); duke@435: } duke@435: duke@435: // Used by report_vm_out_of_memory to detect recursion. duke@435: static jint _exiting_out_of_mem = 0; duke@435: jcoomes@1845: void report_vm_out_of_memory(const char* file, int line, size_t size, jcoomes@1845: const char* message) { coleenp@2418: if (Debugging) return; duke@435: duke@435: // We try to gather additional information for the first out of memory duke@435: // error only; gathering additional data might cause an allocation and a duke@435: // recursive out_of_memory condition. duke@435: duke@435: const jint exiting = 1; duke@435: // If we succeed in changing the value, we're the first one in. duke@435: bool first_time_here = Atomic::xchg(exiting, &_exiting_out_of_mem) != exiting; duke@435: duke@435: if (first_time_here) { duke@435: Thread* thread = ThreadLocalStorage::get_thread_slow(); jcoomes@1845: VMError(thread, file, line, size, message).report_and_die(); duke@435: } poonam@662: poonam@662: // Dump core and abort poonam@662: vm_abort(true); duke@435: } duke@435: jcoomes@1845: void report_should_not_call(const char* file, int line) { jcoomes@1845: report_vm_error(file, line, "ShouldNotCall()"); duke@435: } duke@435: jcoomes@1845: void report_should_not_reach_here(const char* file, int line) { jcoomes@1845: report_vm_error(file, line, "ShouldNotReachHere()"); duke@435: } duke@435: jcoomes@1845: void report_unimplemented(const char* file, int line) { jcoomes@1845: report_vm_error(file, line, "Unimplemented()"); duke@435: } duke@435: jcoomes@1845: void report_untested(const char* file, int line, const char* message) { duke@435: #ifndef PRODUCT jcoomes@1845: warning("Untested: %s in %s: %d\n", message, file, line); duke@435: #endif // PRODUCT duke@435: } duke@435: duke@435: void report_java_out_of_memory(const char* message) { duke@435: static jint out_of_memory_reported = 0; duke@435: duke@435: // A number of threads may attempt to report OutOfMemoryError at around the duke@435: // same time. To avoid dumping the heap or executing the data collection duke@435: // commands multiple times we just do it once when the first threads reports duke@435: // the error. duke@435: if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) { duke@435: // create heap dump before OnOutOfMemoryError commands are executed duke@435: if (HeapDumpOnOutOfMemoryError) { duke@435: tty->print_cr("java.lang.OutOfMemoryError: %s", message); thurka@2130: HeapDumper::dump_heap_from_oome(); duke@435: } duke@435: duke@435: if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { duke@435: VMError err(message); duke@435: err.report_java_out_of_memory(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: extern "C" void ps(); duke@435: duke@435: static bool error_reported = false; duke@435: duke@435: // call this when the VM is dying--it might loosen some asserts duke@435: void set_error_reported() { duke@435: error_reported = true; duke@435: } duke@435: duke@435: bool is_error_reported() { duke@435: return error_reported; duke@435: } duke@435: jcoomes@1845: #ifndef PRODUCT jcoomes@1845: #include jcoomes@1845: jcoomes@1845: void test_error_handler(size_t test_num) jcoomes@1845: { jcoomes@1845: if (test_num == 0) return; jcoomes@1845: jcoomes@1845: // If asserts are disabled, use the corresponding guarantee instead. jcoomes@1845: size_t n = test_num; jcoomes@1845: NOT_DEBUG(if (n <= 2) n += 2); jcoomes@1845: jcoomes@1845: const char* const str = "hello"; jcoomes@1845: const size_t num = (size_t)os::vm_page_size(); jcoomes@1845: jcoomes@1845: const char* const eol = os::line_separator(); jcoomes@1845: const char* const msg = "this message should be truncated during formatting"; jcoomes@1845: jcoomes@1845: // Keep this in sync with test/runtime/6888954/vmerrors.sh. jcoomes@1845: switch (n) { jcoomes@1845: case 1: assert(str == NULL, "expected null"); jcoomes@1845: case 2: assert(num == 1023 && *str == 'X', jcoomes@1845: err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); jcoomes@1845: case 3: guarantee(str == NULL, "expected null"); jcoomes@1845: case 4: guarantee(num == 1023 && *str == 'X', jcoomes@1845: err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); jcoomes@1845: case 5: fatal("expected null"); jcoomes@1845: case 6: fatal(err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); jcoomes@1845: case 7: fatal(err_msg("%s%s# %s%s# %s%s# %s%s# %s%s# " jcoomes@1845: "%s%s# %s%s# %s%s# %s%s# %s%s# " jcoomes@1845: "%s%s# %s%s# %s%s# %s%s# %s", jcoomes@1845: msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, jcoomes@1845: msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, jcoomes@1845: msg, eol, msg, eol, msg, eol, msg, eol, msg)); jcoomes@1845: case 8: vm_exit_out_of_memory(num, "ChunkPool::allocate"); jcoomes@1845: case 9: ShouldNotCallThis(); jcoomes@1845: case 10: ShouldNotReachHere(); jcoomes@1845: case 11: Unimplemented(); jcoomes@1845: // This is last because it does not generate an hs_err* file on Windows. jcoomes@1845: case 12: os::signal_raise(SIGSEGV); jcoomes@1845: jcoomes@1845: default: ShouldNotReachHere(); jcoomes@1845: } jcoomes@1845: } jcoomes@1845: #endif // #ifndef PRODUCT jcoomes@1845: duke@435: // ------ helper functions for debugging go here ------------ duke@435: duke@435: #ifndef PRODUCT duke@435: // All debug entries should be wrapped with a stack allocated duke@435: // Command object. It makes sure a resource mark is set and duke@435: // flushes the logfile to prevent file sharing problems. duke@435: duke@435: class Command : public StackObj { duke@435: private: duke@435: ResourceMark rm; duke@435: ResetNoHandleMark rnhm; duke@435: HandleMark hm; duke@435: bool debug_save; duke@435: public: duke@435: static int level; duke@435: Command(const char* str) { duke@435: debug_save = Debugging; duke@435: Debugging = true; duke@435: if (level++ > 0) return; duke@435: tty->cr(); duke@435: tty->print_cr("\"Executing %s\"", str); duke@435: } duke@435: duke@435: ~Command() { tty->flush(); Debugging = debug_save; level--; } duke@435: }; duke@435: duke@435: int Command::level = 0; duke@435: duke@435: extern "C" void blob(CodeBlob* cb) { duke@435: Command c("blob"); duke@435: cb->print(); duke@435: } duke@435: duke@435: duke@435: extern "C" void dump_vtable(address p) { duke@435: Command c("dump_vtable"); duke@435: klassOop k = (klassOop)p; duke@435: instanceKlass::cast(k)->vtable()->print(); duke@435: } duke@435: duke@435: duke@435: extern "C" void nm(intptr_t p) { duke@435: // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatability) duke@435: Command c("nm"); duke@435: CodeBlob* cb = CodeCache::find_blob((address)p); duke@435: if (cb == NULL) { duke@435: tty->print_cr("NULL"); duke@435: } else { duke@435: cb->print(); duke@435: } duke@435: } duke@435: duke@435: duke@435: extern "C" void disnm(intptr_t p) { duke@435: Command c("disnm"); duke@435: CodeBlob* cb = CodeCache::find_blob((address) p); twisti@2350: nmethod* nm = cb->as_nmethod_or_null(); twisti@2350: if (nm) { twisti@2350: nm->print(); twisti@2350: Disassembler::decode(nm); twisti@2350: } else { twisti@2350: cb->print(); twisti@2350: Disassembler::decode(cb); twisti@2350: } duke@435: } duke@435: duke@435: duke@435: extern "C" void printnm(intptr_t p) { duke@435: char buffer[256]; duke@435: sprintf(buffer, "printnm: " INTPTR_FORMAT, p); duke@435: Command c(buffer); duke@435: CodeBlob* cb = CodeCache::find_blob((address) p); duke@435: if (cb->is_nmethod()) { duke@435: nmethod* nm = (nmethod*)cb; duke@435: nm->print_nmethod(true); duke@435: } duke@435: } duke@435: duke@435: duke@435: extern "C" void universe() { duke@435: Command c("universe"); duke@435: Universe::print(); duke@435: } duke@435: duke@435: duke@435: extern "C" void verify() { duke@435: // try to run a verify on the entire system duke@435: // note: this may not be safe if we're not at a safepoint; for debugging, duke@435: // this manipulates the safepoint settings to avoid assertion failures duke@435: Command c("universe verify"); duke@435: bool safe = SafepointSynchronize::is_at_safepoint(); duke@435: if (!safe) { duke@435: tty->print_cr("warning: not at safepoint -- verify may fail"); duke@435: SafepointSynchronize::set_is_at_safepoint(); duke@435: } duke@435: // Ensure Eden top is correct before verification duke@435: Universe::heap()->prepare_for_verify(); duke@435: Universe::verify(true); duke@435: if (!safe) SafepointSynchronize::set_is_not_at_safepoint(); duke@435: } duke@435: duke@435: duke@435: extern "C" void pp(void* p) { duke@435: Command c("pp"); duke@435: FlagSetting fl(PrintVMMessages, true); duke@435: if (Universe::heap()->is_in(p)) { duke@435: oop obj = oop(p); duke@435: obj->print(); duke@435: } else { duke@435: tty->print("%#p", p); duke@435: } duke@435: } duke@435: duke@435: duke@435: // pv: print vm-printable object duke@435: extern "C" void pa(intptr_t p) { ((AllocatedObj*) p)->print(); } duke@435: extern "C" void findpc(intptr_t x); duke@435: duke@435: extern "C" void ps() { // print stack duke@435: Command c("ps"); duke@435: duke@435: duke@435: // Prints the stack of the current Java thread duke@435: JavaThread* p = JavaThread::active(); duke@435: tty->print(" for thread: "); duke@435: p->print(); duke@435: tty->cr(); duke@435: duke@435: if (p->has_last_Java_frame()) { duke@435: // If the last_Java_fp is set we are in C land and duke@435: // can call the standard stack_trace function. duke@435: p->trace_stack(); duke@435: } else { duke@435: frame f = os::current_frame(); duke@435: RegisterMap reg_map(p); duke@435: f = f.sender(®_map); duke@435: tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id()); duke@435: p->trace_stack_from(vframe::new_vframe(&f, ®_map, p)); duke@435: pd_ps(f); duke@435: } duke@435: duke@435: } duke@435: duke@435: duke@435: extern "C" void psf() { // print stack frames duke@435: { duke@435: Command c("psf"); duke@435: JavaThread* p = JavaThread::active(); duke@435: tty->print(" for thread: "); duke@435: p->print(); duke@435: tty->cr(); duke@435: if (p->has_last_Java_frame()) { duke@435: p->trace_frames(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: extern "C" void threads() { duke@435: Command c("threads"); duke@435: Threads::print(false, true); duke@435: } duke@435: duke@435: duke@435: extern "C" void psd() { duke@435: Command c("psd"); duke@435: SystemDictionary::print(); duke@435: } duke@435: duke@435: duke@435: extern "C" void safepoints() { duke@435: Command c("safepoints"); duke@435: SafepointSynchronize::print_state(); duke@435: } duke@435: duke@435: duke@435: extern "C" void pss() { // print all stacks duke@435: Command c("pss"); duke@435: Threads::print(true, true); duke@435: } duke@435: duke@435: duke@435: extern "C" void debug() { // to set things up for compiler debugging duke@435: Command c("debug"); duke@435: WizardMode = true; duke@435: PrintVMMessages = PrintCompilation = true; duke@435: PrintInlining = PrintAssembly = true; duke@435: tty->flush(); duke@435: } duke@435: duke@435: duke@435: extern "C" void ndebug() { // undo debug() duke@435: Command c("ndebug"); duke@435: PrintCompilation = false; duke@435: PrintInlining = PrintAssembly = false; duke@435: tty->flush(); duke@435: } duke@435: duke@435: duke@435: extern "C" void flush() { duke@435: Command c("flush"); duke@435: tty->flush(); duke@435: } duke@435: duke@435: duke@435: extern "C" void events() { duke@435: Command c("events"); duke@435: Events::print_last(tty, 50); duke@435: } duke@435: duke@435: duke@435: extern "C" void nevents(int n) { duke@435: Command c("events"); duke@435: Events::print_last(tty, n); duke@435: } duke@435: duke@435: duke@435: // Given a heap address that was valid before the most recent GC, if duke@435: // the oop that used to contain it is still live, prints the new duke@435: // location of the oop and the address. Useful for tracking down duke@435: // certain kinds of naked oop and oop map bugs. duke@435: extern "C" void pnl(intptr_t old_heap_addr) { duke@435: // Print New Location of old heap address duke@435: Command c("pnl"); duke@435: #ifndef VALIDATE_MARK_SWEEP duke@435: tty->print_cr("Requires build with VALIDATE_MARK_SWEEP defined (debug build) and RecordMarkSweepCompaction enabled"); duke@435: #else duke@435: MarkSweep::print_new_location_of_heap_address((HeapWord*) old_heap_addr); duke@435: #endif duke@435: } duke@435: duke@435: duke@435: extern "C" methodOop findm(intptr_t pc) { duke@435: Command c("findm"); duke@435: nmethod* nm = CodeCache::find_nmethod((address)pc); duke@435: return (nm == NULL) ? (methodOop)NULL : nm->method(); duke@435: } duke@435: duke@435: duke@435: extern "C" nmethod* findnm(intptr_t addr) { duke@435: Command c("findnm"); duke@435: return CodeCache::find_nmethod((address)addr); duke@435: } duke@435: duke@435: static address same_page(address x, address y) { duke@435: intptr_t page_bits = -os::vm_page_size(); duke@435: if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) { duke@435: return x; duke@435: } else if (x > y) { duke@435: return (address)(intptr_t(y) | ~page_bits) + 1; duke@435: } else { duke@435: return (address)(intptr_t(y) & page_bits); duke@435: } duke@435: } duke@435: duke@435: class LookForRefInGenClosure : public OopsInGenClosure { duke@435: public: duke@435: oop target; duke@435: void do_oop(oop* o) { duke@435: if (o != NULL && *o == target) { ysr@777: tty->print_cr(INTPTR_FORMAT, o); duke@435: } duke@435: } coleenp@548: void do_oop(narrowOop* o) { ShouldNotReachHere(); } duke@435: }; duke@435: duke@435: duke@435: class LookForRefInObjectClosure : public ObjectClosure { duke@435: private: duke@435: LookForRefInGenClosure look_in_object; duke@435: public: duke@435: LookForRefInObjectClosure(oop target) { look_in_object.target = target; } duke@435: void do_object(oop obj) { duke@435: obj->oop_iterate(&look_in_object); duke@435: } duke@435: }; duke@435: duke@435: duke@435: static void findref(intptr_t x) { ysr@777: CollectedHeap *ch = Universe::heap(); duke@435: LookForRefInGenClosure lookFor; duke@435: lookFor.target = (oop) x; duke@435: LookForRefInObjectClosure look_in_object((oop) x); duke@435: duke@435: tty->print_cr("Searching heap:"); ysr@777: ch->object_iterate(&look_in_object); duke@435: duke@435: tty->print_cr("Searching strong roots:"); duke@435: Universe::oops_do(&lookFor, false); duke@435: JNIHandles::oops_do(&lookFor); // Global (strong) JNI handles jrose@1424: Threads::oops_do(&lookFor, NULL); duke@435: ObjectSynchronizer::oops_do(&lookFor); duke@435: //FlatProfiler::oops_do(&lookFor); duke@435: SystemDictionary::oops_do(&lookFor); duke@435: jrose@1424: tty->print_cr("Searching code cache:"); jrose@1424: CodeCache::oops_do(&lookFor); jrose@1424: duke@435: tty->print_cr("Done."); duke@435: } duke@435: duke@435: class FindClassObjectClosure: public ObjectClosure { duke@435: private: duke@435: const char* _target; duke@435: public: duke@435: FindClassObjectClosure(const char name[]) { _target = name; } duke@435: duke@435: virtual void do_object(oop obj) { duke@435: if (obj->is_klass()) { duke@435: Klass* k = klassOop(obj)->klass_part(); duke@435: if (k->name() != NULL) { duke@435: ResourceMark rm; duke@435: const char* ext = k->external_name(); duke@435: if ( strcmp(_target, ext) == 0 ) { duke@435: tty->print_cr("Found " INTPTR_FORMAT, obj); duke@435: obj->print(); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: }; duke@435: duke@435: // duke@435: extern "C" void findclass(const char name[]) { duke@435: Command c("findclass"); duke@435: if (name != NULL) { duke@435: tty->print_cr("Finding class %s -> ", name); duke@435: FindClassObjectClosure srch(name); duke@435: Universe::heap()->permanent_object_iterate(&srch); duke@435: } duke@435: } duke@435: duke@435: // Another interface that isn't ambiguous in dbx. duke@435: // Can we someday rename the other find to hsfind? duke@435: extern "C" void hsfind(intptr_t x) { duke@435: Command c("hsfind"); bobv@2036: os::print_location(tty, x, false); duke@435: } duke@435: duke@435: duke@435: extern "C" void hsfindref(intptr_t x) { duke@435: Command c("hsfindref"); duke@435: findref(x); duke@435: } duke@435: duke@435: extern "C" void find(intptr_t x) { duke@435: Command c("find"); bobv@2036: os::print_location(tty, x, false); duke@435: } duke@435: duke@435: duke@435: extern "C" void findpc(intptr_t x) { duke@435: Command c("findpc"); bobv@2036: os::print_location(tty, x, true); duke@435: } duke@435: duke@435: duke@435: // int versions of all methods to avoid having to type type casts in the debugger duke@435: duke@435: void pp(intptr_t p) { pp((void*)p); } duke@435: void pp(oop p) { pp((void*)p); } duke@435: duke@435: void help() { duke@435: Command c("help"); duke@435: tty->print_cr("basic"); duke@435: tty->print_cr(" pp(void* p) - try to make sense of p"); duke@435: tty->print_cr(" pv(intptr_t p)- ((PrintableResourceObj*) p)->print()"); duke@435: tty->print_cr(" ps() - print current thread stack"); duke@435: tty->print_cr(" pss() - print all thread stacks"); duke@435: tty->print_cr(" pm(int pc) - print methodOop given compiled PC"); duke@435: tty->print_cr(" findm(intptr_t pc) - finds methodOop"); duke@435: tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it"); duke@435: duke@435: tty->print_cr("misc."); duke@435: tty->print_cr(" flush() - flushes the log file"); duke@435: tty->print_cr(" events() - dump last 50 events"); duke@435: duke@435: duke@435: tty->print_cr("compiler debugging"); duke@435: tty->print_cr(" debug() - to set things up for compiler debugging"); duke@435: tty->print_cr(" ndebug() - undo debug"); duke@435: } duke@435: duke@435: #if 0 duke@435: duke@435: // BobV's command parser for debugging on windows when nothing else works. duke@435: duke@435: enum CommandID { duke@435: CMDID_HELP, duke@435: CMDID_QUIT, duke@435: CMDID_HSFIND, duke@435: CMDID_PSS, duke@435: CMDID_PS, duke@435: CMDID_PSF, duke@435: CMDID_FINDM, duke@435: CMDID_FINDNM, duke@435: CMDID_PP, duke@435: CMDID_BPT, duke@435: CMDID_EXIT, duke@435: CMDID_VERIFY, duke@435: CMDID_THREADS, duke@435: CMDID_ILLEGAL = 99 duke@435: }; duke@435: duke@435: struct CommandParser { duke@435: char *name; duke@435: CommandID code; duke@435: char *description; duke@435: }; duke@435: duke@435: struct CommandParser CommandList[] = { duke@435: (char *)"help", CMDID_HELP, " Dump this list", duke@435: (char *)"quit", CMDID_QUIT, " Return from this routine", duke@435: (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address", duke@435: (char *)"ps", CMDID_PS, " Print Current Thread Stack Trace", duke@435: (char *)"pss", CMDID_PSS, " Print All Thread Stack Trace", duke@435: (char *)"psf", CMDID_PSF, " Print All Stack Frames", duke@435: (char *)"findm", CMDID_FINDM, " Find a methodOop from a PC", duke@435: (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC", duke@435: (char *)"pp", CMDID_PP, " Find out something about a pointer", duke@435: (char *)"break", CMDID_BPT, " Execute a breakpoint", duke@435: (char *)"exitvm", CMDID_EXIT, "Exit the VM", duke@435: (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify", duke@435: (char *)"thread", CMDID_THREADS, "Dump Info on all Threads", duke@435: (char *)0, CMDID_ILLEGAL duke@435: }; duke@435: duke@435: duke@435: // get_debug_command() duke@435: // duke@435: // Read a command from standard input. duke@435: // This is useful when you have a debugger duke@435: // which doesn't support calling into functions. duke@435: // duke@435: void get_debug_command() duke@435: { duke@435: ssize_t count; duke@435: int i,j; duke@435: bool gotcommand; duke@435: intptr_t addr; duke@435: char buffer[256]; duke@435: nmethod *nm; duke@435: methodOop m; duke@435: duke@435: tty->print_cr("You have entered the diagnostic command interpreter"); duke@435: tty->print("The supported commands are:\n"); duke@435: for ( i=0; ; i++ ) { duke@435: if ( CommandList[i].code == CMDID_ILLEGAL ) duke@435: break; duke@435: tty->print_cr(" %s \n", CommandList[i].name ); duke@435: } duke@435: duke@435: while ( 1 ) { duke@435: gotcommand = false; duke@435: tty->print("Please enter a command: "); duke@435: count = scanf("%s", buffer) ; duke@435: if ( count >=0 ) { duke@435: for ( i=0; ; i++ ) { duke@435: if ( CommandList[i].code == CMDID_ILLEGAL ) { duke@435: if (!gotcommand) tty->print("Invalid command, please try again\n"); duke@435: break; duke@435: } duke@435: if ( strcmp(buffer, CommandList[i].name) == 0 ) { duke@435: gotcommand = true; duke@435: switch ( CommandList[i].code ) { duke@435: case CMDID_PS: duke@435: ps(); duke@435: break; duke@435: case CMDID_PSS: duke@435: pss(); duke@435: break; duke@435: case CMDID_PSF: duke@435: psf(); duke@435: break; duke@435: case CMDID_FINDM: duke@435: tty->print("Please enter the hex addr to pass to findm: "); duke@435: scanf("%I64X", &addr); duke@435: m = (methodOop)findm(addr); duke@435: tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m); duke@435: break; duke@435: case CMDID_FINDNM: duke@435: tty->print("Please enter the hex addr to pass to findnm: "); duke@435: scanf("%I64X", &addr); duke@435: nm = (nmethod*)findnm(addr); duke@435: tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm); duke@435: break; duke@435: case CMDID_PP: duke@435: tty->print("Please enter the hex addr to pass to pp: "); duke@435: scanf("%I64X", &addr); duke@435: pp((void*)addr); duke@435: break; duke@435: case CMDID_EXIT: duke@435: exit(0); duke@435: case CMDID_HELP: duke@435: tty->print("Here are the supported commands: "); duke@435: for ( j=0; ; j++ ) { duke@435: if ( CommandList[j].code == CMDID_ILLEGAL ) duke@435: break; duke@435: tty->print_cr(" %s -- %s\n", CommandList[j].name, duke@435: CommandList[j].description ); duke@435: } duke@435: break; duke@435: case CMDID_QUIT: duke@435: return; duke@435: break; duke@435: case CMDID_BPT: duke@435: BREAKPOINT; duke@435: break; duke@435: case CMDID_VERIFY: duke@435: verify();; duke@435: break; duke@435: case CMDID_THREADS: duke@435: threads();; duke@435: break; duke@435: case CMDID_HSFIND: duke@435: tty->print("Please enter the hex addr to pass to hsfind: "); duke@435: scanf("%I64X", &addr); duke@435: tty->print("Calling hsfind(0x%I64X)\n", addr); duke@435: hsfind(addr); duke@435: break; duke@435: default: duke@435: case CMDID_ILLEGAL: duke@435: break; duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } duke@435: #endif duke@435: duke@435: #endif // PRODUCT