Fri, 10 Jun 2011 15:08:36 -0700
6941923: RFE: Handling large log files produced by long running Java Applications
Summary: supply optinal flags to realize gc log rotation
Reviewed-by: ysr, jwilhelm
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 */
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
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
77 #ifdef _DEBUG
78 # ifndef ASSERT
79 configuration error: ASSERT must be defined in debug version
80 # endif // ASSERT
81 #endif // _DEBUG
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
91 void warning(const char* format, ...) {
92 if (PrintWarnings) {
93 // In case error happens before init or during shutdown
94 if (tty == NULL) ostream_init();
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 }
105 #ifndef PRODUCT
107 #define is_token_break(ch) (isspace(ch) || (ch) == ',')
109 static const char* last_file_name = NULL;
110 static int last_line_no = -1;
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.
115 bool 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;
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;
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 }
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 }
201 #undef is_token_break
203 #else
205 // Place-holder for non-existent suppression check:
206 #define error_is_suppressed(file_name, line_no) (false)
208 #endif //PRODUCT
210 void 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 }
219 void report_fatal(const char* file, int line, const char* message)
220 {
221 report_vm_error(file, line, "fatal error", message);
222 }
224 // Used by report_vm_out_of_memory to detect recursion.
225 static jint _exiting_out_of_mem = 0;
227 void report_vm_out_of_memory(const char* file, int line, size_t size,
228 const char* message) {
229 if (Debugging) return;
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.
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;
239 if (first_time_here) {
240 Thread* thread = ThreadLocalStorage::get_thread_slow();
241 VMError(thread, file, line, size, message).report_and_die();
242 }
244 // Dump core and abort
245 vm_abort(true);
246 }
248 void report_should_not_call(const char* file, int line) {
249 report_vm_error(file, line, "ShouldNotCall()");
250 }
252 void report_should_not_reach_here(const char* file, int line) {
253 report_vm_error(file, line, "ShouldNotReachHere()");
254 }
256 void report_unimplemented(const char* file, int line) {
257 report_vm_error(file, line, "Unimplemented()");
258 }
260 void 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 }
266 void 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 };
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 }
287 void report_java_out_of_memory(const char* message) {
288 static jint out_of_memory_reported = 0;
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 }
301 if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
302 VMError err(message);
303 err.report_java_out_of_memory();
304 }
305 }
306 }
309 extern "C" void ps();
311 static bool error_reported = false;
313 // call this when the VM is dying--it might loosen some asserts
314 void set_error_reported() {
315 error_reported = true;
316 }
318 bool is_error_reported() {
319 return error_reported;
320 }
322 #ifndef PRODUCT
323 #include <signal.h>
325 void test_error_handler(size_t test_num)
326 {
327 if (test_num == 0) return;
329 // If asserts are disabled, use the corresponding guarantee instead.
330 size_t n = test_num;
331 NOT_DEBUG(if (n <= 2) n += 2);
333 const char* const str = "hello";
334 const size_t num = (size_t)os::vm_page_size();
336 const char* const eol = os::line_separator();
337 const char* const msg = "this message should be truncated during formatting";
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);
362 default: ShouldNotReachHere();
363 }
364 }
365 #endif // #ifndef PRODUCT
367 // ------ helper functions for debugging go here ------------
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.
374 class 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 }
390 ~Command() { tty->flush(); Debugging = debug_save; level--; }
391 };
393 int Command::level = 0;
395 extern "C" void blob(CodeBlob* cb) {
396 Command c("blob");
397 cb->print();
398 }
401 extern "C" void dump_vtable(address p) {
402 Command c("dump_vtable");
403 klassOop k = (klassOop)p;
404 instanceKlass::cast(k)->vtable()->print();
405 }
408 extern "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 }
420 extern "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 }
434 extern "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 }
446 extern "C" void universe() {
447 Command c("universe");
448 Universe::print();
449 }
452 extern "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 }
469 extern "C" void pp(void* p) {
470 Command c("pp");
471 FlagSetting fl(PrintVMMessages, true);
472 FlagSetting f2(DisplayVMOutput, true);
473 if (Universe::heap()->is_in(p)) {
474 oop obj = oop(p);
475 obj->print();
476 } else {
477 tty->print("%#p", p);
478 }
479 }
482 // pv: print vm-printable object
483 extern "C" void pa(intptr_t p) { ((AllocatedObj*) p)->print(); }
484 extern "C" void findpc(intptr_t x);
486 extern "C" void ps() { // print stack
487 Command c("ps");
490 // Prints the stack of the current Java thread
491 JavaThread* p = JavaThread::active();
492 tty->print(" for thread: ");
493 p->print();
494 tty->cr();
496 if (p->has_last_Java_frame()) {
497 // If the last_Java_fp is set we are in C land and
498 // can call the standard stack_trace function.
499 p->trace_stack();
500 } else {
501 frame f = os::current_frame();
502 RegisterMap reg_map(p);
503 f = f.sender(®_map);
504 tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id());
505 p->trace_stack_from(vframe::new_vframe(&f, ®_map, p));
506 pd_ps(f);
507 }
509 }
511 extern "C" void pfl() {
512 // print frame layout
513 Command c("pfl");
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->print_frame_layout();
520 }
521 }
523 extern "C" void psf() { // print stack frames
524 {
525 Command c("psf");
526 JavaThread* p = JavaThread::active();
527 tty->print(" for thread: ");
528 p->print();
529 tty->cr();
530 if (p->has_last_Java_frame()) {
531 p->trace_frames();
532 }
533 }
534 }
537 extern "C" void threads() {
538 Command c("threads");
539 Threads::print(false, true);
540 }
543 extern "C" void psd() {
544 Command c("psd");
545 SystemDictionary::print();
546 }
549 extern "C" void safepoints() {
550 Command c("safepoints");
551 SafepointSynchronize::print_state();
552 }
555 extern "C" void pss() { // print all stacks
556 Command c("pss");
557 Threads::print(true, true);
558 }
561 extern "C" void debug() { // to set things up for compiler debugging
562 Command c("debug");
563 WizardMode = true;
564 PrintVMMessages = PrintCompilation = true;
565 PrintInlining = PrintAssembly = true;
566 tty->flush();
567 }
570 extern "C" void ndebug() { // undo debug()
571 Command c("ndebug");
572 PrintCompilation = false;
573 PrintInlining = PrintAssembly = false;
574 tty->flush();
575 }
578 extern "C" void flush() {
579 Command c("flush");
580 tty->flush();
581 }
584 extern "C" void events() {
585 Command c("events");
586 Events::print_last(tty, 50);
587 }
590 extern "C" void nevents(int n) {
591 Command c("events");
592 Events::print_last(tty, n);
593 }
596 // Given a heap address that was valid before the most recent GC, if
597 // the oop that used to contain it is still live, prints the new
598 // location of the oop and the address. Useful for tracking down
599 // certain kinds of naked oop and oop map bugs.
600 extern "C" void pnl(intptr_t old_heap_addr) {
601 // Print New Location of old heap address
602 Command c("pnl");
603 #ifndef VALIDATE_MARK_SWEEP
604 tty->print_cr("Requires build with VALIDATE_MARK_SWEEP defined (debug build) and RecordMarkSweepCompaction enabled");
605 #else
606 MarkSweep::print_new_location_of_heap_address((HeapWord*) old_heap_addr);
607 #endif
608 }
611 extern "C" methodOop findm(intptr_t pc) {
612 Command c("findm");
613 nmethod* nm = CodeCache::find_nmethod((address)pc);
614 return (nm == NULL) ? (methodOop)NULL : nm->method();
615 }
618 extern "C" nmethod* findnm(intptr_t addr) {
619 Command c("findnm");
620 return CodeCache::find_nmethod((address)addr);
621 }
623 static address same_page(address x, address y) {
624 intptr_t page_bits = -os::vm_page_size();
625 if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) {
626 return x;
627 } else if (x > y) {
628 return (address)(intptr_t(y) | ~page_bits) + 1;
629 } else {
630 return (address)(intptr_t(y) & page_bits);
631 }
632 }
634 class LookForRefInGenClosure : public OopsInGenClosure {
635 public:
636 oop target;
637 void do_oop(oop* o) {
638 if (o != NULL && *o == target) {
639 tty->print_cr(INTPTR_FORMAT, o);
640 }
641 }
642 void do_oop(narrowOop* o) { ShouldNotReachHere(); }
643 };
646 class LookForRefInObjectClosure : public ObjectClosure {
647 private:
648 LookForRefInGenClosure look_in_object;
649 public:
650 LookForRefInObjectClosure(oop target) { look_in_object.target = target; }
651 void do_object(oop obj) {
652 obj->oop_iterate(&look_in_object);
653 }
654 };
657 static void findref(intptr_t x) {
658 CollectedHeap *ch = Universe::heap();
659 LookForRefInGenClosure lookFor;
660 lookFor.target = (oop) x;
661 LookForRefInObjectClosure look_in_object((oop) x);
663 tty->print_cr("Searching heap:");
664 ch->object_iterate(&look_in_object);
666 tty->print_cr("Searching strong roots:");
667 Universe::oops_do(&lookFor, false);
668 JNIHandles::oops_do(&lookFor); // Global (strong) JNI handles
669 Threads::oops_do(&lookFor, NULL);
670 ObjectSynchronizer::oops_do(&lookFor);
671 //FlatProfiler::oops_do(&lookFor);
672 SystemDictionary::oops_do(&lookFor);
674 tty->print_cr("Searching code cache:");
675 CodeCache::oops_do(&lookFor);
677 tty->print_cr("Done.");
678 }
680 class FindClassObjectClosure: public ObjectClosure {
681 private:
682 const char* _target;
683 public:
684 FindClassObjectClosure(const char name[]) { _target = name; }
686 virtual void do_object(oop obj) {
687 if (obj->is_klass()) {
688 Klass* k = klassOop(obj)->klass_part();
689 if (k->name() != NULL) {
690 ResourceMark rm;
691 const char* ext = k->external_name();
692 if ( strcmp(_target, ext) == 0 ) {
693 tty->print_cr("Found " INTPTR_FORMAT, obj);
694 obj->print();
695 }
696 }
697 }
698 }
699 };
701 //
702 extern "C" void findclass(const char name[]) {
703 Command c("findclass");
704 if (name != NULL) {
705 tty->print_cr("Finding class %s -> ", name);
706 FindClassObjectClosure srch(name);
707 Universe::heap()->permanent_object_iterate(&srch);
708 }
709 }
711 // Another interface that isn't ambiguous in dbx.
712 // Can we someday rename the other find to hsfind?
713 extern "C" void hsfind(intptr_t x) {
714 Command c("hsfind");
715 os::print_location(tty, x, false);
716 }
719 extern "C" void hsfindref(intptr_t x) {
720 Command c("hsfindref");
721 findref(x);
722 }
724 extern "C" void find(intptr_t x) {
725 Command c("find");
726 os::print_location(tty, x, false);
727 }
730 extern "C" void findpc(intptr_t x) {
731 Command c("findpc");
732 os::print_location(tty, x, true);
733 }
736 // int versions of all methods to avoid having to type type casts in the debugger
738 void pp(intptr_t p) { pp((void*)p); }
739 void pp(oop p) { pp((void*)p); }
741 void help() {
742 Command c("help");
743 tty->print_cr("basic");
744 tty->print_cr(" pp(void* p) - try to make sense of p");
745 tty->print_cr(" pv(intptr_t p)- ((PrintableResourceObj*) p)->print()");
746 tty->print_cr(" ps() - print current thread stack");
747 tty->print_cr(" pss() - print all thread stacks");
748 tty->print_cr(" pm(int pc) - print methodOop given compiled PC");
749 tty->print_cr(" findm(intptr_t pc) - finds methodOop");
750 tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
752 tty->print_cr("misc.");
753 tty->print_cr(" flush() - flushes the log file");
754 tty->print_cr(" events() - dump last 50 events");
757 tty->print_cr("compiler debugging");
758 tty->print_cr(" debug() - to set things up for compiler debugging");
759 tty->print_cr(" ndebug() - undo debug");
760 }
762 #if 0
764 // BobV's command parser for debugging on windows when nothing else works.
766 enum CommandID {
767 CMDID_HELP,
768 CMDID_QUIT,
769 CMDID_HSFIND,
770 CMDID_PSS,
771 CMDID_PS,
772 CMDID_PSF,
773 CMDID_FINDM,
774 CMDID_FINDNM,
775 CMDID_PP,
776 CMDID_BPT,
777 CMDID_EXIT,
778 CMDID_VERIFY,
779 CMDID_THREADS,
780 CMDID_ILLEGAL = 99
781 };
783 struct CommandParser {
784 char *name;
785 CommandID code;
786 char *description;
787 };
789 struct CommandParser CommandList[] = {
790 (char *)"help", CMDID_HELP, " Dump this list",
791 (char *)"quit", CMDID_QUIT, " Return from this routine",
792 (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address",
793 (char *)"ps", CMDID_PS, " Print Current Thread Stack Trace",
794 (char *)"pss", CMDID_PSS, " Print All Thread Stack Trace",
795 (char *)"psf", CMDID_PSF, " Print All Stack Frames",
796 (char *)"findm", CMDID_FINDM, " Find a methodOop from a PC",
797 (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC",
798 (char *)"pp", CMDID_PP, " Find out something about a pointer",
799 (char *)"break", CMDID_BPT, " Execute a breakpoint",
800 (char *)"exitvm", CMDID_EXIT, "Exit the VM",
801 (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify",
802 (char *)"thread", CMDID_THREADS, "Dump Info on all Threads",
803 (char *)0, CMDID_ILLEGAL
804 };
807 // get_debug_command()
808 //
809 // Read a command from standard input.
810 // This is useful when you have a debugger
811 // which doesn't support calling into functions.
812 //
813 void get_debug_command()
814 {
815 ssize_t count;
816 int i,j;
817 bool gotcommand;
818 intptr_t addr;
819 char buffer[256];
820 nmethod *nm;
821 methodOop m;
823 tty->print_cr("You have entered the diagnostic command interpreter");
824 tty->print("The supported commands are:\n");
825 for ( i=0; ; i++ ) {
826 if ( CommandList[i].code == CMDID_ILLEGAL )
827 break;
828 tty->print_cr(" %s \n", CommandList[i].name );
829 }
831 while ( 1 ) {
832 gotcommand = false;
833 tty->print("Please enter a command: ");
834 count = scanf("%s", buffer) ;
835 if ( count >=0 ) {
836 for ( i=0; ; i++ ) {
837 if ( CommandList[i].code == CMDID_ILLEGAL ) {
838 if (!gotcommand) tty->print("Invalid command, please try again\n");
839 break;
840 }
841 if ( strcmp(buffer, CommandList[i].name) == 0 ) {
842 gotcommand = true;
843 switch ( CommandList[i].code ) {
844 case CMDID_PS:
845 ps();
846 break;
847 case CMDID_PSS:
848 pss();
849 break;
850 case CMDID_PSF:
851 psf();
852 break;
853 case CMDID_FINDM:
854 tty->print("Please enter the hex addr to pass to findm: ");
855 scanf("%I64X", &addr);
856 m = (methodOop)findm(addr);
857 tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m);
858 break;
859 case CMDID_FINDNM:
860 tty->print("Please enter the hex addr to pass to findnm: ");
861 scanf("%I64X", &addr);
862 nm = (nmethod*)findnm(addr);
863 tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm);
864 break;
865 case CMDID_PP:
866 tty->print("Please enter the hex addr to pass to pp: ");
867 scanf("%I64X", &addr);
868 pp((void*)addr);
869 break;
870 case CMDID_EXIT:
871 exit(0);
872 case CMDID_HELP:
873 tty->print("Here are the supported commands: ");
874 for ( j=0; ; j++ ) {
875 if ( CommandList[j].code == CMDID_ILLEGAL )
876 break;
877 tty->print_cr(" %s -- %s\n", CommandList[j].name,
878 CommandList[j].description );
879 }
880 break;
881 case CMDID_QUIT:
882 return;
883 break;
884 case CMDID_BPT:
885 BREAKPOINT;
886 break;
887 case CMDID_VERIFY:
888 verify();;
889 break;
890 case CMDID_THREADS:
891 threads();;
892 break;
893 case CMDID_HSFIND:
894 tty->print("Please enter the hex addr to pass to hsfind: ");
895 scanf("%I64X", &addr);
896 tty->print("Calling hsfind(0x%I64X)\n", addr);
897 hsfind(addr);
898 break;
899 default:
900 case CMDID_ILLEGAL:
901 break;
902 }
903 }
904 }
905 }
906 }
907 }
908 #endif
910 #endif // PRODUCT