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(&reg_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, &reg_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