2004-12-11 Martin Baulig <martin@ximian.com>
[mono.git] / mono / dis / dis-cil.c
index a1fba0e24a1945cff4b0f3bd8d45bf483b266fdb..dfc250e96f5f157cbdd87a8312d3ba777dfb9330 100644 (file)
@@ -9,49 +9,14 @@
 #include <config.h>
 #include <glib.h>
 #include <stdio.h>
+#ifdef HAVE_WCHAR_H
 #include <wchar.h>
+#endif
 #include "meta.h"
 #include "get.h"
 #include "dump.h"
 #include "dis-cil.h"
-
-enum {
-       InlineBrTarget,
-       InlineField,
-       InlineI,
-       InlineI8,
-       InlineMethod,
-       InlineNone,
-       InlineR,
-       InlineSig,
-       InlineString,
-       InlineSwitch,
-       InlineTok,
-       InlineType,
-       InlineVar,
-       ShortInlineBrTarget,
-       ShortInlineI,
-       ShortInlineR,
-       ShortInlineVar
-};
-
-#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
-       { b, e, g, h, i },
-
-typedef struct {
-       char *name;
-       int   argument;
-
-       /*
-        * we are not really using any of the following:
-        */
-       int   bytes;
-       unsigned char  o1, o2;
-} opcode_t;
-
-static opcode_t opcodes [300] = {
-#include "mono/cil/opcode.def"
-};
+#include "mono/metadata/opcodes.h"
 
 /*
  * Strings on the US heap are encoded using UTF-16.  Poor man's
@@ -60,7 +25,7 @@ static opcode_t opcodes [300] = {
 static char *
 get_encoded_user_string (const char *ptr)
 {
-       char *res;
+       char *res, *result;
        int len, i, j;
 
        len = mono_metadata_decode_blob_size (ptr, &ptr);
@@ -73,91 +38,166 @@ get_encoded_user_string (const char *ptr)
                res [j] = ptr [i];
 
        res [j] = 0;
-               
-       return res;
+
+       result = g_strescape (res, NULL);
+       g_free (res);
+       
+       return result;
 }
 
+#define CODE_INDENT g_assert (indent_level < 512); \
+       indent[indent_level*2] = ' ';   \
+       indent[indent_level*2+1] = ' '; \
+       ++indent_level; \
+       indent[indent_level*2] = 0;
+#define CODE_UNINDENT g_assert (indent_level); \
+       --indent_level; \
+       indent[indent_level*2] = 0;
+
 void
-dissasemble_cil (metadata_t *m, const unsigned char *start, int size) 
+dissasemble_cil (MonoImage *m, MonoMethodHeader *mh, MonoGenericContext *context)
 {
+       const unsigned char *start = mh->code;
+       int size = mh->code_size;
        const unsigned char *end = start + size;
        const unsigned char *ptr = start;
-       opcode_t *entry;
+       const MonoOpcode *entry;
+       char indent[1024];
+       int i, 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",
+                       clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len);
+#undef clause
+       }
+#endif
+
+       if (mh->num_clauses) {
+              trys = g_malloc0 (sizeof (gboolean) * mh->num_clauses);
+              trys [0] = 1;
+              for (i=1; i < mh->num_clauses; ++i) {
+#define pcl mh->clauses [i-1]  
+#define cl mh->clauses [i]     
+                      if (pcl.try_offset != cl.try_offset || pcl.try_len != cl.try_len)
+                              trys [i] = 1;
+#undef pcl
+#undef cl
+              }
+       }
 
        while (ptr < end){
+               for (i = mh->num_clauses - 1; i >= 0 ; --i) {
+                       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) {
+                                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,
+                                                                                FALSE, FALSE);
+                                        fprintf (output, "\t%s%s %s { // %d\n", indent,
+                                                        clause_names [mh->clauses[i].flags], klass, i);
+                                        g_free (klass);
+                                }
+                               CODE_INDENT;
+                                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;
                if (*ptr == 0xfe){
                        ptr++;
-                       entry = &opcodes [*ptr + 256];
-               } else 
-                       entry = &opcodes [*ptr];
+                       i = *ptr + 256;
+               } 
+               entry = &mono_opcodes [i];
 
-               fprintf (output, "\tIL_%04x: %s ", (int) (ptr - start), entry->name);
+                if (in_fault && entry->opval == 0xDC)
+                        fprintf (output, " %s", "endfault");
+                else
+                        fprintf (output, " %s ", mono_opcode_name (i));
                ptr++;
                switch (entry->argument){
-               case InlineBrTarget: {
-                       gint target = *(gint32 *) ptr;
-                       fprintf (output, "IL_%04x", ((int) (ptr - start)) + 4 + target);
+               case MonoInlineBrTarget: {
+                       gint target = read32 (ptr);
+                       fprintf (output, "IL_%04x\n", ((int) (ptr - start)) + 4 + target);
                        ptr += 4;
                        break;
                }
                        
-               case InlineField: {
-                       guint32 token = *(guint32 *) ptr;
+               case MonoInlineField: {
+                       guint32 token = read32 (ptr);
                        char *s;
                        
-                       s = get_field (m, token);
+                       s = get_field (m, token, context);
                        fprintf (output, "%s", s);
                        g_free (s);
                        ptr += 4;
                        break;
                }
                
-               case InlineI: {
-                       int value = *(int *) ptr;
+               case MonoInlineI: {
+                       int value = read32 (ptr);
 
                        fprintf (output, "%d", value);
                        ptr += 4;
                        break;
                }
                
-               case InlineI8: {
-                       gint64 top = *(guint64 *) ptr;
+               case MonoInlineI8: {
+                       gint64 top = read64 (ptr);
 
-                       fprintf (output, "%lld", (long long) top);
+                       fprintf (output, "0x%llx", (long long) top);
                        ptr += 8;
                        break;
                }
                
-               case InlineMethod: {
-                       guint32 token = *(guint32 *) ptr;
+               case MonoInlineMethod: {
+                       guint32 token = read32 (ptr);
                        char *s;
 
-                       s = get_method (m, token);
+                       s = get_method (m, token, context);
                        fprintf (output, "%s", s);
                        g_free (s);
                        ptr += 4;
                        break;
                }
                
-               case InlineNone:
+               case MonoInlineNone:
                        break;
                        
-               case InlineR: {
-                       double r = *(double *) ptr;
+               case MonoInlineR: {
+                       double r;
+                       readr8 (ptr, &r);
                        fprintf (output, "%g", r);
                        ptr += 8;
                        break;
                }
                
-               case InlineSig: {
-                       guint32 token = *(guint32 *) ptr;
+               case MonoInlineSig: {
+                       guint32 token = read32 (ptr);
                        fprintf (output, "signature-0x%08x", token);
                        ptr += 4;
                        break;
                }
                
-               case InlineString: {
-                       guint32 token = *(guint32 *) ptr;
+               case MonoInlineString: {
+                       guint32 token = read32 (ptr);
                        
                        char *s = get_encoded_user_string (
                                mono_metadata_user_string (m, token & 0xffffff));
@@ -171,25 +211,30 @@ dissasemble_cil (metadata_t *m, const unsigned char *start, int size)
                        break;
                }
 
-               case InlineSwitch: {
-                       guint32 count = *(guint32 *) ptr;
-                       guint32 i;
+               case MonoInlineSwitch: {
+                       guint32 count = read32 (ptr);
+                       const unsigned char *endswitch;
+                       guint32 n;
                        
                        ptr += 4;
-                       fprintf (output, "(\n\t\t\t");
-                       for (i = 0; i < count; i++){
-                               fprintf (output, "IL_%x", *(guint32 *) ptr);
+                       endswitch = ptr + sizeof (guint32) * count;
+                       fprintf (output, count > 0 ? "(\n" : "( )");
+                       CODE_INDENT;
+                       for (n = 0; n < count; n++){
+                               fprintf (output, "\t%sIL_%04x%s", indent, 
+                                       endswitch-start+read32 (ptr), 
+                                       n == count - 1 ? ")" : ",\n");
                                ptr += 4;
                        }
-                       fprintf (output, "\t\t\t)");
+                       CODE_UNINDENT;
                        break;
                }
 
-               case InlineTok: {
-                       guint32 token = *(guint32 *) ptr;
+               case MonoInlineTok: {
+                       guint32 token = read32 (ptr);
                        char *s;
                        
-                       s = get_token (m, token);
+                       s = get_token (m, token, context);
                        fprintf (output, "%s", s);
                        g_free (s);
                        
@@ -197,32 +242,32 @@ dissasemble_cil (metadata_t *m, const unsigned char *start, int size)
                        break;
                }
                
-               case InlineType: {
-                       guint32 token = *(guint32 *) ptr;
-                       char *s = get_token_type (m, token);
+               case MonoInlineType: {
+                       guint32 token = read32 (ptr);
+                       char *s = get_token_type (m, token, context);
                        fprintf (output, "%s", s);
                        g_free (s);
                        ptr += 4;
                        break;
                }
 
-               case InlineVar: {
-                       gint16 var_idx = *(gint16 *) ptr;
+               case MonoInlineVar: {
+                       guint16 var_idx = read16 (ptr);
 
-                       fprintf (output, "variable-%d\n", var_idx);
+                       fprintf (output, "%d\n", var_idx);
                        ptr += 2;
                        break;
                }
 
-               case ShortInlineBrTarget: {
+               case MonoShortInlineBrTarget: {
                        signed char x = *ptr;
                        
-                       fprintf (output, "IL_%04x", ptr - start + 1 + x);
+                       fprintf (output, "IL_%04x\n", ptr - start + 1 + x);
                        ptr++;
                        break;
                }
 
-               case ShortInlineI: {
+               case MonoShortInlineI: {
                        char x = *ptr;
 
                        fprintf (output, "0x%02x", x);
@@ -230,24 +275,40 @@ dissasemble_cil (metadata_t *m, const unsigned char *start, int size)
                        break;
                }
 
-               case ShortInlineR: {
-                       float f = *(float *) ptr;
+               case MonoShortInlineR: {
+                       float f;
+                       readr4 (ptr, &f);
 
                        fprintf (output, "%g", (double) f);
                        ptr += 4;
                        break;
                }
 
-               case ShortInlineVar: {
-                       signed char x = *ptr;
+               case MonoShortInlineVar: {
+                       unsigned char x = *ptr;
 
-                       fprintf (output, "V_%d", (int) x);
+                       fprintf (output, "%d", (int) x);
                        ptr++;
                        break;
                }
-
+               default:
+                       break;
                }
 
                fprintf (output, "\n");
+               for (i = 0; i < mh->num_clauses; ++i) {
+                       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);
 }