changeset 2526:5cc05c7552ef

* tapset/jstack.stp.in: Wrap heap accessors in try-catch block. When we cannot read some part of the hotspot code heap catch that error and report the frame (address) without trying to decode it.
author Mark Wielaard <mark@klomp.org>
date Tue, 13 Mar 2012 23:21:36 +0100
parents 3622f089d9f3
children 527807ac6196
files ChangeLog tapset/jstack.stp.in
diffstat 2 files changed, 132 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Mar 13 17:24:50 2012 +0100
+++ b/ChangeLog	Tue Mar 13 23:21:36 2012 +0100
@@ -1,3 +1,8 @@
+2012-03-13  Mark Wielaard  <mjw@redhat.com>
+
+	* tapset/jstack.stp.in: Wrap heap accessors in try-catch block to be
+	able to report unusual frames.
+
 2012-03-13  Mark Wielaard  <mjw@redhat.com>
 
 	* tapset/jstack.stp.in: Use @var construct if available to pick
--- a/tapset/jstack.stp.in	Tue Mar 13 17:24:50 2012 +0100
+++ b/tapset/jstack.stp.in	Tue Mar 13 23:21:36 2012 +0100
@@ -309,129 +309,143 @@
             }
           block = CodeCache_low + (segment << CodeHeap_log2_segment_size);
 
-          // Do some sanity checking.
-          used = @cast(block, "HeapBlock",
-                       "@ABS_SERVER_LIBJVM_SO@")->_header->_used;
-          if (used != 1)
-            {
-              // Something very odd has happened.
-              frame = sprintf("0x%x <?unused-code-block?>", pc);
-              blob_name = "unused";
-              trust_fp = 0;
-              frame_size = 0;
-            }
-          else
+          // Some of this is "fuzzy" so catch any read error in case we
+          // "guessed" wrong.
+          try
             {
-	      // We don't like spaces in frames (makes it hard to return
-              // a space separated frame list). So make sure they are
-              // replaced by underscores when used in frames.
-              blob = block + HeapBlock_Header_size;
-              blob_name_ptr = @cast(blob, "CodeBlob",
-                                    "@ABS_SERVER_LIBJVM_SO@")->_name;
-              blob_name = ((blob_name_ptr == 0) ? "<unknown-code-blob>"
-                           : user_string(blob_name_ptr));
-            }
-
-	  // For compiled code the methodOop is part of the code blob.
-          // For the interpreter (and other code blobs) it is on the
-          // stack relative to the frame pointer.
-          if (blob_name == "nmethod")
-            methodOopPtr = @cast(blob, "nmethod",
-                                 "@ABS_SERVER_LIBJVM_SO@")->_method
-          else 
-            methodOopPtr = user_long(fp + (-3 * ptr_size)) & ptr_mask
-
-          // Start optimistic. A methodOop is only valid if it was
-          // heap allocated. And if the "type class" oop equals the
-          // Universe::methodKlassObj.
-          if (heap_start > methodOopPtr || methodOopPtr >= heap_end)
-            isMethodOop = 0
-          else
-            {
-              methodOopKlass = @cast(methodOopPtr, "methodOopDesc",
-                                     "@ABS_SERVER_LIBJVM_SO@")->_metadata->_klass;
-              isMethodOop = (methodOopKlass == Universe_methodKlassObj[pid()]);
-            }
 
-          if (isMethodOop)
-            {
-              // The java class is the holder of the constants (strings)
-              // that describe the method and signature. This constant pool
-              // contains symbolic information that describe the properties
-              // of the class. The indexes for methods and signaturates in
-              // the constant pool are symbolOopDescs that contain utf8
-              // strings (plus lenghts). (We could also sanity check that
-              // the tag value is correct [CONSTANT_String = 8]).
-              // Note that the class name uses '/' instead of '.' as
-              // package name separator and that the method signature is
-              // encoded as a method descriptor string. Both of which we
-              // don't demangle here.
-              constantPoolOopDesc = @cast(methodOopPtr, "methodOopDesc",
-                                          "@ABS_SERVER_LIBJVM_SO@")->_constants;
-              constantPoolOop_base = constantPoolOopDesc + constantPoolOopDesc_size;
-
-              klassPtr = @cast(constantPoolOopDesc, "constantPoolOopDesc",
-                               "@ABS_SERVER_LIBJVM_SO@")->_pool_holder;
-              klassSymbol = @cast(klassPtr + oopDesc_size, "Klass",
-                                  "@ABS_SERVER_LIBJVM_SO@")->_name;
-              klassName = &@cast(klassSymbol, "symbolOopDesc",
-                                 "@ABS_SERVER_LIBJVM_SO@")->_body[0];
-              klassLength = @cast(klassSymbol, "symbolOopDesc",
-                                  "@ABS_SERVER_LIBJVM_SO@")->_length;
-
-              methodIndex = @cast(methodOopPtr, "methodOopDesc",
-                                  "@ABS_SERVER_LIBJVM_SO@")->_constMethod->_name_index;
-              methodOopDesc = user_long(constantPoolOop_base + (methodIndex * ptr_size));
-              methodName = &@cast(methodOopDesc, "symbolOopDesc",
-                                  "@ABS_SERVER_LIBJVM_SO@")->_body[0];
-              methodLength = @cast(methodOopDesc, "symbolOopDesc",
-                                   "@ABS_SERVER_LIBJVM_SO@")->_length;
-
-              if (log_sig)
+              // Do some sanity checking.
+              used = @cast(block, "HeapBlock",
+                           "@ABS_SERVER_LIBJVM_SO@")->_header->_used;
+              if (used != 1)
                 {
-                  sigIndex = @cast(methodOopPtr, "methodOopDesc",
-                                   "@ABS_SERVER_LIBJVM_SO@")->_constMethod->_signature_index;
-                  sigOopDesc = user_long(constantPoolOop_base
-                                         + (sigIndex * ptr_size));
-                  sigName = &@cast(sigOopDesc, "symbolOopDesc",
-                                   "@ABS_SERVER_LIBJVM_SO@")->_body[0];
-                  sigLength = @cast(sigOopDesc, "symbolOopDesc",
-                                    "@ABS_SERVER_LIBJVM_SO@")->_length;
-                  sig = user_string_n(sigName, sigLength);
+                  // Something very odd has happened.
+                  frame = sprintf("<unused_code_block@0x%x>", pc);
+                  blob_name = "unused";
+                  trust_fp = 0;
+                  frame_size = 0;
                 }
               else
-                sig = "";
+                {
+                  // We don't like spaces in frames (makes it hard to return
+                  // a space separated frame list). So make sure they are
+                  // replaced by underscores when used in frames.
+                  blob = block + HeapBlock_Header_size;
+                  blob_name_ptr = @cast(blob, "CodeBlob",
+                                        "@ABS_SERVER_LIBJVM_SO@")->_name;
+                  blob_name = ((blob_name_ptr == 0) ? "<unknown-code-blob>"
+                               : user_string(blob_name_ptr));
+                }
+
+              // For compiled code the methodOop is part of the code blob.
+              // For the interpreter (and other code blobs) it is on the
+              // stack relative to the frame pointer.
+              if (blob_name == "nmethod")
+                methodOopPtr = @cast(blob, "nmethod",
+                                     "@ABS_SERVER_LIBJVM_SO@")->_method
+              else 
+                methodOopPtr = user_long(fp + (-3 * ptr_size)) & ptr_mask
 
-              code_name = (log_native
-                           ? sprintf("<%s@0x%x>",
-                                     str_replace(blob_name, " ", "_"), pc)
-                           : "");
+              // Start optimistic. A methodOop is only valid if it was
+              // heap allocated. And if the "type class" oop equals the
+              // Universe::methodKlassObj.
+              if (heap_start > methodOopPtr || methodOopPtr >= heap_end)
+                isMethodOop = 0
+              else
+                {
+                  methodOopKlass = @cast(methodOopPtr, "methodOopDesc",
+                                         "@ABS_SERVER_LIBJVM_SO@")->_metadata->_klass;
+                  isMethodOop = (methodOopKlass == Universe_methodKlassObj[pid()]);
+                }
+
+              if (isMethodOop)
+                {
+                  // The java class is the holder of the constants (strings)
+                  // that describe the method and signature. This constant pool
+                  // contains symbolic information that describe the properties
+                  // of the class. The indexes for methods and signaturates in
+                  // the constant pool are symbolOopDescs that contain utf8
+                  // strings (plus lenghts). (We could also sanity check that
+                  // the tag value is correct [CONSTANT_String = 8]).
+                  // Note that the class name uses '/' instead of '.' as
+                  // package name separator and that the method signature is
+                  // encoded as a method descriptor string. Both of which we
+                  // don't demangle here.
+                  constantPoolOopDesc = @cast(methodOopPtr, "methodOopDesc",
+                                              "@ABS_SERVER_LIBJVM_SO@")->_constants;
+                  constantPoolOop_base = constantPoolOopDesc + constantPoolOopDesc_size;
+
+                  klassPtr = @cast(constantPoolOopDesc, "constantPoolOopDesc",
+                                   "@ABS_SERVER_LIBJVM_SO@")->_pool_holder;
+                  klassSymbol = @cast(klassPtr + oopDesc_size, "Klass",
+                                      "@ABS_SERVER_LIBJVM_SO@")->_name;
+                  klassName = &@cast(klassSymbol, "symbolOopDesc",
+                                     "@ABS_SERVER_LIBJVM_SO@")->_body[0];
+                  klassLength = @cast(klassSymbol, "symbolOopDesc",
+                                      "@ABS_SERVER_LIBJVM_SO@")->_length;
 
-              frame = sprintf("%s.%s%s%s",
-                              user_string_n(klassName, klassLength),
-                              user_string_n(methodName, methodLength),
-                              sig, code_name);
+                  methodIndex = @cast(methodOopPtr, "methodOopDesc",
+                                      "@ABS_SERVER_LIBJVM_SO@")->_constMethod->_name_index;
+                  methodOopDesc = user_long(constantPoolOop_base + (methodIndex * ptr_size));
+                  methodName = &@cast(methodOopDesc, "symbolOopDesc",
+                                      "@ABS_SERVER_LIBJVM_SO@")->_body[0];
+                  methodLength = @cast(methodOopDesc, "symbolOopDesc",
+                                       "@ABS_SERVER_LIBJVM_SO@")->_length;
+
+                  if (log_sig)
+                    {
+                      sigIndex = @cast(methodOopPtr, "methodOopDesc",
+                                       "@ABS_SERVER_LIBJVM_SO@")->_constMethod->_signature_index;
+                      sigOopDesc = user_long(constantPoolOop_base
+                                             + (sigIndex * ptr_size));
+                      sigName = &@cast(sigOopDesc, "symbolOopDesc",
+                                       "@ABS_SERVER_LIBJVM_SO@")->_body[0];
+                      sigLength = @cast(sigOopDesc, "symbolOopDesc",
+                                        "@ABS_SERVER_LIBJVM_SO@")->_length;
+                      sig = user_string_n(sigName, sigLength);
+                    }
+                  else
+                    sig = "";
+
+                  code_name = (log_native
+                               ? sprintf("<%s@0x%x>",
+                                         str_replace(blob_name, " ", "_"), pc)
+                               : "");
+
+                  frame = sprintf("%s.%s%s%s",
+                                  user_string_n(klassName, klassLength),
+                                  user_string_n(methodName, methodLength),
+                                  sig, code_name);
+                }
+              else
+                {
+                  // This is probably just an internal function, not a java
+                  // method, just print the blob_name and continue.
+                  // fp is probably still trusted.
+                  if (log_native)
+                    frame = sprintf("<%s@0x%x>",
+                                    str_replace(blob_name, " ", "_"), pc);
+                }
+
+              // We cannot trust the frame pointer of compiled methods.
+              // The server (c2) jit compiler uses the fp register.
+              // We do know the method frame size on the stack. But
+              // this seems to be useful only as a hint of the minimum
+              // stack being used.
+              if (blob_name == "nmethod")
+                {
+                  trust_fp = 0;
+                  frame_size = @cast(blob, "CodeBlob",
+                                     "@ABS_SERVER_LIBJVM_SO@")->_frame_size;
+                }
+
             }
-          else
+          catch
             {
-              // This is probably just an internal function, not a java
-              // method, just print the blob_name and continue.
-              // fp is probably still trusted.
-              if (log_native)
-                frame = sprintf("<%s@0x%x>",
-                                str_replace(blob_name, " ", "_"), pc);
-            }
-
-          // We cannot trust the frame pointer of compiled methods.
-          // The server (c2) jit compiler uses the fp register.
-          // We do know the method frame size on the stack. But
-          // this seems to be useful only as a hint of the minimum
-          // stack being used.
-          if (blob_name == "nmethod")
-            {
+              // Some assumption above totally failed and we got an address
+              // read error. Give up and mark frame pointer as suspect.
+              frame = sprintf("<unknown_frame@0x%x>", pc);
               trust_fp = 0;
-              frame_size = @cast(blob, "CodeBlob",
-                                 "@ABS_SERVER_LIBJVM_SO@")->_frame_size;
             }
         }
       else