debug.cpp revision 2273:1d1603768966
1/* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25#include "precompiled.hpp" 26#include "classfile/systemDictionary.hpp" 27#include "code/codeCache.hpp" 28#include "code/icBuffer.hpp" 29#include "code/nmethod.hpp" 30#include "code/vtableStubs.hpp" 31#include "compiler/compileBroker.hpp" 32#include "compiler/disassembler.hpp" 33#include "gc_implementation/shared/markSweep.hpp" 34#include "gc_interface/collectedHeap.hpp" 35#include "interpreter/bytecodeHistogram.hpp" 36#include "interpreter/interpreter.hpp" 37#include "memory/resourceArea.hpp" 38#include "memory/universe.hpp" 39#include "oops/oop.inline.hpp" 40#include "prims/privilegedStack.hpp" 41#include "runtime/arguments.hpp" 42#include "runtime/frame.hpp" 43#include "runtime/java.hpp" 44#include "runtime/sharedRuntime.hpp" 45#include "runtime/stubCodeGenerator.hpp" 46#include "runtime/stubRoutines.hpp" 47#include "runtime/vframe.hpp" 48#include "services/heapDumper.hpp" 49#include "utilities/defaultStream.hpp" 50#include "utilities/events.hpp" 51#include "utilities/top.hpp" 52#include "utilities/vmError.hpp" 53#ifdef TARGET_OS_FAMILY_linux 54# include "os_linux.inline.hpp" 55# include "thread_linux.inline.hpp" 56#endif 57#ifdef TARGET_OS_FAMILY_solaris 58# include "os_solaris.inline.hpp" 59# include "thread_solaris.inline.hpp" 60#endif 61#ifdef TARGET_OS_FAMILY_windows 62# include "os_windows.inline.hpp" 63# include "thread_windows.inline.hpp" 64#endif 65 66#ifndef ASSERT 67# ifdef _DEBUG 68 // NOTE: don't turn the lines below into a comment -- if you're getting 69 // a compile error here, change the settings to define ASSERT 70 ASSERT should be defined when _DEBUG is defined. It is not intended to be used for debugging 71 functions that do not slow down the system too much and thus can be left in optimized code. 72 On the other hand, the code should not be included in a production version. 73# endif // _DEBUG 74#endif // ASSERT 75 76 77#ifdef _DEBUG 78# ifndef ASSERT 79 configuration error: ASSERT must be defined in debug version 80# endif // ASSERT 81#endif // _DEBUG 82 83 84#ifdef PRODUCT 85# if -defined _DEBUG || -defined ASSERT 86 configuration error: ASSERT et al. must not be defined in PRODUCT version 87# endif 88#endif // PRODUCT 89 90 91void warning(const char* format, ...) { 92 if (PrintWarnings) { 93 // In case error happens before init or during shutdown 94 if (tty == NULL) ostream_init(); 95 96 tty->print("%s warning: ", VM_Version::vm_name()); 97 va_list ap; 98 va_start(ap, format); 99 tty->vprint_cr(format, ap); 100 va_end(ap); 101 } 102 if (BreakAtWarning) BREAKPOINT; 103} 104 105#ifndef PRODUCT 106 107#define is_token_break(ch) (isspace(ch) || (ch) == ',') 108 109static const char* last_file_name = NULL; 110static int last_line_no = -1; 111 112// assert/guarantee/... may happen very early during VM initialization. 113// Don't rely on anything that is initialized by Threads::create_vm(). For 114// example, don't use tty. 115bool error_is_suppressed(const char* file_name, int line_no) { 116 // The following 1-element cache requires that passed-in 117 // file names are always only constant literals. 118 if (file_name == last_file_name && line_no == last_line_no) return true; 119 120 int file_name_len = (int)strlen(file_name); 121 char separator = os::file_separator()[0]; 122 const char* base_name = strrchr(file_name, separator); 123 if (base_name == NULL) 124 base_name = file_name; 125 126 // scan the SuppressErrorAt option 127 const char* cp = SuppressErrorAt; 128 for (;;) { 129 const char* sfile; 130 int sfile_len; 131 int sline; 132 bool noisy; 133 while ((*cp) != '\0' && is_token_break(*cp)) cp++; 134 if ((*cp) == '\0') break; 135 sfile = cp; 136 while ((*cp) != '\0' && !is_token_break(*cp) && (*cp) != ':') cp++; 137 sfile_len = cp - sfile; 138 if ((*cp) == ':') cp++; 139 sline = 0; 140 while ((*cp) != '\0' && isdigit(*cp)) { 141 sline *= 10; 142 sline += (*cp) - '0'; 143 cp++; 144 } 145 // "file:line!" means the assert suppression is not silent 146 noisy = ((*cp) == '!'); 147 while ((*cp) != '\0' && !is_token_break(*cp)) cp++; 148 // match the line 149 if (sline != 0) { 150 if (sline != line_no) continue; 151 } 152 // match the file 153 if (sfile_len > 0) { 154 const char* look = file_name; 155 const char* look_max = file_name + file_name_len - sfile_len; 156 const char* foundp; 157 bool match = false; 158 while (!match 159 && (foundp = strchr(look, sfile[0])) != NULL 160 && foundp <= look_max) { 161 match = true; 162 for (int i = 1; i < sfile_len; i++) { 163 if (sfile[i] != foundp[i]) { 164 match = false; 165 break; 166 } 167 } 168 look = foundp + 1; 169 } 170 if (!match) continue; 171 } 172 // got a match! 173 if (noisy) { 174 fdStream out(defaultStream::output_fd()); 175 out.print_raw("[error suppressed at "); 176 out.print_raw(base_name); 177 char buf[16]; 178 jio_snprintf(buf, sizeof(buf), ":%d]", line_no); 179 out.print_raw_cr(buf); 180 } else { 181 // update 1-element cache for fast silent matches 182 last_file_name = file_name; 183 last_line_no = line_no; 184 } 185 return true; 186 } 187 188 if (!is_error_reported()) { 189 // print a friendly hint: 190 fdStream out(defaultStream::output_fd()); 191 out.print_raw_cr("# To suppress the following error report, specify this argument"); 192 out.print_raw ("# after -XX: or in .hotspotrc: SuppressErrorAt="); 193 out.print_raw (base_name); 194 char buf[16]; 195 jio_snprintf(buf, sizeof(buf), ":%d", line_no); 196 out.print_raw_cr(buf); 197 } 198 return false; 199} 200 201#undef is_token_break 202 203#else 204 205// Place-holder for non-existent suppression check: 206#define error_is_suppressed(file_name, line_no) (false) 207 208#endif //PRODUCT 209 210void report_vm_error(const char* file, int line, const char* error_msg, 211 const char* detail_msg) 212{ 213 if (Debugging || error_is_suppressed(file, line)) return; 214 Thread* const thread = ThreadLocalStorage::get_thread_slow(); 215 VMError err(thread, file, line, error_msg, detail_msg); 216 err.report_and_die(); 217} 218 219void report_fatal(const char* file, int line, const char* message) 220{ 221 report_vm_error(file, line, "fatal error", message); 222} 223 224// Used by report_vm_out_of_memory to detect recursion. 225static jint _exiting_out_of_mem = 0; 226 227void report_vm_out_of_memory(const char* file, int line, size_t size, 228 const char* message) { 229 if (Debugging) return; 230 231 // We try to gather additional information for the first out of memory 232 // error only; gathering additional data might cause an allocation and a 233 // recursive out_of_memory condition. 234 235 const jint exiting = 1; 236 // If we succeed in changing the value, we're the first one in. 237 bool first_time_here = Atomic::xchg(exiting, &_exiting_out_of_mem) != exiting; 238 239 if (first_time_here) { 240 Thread* thread = ThreadLocalStorage::get_thread_slow(); 241 VMError(thread, file, line, size, message).report_and_die(); 242 } 243 244 // Dump core and abort 245 vm_abort(true); 246} 247 248void report_should_not_call(const char* file, int line) { 249 report_vm_error(file, line, "ShouldNotCall()"); 250} 251 252void report_should_not_reach_here(const char* file, int line) { 253 report_vm_error(file, line, "ShouldNotReachHere()"); 254} 255 256void report_unimplemented(const char* file, int line) { 257 report_vm_error(file, line, "Unimplemented()"); 258} 259 260void report_untested(const char* file, int line, const char* message) { 261#ifndef PRODUCT 262 warning("Untested: %s in %s: %d\n", message, file, line); 263#endif // PRODUCT 264} 265 266void report_out_of_shared_space(SharedSpaceType shared_space) { 267 static const char* name[] = { 268 "permanent generation", 269 "shared read only space", 270 "shared read write space", 271 "shared miscellaneous data space" 272 }; 273 static const char* flag[] = { 274 "PermGen", 275 "SharedReadOnlySize", 276 "SharedReadWriteSize", 277 "SharedMiscDataSize" 278 }; 279 280 warning("\nThe %s is not large enough\n" 281 "to preload requested classes. Use -XX:%s=\n" 282 "to increase the initial size of %s.\n", 283 name[shared_space], flag[shared_space], name[shared_space]); 284 exit(2); 285} 286 287void report_java_out_of_memory(const char* message) { 288 static jint out_of_memory_reported = 0; 289 290 // A number of threads may attempt to report OutOfMemoryError at around the 291 // same time. To avoid dumping the heap or executing the data collection 292 // commands multiple times we just do it once when the first threads reports 293 // the error. 294 if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) { 295 // create heap dump before OnOutOfMemoryError commands are executed 296 if (HeapDumpOnOutOfMemoryError) { 297 tty->print_cr("java.lang.OutOfMemoryError: %s", message); 298 HeapDumper::dump_heap_from_oome(); 299 } 300 301 if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { 302 VMError err(message); 303 err.report_java_out_of_memory(); 304 } 305 } 306} 307 308 309extern "C" void ps(); 310 311static bool error_reported = false; 312 313// call this when the VM is dying--it might loosen some asserts 314void set_error_reported() { 315 error_reported = true; 316} 317 318bool is_error_reported() { 319 return error_reported; 320} 321 322#ifndef PRODUCT 323#include <signal.h> 324 325void test_error_handler(size_t test_num) 326{ 327 if (test_num == 0) return; 328 329 // If asserts are disabled, use the corresponding guarantee instead. 330 size_t n = test_num; 331 NOT_DEBUG(if (n <= 2) n += 2); 332 333 const char* const str = "hello"; 334 const size_t num = (size_t)os::vm_page_size(); 335 336 const char* const eol = os::line_separator(); 337 const char* const msg = "this message should be truncated during formatting"; 338 339 // Keep this in sync with test/runtime/6888954/vmerrors.sh. 340 switch (n) { 341 case 1: assert(str == NULL, "expected null"); 342 case 2: assert(num == 1023 && *str == 'X', 343 err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); 344 case 3: guarantee(str == NULL, "expected null"); 345 case 4: guarantee(num == 1023 && *str == 'X', 346 err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); 347 case 5: fatal("expected null"); 348 case 6: fatal(err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); 349 case 7: fatal(err_msg("%s%s# %s%s# %s%s# %s%s# %s%s# " 350 "%s%s# %s%s# %s%s# %s%s# %s%s# " 351 "%s%s# %s%s# %s%s# %s%s# %s", 352 msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, 353 msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, 354 msg, eol, msg, eol, msg, eol, msg, eol, msg)); 355 case 8: vm_exit_out_of_memory(num, "ChunkPool::allocate"); 356 case 9: ShouldNotCallThis(); 357 case 10: ShouldNotReachHere(); 358 case 11: Unimplemented(); 359 // This is last because it does not generate an hs_err* file on Windows. 360 case 12: os::signal_raise(SIGSEGV); 361 362 default: ShouldNotReachHere(); 363 } 364} 365#endif // #ifndef PRODUCT 366 367// ------ helper functions for debugging go here ------------ 368 369#ifndef PRODUCT 370// All debug entries should be wrapped with a stack allocated 371// Command object. It makes sure a resource mark is set and 372// flushes the logfile to prevent file sharing problems. 373 374class Command : public StackObj { 375 private: 376 ResourceMark rm; 377 ResetNoHandleMark rnhm; 378 HandleMark hm; 379 bool debug_save; 380 public: 381 static int level; 382 Command(const char* str) { 383 debug_save = Debugging; 384 Debugging = true; 385 if (level++ > 0) return; 386 tty->cr(); 387 tty->print_cr("\"Executing %s\"", str); 388 } 389 390 ~Command() { tty->flush(); Debugging = debug_save; level--; } 391}; 392 393int Command::level = 0; 394 395extern "C" void blob(CodeBlob* cb) { 396 Command c("blob"); 397 cb->print(); 398} 399 400 401extern "C" void dump_vtable(address p) { 402 Command c("dump_vtable"); 403 klassOop k = (klassOop)p; 404 instanceKlass::cast(k)->vtable()->print(); 405} 406 407 408extern "C" void nm(intptr_t p) { 409 // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatability) 410 Command c("nm"); 411 CodeBlob* cb = CodeCache::find_blob((address)p); 412 if (cb == NULL) { 413 tty->print_cr("NULL"); 414 } else { 415 cb->print(); 416 } 417} 418 419 420extern "C" void disnm(intptr_t p) { 421 Command c("disnm"); 422 CodeBlob* cb = CodeCache::find_blob((address) p); 423 nmethod* nm = cb->as_nmethod_or_null(); 424 if (nm) { 425 nm->print(); 426 Disassembler::decode(nm); 427 } else { 428 cb->print(); 429 Disassembler::decode(cb); 430 } 431} 432 433 434extern "C" void printnm(intptr_t p) { 435 char buffer[256]; 436 sprintf(buffer, "printnm: " INTPTR_FORMAT, p); 437 Command c(buffer); 438 CodeBlob* cb = CodeCache::find_blob((address) p); 439 if (cb->is_nmethod()) { 440 nmethod* nm = (nmethod*)cb; 441 nm->print_nmethod(true); 442 } 443} 444 445 446extern "C" void universe() { 447 Command c("universe"); 448 Universe::print(); 449} 450 451 452extern "C" void verify() { 453 // try to run a verify on the entire system 454 // note: this may not be safe if we're not at a safepoint; for debugging, 455 // this manipulates the safepoint settings to avoid assertion failures 456 Command c("universe verify"); 457 bool safe = SafepointSynchronize::is_at_safepoint(); 458 if (!safe) { 459 tty->print_cr("warning: not at safepoint -- verify may fail"); 460 SafepointSynchronize::set_is_at_safepoint(); 461 } 462 // Ensure Eden top is correct before verification 463 Universe::heap()->prepare_for_verify(); 464 Universe::verify(true); 465 if (!safe) SafepointSynchronize::set_is_not_at_safepoint(); 466} 467 468 469extern "C" void pp(void* p) { 470 Command c("pp"); 471 FlagSetting fl(PrintVMMessages, true); 472 if (Universe::heap()->is_in(p)) { 473 oop obj = oop(p); 474 obj->print(); 475 } else { 476 tty->print("%#p", p); 477 } 478} 479 480 481// pv: print vm-printable object 482extern "C" void pa(intptr_t p) { ((AllocatedObj*) p)->print(); } 483extern "C" void findpc(intptr_t x); 484 485extern "C" void ps() { // print stack 486 Command c("ps"); 487 488 489 // Prints the stack of the current Java thread 490 JavaThread* p = JavaThread::active(); 491 tty->print(" for thread: "); 492 p->print(); 493 tty->cr(); 494 495 if (p->has_last_Java_frame()) { 496 // If the last_Java_fp is set we are in C land and 497 // can call the standard stack_trace function. 498 p->trace_stack(); 499 } else { 500 frame f = os::current_frame(); 501 RegisterMap reg_map(p); 502 f = f.sender(®_map); 503 tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id()); 504 p->trace_stack_from(vframe::new_vframe(&f, ®_map, p)); 505 pd_ps(f); 506 } 507 508} 509 510 511extern "C" void psf() { // print stack frames 512 { 513 Command c("psf"); 514 JavaThread* p = JavaThread::active(); 515 tty->print(" for thread: "); 516 p->print(); 517 tty->cr(); 518 if (p->has_last_Java_frame()) { 519 p->trace_frames(); 520 } 521 } 522} 523 524 525extern "C" void threads() { 526 Command c("threads"); 527 Threads::print(false, true); 528} 529 530 531extern "C" void psd() { 532 Command c("psd"); 533 SystemDictionary::print(); 534} 535 536 537extern "C" void safepoints() { 538 Command c("safepoints"); 539 SafepointSynchronize::print_state(); 540} 541 542 543extern "C" void pss() { // print all stacks 544 Command c("pss"); 545 Threads::print(true, true); 546} 547 548 549extern "C" void debug() { // to set things up for compiler debugging 550 Command c("debug"); 551 WizardMode = true; 552 PrintVMMessages = PrintCompilation = true; 553 PrintInlining = PrintAssembly = true; 554 tty->flush(); 555} 556 557 558extern "C" void ndebug() { // undo debug() 559 Command c("ndebug"); 560 PrintCompilation = false; 561 PrintInlining = PrintAssembly = false; 562 tty->flush(); 563} 564 565 566extern "C" void flush() { 567 Command c("flush"); 568 tty->flush(); 569} 570 571 572extern "C" void events() { 573 Command c("events"); 574 Events::print_last(tty, 50); 575} 576 577 578extern "C" void nevents(int n) { 579 Command c("events"); 580 Events::print_last(tty, n); 581} 582 583 584// Given a heap address that was valid before the most recent GC, if 585// the oop that used to contain it is still live, prints the new 586// location of the oop and the address. Useful for tracking down 587// certain kinds of naked oop and oop map bugs. 588extern "C" void pnl(intptr_t old_heap_addr) { 589 // Print New Location of old heap address 590 Command c("pnl"); 591#ifndef VALIDATE_MARK_SWEEP 592 tty->print_cr("Requires build with VALIDATE_MARK_SWEEP defined (debug build) and RecordMarkSweepCompaction enabled"); 593#else 594 MarkSweep::print_new_location_of_heap_address((HeapWord*) old_heap_addr); 595#endif 596} 597 598 599extern "C" methodOop findm(intptr_t pc) { 600 Command c("findm"); 601 nmethod* nm = CodeCache::find_nmethod((address)pc); 602 return (nm == NULL) ? (methodOop)NULL : nm->method(); 603} 604 605 606extern "C" nmethod* findnm(intptr_t addr) { 607 Command c("findnm"); 608 return CodeCache::find_nmethod((address)addr); 609} 610 611static address same_page(address x, address y) { 612 intptr_t page_bits = -os::vm_page_size(); 613 if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) { 614 return x; 615 } else if (x > y) { 616 return (address)(intptr_t(y) | ~page_bits) + 1; 617 } else { 618 return (address)(intptr_t(y) & page_bits); 619 } 620} 621 622class LookForRefInGenClosure : public OopsInGenClosure { 623public: 624 oop target; 625 void do_oop(oop* o) { 626 if (o != NULL && *o == target) { 627 tty->print_cr(INTPTR_FORMAT, o); 628 } 629 } 630 void do_oop(narrowOop* o) { ShouldNotReachHere(); } 631}; 632 633 634class LookForRefInObjectClosure : public ObjectClosure { 635private: 636 LookForRefInGenClosure look_in_object; 637public: 638 LookForRefInObjectClosure(oop target) { look_in_object.target = target; } 639 void do_object(oop obj) { 640 obj->oop_iterate(&look_in_object); 641 } 642}; 643 644 645static void findref(intptr_t x) { 646 CollectedHeap *ch = Universe::heap(); 647 LookForRefInGenClosure lookFor; 648 lookFor.target = (oop) x; 649 LookForRefInObjectClosure look_in_object((oop) x); 650 651 tty->print_cr("Searching heap:"); 652 ch->object_iterate(&look_in_object); 653 654 tty->print_cr("Searching strong roots:"); 655 Universe::oops_do(&lookFor, false); 656 JNIHandles::oops_do(&lookFor); // Global (strong) JNI handles 657 Threads::oops_do(&lookFor, NULL); 658 ObjectSynchronizer::oops_do(&lookFor); 659 //FlatProfiler::oops_do(&lookFor); 660 SystemDictionary::oops_do(&lookFor); 661 662 tty->print_cr("Searching code cache:"); 663 CodeCache::oops_do(&lookFor); 664 665 tty->print_cr("Done."); 666} 667 668class FindClassObjectClosure: public ObjectClosure { 669 private: 670 const char* _target; 671 public: 672 FindClassObjectClosure(const char name[]) { _target = name; } 673 674 virtual void do_object(oop obj) { 675 if (obj->is_klass()) { 676 Klass* k = klassOop(obj)->klass_part(); 677 if (k->name() != NULL) { 678 ResourceMark rm; 679 const char* ext = k->external_name(); 680 if ( strcmp(_target, ext) == 0 ) { 681 tty->print_cr("Found " INTPTR_FORMAT, obj); 682 obj->print(); 683 } 684 } 685 } 686 } 687}; 688 689// 690extern "C" void findclass(const char name[]) { 691 Command c("findclass"); 692 if (name != NULL) { 693 tty->print_cr("Finding class %s -> ", name); 694 FindClassObjectClosure srch(name); 695 Universe::heap()->permanent_object_iterate(&srch); 696 } 697} 698 699// Another interface that isn't ambiguous in dbx. 700// Can we someday rename the other find to hsfind? 701extern "C" void hsfind(intptr_t x) { 702 Command c("hsfind"); 703 os::print_location(tty, x, false); 704} 705 706 707extern "C" void hsfindref(intptr_t x) { 708 Command c("hsfindref"); 709 findref(x); 710} 711 712extern "C" void find(intptr_t x) { 713 Command c("find"); 714 os::print_location(tty, x, false); 715} 716 717 718extern "C" void findpc(intptr_t x) { 719 Command c("findpc"); 720 os::print_location(tty, x, true); 721} 722 723 724// int versions of all methods to avoid having to type type casts in the debugger 725 726void pp(intptr_t p) { pp((void*)p); } 727void pp(oop p) { pp((void*)p); } 728 729void help() { 730 Command c("help"); 731 tty->print_cr("basic"); 732 tty->print_cr(" pp(void* p) - try to make sense of p"); 733 tty->print_cr(" pv(intptr_t p)- ((PrintableResourceObj*) p)->print()"); 734 tty->print_cr(" ps() - print current thread stack"); 735 tty->print_cr(" pss() - print all thread stacks"); 736 tty->print_cr(" pm(int pc) - print methodOop given compiled PC"); 737 tty->print_cr(" findm(intptr_t pc) - finds methodOop"); 738 tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it"); 739 740 tty->print_cr("misc."); 741 tty->print_cr(" flush() - flushes the log file"); 742 tty->print_cr(" events() - dump last 50 events"); 743 744 745 tty->print_cr("compiler debugging"); 746 tty->print_cr(" debug() - to set things up for compiler debugging"); 747 tty->print_cr(" ndebug() - undo debug"); 748} 749 750#if 0 751 752// BobV's command parser for debugging on windows when nothing else works. 753 754enum CommandID { 755 CMDID_HELP, 756 CMDID_QUIT, 757 CMDID_HSFIND, 758 CMDID_PSS, 759 CMDID_PS, 760 CMDID_PSF, 761 CMDID_FINDM, 762 CMDID_FINDNM, 763 CMDID_PP, 764 CMDID_BPT, 765 CMDID_EXIT, 766 CMDID_VERIFY, 767 CMDID_THREADS, 768 CMDID_ILLEGAL = 99 769}; 770 771struct CommandParser { 772 char *name; 773 CommandID code; 774 char *description; 775}; 776 777struct CommandParser CommandList[] = { 778 (char *)"help", CMDID_HELP, " Dump this list", 779 (char *)"quit", CMDID_QUIT, " Return from this routine", 780 (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address", 781 (char *)"ps", CMDID_PS, " Print Current Thread Stack Trace", 782 (char *)"pss", CMDID_PSS, " Print All Thread Stack Trace", 783 (char *)"psf", CMDID_PSF, " Print All Stack Frames", 784 (char *)"findm", CMDID_FINDM, " Find a methodOop from a PC", 785 (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC", 786 (char *)"pp", CMDID_PP, " Find out something about a pointer", 787 (char *)"break", CMDID_BPT, " Execute a breakpoint", 788 (char *)"exitvm", CMDID_EXIT, "Exit the VM", 789 (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify", 790 (char *)"thread", CMDID_THREADS, "Dump Info on all Threads", 791 (char *)0, CMDID_ILLEGAL 792}; 793 794 795// get_debug_command() 796// 797// Read a command from standard input. 798// This is useful when you have a debugger 799// which doesn't support calling into functions. 800// 801void get_debug_command() 802{ 803 ssize_t count; 804 int i,j; 805 bool gotcommand; 806 intptr_t addr; 807 char buffer[256]; 808 nmethod *nm; 809 methodOop m; 810 811 tty->print_cr("You have entered the diagnostic command interpreter"); 812 tty->print("The supported commands are:\n"); 813 for ( i=0; ; i++ ) { 814 if ( CommandList[i].code == CMDID_ILLEGAL ) 815 break; 816 tty->print_cr(" %s \n", CommandList[i].name ); 817 } 818 819 while ( 1 ) { 820 gotcommand = false; 821 tty->print("Please enter a command: "); 822 count = scanf("%s", buffer) ; 823 if ( count >=0 ) { 824 for ( i=0; ; i++ ) { 825 if ( CommandList[i].code == CMDID_ILLEGAL ) { 826 if (!gotcommand) tty->print("Invalid command, please try again\n"); 827 break; 828 } 829 if ( strcmp(buffer, CommandList[i].name) == 0 ) { 830 gotcommand = true; 831 switch ( CommandList[i].code ) { 832 case CMDID_PS: 833 ps(); 834 break; 835 case CMDID_PSS: 836 pss(); 837 break; 838 case CMDID_PSF: 839 psf(); 840 break; 841 case CMDID_FINDM: 842 tty->print("Please enter the hex addr to pass to findm: "); 843 scanf("%I64X", &addr); 844 m = (methodOop)findm(addr); 845 tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m); 846 break; 847 case CMDID_FINDNM: 848 tty->print("Please enter the hex addr to pass to findnm: "); 849 scanf("%I64X", &addr); 850 nm = (nmethod*)findnm(addr); 851 tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm); 852 break; 853 case CMDID_PP: 854 tty->print("Please enter the hex addr to pass to pp: "); 855 scanf("%I64X", &addr); 856 pp((void*)addr); 857 break; 858 case CMDID_EXIT: 859 exit(0); 860 case CMDID_HELP: 861 tty->print("Here are the supported commands: "); 862 for ( j=0; ; j++ ) { 863 if ( CommandList[j].code == CMDID_ILLEGAL ) 864 break; 865 tty->print_cr(" %s -- %s\n", CommandList[j].name, 866 CommandList[j].description ); 867 } 868 break; 869 case CMDID_QUIT: 870 return; 871 break; 872 case CMDID_BPT: 873 BREAKPOINT; 874 break; 875 case CMDID_VERIFY: 876 verify();; 877 break; 878 case CMDID_THREADS: 879 threads();; 880 break; 881 case CMDID_HSFIND: 882 tty->print("Please enter the hex addr to pass to hsfind: "); 883 scanf("%I64X", &addr); 884 tty->print("Calling hsfind(0x%I64X)\n", addr); 885 hsfind(addr); 886 break; 887 default: 888 case CMDID_ILLEGAL: 889 break; 890 } 891 } 892 } 893 } 894 } 895} 896#endif 897 898#endif // PRODUCT 899