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