2005-06-27 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / metadata / mono-debug.c
1 #include <config.h>
2 #include <mono/metadata/assembly.h>
3 #include <mono/metadata/tabledefs.h>
4 #include <mono/metadata/tokentype.h>
5 #include <mono/metadata/appdomain.h>
6 #include <mono/metadata/class-internals.h>
7 #include <mono/metadata/mono-debug.h>
8 #include <mono/metadata/mono-debug-debugger.h>
9 #include <mono/metadata/mono-endian.h>
10 #include <string.h>
11
12 #define SYMFILE_TABLE_CHUNK_SIZE        16
13 #define DATA_TABLE_PTR_CHUNK_SIZE       256
14 #define DATA_TABLE_CHUNK_SIZE           32768
15
16 MonoSymbolTable *mono_symbol_table = NULL;
17 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
18
19 static gboolean in_the_mono_debugger = FALSE;
20 static gboolean mono_debug_initialized = FALSE;
21 GHashTable *mono_debug_handles = NULL;
22
23 static GHashTable *method_hash = NULL;
24
25 static MonoDebugHandle     *mono_debug_open_image      (MonoImage *image);
26 static void                 mono_debug_close_image     (MonoDebugHandle *debug);
27
28 static MonoDebugHandle     *_mono_debug_get_image      (MonoImage *image);
29 static void                 mono_debug_add_assembly    (MonoAssembly *assembly,
30                                                         gpointer user_data);
31 static void                 mono_debug_start_add_type  (MonoClass *klass);
32 static void                 mono_debug_add_type        (MonoClass *klass);
33
34 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
35 extern void (*mono_debugger_start_class_init_func) (MonoClass *klass);
36
37 typedef struct {
38         guint32 symfile_id;
39         guint32 domain_id;
40         guint32 method_id;
41 } MethodHashEntry;
42
43 static guint
44 method_hash_hash (gconstpointer data)
45 {
46         const MethodHashEntry *entry = (const MethodHashEntry *) data;
47         return entry->symfile_id | (entry->domain_id << 16);
48 }
49
50 static gint
51 method_hash_equal (gconstpointer ka, gconstpointer kb)
52 {
53         const MethodHashEntry *a = (const MethodHashEntry *) ka;
54         const MethodHashEntry *b = (const MethodHashEntry *) kb;
55
56         if ((a->symfile_id != b->symfile_id) || (a->method_id != b->method_id) || (a->domain_id != b->domain_id))
57                 return 0;
58         return 1;
59 }
60
61 /*
62  * Initialize debugging support.
63  *
64  * This method must be called after loading corlib,
65  * but before opening the application's main assembly because we need to set some
66  * callbacks here.
67  */
68 void
69 mono_debug_init (MonoDebugFormat format)
70 {
71         g_assert (!mono_debug_initialized);
72
73         mono_debug_initialized = TRUE;
74         mono_debug_format = format;
75         in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
76
77         mono_debugger_initialize (in_the_mono_debugger);
78
79         mono_debugger_lock ();
80
81         mono_symbol_table = g_new0 (MonoSymbolTable, 1);
82         mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
83         mono_symbol_table->version = MONO_DEBUGGER_VERSION;
84         mono_symbol_table->total_size = sizeof (MonoSymbolTable);
85
86         mono_debug_handles = g_hash_table_new_full
87                 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
88         method_hash = g_hash_table_new (method_hash_hash, method_hash_equal);
89
90         mono_debugger_start_class_init_func = mono_debug_start_add_type;
91         mono_debugger_class_init_func = mono_debug_add_type;
92         mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
93
94         if (!in_the_mono_debugger)
95                 mono_debugger_unlock ();
96 }
97
98 void
99 mono_debug_init_1 (MonoDomain *domain)
100 {
101         MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
102
103         if (in_the_mono_debugger)
104                 mono_debugger_add_builtin_types (handle);
105 }
106
107 /*
108  * Initialize debugging support - part 2.
109  *
110  * This method must be called after loading the application's main assembly.
111  */
112 void
113 mono_debug_init_2 (MonoAssembly *assembly)
114 {
115         mono_debug_open_image (mono_assembly_get_image (assembly));
116 }
117
118 void
119 mono_debug_cleanup (void)
120 {
121         mono_debugger_cleanup ();
122
123         if (mono_debug_handles)
124                 g_hash_table_destroy (mono_debug_handles);
125         mono_debug_handles = NULL;
126 }
127
128 static MonoDebugHandle *
129 _mono_debug_get_image (MonoImage *image)
130 {
131         return g_hash_table_lookup (mono_debug_handles, image);
132 }
133
134 static MonoDebugHandle *
135 allocate_debug_handle (MonoSymbolTable *table)
136 {
137         MonoDebugHandle *handle;
138
139         if (!table->symbol_files)
140                 table->symbol_files = g_new0 (MonoDebugHandle *, SYMFILE_TABLE_CHUNK_SIZE);
141         else if (!((table->num_symbol_files + 1) % SYMFILE_TABLE_CHUNK_SIZE)) {
142                 guint32 chunks = (table->num_symbol_files + 1) / SYMFILE_TABLE_CHUNK_SIZE;
143                 guint32 size = sizeof (MonoDebugHandle *) * SYMFILE_TABLE_CHUNK_SIZE * (chunks + 1);
144
145                 table->symbol_files = g_realloc (table->symbol_files, size);
146         }
147
148         handle = g_new0 (MonoDebugHandle, 1);
149         handle->index = table->num_symbol_files;
150         table->symbol_files [table->num_symbol_files++] = handle;
151         return handle;
152 }
153
154 static MonoDebugHandle *
155 mono_debug_open_image (MonoImage *image)
156 {
157         MonoDebugHandle *handle;
158
159         if (mono_image_is_dynamic (image))
160                 return NULL;
161
162         handle = _mono_debug_get_image (image);
163         if (handle != NULL)
164                 return handle;
165
166         handle = allocate_debug_handle (mono_symbol_table);
167
168         handle->image = image;
169         mono_image_addref (image);
170         handle->image_file = g_strdup (mono_image_get_filename (image));
171
172         g_hash_table_insert (mono_debug_handles, image, handle);
173
174         handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
175         if (in_the_mono_debugger)
176                 mono_debugger_add_symbol_file (handle);
177
178         return handle;
179 }
180
181 static void
182 mono_debug_close_image (MonoDebugHandle *handle)
183 {
184         if (handle->symfile)
185                 mono_debug_close_mono_symbol_file (handle->symfile);
186         /* decrease the refcount added with mono_image_addref () */
187         mono_image_close (handle->image);
188         g_free (handle->image_file);
189         g_free (handle->_priv);
190         g_free (handle);
191 }
192
193 static void
194 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
195 {
196         mono_debugger_lock ();
197         mono_debug_open_image (mono_assembly_get_image (assembly));
198         mono_debugger_unlock ();
199 }
200
201 /*
202  * Allocate a new data item of size `size'.
203  * Returns the global offset which is to be used to reference this data item and
204  * a pointer (in the `ptr' argument) which is to be used to write it.
205  */
206 static guint8 *
207 allocate_data_item (MonoDebugDataItemType type, guint32 size)
208 {
209         guint32 chunk_size;
210         guint8 *data;
211
212         g_assert (mono_symbol_table);
213
214         if (size + 12 < DATA_TABLE_CHUNK_SIZE)
215                 chunk_size = DATA_TABLE_CHUNK_SIZE;
216         else
217                 chunk_size = size + 12;
218
219         /* Initialize things if necessary. */
220         if (!mono_symbol_table->current_data_table) {
221                 mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
222                 mono_symbol_table->current_data_table_size = chunk_size;
223                 mono_symbol_table->current_data_table_offset = 4;
224
225                 * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
226         }
227
228  again:
229         /* First let's check whether there's still enough room in the current_data_table. */
230         if (mono_symbol_table->current_data_table_offset + size + 8 < mono_symbol_table->current_data_table_size) {
231                 data = ((guint8 *) mono_symbol_table->current_data_table) + mono_symbol_table->current_data_table_offset;
232                 mono_symbol_table->current_data_table_offset += size + 8;
233
234                 * ((guint32 *) data) = size;
235                 data += 4;
236                 * ((guint32 *) data) = type;
237                 data += 4;
238                 return data;
239         }
240
241         /* Add the current_data_table to the data_tables vector and ... */
242         if (!mono_symbol_table->data_tables) {
243                 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE;
244                 mono_symbol_table->data_tables = g_malloc0 (tsize);
245         }
246
247         if (!((mono_symbol_table->num_data_tables + 1) % DATA_TABLE_PTR_CHUNK_SIZE)) {
248                 guint32 chunks = (mono_symbol_table->num_data_tables + 1) / DATA_TABLE_PTR_CHUNK_SIZE;
249                 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
250
251                 mono_symbol_table->data_tables = g_realloc (mono_symbol_table->data_tables, tsize);
252         }
253
254         mono_symbol_table->data_tables [mono_symbol_table->num_data_tables++] = mono_symbol_table->current_data_table;
255
256         /* .... allocate a new current_data_table. */
257         mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
258         mono_symbol_table->current_data_table_size = chunk_size;
259         mono_symbol_table->current_data_table_offset = 4;
260         * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
261
262         goto again;
263 }
264
265 struct LookupMethodData
266 {
267         MonoDebugMethodInfo *minfo;
268         MonoMethod *method;
269 };
270
271 static void
272 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
273 {
274         MonoDebugHandle *handle = (MonoDebugHandle *) value;
275         struct LookupMethodData *data = (struct LookupMethodData *) user_data;
276
277         if (data->minfo)
278                 return;
279
280         if (handle->symfile)
281                 data->minfo = mono_debug_find_method (handle, data->method);
282 }
283
284 static MonoDebugMethodInfo *
285 _mono_debug_lookup_method (MonoMethod *method)
286 {
287         struct LookupMethodData data;
288
289         data.minfo = NULL;
290         data.method = method;
291
292         if (!mono_debug_handles)
293                 return NULL;
294
295         g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
296         return data.minfo;
297 }
298
299 static inline void
300 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
301 {
302         do {
303                 guint8 byte = value & 0x7f;
304                 value >>= 7;
305                 if (value)
306                         byte |= 0x80;
307                 *ptr++ = byte;
308         } while (value);
309
310         *rptr = ptr;
311 }
312
313 static inline void
314 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
315 {
316         gboolean more = 1;
317
318         while (more) {
319                 guint8 byte = value & 0x7f;
320                 value >>= 7;
321
322                 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
323                         more = 0;
324                 else
325                         byte |= 0x80;
326                 *ptr++ = byte;
327         }
328
329         *rptr = ptr;
330 }
331
332 static void
333 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
334 {
335         write_leb128 (var->index, ptr, &ptr);
336         write_sleb128 (var->offset, ptr, &ptr);
337         write_leb128 (var->size, ptr, &ptr);
338         write_leb128 (var->begin_scope, ptr, &ptr);
339         write_leb128 (var->end_scope, ptr, &ptr);
340         *rptr = ptr;
341 }
342
343 /*
344  * This is called by the JIT to tell the debugging code about a newly
345  * compiled method.
346  */
347 MonoDebugMethodAddress *
348 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
349 {
350         MonoDebugMethodAddress *address;
351         char buffer [BUFSIZ];
352         guint8 *ptr, *oldptr;
353         guint32 i, size, total_size, max_size;
354         gint32 last_il_offset = 0, last_native_offset = 0;
355         MonoDebugHandle *handle;
356         MonoDebugMethodInfo *minfo;
357         MethodHashEntry *hash;
358
359         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
360             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
361             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
362             (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
363                 return NULL;
364
365         if (method->wrapper_type != MONO_WRAPPER_NONE)
366                 return NULL;
367
368         mono_debugger_lock ();
369
370         handle = _mono_debug_get_image (method->klass->image);
371         if (!handle || !handle->symfile || !handle->symfile->offset_table) {
372                 mono_debugger_unlock ();
373                 return NULL;
374         }
375
376         minfo = _mono_debug_lookup_method (method);
377         if (!minfo) {
378                 mono_debugger_unlock ();
379                 return NULL;
380         }
381
382         max_size = 24 + 8 * jit->num_line_numbers + 16 * minfo->num_lexical_blocks + 20 * (1 + jit->num_params + jit->num_locals);
383         if (max_size > BUFSIZ)
384                 ptr = oldptr = g_malloc (max_size);
385         else
386                 ptr = oldptr = buffer;
387
388         write_leb128 (jit->prologue_end, ptr, &ptr);
389         write_leb128 (jit->epilogue_begin, ptr, &ptr);
390
391         write_leb128 (jit->num_line_numbers, ptr, &ptr);
392         for (i = 0; i < jit->num_line_numbers; i++) {
393                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
394
395                 write_sleb128 (lne->il_offset - last_il_offset, ptr, &ptr);
396                 write_sleb128 (lne->native_offset - last_native_offset, ptr, &ptr);
397
398                 last_il_offset = lne->il_offset;
399                 last_native_offset = lne->native_offset;
400         }
401
402         jit->num_lexical_blocks = minfo->num_lexical_blocks;
403         jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
404         for (i = 0; i < jit->num_lexical_blocks; i ++) {
405                 MonoDebugLexicalBlockEntry *jit_lbe = &jit->lexical_blocks [i];
406                 MonoSymbolFileLexicalBlockEntry *minfo_lbe = &minfo->lexical_blocks [i];
407
408                 jit_lbe->il_start_offset = minfo_lbe->_start_offset;
409                 jit_lbe->native_start_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_start_offset);
410
411                 jit_lbe->il_end_offset = minfo_lbe->_end_offset;
412                 jit_lbe->native_end_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_end_offset);
413         }
414
415         last_il_offset = 0;
416         last_native_offset = 0;
417         write_leb128 (jit->num_lexical_blocks, ptr, &ptr);
418         for (i = 0; i < jit->num_lexical_blocks; i++) {
419                 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
420
421                 write_sleb128 (lbe->il_start_offset - last_il_offset, ptr, &ptr);
422                 write_sleb128 (lbe->native_start_offset - last_native_offset, ptr, &ptr);
423
424                 last_il_offset = lbe->il_start_offset;
425                 last_native_offset = lbe->native_start_offset;
426
427                 write_sleb128 (lbe->il_end_offset - last_il_offset, ptr, &ptr);
428                 write_sleb128 (lbe->native_end_offset - last_native_offset, ptr, &ptr);
429
430                 last_il_offset = lbe->il_end_offset;
431                 last_native_offset = lbe->native_end_offset;
432         }
433
434         *ptr++ = jit->this_var ? 1 : 0;
435         if (jit->this_var)
436                 write_variable (jit->this_var, ptr, &ptr);
437
438         write_leb128 (jit->num_params, ptr, &ptr);
439         for (i = 0; i < jit->num_params; i++)
440                 write_variable (&jit->params [i], ptr, &ptr);
441
442         write_leb128 (jit->num_locals, ptr, &ptr);
443         for (i = 0; i < jit->num_locals; i++)
444                 write_variable (&jit->locals [i], ptr, &ptr);
445
446         size = ptr - oldptr;
447         g_assert (size < max_size);
448         total_size = size + sizeof (MonoDebugMethodAddress);
449
450         if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
451                 // FIXME: Maybe we should print a warning here.
452                 //        This should only happen for very big methods, for instance
453                 //        with more than 40.000 line numbers and more than 5.000
454                 //        local variables.
455                 mono_debugger_unlock ();
456                 return NULL;
457         }
458
459         address = (MonoDebugMethodAddress *) allocate_data_item (MONO_DEBUG_DATA_ITEM_METHOD, total_size);
460
461         address->size = total_size;
462         address->symfile_id = handle->index;
463         address->domain_id = mono_domain_get_id (domain);
464         address->method_id = minfo->index;
465         address->code_start = jit->code_start;
466         address->code_size = jit->code_size;
467         address->wrapper_addr = jit->wrapper_addr;
468
469         memcpy (&address->data, oldptr, size);
470
471         if (max_size > BUFSIZ)
472                 g_free (oldptr);
473
474         hash = g_new0 (MethodHashEntry, 1);
475         hash->symfile_id = address->symfile_id;
476         hash->domain_id = address->domain_id;
477         hash->method_id = address->method_id;
478
479         g_hash_table_insert (method_hash, hash, address);
480
481         if (in_the_mono_debugger)
482                 mono_debugger_add_method (jit);
483
484         mono_debugger_unlock ();
485
486         return address;
487 }
488
489 static inline guint32
490 read_leb128 (guint8 *ptr, guint8 **rptr)
491 {
492         guint32 result = 0, shift = 0;
493
494         while (TRUE) {
495                 guint8 byte = *ptr++;
496
497                 result |= (byte & 0x7f) << shift;
498                 if ((byte & 0x80) == 0)
499                         break;
500                 shift += 7;
501         }
502
503         *rptr = ptr;
504         return result;
505 }
506
507 static inline gint32
508 read_sleb128 (guint8 *ptr, guint8 **rptr)
509 {
510         gint32 result = 0;
511         guint32 shift = 0;
512
513         while (TRUE) {
514                 guint8 byte = *ptr++;
515
516                 result |= (byte & 0x7f) << shift;
517                 shift += 7;
518
519                 if (byte & 0x80)
520                         continue;
521
522                 if ((shift < 32) && (byte & 0x40))
523                         result |= - (1 << shift);
524                 break;
525         }
526
527         *rptr = ptr;
528         return result;
529 }
530
531 static void
532 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
533 {
534         var->index = read_leb128 (ptr, &ptr);
535         var->offset = read_sleb128 (ptr, &ptr);
536         var->size = read_leb128 (ptr, &ptr);
537         var->begin_scope = read_leb128 (ptr, &ptr);
538         var->end_scope = read_leb128 (ptr, &ptr);
539         *rptr = ptr;
540 }
541
542 MonoDebugMethodJitInfo *
543 mono_debug_read_method (MonoDebugMethodAddress *address)
544 {
545         MonoDebugMethodJitInfo *jit;
546         guint32 i, il_offset = 0, native_offset = 0;
547         guint8 *ptr;
548
549         if (address->jit)
550                 return address->jit;
551
552         jit = address->jit = g_new0 (MonoDebugMethodJitInfo, 1);
553         jit->code_start = address->code_start;
554         jit->code_size = address->code_size;
555         jit->wrapper_addr = address->wrapper_addr;
556
557         ptr = (guint8 *) &address->data;
558
559         jit->prologue_end = read_leb128 (ptr, &ptr);
560         jit->epilogue_begin = read_leb128 (ptr, &ptr);
561
562         jit->num_line_numbers = read_leb128 (ptr, &ptr);
563         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
564         for (i = 0; i < jit->num_line_numbers; i++) {
565                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
566
567                 il_offset += read_sleb128 (ptr, &ptr);
568                 native_offset += read_sleb128 (ptr, &ptr);
569
570                 lne->il_offset = il_offset;
571                 lne->native_offset = native_offset;
572         }
573
574         il_offset = 0;
575         native_offset = 0;
576         jit->num_lexical_blocks = read_leb128 (ptr, &ptr);
577         jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
578         for (i = 0; i < jit->num_lexical_blocks; i ++) {
579                 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
580
581                 il_offset += read_sleb128 (ptr, &ptr);
582                 native_offset += read_sleb128 (ptr, &ptr);
583
584                 lbe->il_start_offset = il_offset;
585                 lbe->native_start_offset = native_offset;
586
587                 il_offset += read_sleb128 (ptr, &ptr);
588                 native_offset += read_sleb128 (ptr, &ptr);
589
590                 lbe->il_end_offset = il_offset;
591                 lbe->native_end_offset = native_offset;
592         }
593
594         if (*ptr++) {
595                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
596                 read_variable (jit->this_var, ptr, &ptr);
597         }
598
599         jit->num_params = read_leb128 (ptr, &ptr);
600         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
601         for (i = 0; i < jit->num_params; i++)
602                 read_variable (&jit->params [i], ptr, &ptr);
603
604         jit->num_locals = read_leb128 (ptr, &ptr);
605         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
606         for (i = 0; i < jit->num_locals; i++)
607                 read_variable (&jit->locals [i], ptr, &ptr);
608
609         return jit;
610 }
611
612 void
613 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
614 {
615         if (jit->address)
616                 jit->address->jit = NULL;
617
618         g_free (jit->line_numbers);
619         g_free (jit->this_var);
620         g_free (jit->params);
621         g_free (jit->locals);
622         g_free (jit);
623 }
624
625 /*
626  * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
627  * a new class is initialized.
628  */
629 static void
630 mono_debug_start_add_type (MonoClass *klass)
631 {
632         MonoDebugHandle *handle;
633
634         handle = _mono_debug_get_image (klass->image);
635         if (!handle)
636                 return;
637
638         if (in_the_mono_debugger)
639                 mono_debugger_add_type (handle, klass);
640 }
641
642 static guint32
643 get_token (MonoClass *klass)
644 {
645         while (klass->rank)
646                 klass = klass->element_class;
647
648         return klass->type_token;
649 }
650
651 static void
652 mono_debug_add_type (MonoClass *klass)
653 {
654         MonoDebugHandle *handle;
655         MonoDebugClassEntry *entry;
656         char buffer [BUFSIZ];
657         guint8 *ptr, *oldptr;
658         guint32 token, size, total_size, max_size;
659         int base_offset = 0;
660
661         handle = _mono_debug_get_image (klass->image);
662         if (!handle)
663                 return;
664
665         if (klass->generic_class ||
666             (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
667                 return;
668
669         max_size = 12 + sizeof (gpointer);
670         if (max_size > BUFSIZ)
671                 ptr = oldptr = g_malloc (max_size);
672         else
673                 ptr = oldptr = buffer;
674
675         token = get_token (klass);
676         if (!token)
677                 return;
678
679         if (klass->valuetype)
680                 base_offset = - (int)(sizeof (MonoObject));
681
682         write_leb128 (token, ptr, &ptr);
683         write_leb128 (klass->rank, ptr, &ptr);
684         write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
685         * ((gpointer *) ptr) = klass;
686         ptr += sizeof (gpointer);
687
688         size = ptr - oldptr;
689         g_assert (size < max_size);
690         total_size = size + sizeof (MonoDebugClassEntry);
691
692         if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
693                 // FIXME: Maybe we should print a warning here.
694                 //        This should only happen for very big methods, for instance
695                 //        with more than 40.000 line numbers and more than 5.000
696                 //        local variables.
697                 return;
698         }
699
700         entry = (MonoDebugClassEntry *) allocate_data_item (MONO_DEBUG_DATA_ITEM_CLASS, total_size);
701
702         entry->size = total_size;
703         entry->symfile_id = handle->index;
704
705         memcpy (&entry->data, oldptr, size);
706
707         if (max_size > BUFSIZ)
708                 g_free (oldptr);
709
710         mono_debugger_start_add_type (handle, klass);
711 }
712
713 static MonoDebugMethodJitInfo *
714 find_method (MonoDebugMethodInfo *minfo, MonoDomain *domain)
715 {
716         MethodHashEntry lookup;
717         MonoDebugMethodAddress *address;
718
719         lookup.symfile_id = minfo->handle->index;
720         lookup.domain_id = mono_domain_get_id (domain);
721         lookup.method_id = minfo->index;
722
723         address = g_hash_table_lookup (method_hash, &lookup);
724         if (!address)
725                 return NULL;
726
727         return mono_debug_read_method (address);
728 }
729
730 static gint32
731 il_offset_from_address (MonoDebugMethodInfo *minfo, MonoDomain *domain, guint32 native_offset)
732 {
733         MonoDebugMethodJitInfo *jit;
734         int i;
735
736         jit = find_method (minfo, domain);
737         if (!jit || !jit->line_numbers)
738                 return -1;
739
740         for (i = jit->num_line_numbers - 1; i >= 0; i--) {
741                 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
742
743                 if (lne.native_offset <= native_offset)
744                         return lne.il_offset;
745         }
746
747         return -1;
748 }
749
750 /**
751  * mono_debug_source_location_from_address:
752  * @method:
753  * @address:
754  * @line_number:
755  * @domain:
756  *
757  * Used by the exception code to get a source location from a machine address.
758  *
759  * Returns: a textual representation of the specified address which is suitable to be displayed to
760  * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
761  *
762  * If the optional @line_number argument is not NULL, the line number is stored there and just the
763  * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
764  * line number 8 in the variable pointed to by @line_number).
765  */
766 gchar *
767 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
768                                          MonoDomain *domain)
769 {
770         MonoDebugMethodInfo *minfo;
771         char *res = NULL;
772         gint32 offset;
773
774         mono_loader_lock ();
775         minfo = _mono_debug_lookup_method (method);
776         if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
777                 mono_loader_unlock ();
778                 return NULL;
779         }
780
781         offset = il_offset_from_address (minfo, domain, address);
782                 
783         if (offset >= 0)
784                 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
785
786         mono_loader_unlock ();
787         return res;
788 }
789
790 /**
791  * mono_debug_source_location_from_il_offset:
792  * @method:
793  * @offset:
794  * @line_number:
795  *
796  * Used by the exception code to get a source location from an IL offset.
797  *
798  * Returns a textual representation of the specified address which is suitable to be displayed to
799  * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
800  *
801  * If the optional @line_number argument is not NULL, the line number is stored there and just the
802  * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
803  * line number 8 in the variable pointed to by @line_number).
804  */
805 gchar *
806 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
807 {
808         char *res;
809         MonoDebugMethodInfo *minfo;
810
811         mono_loader_lock ();
812         minfo = _mono_debug_lookup_method (method);
813         if (!minfo || !minfo->handle || !minfo->handle->symfile) {
814                 mono_loader_unlock ();
815                 return NULL;
816         }
817
818         res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
819         mono_loader_unlock ();
820         return res;
821 }
822
823 /**
824  * mono_debug_il_offset_from_address:
825  * @method:
826  * @address:
827  * @domain:
828  *
829  * Returns: the IL offset corresponding to machine address @address which is an offset
830  * relative to the beginning of the method @method.
831  */
832 gint32
833 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
834 {
835         MonoDebugMethodInfo *minfo;
836         gint32 res;
837
838         if (address < 0)
839                 return -1;
840
841         mono_loader_lock ();
842         minfo = _mono_debug_lookup_method (method);
843         if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
844             !minfo->handle->symfile->offset_table) {
845                 mono_loader_unlock ();
846                 return -1;
847         }
848
849         res = il_offset_from_address (minfo, domain, address);
850         mono_loader_unlock ();
851         return res;
852 }
853
854 /**
855  * mono_debug_address_from_il_offset:
856  * @method:
857  * @il_offset:
858  * @domain:
859  *
860  * Returns: the machine address corresponding to IL offset @il_offset.
861  * The returned value is an offset relative to the beginning of the method @method.
862  */
863 gint32
864 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
865 {
866         MonoDebugMethodInfo *minfo;
867         MonoDebugMethodJitInfo *jit;
868         gint32 res;
869
870         if (il_offset < 0)
871                 return -1;
872
873         mono_loader_lock ();
874         minfo = _mono_debug_lookup_method (method);
875         if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
876             !minfo->handle->symfile->offset_table) {
877                 mono_loader_unlock ();
878                 return -1;
879         }
880
881         jit = find_method (minfo, domain);
882         if (!jit) {
883                 mono_loader_unlock ();
884                 return -1;
885         }
886
887         res = _mono_debug_address_from_il_offset (jit, il_offset);
888         mono_loader_unlock ();
889         return res;
890 }