debug.cpp revision 4558:746b070f5022
1130561Sobrien/*
2130561Sobrien * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3130561Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4130561Sobrien *
5130561Sobrien * This code is free software; you can redistribute it and/or modify it
6130561Sobrien * under the terms of the GNU General Public License version 2 only, as
7130561Sobrien * published by the Free Software Foundation.
8130561Sobrien *
9130561Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT
10130561Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11130561Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12130561Sobrien * version 2 for more details (a copy is included in the LICENSE file that
13130561Sobrien * accompanied this code).
14130561Sobrien *
15130561Sobrien * You should have received a copy of the GNU General Public License version
16130561Sobrien * 2 along with this work; if not, write to the Free Software Foundation,
17130561Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18130561Sobrien *
19130561Sobrien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20130561Sobrien * or visit www.oracle.com if you need additional information or have any
21130561Sobrien * questions.
22130561Sobrien *
23130561Sobrien */
24130561Sobrien
25130561Sobrien#include "precompiled.hpp"
26130561Sobrien#include "classfile/systemDictionary.hpp"
27130561Sobrien#include "code/codeCache.hpp"
28130561Sobrien#include "code/icBuffer.hpp"
29130561Sobrien#include "code/nmethod.hpp"
30130561Sobrien#include "code/vtableStubs.hpp"
31130561Sobrien#include "compiler/compileBroker.hpp"
32130561Sobrien#include "compiler/disassembler.hpp"
33130561Sobrien#include "gc_implementation/shared/markSweep.hpp"
34130561Sobrien#include "gc_interface/collectedHeap.hpp"
35130561Sobrien#include "interpreter/bytecodeHistogram.hpp"
36130561Sobrien#include "interpreter/interpreter.hpp"
37130561Sobrien#include "memory/resourceArea.hpp"
38130561Sobrien#include "memory/universe.hpp"
39130561Sobrien#include "oops/oop.inline.hpp"
40130561Sobrien#include "prims/privilegedStack.hpp"
41130561Sobrien#include "runtime/arguments.hpp"
42130561Sobrien#include "runtime/frame.hpp"
43130561Sobrien#include "runtime/java.hpp"
44130561Sobrien#include "runtime/sharedRuntime.hpp"
45130561Sobrien#include "runtime/stubCodeGenerator.hpp"
46130561Sobrien#include "runtime/stubRoutines.hpp"
47130561Sobrien#include "runtime/thread.inline.hpp"
48130561Sobrien#include "runtime/vframe.hpp"
49130561Sobrien#include "services/heapDumper.hpp"
50130561Sobrien#include "utilities/defaultStream.hpp"
51130561Sobrien#include "utilities/events.hpp"
52130561Sobrien#include "utilities/top.hpp"
53130561Sobrien#include "utilities/vmError.hpp"
54130561Sobrien#ifdef TARGET_OS_FAMILY_linux
55130561Sobrien# include "os_linux.inline.hpp"
56130561Sobrien#endif
57130561Sobrien#ifdef TARGET_OS_FAMILY_solaris
58130561Sobrien# include "os_solaris.inline.hpp"
59130561Sobrien#endif
60130561Sobrien#ifdef TARGET_OS_FAMILY_windows
61130561Sobrien# include "os_windows.inline.hpp"
62130561Sobrien#endif
63130561Sobrien#ifdef TARGET_OS_FAMILY_bsd
64130561Sobrien# include "os_bsd.inline.hpp"
65130561Sobrien#endif
66130561Sobrien
67130561Sobrien#ifndef ASSERT
68130561Sobrien#  ifdef _DEBUG
69130561Sobrien   // NOTE: don't turn the lines below into a comment -- if you're getting
70130561Sobrien   // a compile error here, change the settings to define ASSERT
71130561Sobrien   ASSERT should be defined when _DEBUG is defined.  It is not intended to be used for debugging
72130561Sobrien   functions that do not slow down the system too much and thus can be left in optimized code.
73130561Sobrien   On the other hand, the code should not be included in a production version.
74130561Sobrien#  endif // _DEBUG
75130561Sobrien#endif // ASSERT
76130561Sobrien
77130561Sobrien
78130561Sobrien#ifdef _DEBUG
79130561Sobrien#  ifndef ASSERT
80130561Sobrien     configuration error: ASSERT must be defined in debug version
81130561Sobrien#  endif // ASSERT
82130561Sobrien#endif // _DEBUG
83130561Sobrien
84130561Sobrien
85130561Sobrien#ifdef PRODUCT
86130561Sobrien#  if -defined _DEBUG || -defined ASSERT
87130561Sobrien     configuration error: ASSERT et al. must not be defined in PRODUCT version
88130561Sobrien#  endif
89130561Sobrien#endif // PRODUCT
90130561Sobrien
91130561SobrienFormatBufferResource::FormatBufferResource(const char * format, ...)
92130561Sobrien  : FormatBufferBase((char*)resource_allocate_bytes(RES_BUFSZ)) {
93130561Sobrien  va_list argp;
94130561Sobrien  va_start(argp, format);
95130561Sobrien  jio_vsnprintf(_buf, RES_BUFSZ, format, argp);
96130561Sobrien  va_end(argp);
97130561Sobrien}
98130561Sobrien
99130561Sobrienvoid warning(const char* format, ...) {
100130561Sobrien  if (PrintWarnings) {
101130561Sobrien    FILE* const err = defaultStream::error_stream();
102130561Sobrien    jio_fprintf(err, "%s warning: ", VM_Version::vm_name());
103130561Sobrien    va_list ap;
104130561Sobrien    va_start(ap, format);
105130561Sobrien    vfprintf(err, format, ap);
106130561Sobrien    va_end(ap);
107130561Sobrien    fputc('\n', err);
108130561Sobrien  }
109130561Sobrien  if (BreakAtWarning) BREAKPOINT;
110130561Sobrien}
111130561Sobrien
112130561Sobrien#ifndef PRODUCT
113130561Sobrien
114130561Sobrien#define is_token_break(ch) (isspace(ch) || (ch) == ',')
115130561Sobrien
116130561Sobrienstatic const char* last_file_name = NULL;
117130561Sobrienstatic int         last_line_no   = -1;
118130561Sobrien
119130561Sobrien// assert/guarantee/... may happen very early during VM initialization.
120130561Sobrien// Don't rely on anything that is initialized by Threads::create_vm(). For
121130561Sobrien// example, don't use tty.
122130561Sobrienbool error_is_suppressed(const char* file_name, int line_no) {
123130561Sobrien  // The following 1-element cache requires that passed-in
124130561Sobrien  // file names are always only constant literals.
125130561Sobrien  if (file_name == last_file_name && line_no == last_line_no)  return true;
126130561Sobrien
127130561Sobrien  int file_name_len = (int)strlen(file_name);
128130561Sobrien  char separator = os::file_separator()[0];
129130561Sobrien  const char* base_name = strrchr(file_name, separator);
130130561Sobrien  if (base_name == NULL)
131130561Sobrien    base_name = file_name;
132130561Sobrien
133130561Sobrien  // scan the SuppressErrorAt option
134130561Sobrien  const char* cp = SuppressErrorAt;
135130561Sobrien  for (;;) {
136130561Sobrien    const char* sfile;
137130561Sobrien    int sfile_len;
138130561Sobrien    int sline;
139130561Sobrien    bool noisy;
140130561Sobrien    while ((*cp) != '\0' && is_token_break(*cp))  cp++;
141130561Sobrien    if ((*cp) == '\0')  break;
142130561Sobrien    sfile = cp;
143130561Sobrien    while ((*cp) != '\0' && !is_token_break(*cp) && (*cp) != ':')  cp++;
144130561Sobrien    sfile_len = cp - sfile;
145130561Sobrien    if ((*cp) == ':')  cp++;
146130561Sobrien    sline = 0;
147130561Sobrien    while ((*cp) != '\0' && isdigit(*cp)) {
148130561Sobrien      sline *= 10;
149130561Sobrien      sline += (*cp) - '0';
150130561Sobrien      cp++;
151130561Sobrien    }
152130561Sobrien    // "file:line!" means the assert suppression is not silent
153130561Sobrien    noisy = ((*cp) == '!');
154130561Sobrien    while ((*cp) != '\0' && !is_token_break(*cp))  cp++;
155130561Sobrien    // match the line
156130561Sobrien    if (sline != 0) {
157130561Sobrien      if (sline != line_no)  continue;
158130561Sobrien    }
159130561Sobrien    // match the file
160130561Sobrien    if (sfile_len > 0) {
161130561Sobrien      const char* look = file_name;
162130561Sobrien      const char* look_max = file_name + file_name_len - sfile_len;
163130561Sobrien      const char* foundp;
164130561Sobrien      bool match = false;
165130561Sobrien      while (!match
166130561Sobrien             && (foundp = strchr(look, sfile[0])) != NULL
167130561Sobrien             && foundp <= look_max) {
168130561Sobrien        match = true;
169130561Sobrien        for (int i = 1; i < sfile_len; i++) {
170130561Sobrien          if (sfile[i] != foundp[i]) {
171130561Sobrien            match = false;
172130561Sobrien            break;
173130561Sobrien          }
174130561Sobrien        }
175130561Sobrien        look = foundp + 1;
176130561Sobrien      }
177130561Sobrien      if (!match)  continue;
178130561Sobrien    }
179130561Sobrien    // got a match!
180130561Sobrien    if (noisy) {
181130561Sobrien      fdStream out(defaultStream::output_fd());
182130561Sobrien      out.print_raw("[error suppressed at ");
183130561Sobrien      out.print_raw(base_name);
184130561Sobrien      char buf[16];
185130561Sobrien      jio_snprintf(buf, sizeof(buf), ":%d]", line_no);
186130561Sobrien      out.print_raw_cr(buf);
187130561Sobrien    } else {
188130561Sobrien      // update 1-element cache for fast silent matches
189130561Sobrien      last_file_name = file_name;
190130561Sobrien      last_line_no   = line_no;
191130561Sobrien    }
192130561Sobrien    return true;
193130561Sobrien  }
194130561Sobrien
195130561Sobrien  if (!is_error_reported()) {
196130561Sobrien    // print a friendly hint:
197130561Sobrien    fdStream out(defaultStream::output_fd());
198130561Sobrien    out.print_raw_cr("# To suppress the following error report, specify this argument");
199130561Sobrien    out.print_raw   ("# after -XX: or in .hotspotrc:  SuppressErrorAt=");
200130561Sobrien    out.print_raw   (base_name);
201130561Sobrien    char buf[16];
202130561Sobrien    jio_snprintf(buf, sizeof(buf), ":%d", line_no);
203130561Sobrien    out.print_raw_cr(buf);
204130561Sobrien  }
205130561Sobrien  return false;
206130561Sobrien}
207130561Sobrien
208130561Sobrien#undef is_token_break
209130561Sobrien
210130561Sobrien#else
211130561Sobrien
212130561Sobrien// Place-holder for non-existent suppression check:
213130561Sobrien#define error_is_suppressed(file_name, line_no) (false)
214130561Sobrien
215130561Sobrien#endif // !PRODUCT
216130561Sobrien
217130561Sobrienvoid report_vm_error(const char* file, int line, const char* error_msg,
218130561Sobrien                     const char* detail_msg)
219130561Sobrien{
220130561Sobrien  if (Debugging || error_is_suppressed(file, line)) return;
221130561Sobrien  Thread* const thread = ThreadLocalStorage::get_thread_slow();
222130561Sobrien  VMError err(thread, file, line, error_msg, detail_msg);
223130561Sobrien  err.report_and_die();
224130561Sobrien}
225130561Sobrien
226130561Sobrienvoid report_fatal(const char* file, int line, const char* message)
227130561Sobrien{
228130561Sobrien  report_vm_error(file, line, "fatal error", message);
229130561Sobrien}
230130561Sobrien
231130561Sobrienvoid report_vm_out_of_memory(const char* file, int line, size_t size,
232130561Sobrien                             VMErrorType vm_err_type, const char* message) {
233130561Sobrien  if (Debugging) return;
234130561Sobrien
235130561Sobrien  Thread* thread = ThreadLocalStorage::get_thread_slow();
236130561Sobrien  VMError(thread, file, line, size, vm_err_type, message).report_and_die();
237130561Sobrien
238130561Sobrien  // The UseOSErrorReporting option in report_and_die() may allow a return
239130561Sobrien  // to here. If so then we'll have to figure out how to handle it.
240130561Sobrien  guarantee(false, "report_and_die() should not return here");
241130561Sobrien}
242130561Sobrien
243130561Sobrienvoid report_should_not_call(const char* file, int line) {
244130561Sobrien  report_vm_error(file, line, "ShouldNotCall()");
245130561Sobrien}
246130561Sobrien
247130561Sobrienvoid report_should_not_reach_here(const char* file, int line) {
248130561Sobrien  report_vm_error(file, line, "ShouldNotReachHere()");
249130561Sobrien}
250130561Sobrien
251130561Sobrienvoid report_unimplemented(const char* file, int line) {
252130561Sobrien  report_vm_error(file, line, "Unimplemented()");
253130561Sobrien}
254130561Sobrien
255130561Sobrienvoid report_untested(const char* file, int line, const char* message) {
256130561Sobrien#ifndef PRODUCT
257130561Sobrien  warning("Untested: %s in %s: %d\n", message, file, line);
258130561Sobrien#endif // !PRODUCT
259130561Sobrien}
260130561Sobrien
261130561Sobrienvoid report_out_of_shared_space(SharedSpaceType shared_space) {
262130561Sobrien  static const char* name[] = {
263130561Sobrien    "native memory for metadata",
264130561Sobrien    "shared read only space",
265130561Sobrien    "shared read write space",
266130561Sobrien    "shared miscellaneous data space"
267130561Sobrien  };
268130561Sobrien  static const char* flag[] = {
269130561Sobrien    "Metaspace",
270130561Sobrien    "SharedReadOnlySize",
271130561Sobrien    "SharedReadWriteSize",
272130561Sobrien    "SharedMiscDataSize"
273130561Sobrien  };
274130561Sobrien
275130561Sobrien   warning("\nThe %s is not large enough\n"
276130561Sobrien           "to preload requested classes. Use -XX:%s=\n"
277130561Sobrien           "to increase the initial size of %s.\n",
278130561Sobrien           name[shared_space], flag[shared_space], name[shared_space]);
279130561Sobrien   exit(2);
280130561Sobrien}
281130561Sobrien
282130561Sobrienvoid report_java_out_of_memory(const char* message) {
283130561Sobrien  static jint out_of_memory_reported = 0;
284130561Sobrien
285130561Sobrien  // A number of threads may attempt to report OutOfMemoryError at around the
286130561Sobrien  // same time. To avoid dumping the heap or executing the data collection
287130561Sobrien  // commands multiple times we just do it once when the first threads reports
288130561Sobrien  // the error.
289130561Sobrien  if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) {
290130561Sobrien    // create heap dump before OnOutOfMemoryError commands are executed
291130561Sobrien    if (HeapDumpOnOutOfMemoryError) {
292130561Sobrien      tty->print_cr("java.lang.OutOfMemoryError: %s", message);
293130561Sobrien      HeapDumper::dump_heap_from_oome();
294130561Sobrien    }
295130561Sobrien
296130561Sobrien    if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
297130561Sobrien      VMError err(message);
298130561Sobrien      err.report_java_out_of_memory();
299130561Sobrien    }
300130561Sobrien  }
301130561Sobrien}
302130561Sobrien
303130561Sobrienstatic bool error_reported = false;
304130561Sobrien
305130561Sobrien// call this when the VM is dying--it might loosen some asserts
306130561Sobrienvoid set_error_reported() {
307130561Sobrien  error_reported = true;
308130561Sobrien}
309130561Sobrien
310130561Sobrienbool is_error_reported() {
311130561Sobrien    return error_reported;
312130561Sobrien}
313130561Sobrien
314130561Sobrien#ifndef PRODUCT
315130561Sobrien#include <signal.h>
316130561Sobrien
317130561Sobrienvoid test_error_handler(size_t test_num)
318130561Sobrien{
319130561Sobrien  if (test_num == 0) return;
320130561Sobrien
321130561Sobrien  // If asserts are disabled, use the corresponding guarantee instead.
322130561Sobrien  size_t n = test_num;
323130561Sobrien  NOT_DEBUG(if (n <= 2) n += 2);
324130561Sobrien
325130561Sobrien  const char* const str = "hello";
326130561Sobrien  const size_t      num = (size_t)os::vm_page_size();
327130561Sobrien
328130561Sobrien  const char* const eol = os::line_separator();
329130561Sobrien  const char* const msg = "this message should be truncated during formatting";
330130561Sobrien
331130561Sobrien  // Keep this in sync with test/runtime/6888954/vmerrors.sh.
332130561Sobrien  switch (n) {
333130561Sobrien    case  1: assert(str == NULL, "expected null");
334130561Sobrien    case  2: assert(num == 1023 && *str == 'X',
335130561Sobrien                    err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
336130561Sobrien    case  3: guarantee(str == NULL, "expected null");
337130561Sobrien    case  4: guarantee(num == 1023 && *str == 'X',
338130561Sobrien                       err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
339130561Sobrien    case  5: fatal("expected null");
340130561Sobrien    case  6: fatal(err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
341130561Sobrien    case  7: fatal(err_msg("%s%s#    %s%s#    %s%s#    %s%s#    %s%s#    "
342130561Sobrien                           "%s%s#    %s%s#    %s%s#    %s%s#    %s%s#    "
343130561Sobrien                           "%s%s#    %s%s#    %s%s#    %s%s#    %s",
344130561Sobrien                           msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
345130561Sobrien                           msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
346130561Sobrien                           msg, eol, msg, eol, msg, eol, msg, eol, msg));
347130561Sobrien    case  8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate");
348130561Sobrien    case  9: ShouldNotCallThis();
349130561Sobrien    case 10: ShouldNotReachHere();
350130561Sobrien    case 11: Unimplemented();
351130561Sobrien    // This is last because it does not generate an hs_err* file on Windows.
352130561Sobrien    case 12: os::signal_raise(SIGSEGV);
353130561Sobrien
354130561Sobrien    default: ShouldNotReachHere();
355130561Sobrien  }
356130561Sobrien}
357130561Sobrien#endif // !PRODUCT
358130561Sobrien
359130561Sobrien// ------ helper functions for debugging go here ------------
360130561Sobrien
361130561Sobrien// All debug entries should be wrapped with a stack allocated
362130561Sobrien// Command object. It makes sure a resource mark is set and
363130561Sobrien// flushes the logfile to prevent file sharing problems.
364130561Sobrien
365130561Sobrienclass Command : public StackObj {
366130561Sobrien private:
367130561Sobrien  ResourceMark rm;
368130561Sobrien  ResetNoHandleMark rnhm;
369130561Sobrien  HandleMark   hm;
370130561Sobrien  bool debug_save;
371130561Sobrien public:
372130561Sobrien  static int level;
373130561Sobrien  Command(const char* str) {
374130561Sobrien    debug_save = Debugging;
375130561Sobrien    Debugging = true;
376130561Sobrien    if (level++ > 0)  return;
377130561Sobrien    tty->cr();
378130561Sobrien    tty->print_cr("\"Executing %s\"", str);
379130561Sobrien  }
380130561Sobrien
381130561Sobrien  ~Command() {
382130561Sobrien        tty->flush();
383130561Sobrien        Debugging = debug_save;
384130561Sobrien        level--;
385130561Sobrien  }
386130561Sobrien};
387130561Sobrien
388130561Sobrienint Command::level = 0;
389130561Sobrien
390130561Sobrien#ifndef PRODUCT
391130561Sobrien
392130561Sobrienextern "C" void blob(CodeBlob* cb) {
393130561Sobrien  Command c("blob");
394130561Sobrien  cb->print();
395130561Sobrien}
396130561Sobrien
397130561Sobrien
398130561Sobrienextern "C" void dump_vtable(address p) {
399130561Sobrien  Command c("dump_vtable");
400130561Sobrien  Klass* k = (Klass*)p;
401130561Sobrien  InstanceKlass::cast(k)->vtable()->print();
402130561Sobrien}
403130561Sobrien
404130561Sobrien
405130561Sobrienextern "C" void nm(intptr_t p) {
406130561Sobrien  // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatability)
407130561Sobrien  Command c("nm");
408130561Sobrien  CodeBlob* cb = CodeCache::find_blob((address)p);
409130561Sobrien  if (cb == NULL) {
410130561Sobrien    tty->print_cr("NULL");
411130561Sobrien  } else {
412130561Sobrien    cb->print();
413130561Sobrien  }
414130561Sobrien}
415130561Sobrien
416130561Sobrien
417130561Sobrienextern "C" void disnm(intptr_t p) {
418130561Sobrien  Command c("disnm");
419130561Sobrien  CodeBlob* cb = CodeCache::find_blob((address) p);
420130561Sobrien  nmethod* nm = cb->as_nmethod_or_null();
421130561Sobrien  if (nm) {
422130561Sobrien    nm->print();
423130561Sobrien    Disassembler::decode(nm);
424130561Sobrien  } else {
425130561Sobrien    cb->print();
426130561Sobrien    Disassembler::decode(cb);
427130561Sobrien  }
428130561Sobrien}
429130561Sobrien
430130561Sobrien
431130561Sobrienextern "C" void printnm(intptr_t p) {
432130561Sobrien  char buffer[256];
433130561Sobrien  sprintf(buffer, "printnm: " INTPTR_FORMAT, p);
434130561Sobrien  Command c(buffer);
435130561Sobrien  CodeBlob* cb = CodeCache::find_blob((address) p);
436130561Sobrien  if (cb->is_nmethod()) {
437130561Sobrien    nmethod* nm = (nmethod*)cb;
438130561Sobrien    nm->print_nmethod(true);
439130561Sobrien  }
440130561Sobrien}
441130561Sobrien
442130561Sobrien
443130561Sobrienextern "C" void universe() {
444130561Sobrien  Command c("universe");
445130561Sobrien  Universe::print();
446130561Sobrien}
447130561Sobrien
448130561Sobrien
449130561Sobrienextern "C" void verify() {
450130561Sobrien  // try to run a verify on the entire system
451130561Sobrien  // note: this may not be safe if we're not at a safepoint; for debugging,
452130561Sobrien  // this manipulates the safepoint settings to avoid assertion failures
453130561Sobrien  Command c("universe verify");
454130561Sobrien  bool safe = SafepointSynchronize::is_at_safepoint();
455130561Sobrien  if (!safe) {
456130561Sobrien    tty->print_cr("warning: not at safepoint -- verify may fail");
457130561Sobrien    SafepointSynchronize::set_is_at_safepoint();
458130561Sobrien  }
459130561Sobrien  // Ensure Eden top is correct before verification
460130561Sobrien  Universe::heap()->prepare_for_verify();
461130561Sobrien  Universe::verify();
462130561Sobrien  if (!safe) SafepointSynchronize::set_is_not_at_safepoint();
463130561Sobrien}
464130561Sobrien
465130561Sobrien
466130561Sobrienextern "C" void pp(void* p) {
467130561Sobrien  Command c("pp");
468130561Sobrien  FlagSetting fl(PrintVMMessages, true);
469130561Sobrien  FlagSetting f2(DisplayVMOutput, true);
470130561Sobrien  if (Universe::heap()->is_in(p)) {
471130561Sobrien    oop obj = oop(p);
472130561Sobrien    obj->print();
473130561Sobrien  } else {
474130561Sobrien    tty->print(PTR_FORMAT, p);
475130561Sobrien  }
476130561Sobrien}
477130561Sobrien
478130561Sobrien
479130561Sobrien// pv: print vm-printable object
480130561Sobrienextern "C" void pa(intptr_t p)   { ((AllocatedObj*) p)->print(); }
481130561Sobrienextern "C" void findpc(intptr_t x);
482130561Sobrien
483130561Sobrien#endif // !PRODUCT
484130561Sobrien
485130561Sobrienextern "C" void ps() { // print stack
486130561Sobrien  if (Thread::current() == NULL) return;
487130561Sobrien  Command c("ps");
488130561Sobrien
489130561Sobrien
490130561Sobrien  // Prints the stack of the current Java thread
491130561Sobrien  JavaThread* p = JavaThread::active();
492130561Sobrien  tty->print(" for thread: ");
493130561Sobrien  p->print();
494130561Sobrien  tty->cr();
495130561Sobrien
496130561Sobrien  if (p->has_last_Java_frame()) {
497130561Sobrien    // If the last_Java_fp is set we are in C land and
498130561Sobrien    // can call the standard stack_trace function.
499130561Sobrien#ifdef PRODUCT
500130561Sobrien    p->print_stack();
501130561Sobrien  } else {
502130561Sobrien    tty->print_cr("Cannot find the last Java frame, printing stack disabled.");
503130561Sobrien#else // !PRODUCT
504130561Sobrien    p->trace_stack();
505130561Sobrien  } else {
506130561Sobrien    frame f = os::current_frame();
507130561Sobrien    RegisterMap reg_map(p);
508130561Sobrien    f = f.sender(&reg_map);
509130561Sobrien    tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id());
510130561Sobrien    p->trace_stack_from(vframe::new_vframe(&f, &reg_map, p));
511130561Sobrien  pd_ps(f);
512130561Sobrien#endif // PRODUCT
513130561Sobrien  }
514130561Sobrien
515130561Sobrien}
516130561Sobrien
517130561Sobrienextern "C" void pfl() {
518130561Sobrien  // print frame layout
519130561Sobrien  Command c("pfl");
520130561Sobrien  JavaThread* p = JavaThread::active();
521130561Sobrien  tty->print(" for thread: ");
522130561Sobrien  p->print();
523130561Sobrien  tty->cr();
524130561Sobrien  if (p->has_last_Java_frame()) {
525130561Sobrien    p->print_frame_layout();
526130561Sobrien  }
527130561Sobrien}
528130561Sobrien
529130561Sobrien#ifndef PRODUCT
530130561Sobrien
531130561Sobrienextern "C" void psf() { // print stack frames
532130561Sobrien  {
533130561Sobrien    Command c("psf");
534130561Sobrien    JavaThread* p = JavaThread::active();
535130561Sobrien    tty->print(" for thread: ");
536130561Sobrien    p->print();
537130561Sobrien    tty->cr();
538130561Sobrien    if (p->has_last_Java_frame()) {
539130561Sobrien      p->trace_frames();
540130561Sobrien    }
541130561Sobrien  }
542130561Sobrien}
543130561Sobrien
544130561Sobrien
545130561Sobrienextern "C" void threads() {
546130561Sobrien  Command c("threads");
547130561Sobrien  Threads::print(false, true);
548130561Sobrien}
549130561Sobrien
550130561Sobrien
551130561Sobrienextern "C" void psd() {
552130561Sobrien  Command c("psd");
553130561Sobrien  SystemDictionary::print();
554130561Sobrien}
555130561Sobrien
556130561Sobrien
557130561Sobrienextern "C" void safepoints() {
558130561Sobrien  Command c("safepoints");
559130561Sobrien  SafepointSynchronize::print_state();
560130561Sobrien}
561130561Sobrien
562130561Sobrien#endif // !PRODUCT
563130561Sobrien
564130561Sobrienextern "C" void pss() { // print all stacks
565130561Sobrien  if (Thread::current() == NULL) return;
566130561Sobrien  Command c("pss");
567130561Sobrien  Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true));
568130561Sobrien}
569130561Sobrien
570130561Sobrien#ifndef PRODUCT
571130561Sobrien
572130561Sobrienextern "C" void debug() {               // to set things up for compiler debugging
573130561Sobrien  Command c("debug");
574130561Sobrien  WizardMode = true;
575130561Sobrien  PrintVMMessages = PrintCompilation = true;
576130561Sobrien  PrintInlining = PrintAssembly = true;
577130561Sobrien  tty->flush();
578130561Sobrien}
579130561Sobrien
580130561Sobrien
581130561Sobrienextern "C" void ndebug() {              // undo debug()
582130561Sobrien  Command c("ndebug");
583130561Sobrien  PrintCompilation = false;
584130561Sobrien  PrintInlining = PrintAssembly = false;
585130561Sobrien  tty->flush();
586130561Sobrien}
587130561Sobrien
588130561Sobrien
589130561Sobrienextern "C" void flush()  {
590130561Sobrien  Command c("flush");
591130561Sobrien  tty->flush();
592130561Sobrien}
593130561Sobrien
594130561Sobrienextern "C" void events() {
595130561Sobrien  Command c("events");
596130561Sobrien  Events::print();
597130561Sobrien}
598130561Sobrien
599130561Sobrienextern "C" Method* findm(intptr_t pc) {
600130561Sobrien  Command c("findm");
601130561Sobrien  nmethod* nm = CodeCache::find_nmethod((address)pc);
602130561Sobrien  return (nm == NULL) ? (Method*)NULL : nm->method();
603130561Sobrien}
604130561Sobrien
605130561Sobrien
606130561Sobrienextern "C" nmethod* findnm(intptr_t addr) {
607130561Sobrien  Command c("findnm");
608130561Sobrien  return  CodeCache::find_nmethod((address)addr);
609130561Sobrien}
610130561Sobrien
611130561Sobrien// Another interface that isn't ambiguous in dbx.
612130561Sobrien// Can we someday rename the other find to hsfind?
613130561Sobrienextern "C" void hsfind(intptr_t x) {
614130561Sobrien  Command c("hsfind");
615130561Sobrien  os::print_location(tty, x, false);
616130561Sobrien}
617130561Sobrien
618130561Sobrien
619130561Sobrienextern "C" void find(intptr_t x) {
620130561Sobrien  Command c("find");
621130561Sobrien  os::print_location(tty, x, false);
622130561Sobrien}
623130561Sobrien
624130561Sobrien
625130561Sobrienextern "C" void findpc(intptr_t x) {
626130561Sobrien  Command c("findpc");
627130561Sobrien  os::print_location(tty, x, true);
628130561Sobrien}
629130561Sobrien
630130561Sobrien
631130561Sobrien// Need method pointer to find bcp, when not in permgen.
632130561Sobrienextern "C" void findbcp(intptr_t method, intptr_t bcp) {
633130561Sobrien  Command c("findbcp");
634130561Sobrien  Method* mh = (Method*)method;
635130561Sobrien  if (!mh->is_native()) {
636130561Sobrien    tty->print_cr("bci_from(%p) = %d; print_codes():",
637130561Sobrien                        mh, mh->bci_from(address(bcp)));
638130561Sobrien    mh->print_codes_on(tty);
639130561Sobrien  }
640130561Sobrien}
641130561Sobrien
642130561Sobrien// int versions of all methods to avoid having to type type casts in the debugger
643130561Sobrien
644130561Sobrienvoid pp(intptr_t p)          { pp((void*)p); }
645130561Sobrienvoid pp(oop p)               { pp((void*)p); }
646130561Sobrien
647130561Sobrienvoid help() {
648130561Sobrien  Command c("help");
649130561Sobrien  tty->print_cr("basic");
650130561Sobrien  tty->print_cr("  pp(void* p)   - try to make sense of p");
651130561Sobrien  tty->print_cr("  pv(intptr_t p)- ((PrintableResourceObj*) p)->print()");
652130561Sobrien  tty->print_cr("  ps()          - print current thread stack");
653130561Sobrien  tty->print_cr("  pss()         - print all thread stacks");
654130561Sobrien  tty->print_cr("  pm(int pc)    - print Method* given compiled PC");
655130561Sobrien  tty->print_cr("  findm(intptr_t pc) - finds Method*");
656130561Sobrien  tty->print_cr("  find(intptr_t x)   - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
657130561Sobrien
658130561Sobrien  tty->print_cr("misc.");
659130561Sobrien  tty->print_cr("  flush()       - flushes the log file");
660130561Sobrien  tty->print_cr("  events()      - dump events from ring buffers");
661130561Sobrien
662130561Sobrien
663130561Sobrien  tty->print_cr("compiler debugging");
664130561Sobrien  tty->print_cr("  debug()       - to set things up for compiler debugging");
665130561Sobrien  tty->print_cr("  ndebug()      - undo debug");
666130561Sobrien}
667130561Sobrien
668130561Sobrien#if 0
669130561Sobrien
670130561Sobrien// BobV's command parser for debugging on windows when nothing else works.
671130561Sobrien
672130561Sobrienenum CommandID {
673130561Sobrien  CMDID_HELP,
674130561Sobrien  CMDID_QUIT,
675130561Sobrien  CMDID_HSFIND,
676130561Sobrien  CMDID_PSS,
677130561Sobrien  CMDID_PS,
678130561Sobrien  CMDID_PSF,
679130561Sobrien  CMDID_FINDM,
680130561Sobrien  CMDID_FINDNM,
681130561Sobrien  CMDID_PP,
682130561Sobrien  CMDID_BPT,
683130561Sobrien  CMDID_EXIT,
684130561Sobrien  CMDID_VERIFY,
685130561Sobrien  CMDID_THREADS,
686130561Sobrien  CMDID_ILLEGAL = 99
687130561Sobrien};
688130561Sobrien
689130561Sobrienstruct CommandParser {
690130561Sobrien   char *name;
691130561Sobrien   CommandID code;
692130561Sobrien   char *description;
693130561Sobrien};
694130561Sobrien
695130561Sobrienstruct CommandParser CommandList[] = {
696130561Sobrien  (char *)"help", CMDID_HELP, "  Dump this list",
697130561Sobrien  (char *)"quit", CMDID_QUIT, "  Return from this routine",
698130561Sobrien  (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address",
699130561Sobrien  (char *)"ps", CMDID_PS, "    Print Current Thread Stack Trace",
700130561Sobrien  (char *)"pss", CMDID_PSS, "   Print All Thread Stack Trace",
701130561Sobrien  (char *)"psf", CMDID_PSF, "   Print All Stack Frames",
702130561Sobrien  (char *)"findm", CMDID_FINDM, " Find a Method* from a PC",
703130561Sobrien  (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC",
704130561Sobrien  (char *)"pp", CMDID_PP, "    Find out something about a pointer",
705130561Sobrien  (char *)"break", CMDID_BPT, " Execute a breakpoint",
706130561Sobrien  (char *)"exitvm", CMDID_EXIT, "Exit the VM",
707130561Sobrien  (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify",
708130561Sobrien  (char *)"thread", CMDID_THREADS, "Dump Info on all Threads",
709130561Sobrien  (char *)0, CMDID_ILLEGAL
710130561Sobrien};
711130561Sobrien
712130561Sobrien
713130561Sobrien// get_debug_command()
714130561Sobrien//
715130561Sobrien// Read a command from standard input.
716130561Sobrien// This is useful when you have a debugger
717130561Sobrien// which doesn't support calling into functions.
718130561Sobrien//
719130561Sobrienvoid get_debug_command()
720130561Sobrien{
721130561Sobrien  ssize_t count;
722130561Sobrien  int i,j;
723130561Sobrien  bool gotcommand;
724130561Sobrien  intptr_t addr;
725130561Sobrien  char buffer[256];
726130561Sobrien  nmethod *nm;
727130561Sobrien  Method* m;
728130561Sobrien
729130561Sobrien  tty->print_cr("You have entered the diagnostic command interpreter");
730130561Sobrien  tty->print("The supported commands are:\n");
731130561Sobrien  for ( i=0; ; i++ ) {
732130561Sobrien    if ( CommandList[i].code == CMDID_ILLEGAL )
733130561Sobrien      break;
734130561Sobrien    tty->print_cr("  %s \n", CommandList[i].name );
735130561Sobrien  }
736130561Sobrien
737130561Sobrien  while ( 1 ) {
738130561Sobrien    gotcommand = false;
739130561Sobrien    tty->print("Please enter a command: ");
740130561Sobrien    count = scanf("%s", buffer) ;
741130561Sobrien    if ( count >=0 ) {
742130561Sobrien      for ( i=0; ; i++ ) {
743130561Sobrien        if ( CommandList[i].code == CMDID_ILLEGAL ) {
744130561Sobrien          if (!gotcommand) tty->print("Invalid command, please try again\n");
745130561Sobrien          break;
746130561Sobrien        }
747130561Sobrien        if ( strcmp(buffer, CommandList[i].name) == 0 ) {
748130561Sobrien          gotcommand = true;
749130561Sobrien          switch ( CommandList[i].code ) {
750130561Sobrien              case CMDID_PS:
751130561Sobrien                ps();
752130561Sobrien                break;
753130561Sobrien              case CMDID_PSS:
754130561Sobrien                pss();
755130561Sobrien                break;
756130561Sobrien              case CMDID_PSF:
757130561Sobrien                psf();
758130561Sobrien                break;
759130561Sobrien              case CMDID_FINDM:
760130561Sobrien                tty->print("Please enter the hex addr to pass to findm: ");
761130561Sobrien                scanf("%I64X", &addr);
762130561Sobrien                m = (Method*)findm(addr);
763130561Sobrien                tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m);
764130561Sobrien                break;
765130561Sobrien              case CMDID_FINDNM:
766130561Sobrien                tty->print("Please enter the hex addr to pass to findnm: ");
767130561Sobrien                scanf("%I64X", &addr);
768130561Sobrien                nm = (nmethod*)findnm(addr);
769130561Sobrien                tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm);
770130561Sobrien                break;
771130561Sobrien              case CMDID_PP:
772130561Sobrien                tty->print("Please enter the hex addr to pass to pp: ");
773130561Sobrien                scanf("%I64X", &addr);
774130561Sobrien                pp((void*)addr);
775130561Sobrien                break;
776130561Sobrien              case CMDID_EXIT:
777130561Sobrien                exit(0);
778130561Sobrien              case CMDID_HELP:
779130561Sobrien                tty->print("Here are the supported commands: ");
780130561Sobrien                for ( j=0; ; j++ ) {
781130561Sobrien                  if ( CommandList[j].code == CMDID_ILLEGAL )
782130561Sobrien                    break;
783130561Sobrien                  tty->print_cr("  %s --  %s\n", CommandList[j].name,
784130561Sobrien                                                 CommandList[j].description );
785130561Sobrien                }
786130561Sobrien                break;
787130561Sobrien              case CMDID_QUIT:
788130561Sobrien                return;
789130561Sobrien                break;
790130561Sobrien              case CMDID_BPT:
791130561Sobrien                BREAKPOINT;
792130561Sobrien                break;
793130561Sobrien              case CMDID_VERIFY:
794130561Sobrien                verify();;
795130561Sobrien                break;
796130561Sobrien              case CMDID_THREADS:
797130561Sobrien                threads();;
798130561Sobrien                break;
799130561Sobrien              case CMDID_HSFIND:
800130561Sobrien                tty->print("Please enter the hex addr to pass to hsfind: ");
801130561Sobrien                scanf("%I64X", &addr);
802130561Sobrien                tty->print("Calling hsfind(0x%I64X)\n", addr);
803130561Sobrien                hsfind(addr);
804130561Sobrien                break;
805130561Sobrien              default:
806130561Sobrien              case CMDID_ILLEGAL:
807130561Sobrien                break;
808130561Sobrien          }
809130561Sobrien        }
810130561Sobrien      }
811130561Sobrien    }
812130561Sobrien  }
813130561Sobrien}
814130561Sobrien#endif
815130561Sobrien
816130561Sobrien#endif // !PRODUCT
817130561Sobrien