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