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   cb->print();
 365   Disassembler::decode(cb);
 366 }
 367 
 368 
 369 extern "C" void printnm(intptr_t p) {
 370   char buffer[256];
 371   sprintf(buffer, "printnm: " INTPTR_FORMAT, p);
 372   Command c(buffer);
 373   CodeBlob* cb = CodeCache::find_blob((address) p);
 374   if (cb->is_nmethod()) {
 375     nmethod* nm = (nmethod*)cb;
 376     nm->print_nmethod(true);
 377   }
 378 }
 379 
 380 
 381 extern "C" void universe() {
 382   Command c("universe");
 383   Universe::print();
 384 }
 385 
 386 
 387 extern "C" void verify() {
 388   // try to run a verify on the entire system
 389   // note: this may not be safe if we're not at a safepoint; for debugging,
 390   // this manipulates the safepoint settings to avoid assertion failures
 391   Command c("universe verify");
 392   bool safe = SafepointSynchronize::is_at_safepoint();
 393   if (!safe) {
 394     tty->print_cr("warning: not at safepoint -- verify may fail");
 395     SafepointSynchronize::set_is_at_safepoint();
 396   }
 397   // Ensure Eden top is correct before verification
 398   Universe::heap()->prepare_for_verify();
 399   Universe::verify(true);
 400   if (!safe) SafepointSynchronize::set_is_not_at_safepoint();
 401 }
 402 
 403 
 404 extern "C" void pp(void* p) {
 405   Command c("pp");
 406   FlagSetting fl(PrintVMMessages, true);
 407   if (Universe::heap()->is_in(p)) {
 408     oop obj = oop(p);
 409     obj->print();
 410   } else {
 411     tty->print("%#p", p);
 412   }
 413 }
 414 
 415 
 416 // pv: print vm-printable object
 417 extern "C" void pa(intptr_t p)   { ((AllocatedObj*) p)->print(); }
 418 extern "C" void findpc(intptr_t x);
 419 
 420 extern "C" void ps() { // print stack
 421   Command c("ps");
 422 
 423 
 424   // Prints the stack of the current Java thread
 425   JavaThread* p = JavaThread::active();
 426   tty->print(" for thread: ");
 427   p->print();
 428   tty->cr();
 429 
 430   if (p->has_last_Java_frame()) {
 431     // If the last_Java_fp is set we are in C land and
 432     // can call the standard stack_trace function.
 433     p->trace_stack();
 434   } else {
 435     frame f = os::current_frame();
 436     RegisterMap reg_map(p);
 437     f = f.sender(&reg_map);
 438     tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id());
 439     p->trace_stack_from(vframe::new_vframe(&f, &reg_map, p));
 440   pd_ps(f);
 441   }
 442 
 443 }
 444 
 445 
 446 extern "C" void psf() { // print stack frames
 447   {
 448     Command c("psf");
 449     JavaThread* p = JavaThread::active();
 450     tty->print(" for thread: ");
 451     p->print();
 452     tty->cr();
 453     if (p->has_last_Java_frame()) {
 454       p->trace_frames();
 455     }
 456   }
 457 }
 458 
 459 
 460 extern "C" void threads() {
 461   Command c("threads");
 462   Threads::print(false, true);
 463 }
 464 
 465 
 466 extern "C" void psd() {
 467   Command c("psd");
 468   SystemDictionary::print();
 469 }
 470 
 471 
 472 extern "C" void safepoints() {
 473   Command c("safepoints");
 474   SafepointSynchronize::print_state();
 475 }
 476 
 477 
 478 extern "C" void pss() { // print all stacks
 479   Command c("pss");
 480   Threads::print(true, true);
 481 }
 482 
 483 
 484 extern "C" void debug() {               // to set things up for compiler debugging
 485   Command c("debug");
 486   WizardMode = true;
 487   PrintVMMessages = PrintCompilation = true;
 488   PrintInlining = PrintAssembly = true;
 489   tty->flush();
 490 }
 491 
 492 
 493 extern "C" void ndebug() {              // undo debug()
 494   Command c("ndebug");
 495   PrintCompilation = false;
 496   PrintInlining = PrintAssembly = false;
 497   tty->flush();
 498 }
 499 
 500 
 501 extern "C" void flush()  {
 502   Command c("flush");
 503   tty->flush();
 504 }
 505 
 506 
 507 extern "C" void events() {
 508   Command c("events");
 509   Events::print_last(tty, 50);
 510 }
 511 
 512 
 513 extern "C" void nevents(int n) {
 514   Command c("events");
 515   Events::print_last(tty, n);
 516 }
 517 
 518 
 519 // Given a heap address that was valid before the most recent GC, if
 520 // the oop that used to contain it is still live, prints the new
 521 // location of the oop and the address. Useful for tracking down
 522 // certain kinds of naked oop and oop map bugs.
 523 extern "C" void pnl(intptr_t old_heap_addr) {
 524   // Print New Location of old heap address
 525   Command c("pnl");
 526 #ifndef VALIDATE_MARK_SWEEP
 527   tty->print_cr("Requires build with VALIDATE_MARK_SWEEP defined (debug build) and RecordMarkSweepCompaction enabled");
 528 #else
 529   MarkSweep::print_new_location_of_heap_address((HeapWord*) old_heap_addr);
 530 #endif
 531 }
 532 
 533 
 534 extern "C" methodOop findm(intptr_t pc) {
 535   Command c("findm");
 536   nmethod* nm = CodeCache::find_nmethod((address)pc);
 537   return (nm == NULL) ? (methodOop)NULL : nm->method();
 538 }
 539 
 540 
 541 extern "C" nmethod* findnm(intptr_t addr) {
 542   Command c("findnm");
 543   return  CodeCache::find_nmethod((address)addr);
 544 }
 545 
 546 static address same_page(address x, address y) {
 547   intptr_t page_bits = -os::vm_page_size();
 548   if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) {
 549     return x;
 550   } else if (x > y) {
 551     return (address)(intptr_t(y) | ~page_bits) + 1;
 552   } else {
 553     return (address)(intptr_t(y) & page_bits);
 554   }
 555 }
 556 
 557 class LookForRefInGenClosure : public OopsInGenClosure {
 558 public:
 559   oop target;
 560   void do_oop(oop* o) {
 561     if (o != NULL && *o == target) {
 562       tty->print_cr(INTPTR_FORMAT, o);
 563     }
 564   }
 565   void do_oop(narrowOop* o) { ShouldNotReachHere(); }
 566 };
 567 
 568 
 569 class LookForRefInObjectClosure : public ObjectClosure {
 570 private:
 571   LookForRefInGenClosure look_in_object;
 572 public:
 573   LookForRefInObjectClosure(oop target) { look_in_object.target = target; }
 574   void do_object(oop obj) {
 575     obj->oop_iterate(&look_in_object);
 576   }
 577 };
 578 
 579 
 580 static void findref(intptr_t x) {
 581   CollectedHeap *ch = Universe::heap();
 582   LookForRefInGenClosure lookFor;
 583   lookFor.target = (oop) x;
 584   LookForRefInObjectClosure look_in_object((oop) x);
 585 
 586   tty->print_cr("Searching heap:");
 587   ch->object_iterate(&look_in_object);
 588 
 589   tty->print_cr("Searching strong roots:");
 590   Universe::oops_do(&lookFor, false);
 591   JNIHandles::oops_do(&lookFor);   // Global (strong) JNI handles
 592   Threads::oops_do(&lookFor, NULL);
 593   ObjectSynchronizer::oops_do(&lookFor);
 594   //FlatProfiler::oops_do(&lookFor);
 595   SystemDictionary::oops_do(&lookFor);
 596 
 597   tty->print_cr("Searching code cache:");
 598   CodeCache::oops_do(&lookFor);
 599 
 600   tty->print_cr("Done.");
 601 }
 602 
 603 class FindClassObjectClosure: public ObjectClosure {
 604   private:
 605     const char* _target;
 606   public:
 607     FindClassObjectClosure(const char name[])  { _target = name; }
 608 
 609     virtual void do_object(oop obj) {
 610       if (obj->is_klass()) {
 611         Klass* k = klassOop(obj)->klass_part();
 612         if (k->name() != NULL) {
 613           ResourceMark rm;
 614           const char* ext = k->external_name();
 615           if ( strcmp(_target, ext) == 0 ) {
 616             tty->print_cr("Found " INTPTR_FORMAT, obj);
 617             obj->print();
 618           }
 619         }
 620       }
 621     }
 622 };
 623 
 624 //
 625 extern "C" void findclass(const char name[]) {
 626   Command c("findclass");
 627   if (name != NULL) {
 628     tty->print_cr("Finding class %s -> ", name);
 629     FindClassObjectClosure srch(name);
 630     Universe::heap()->permanent_object_iterate(&srch);
 631   }
 632 }
 633 
 634 // Another interface that isn't ambiguous in dbx.
 635 // Can we someday rename the other find to hsfind?
 636 extern "C" void hsfind(intptr_t x) {
 637   Command c("hsfind");
 638   os::print_location(tty, x, false);
 639 }
 640 
 641 
 642 extern "C" void hsfindref(intptr_t x) {
 643   Command c("hsfindref");
 644   findref(x);
 645 }
 646 
 647 extern "C" void find(intptr_t x) {
 648   Command c("find");
 649   os::print_location(tty, x, false);
 650 }
 651 
 652 
 653 extern "C" void findpc(intptr_t x) {
 654   Command c("findpc");
 655   os::print_location(tty, x, true);
 656 }
 657 
 658 
 659 // int versions of all methods to avoid having to type type casts in the debugger
 660 
 661 void pp(intptr_t p)          { pp((void*)p); }
 662 void pp(oop p)               { pp((void*)p); }
 663 
 664 void help() {
 665   Command c("help");
 666   tty->print_cr("basic");
 667   tty->print_cr("  pp(void* p)   - try to make sense of p");
 668   tty->print_cr("  pv(intptr_t p)- ((PrintableResourceObj*) p)->print()");
 669   tty->print_cr("  ps()          - print current thread stack");
 670   tty->print_cr("  pss()         - print all thread stacks");
 671   tty->print_cr("  pm(int pc)    - print methodOop given compiled PC");
 672   tty->print_cr("  findm(intptr_t pc) - finds methodOop");
 673   tty->print_cr("  find(intptr_t x)   - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
 674 
 675   tty->print_cr("misc.");
 676   tty->print_cr("  flush()       - flushes the log file");
 677   tty->print_cr("  events()      - dump last 50 events");
 678 
 679 
 680   tty->print_cr("compiler debugging");
 681   tty->print_cr("  debug()       - to set things up for compiler debugging");
 682   tty->print_cr("  ndebug()      - undo debug");
 683 }
 684 
 685 #if 0
 686 
 687 // BobV's command parser for debugging on windows when nothing else works.
 688 
 689 enum CommandID {
 690   CMDID_HELP,
 691   CMDID_QUIT,
 692   CMDID_HSFIND,
 693   CMDID_PSS,
 694   CMDID_PS,
 695   CMDID_PSF,
 696   CMDID_FINDM,
 697   CMDID_FINDNM,
 698   CMDID_PP,
 699   CMDID_BPT,
 700   CMDID_EXIT,
 701   CMDID_VERIFY,
 702   CMDID_THREADS,
 703   CMDID_ILLEGAL = 99
 704 };
 705 
 706 struct CommandParser {
 707    char *name;
 708    CommandID code;
 709    char *description;
 710 };
 711 
 712 struct CommandParser CommandList[] = {
 713   (char *)"help", CMDID_HELP, "  Dump this list",
 714   (char *)"quit", CMDID_QUIT, "  Return from this routine",
 715   (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address",
 716   (char *)"ps", CMDID_PS, "    Print Current Thread Stack Trace",
 717   (char *)"pss", CMDID_PSS, "   Print All Thread Stack Trace",
 718   (char *)"psf", CMDID_PSF, "   Print All Stack Frames",
 719   (char *)"findm", CMDID_FINDM, " Find a methodOop from a PC",
 720   (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC",
 721   (char *)"pp", CMDID_PP, "    Find out something about a pointer",
 722   (char *)"break", CMDID_BPT, " Execute a breakpoint",
 723   (char *)"exitvm", CMDID_EXIT, "Exit the VM",
 724   (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify",
 725   (char *)"thread", CMDID_THREADS, "Dump Info on all Threads",
 726   (char *)0, CMDID_ILLEGAL
 727 };
 728 
 729 
 730 // get_debug_command()
 731 //
 732 // Read a command from standard input.
 733 // This is useful when you have a debugger
 734 // which doesn't support calling into functions.
 735 //
 736 void get_debug_command()
 737 {
 738   ssize_t count;
 739   int i,j;
 740   bool gotcommand;
 741   intptr_t addr;
 742   char buffer[256];
 743   nmethod *nm;
 744   methodOop m;
 745 
 746   tty->print_cr("You have entered the diagnostic command interpreter");
 747   tty->print("The supported commands are:\n");
 748   for ( i=0; ; i++ ) {
 749     if ( CommandList[i].code == CMDID_ILLEGAL )
 750       break;
 751     tty->print_cr("  %s \n", CommandList[i].name );
 752   }
 753 
 754   while ( 1 ) {
 755     gotcommand = false;
 756     tty->print("Please enter a command: ");
 757     count = scanf("%s", buffer) ;
 758     if ( count >=0 ) {
 759       for ( i=0; ; i++ ) {
 760         if ( CommandList[i].code == CMDID_ILLEGAL ) {
 761           if (!gotcommand) tty->print("Invalid command, please try again\n");
 762           break;
 763         }
 764         if ( strcmp(buffer, CommandList[i].name) == 0 ) {
 765           gotcommand = true;
 766           switch ( CommandList[i].code ) {
 767               case CMDID_PS:
 768                 ps();
 769                 break;
 770               case CMDID_PSS:
 771                 pss();
 772                 break;
 773               case CMDID_PSF:
 774                 psf();
 775                 break;
 776               case CMDID_FINDM:
 777                 tty->print("Please enter the hex addr to pass to findm: ");
 778                 scanf("%I64X", &addr);
 779                 m = (methodOop)findm(addr);
 780                 tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m);
 781                 break;
 782               case CMDID_FINDNM:
 783                 tty->print("Please enter the hex addr to pass to findnm: ");
 784                 scanf("%I64X", &addr);
 785                 nm = (nmethod*)findnm(addr);
 786                 tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm);
 787                 break;
 788               case CMDID_PP:
 789                 tty->print("Please enter the hex addr to pass to pp: ");
 790                 scanf("%I64X", &addr);
 791                 pp((void*)addr);
 792                 break;
 793               case CMDID_EXIT:
 794                 exit(0);
 795               case CMDID_HELP:
 796                 tty->print("Here are the supported commands: ");
 797                 for ( j=0; ; j++ ) {
 798                   if ( CommandList[j].code == CMDID_ILLEGAL )
 799                     break;
 800                   tty->print_cr("  %s --  %s\n", CommandList[j].name,
 801                                                  CommandList[j].description );
 802                 }
 803                 break;
 804               case CMDID_QUIT:
 805                 return;
 806                 break;
 807               case CMDID_BPT:
 808                 BREAKPOINT;
 809                 break;
 810               case CMDID_VERIFY:
 811                 verify();;
 812                 break;
 813               case CMDID_THREADS:
 814                 threads();;
 815                 break;
 816               case CMDID_HSFIND:
 817                 tty->print("Please enter the hex addr to pass to hsfind: ");
 818                 scanf("%I64X", &addr);
 819                 tty->print("Calling hsfind(0x%I64X)\n", addr);
 820                 hsfind(addr);
 821                 break;
 822               default:
 823               case CMDID_ILLEGAL:
 824                 break;
 825           }
 826         }
 827       }
 828     }
 829   }
 830 }
 831 #endif
 832 
 833 #endif // PRODUCT