2002-09-03 Martin Baulig <martin@gnome.org>
[mono.git] / mono / jit / debug-stabs.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <mono/metadata/class.h>
5 #include <mono/metadata/tabledefs.h>
6 #include <mono/metadata/tokentype.h>
7 #include <mono/jit/codegen.h>
8 #include <mono/jit/debug.h>
9
10 #include "debug-private.h"
11
12 typedef struct {
13         const char *name;
14         const char *spec;
15 } BaseTypes;
16
17 /*
18  * Not 64 bit clean.
19  * Note: same order of MonoTypeEnum.
20  */
21 static BaseTypes
22 base_types[] = {
23         {"", NULL},
24         {"Void", "(0,1)"},
25         {"Boolean", ";0;255;"},
26         {"Char", ";0;65535;"},
27         {"SByte", ";-128;127;"},
28         {"Byte", ";0;255;"},
29         {"Int16", ";-32768;32767;"},
30         {"UInt16", ";0;65535;"},
31         {"Int32", ";0020000000000;0017777777777;"},
32         {"UInt32", ";0000000000000;0037777777777;"},
33         {"Int64", ";01000000000000000000000;0777777777777777777777;"},
34         {"UInt64", ";0000000000000;01777777777777777777777;"},
35         {"Single", "r(0,8);4;0;"},
36         {"Double", "r(0,8);8;0;"},
37         {"String", "(0,41)=*(0,42)=xsMonoString:"}, /*string*/
38         {"", }, /*ptr*/
39         {"", }, /*byref*/
40         {"", }, /*valuetype*/
41         {"Class", "(0,44)=*(0,45)=xsMonoObject:"}, /*class*/
42         {"", }, /*unused*/
43         {"Array", }, /*array*/
44         {"", }, /*typedbyref*/
45         {"", }, /*unused*/
46         {"", }, /*unused*/
47         {"IntPtr", ";0020000000000;0017777777777;"},
48         {"UIntPtr", ";0000000000000;0037777777777;"},
49         {"", }, /*unused*/
50         {"FnPtr", "*(0,1)"}, /*fnptr*/
51         {"Object", "(0,47)=*(0,48)=xsMonoObject:"}, /*object*/
52         {"SzArray", "(0,50)=*(0,51))=xsMonoArray:"}, /*szarray*/
53         {NULL, NULL}
54 };
55
56 static void
57 write_method_stabs (MonoDebugHandle *debug, MonoDebugMethodInfo *minfo)
58 {
59         int i;
60         DebugMethodInfo *priv = minfo->user_data;
61         MonoMethod *method = minfo->method;
62         MonoClass *klass = method->klass;
63         MonoMethodSignature *sig = method->signature;
64         char **names = g_new (char*, sig->param_count);
65         gchar *source_file;
66
67         if (!minfo->jit)
68                 return;
69
70         source_file = g_ptr_array_index (debug->source_files, priv->source_file);
71
72         fprintf (debug->f, ".stabs \"%s\",100,0,0,0\n", source_file);
73
74         fprintf (debug->f, ".stabs \"%s:F(0,%d)\",36,0,%d,%p\n", priv->name, sig->ret->type,
75                  priv->start_line, minfo->jit->code_start);
76
77         /* params */
78         mono_method_get_param_names (method, (const char **)names);
79         if (sig->hasthis)
80                 fprintf (debug->f, ".stabs \"this:p(0,%d)=(0,%d)\",160,0,%d,%d\n",
81                          debug->next_idx++, klass->byval_arg.type, priv->start_line,
82                          minfo->jit->this_var->offset);
83         for (i = 0; i < minfo->jit->num_params; i++) {
84                 int stack_offset = minfo->jit->params [i].offset;
85
86                 fprintf (debug->f, ".stabs \"%s:p(0,%d)=(0,%d)\",160,0,%d,%d\n",
87                          names [i], debug->next_idx++, sig->params [i]->type,
88                          priv->start_line, stack_offset);
89         }
90
91         /* local vars */
92         for (i = 0; i < minfo->jit->num_locals; ++i) {
93                 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
94                 int stack_offset = minfo->jit->locals [i].offset;
95
96                 fprintf (debug->f, ".stabs \"local_%d:(0,%d)=(0,%d)\",128,0,%d,%d\n",
97                          i, debug->next_idx++, header->locals [i]->type, priv->start_line, stack_offset);
98         }
99
100         if (priv->line_numbers) {
101                 fprintf (debug->f, ".stabn 68,0,%d,%d\n", priv->start_line, 0);
102                 fprintf (debug->f, ".stabn 68,0,%d,%d\n", priv->first_line,
103                          minfo->jit->prologue_end);
104
105                 for (i = 1; i < priv->line_numbers->len; i++) {
106                         DebugLineNumberInfo *lni = g_ptr_array_index (priv->line_numbers, i);
107
108                         fprintf (debug->f, ".stabn 68,0,%d,%d\n", lni->line,
109                                  lni->address - minfo->jit->code_start);
110                 }
111
112                 fprintf (debug->f, ".stabn 68,0,%d,%d\n", priv->last_line,
113                          minfo->jit->epilogue_begin);
114         }
115
116         /* end of function */
117         fprintf (debug->f, ".stabs \"\",36,0,0,%d\n", minfo->jit->code_size);
118
119         g_free (names);
120         fflush (debug->f);
121 }
122
123 static void
124 get_enumvalue (MonoClass *klass, int idx, char *buf)
125 {
126         guint32 const_cols [MONO_CONSTANT_SIZE];
127         const char *ptr;
128         guint32 crow = mono_metadata_get_constant_index (klass->image, MONO_TOKEN_FIELD_DEF | (idx + 1));
129
130         if (!crow) {
131                 buf [0] = '0';
132                 buf [1] = 0;
133                 return;
134         }
135         mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], crow-1, const_cols, MONO_CONSTANT_SIZE);
136         ptr = mono_metadata_blob_heap (klass->image, const_cols [MONO_CONSTANT_VALUE]);
137         switch (const_cols [MONO_CONSTANT_TYPE]) {
138         case MONO_TYPE_U4:
139         case MONO_TYPE_I4:
140                 /* FIXME: add other types... */
141         default:
142                 g_snprintf (buf, 64, "%d", *(gint32*)ptr);
143         }
144 }
145
146 static void
147 write_method_func (gpointer key, gpointer value, gpointer user_data)
148 {
149         write_method_stabs (user_data, value);
150 }
151
152 static void
153 write_class_stabs (MonoDebugHandle *debug, MonoClass *klass, int idx)
154 {
155         char *name;
156         int i;
157         char buf [64];
158
159         /* output enums ...*/
160         if (klass->enumtype) {
161                 name = g_strdup_printf ("%s%s%s", klass->name_space, klass->name_space [0]? "_": "", klass->name);
162                 fprintf (debug->f, ".stabs \"%s:T%d=e", name, ++debug->next_idx);
163                 g_free (name);
164                 for (i = 0; i < klass->field.count; ++i) {
165                         if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_LITERAL) {
166                                 get_enumvalue (klass, klass->field.first + i, buf);
167                                 fprintf (debug->f, "%s_%s=%s,", klass->name, klass->fields [i].name, buf);
168                         }
169                 }
170                 fprintf (debug->f, ";\",128,0,0,0\n");
171         }
172         fflush (debug->f);
173 }
174
175 static void
176 write_class (gpointer key, gpointer value, gpointer user_data)
177 {
178         write_class_stabs (user_data, key, GPOINTER_TO_INT (value));
179 }
180
181 void
182 mono_debug_write_stabs (MonoDebugHandle *debug)
183 {
184         gchar *source_file;
185         GList *tmp;
186         int i;
187
188         if (!(debug->f = fopen (debug->filename, "w"))) {
189                 g_warning ("Can't create stabs file `%s': %s", debug->filename, g_strerror (errno)); 
190                 return;
191         }
192
193         source_file = g_ptr_array_index (debug->source_files, 0);
194
195         fprintf (debug->f, ".stabs \"%s\",100,0,0,0\n", source_file);
196
197         for (i = 0; base_types [i].name; ++i) {
198                 if (! base_types [i].spec)
199                         continue;
200                 fprintf (debug->f, ".stabs \"%s:t(0,%d)=", base_types [i].name, i);
201                 if (base_types [i].spec [0] == ';') {
202                         fprintf (debug->f, "r(0,%d)%s\"", i, base_types [i].spec);
203                 } else {
204                         fprintf (debug->f, "%s\"", base_types [i].spec);
205                 }
206                 fprintf (debug->f, ",128,0,0,0\n");
207         }
208
209         for (tmp = debug->info; tmp; tmp = tmp->next) {
210                 AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
211
212                 g_hash_table_foreach (info->methods, write_method_func, debug);
213         }
214
215         g_hash_table_foreach (debug->type_hash, write_class, debug);
216
217         fclose (debug->f);
218         debug->f = NULL;
219
220         if (!(debug->flags & MONO_DEBUG_FLAGS_DONT_ASSEMBLE)) {
221                 char *buf;
222
223                 /* yes, it's completely unsafe */
224                 buf = g_strdup_printf ("as %s -o %s", debug->filename, debug->objfile);
225                 system (buf);
226                 g_free (buf);
227         }
228 }