[custom_attrs] Don't return NULL if a single custom attr is missing.
[mono.git] / mono / dis / dis-cil.c
old mode 100644 (file)
new mode 100755 (executable)
index 617a823..bc40414
@@ -9,36 +9,18 @@
 #include <config.h>
 #include <glib.h>
 #include <stdio.h>
+#include <math.h>
+#ifdef HAVE_WCHAR_H
 #include <wchar.h>
+#endif
 #include "meta.h"
 #include "get.h"
 #include "dump.h"
 #include "dis-cil.h"
+#include "util.h"
 #include "mono/metadata/opcodes.h"
-
-/*
- * Strings on the US heap are encoded using UTF-16.  Poor man's
- * UTF-16 to UTF-8.  I know its broken, use libunicode later.
- */
-static char *
-get_encoded_user_string (const char *ptr)
-{
-       char *res;
-       int len, i, j;
-
-       len = mono_metadata_decode_blob_size (ptr, &ptr);
-       res = g_malloc (len + 1);
-
-       /*
-        * I should really use some kind of libunicode here
-        */
-       for (i = 0, j = 0; i < len; j++, i += 2)
-               res [j] = ptr [i];
-
-       res [j] = 0;
-               
-       return res;
-}
+#include "mono/metadata/class-internals.h"
+#include "mono/utils/mono-compiler.h"
 
 #define CODE_INDENT g_assert (indent_level < 512); \
        indent[indent_level*2] = ' ';   \
@@ -50,7 +32,7 @@ get_encoded_user_string (const char *ptr)
        indent[indent_level*2] = 0;
 
 void
-dissasemble_cil (MonoImage *m, MonoMethodHeader *mh) 
+disassemble_cil (MonoImage *m, MonoMethodHeader *mh, MonoGenericContainer *container)
 {
        const unsigned char *start = mh->code;
        int size = mh->code_size;
@@ -58,31 +40,66 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
        const unsigned char *ptr = start;
        const MonoOpcode *entry;
        char indent[1024];
-       int i, indent_level = 0;
-       char *clause_names[] = {"catch", "filter", "finally", "fault"};
-
+       int i, j, indent_level = 0;
+       gboolean in_fault = 0;
+       const char *clause_names[] = {"catch", "filter", "finally", "", "fault"};
+       gboolean *trys = NULL;
        indent [0] = 0;
 
 #ifdef DEBUG
        for (i = 0; i < mh->num_clauses; ++i) {
 #define clause mh->clauses [i]
-               g_print ("out clause %d: from %d len=%d, handler at %d, %d\n", 
+              g_print ("/* out clause %d: from %d len=%d, handler at %d, %d */\n",
                        clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len);
 #undef clause
        }
 #endif
+
+       if (mh->num_clauses) {
+              trys = (gboolean *)g_malloc0 (sizeof (gboolean) * mh->num_clauses);
+              trys [0] = 1;
+              for (i=1; i < mh->num_clauses; ++i) {
+#define jcl mh->clauses [j]    
+#define cl mh->clauses [i]     
+                      trys [i] = 1;
+                      for (j = 0; j < i; j++) {
+                              if (cl.try_offset == jcl.try_offset && cl.try_len == jcl.try_len) {
+                                      trys [i] = 0;
+                                      break;
+                              }
+                      }
+#undef jcl
+#undef cl
+              }
+       }
+
        while (ptr < end){
                for (i = mh->num_clauses - 1; i >= 0 ; --i) {
-                       if ((mh->clauses[i].flags == 0 || mh->clauses[i].flags == 2) && ptr == start + mh->clauses[i].try_offset) {
+                       if (ptr == start + mh->clauses[i].try_offset && trys [i]) {
                                fprintf (output, "\t%s.try { // %d\n", indent, i);
                                CODE_INDENT;
                        }
+                        
                        if (ptr == start + mh->clauses[i].handler_offset) {
-                               char * klass = mh->clauses[i].flags ? g_strdup ("") : dis_stringify_token (m, mh->clauses[i].token_or_filter);
-                               fprintf (output, "\t%s%s %s { // %d\n", indent, clause_names [mh->clauses[i].flags], klass, i);
+                                if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+                                        CODE_UNINDENT;
+                                        fprintf (output, "\t%s} { // %d\n", indent, i);
+                                } else {
+                                        char * klass = mh->clauses[i].flags ? g_strdup ("") :
+                                               dis_stringify_object_with_class (m, mh->clauses[i].data.catch_class,
+                                                                                TRUE, FALSE);
+                                        fprintf (output, "\t%s%s %s { // %d\n", indent,
+                                                        clause_names [mh->clauses[i].flags], klass, i);
+                                        g_free (klass);
+                                }
                                CODE_INDENT;
-                               g_free (klass);
-                       }
+                                if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                                        in_fault = 1;
+                       } 
+                        if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FILTER && ptr == start + mh->clauses[i].data.filter_offset) {
+                                fprintf (output, "\t%s%s {\n", indent, clause_names[1]);
+                                CODE_INDENT;
+                        }
                }
                fprintf (output, "\t%sIL_%04x: ", indent, (int) (ptr - start));
                i = *ptr;
@@ -92,7 +109,10 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                } 
                entry = &mono_opcodes [i];
 
-               fprintf (output, "%s ", mono_opcode_names [i]);
+                if (in_fault && entry->opval == 0xDC)
+                        fprintf (output, " %s", "endfault");
+                else
+                        fprintf (output, " %s ", mono_opcode_name (i));
                ptr++;
                switch (entry->argument){
                case MonoInlineBrTarget: {
@@ -106,7 +126,7 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                        guint32 token = read32 (ptr);
                        char *s;
                        
-                       s = get_field (m, token);
+                       s = get_field (m, token, container);
                        fprintf (output, "%s", s);
                        g_free (s);
                        ptr += 4;
@@ -133,7 +153,7 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                        guint32 token = read32 (ptr);
                        char *s;
 
-                       s = get_method (m, token);
+                       s = get_method (m, token, container);
                        fprintf (output, "%s", s);
                        g_free (s);
                        ptr += 4;
@@ -144,8 +164,21 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                        break;
                        
                case MonoInlineR: {
-                       double r = *(double *) ptr;
-                       fprintf (output, "%g", r);
+                       double r;
+                       int inf;
+                       readr8 (ptr, &r);
+                       inf = dis_isinf (r);
+                       if (inf == -1) 
+                               fprintf (output, "(00 00 00 00 00 00 f0 ff)"); /* negative infinity */
+                       else if (inf == 1)
+                               fprintf (output, "(00 00 00 00 00 00 f0 7f)"); /* positive infinity */
+                       else if (dis_isnan (r))
+                               fprintf (output, "(00 00 00 00 00 00 f8 ff)"); /* NaN */
+                       else {
+                               char *str = stringify_double (r);
+                               fprintf (output, "%s", str);
+                               g_free (str);
+                       }
                        ptr += 8;
                        break;
                }
@@ -159,14 +192,15 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                
                case MonoInlineString: {
                        guint32 token = read32 (ptr);
-                       
-                       char *s = get_encoded_user_string (
-                               mono_metadata_user_string (m, token & 0xffffff));
+                       const char *us_ptr = mono_metadata_user_string (m, token & 0xffffff);
+                       int len = mono_metadata_decode_blob_size (us_ptr, (const char**)&us_ptr);
+
+                       char *s = get_encoded_user_string_or_bytearray ((const guchar*)us_ptr, len);
                        
                        /*
                         * See section 23.1.4 on the encoding of the #US heap
                         */
-                       fprintf (output, "\"%s\"", s);
+                       fprintf (output, "%s", s);
                        g_free (s);
                        ptr += 4;
                        break;
@@ -175,16 +209,16 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                case MonoInlineSwitch: {
                        guint32 count = read32 (ptr);
                        const unsigned char *endswitch;
-                       guint32 i;
+                       guint32 n;
                        
                        ptr += 4;
                        endswitch = ptr + sizeof (guint32) * count;
-                       fprintf (output, "(\n");
+                       fprintf (output, count > 0 ? "(\n" : "( )");
                        CODE_INDENT;
-                       for (i = 0; i < count; i++){
+                       for (n = 0; n < count; n++){
                                fprintf (output, "\t%sIL_%04x%s", indent, 
-                                       endswitch-start+read32 (ptr), 
-                                       i == count - 1 ? ")" : ",\n");
+                                                (int)(endswitch-start+read32 (ptr)), 
+                                                n == count - 1 ? ")" : ",\n");
                                ptr += 4;
                        }
                        CODE_UNINDENT;
@@ -195,7 +229,7 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                        guint32 token = read32 (ptr);
                        char *s;
                        
-                       s = get_token (m, token);
+                       s = get_token (m, token, container);
                        fprintf (output, "%s", s);
                        g_free (s);
                        
@@ -205,7 +239,7 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                
                case MonoInlineType: {
                        guint32 token = read32 (ptr);
-                       char *s = get_token_type (m, token);
+                       char *s = get_token_type (m, token, container);
                        fprintf (output, "%s", s);
                        g_free (s);
                        ptr += 4;
@@ -213,9 +247,9 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                }
 
                case MonoInlineVar: {
-                       gint16 var_idx = read16 (ptr);
+                       guint16 var_idx = read16 (ptr);
 
-                       fprintf (output, "variable-%d\n", var_idx);
+                       fprintf (output, "%d\n", var_idx);
                        ptr += 2;
                        break;
                }
@@ -223,7 +257,7 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                case MonoShortInlineBrTarget: {
                        signed char x = *ptr;
                        
-                       fprintf (output, "IL_%04x\n", ptr - start + 1 + x);
+                       fprintf (output, "IL_%04x\n", (int)(ptr - start + 1 + x));
                        ptr++;
                        break;
                }
@@ -237,15 +271,29 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
                }
 
                case MonoShortInlineR: {
-                       float f = *(float *) ptr;
+                       float f;
+                       int inf;
+                       
+                       readr4 (ptr, &f);
 
-                       fprintf (output, "%g", (double) f);
+                       inf = dis_isinf (f);
+                       if (inf == -1) 
+                               fprintf (output, "(00 00 80 ff)"); /* negative infinity */
+                       else if (inf == 1)
+                               fprintf (output, "(00 00 80 7f)"); /* positive infinity */
+                       else if (dis_isnan (f))
+                               fprintf (output, "(00 00 c0 ff)"); /* NaN */
+                       else {
+                               char *str = stringify_double ((double) f);
+                               fprintf (output, "%s", str);
+                               g_free (str);
+                       }
                        ptr += 4;
                        break;
                }
 
                case MonoShortInlineVar: {
-                       signed char x = *ptr;
+                       unsigned char x = *ptr;
 
                        fprintf (output, "%d", (int) x);
                        ptr++;
@@ -257,14 +305,18 @@ dissasemble_cil (MonoImage *m, MonoMethodHeader *mh)
 
                fprintf (output, "\n");
                for (i = 0; i < mh->num_clauses; ++i) {
-                       if ((mh->clauses[i].flags == 0 || mh->clauses[i].flags == 2)  && ptr == start + mh->clauses[i].try_offset + mh->clauses[i].try_len) {
+                       if (ptr == start + mh->clauses[i].try_offset + mh->clauses[i].try_len && trys [i]) {
                                CODE_UNINDENT;
                                fprintf (output, "\t%s} // end .try %d\n", indent, i);
                        }
                        if (ptr == start + mh->clauses[i].handler_offset + mh->clauses[i].handler_len) {
                                CODE_UNINDENT;
                                fprintf (output, "\t%s} // end handler %d\n", indent, i);
+                                if (mh->clauses[i].flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                                        in_fault = 0;
                        }
                }
        }
+       if (trys)
+               g_free (trys);
 }