2008-07-07 Zoltan Varga <vargaz@gmail.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 DATA_TABLE_CHUNK_SIZE           16384
13
14 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
15
16 #if NO_UNALIGNED_ACCESS
17 #define RETURN_UNALIGNED(type, addr) \
18         { \
19                 type val; \
20                 memcpy(&val, p + offset, sizeof(val)); \
21                 return val; \
22         }
23 #define WRITE_UNALIGNED(type, addr, val) \
24         memcpy(addr, &val, sizeof(type))
25 #define READ_UNALIGNED(type, addr, val) \
26         memcpy(&val, addr, sizeof(type))
27 #else
28 #define RETURN_UNALIGNED(type, addr) \
29         return *(type*)(p + offset);
30 #define WRITE_UNALIGNED(type, addr, val) \
31         (*(type *)(addr) = (val))
32 #define READ_UNALIGNED(type, addr, val) \
33         val = (*(type *)(addr))
34 #endif
35
36 typedef enum {
37         MONO_DEBUG_DATA_ITEM_UNKNOWN            = 0,
38         MONO_DEBUG_DATA_ITEM_CLASS,
39         MONO_DEBUG_DATA_ITEM_METHOD,
40         MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE
41 } MonoDebugDataItemType;
42
43 typedef struct _MonoDebugDataChunk MonoDebugDataChunk;
44
45 struct _MonoDebugDataChunk {
46         guint32 total_size;
47         guint32 allocated_size;
48         guint32 current_offset;
49         guint32 dummy;
50         MonoDebugDataChunk *next;
51         guint8 data [MONO_ZERO_LEN_ARRAY];
52 };
53
54 struct _MonoDebugDataTable {
55         gint32 domain;
56         gint32 _dummy; /* alignment for next field. */
57         MonoDebugDataChunk *first_chunk;
58         MonoDebugDataChunk *current_chunk;
59         GHashTable *method_hash;
60         GHashTable *method_address_hash;
61 };
62
63 typedef struct {
64         const gchar *method_name;
65         const gchar *cil_code;
66         guint32 wrapper_type;
67 } MonoDebugWrapperData;
68
69 typedef struct {
70         guint32 size;
71         guint32 symfile_id;
72         guint32 domain_id;
73         guint32 method_id;
74         MonoDebugWrapperData *wrapper_data;
75         MonoMethod *method;
76         GSList *address_list;
77 } MonoDebugMethodHeader;
78
79 struct _MonoDebugMethodAddress {
80         MonoDebugMethodHeader header;
81         const guint8 *code_start;
82         const guint8 *wrapper_addr;
83         guint32 code_size;
84         guint8 data [MONO_ZERO_LEN_ARRAY];
85 };
86
87 struct _MonoDebugClassEntry {
88         guint32 size;
89         guint8 data [MONO_ZERO_LEN_ARRAY];
90 };
91
92 typedef struct {
93         gpointer code;
94         guint32 size;
95 } MonoDebugDelegateTrampolineEntry;
96
97 MonoSymbolTable *mono_symbol_table = NULL;
98 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
99 gint32 mono_debug_debugger_version = 4;
100 gint32 _mono_debug_using_mono_debugger = 0;
101
102 static gboolean mono_debug_initialized = FALSE;
103 GHashTable *mono_debug_handles = NULL;
104
105 static GHashTable *data_table_hash = NULL;
106 static int next_symbol_file_id = 0;
107
108 static MonoDebugHandle     *mono_debug_open_image      (MonoImage *image, const guint8 *raw_contents, int size);
109
110 static MonoDebugHandle     *_mono_debug_get_image      (MonoImage *image);
111 static void                 mono_debug_add_assembly    (MonoAssembly *assembly,
112                                                         gpointer user_data);
113 static void                 mono_debug_add_type        (MonoClass *klass);
114
115 void _mono_debug_init_corlib (MonoDomain *domain);
116
117 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
118 extern void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass);
119
120 static MonoDebugDataTable *
121 create_data_table (MonoDomain *domain)
122 {
123         MonoDebugDataTable *table;
124         MonoDebugDataChunk *chunk;
125
126         table = g_new0 (MonoDebugDataTable, 1);
127         table->domain = domain ? mono_domain_get_id (domain) : -1;
128
129         table->method_address_hash = g_hash_table_new (NULL, NULL);
130         table->method_hash = g_hash_table_new (NULL, NULL);
131
132         chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + DATA_TABLE_CHUNK_SIZE);
133         chunk->total_size = DATA_TABLE_CHUNK_SIZE;
134
135         table->first_chunk = table->current_chunk = chunk;
136
137         if (domain) {
138                 mono_debug_list_add (&mono_symbol_table->data_tables, table);
139                 g_hash_table_insert (data_table_hash, domain, table);
140         }
141
142         return table;
143 }
144
145 static void
146 free_header_data (gpointer key, gpointer value, gpointer user_data)
147 {
148         MonoDebugMethodHeader *header = (MonoDebugMethodHeader*)value;
149
150         if (header->wrapper_data) {
151                 g_free ((gpointer)header->wrapper_data->method_name);
152                 g_free ((gpointer)header->wrapper_data->cil_code);
153                 g_slist_free (header->address_list);
154                 g_free (header->wrapper_data);
155         }
156 }
157
158 static void
159 free_data_table (MonoDebugDataTable *table)
160 {
161         MonoDebugDataChunk *chunk, *next_chunk;
162
163         g_hash_table_foreach (table->method_hash, free_header_data, NULL);
164         g_hash_table_destroy (table->method_hash);
165         g_hash_table_destroy (table->method_address_hash);
166
167         table->method_hash = NULL;
168         table->method_address_hash = NULL;
169
170         chunk = table->first_chunk;
171         while (chunk) {
172                 next_chunk = chunk->next;
173                 g_free (chunk);
174                 chunk = next_chunk;
175         }
176
177         table->first_chunk = table->current_chunk = NULL;
178         mono_debug_list_remove (&mono_symbol_table->data_tables, table);
179         g_free (table);
180 }
181
182 static MonoDebugDataTable *
183 lookup_data_table (MonoDomain *domain)
184 {
185         MonoDebugDataTable *table;
186
187         table = g_hash_table_lookup (data_table_hash, domain);
188         g_assert (table);
189         return table;
190 }
191
192 static void
193 free_debug_handle (MonoDebugHandle *handle)
194 {
195         if (handle->symfile)
196                 mono_debug_close_mono_symbol_file (handle->symfile);
197         /* decrease the refcount added with mono_image_addref () */
198         free_data_table (handle->type_table);
199         mono_image_close (handle->image);
200         g_free (handle->image_file);
201         g_free (handle);
202 }
203
204 /*
205  * Initialize debugging support.
206  *
207  * This method must be called after loading corlib,
208  * but before opening the application's main assembly because we need to set some
209  * callbacks here.
210  */
211 void
212 mono_debug_init (MonoDebugFormat format)
213 {
214         g_assert (!mono_debug_initialized);
215
216         mono_debug_initialized = TRUE;
217         mono_debug_format = format;
218
219         mono_debugger_initialize (_mono_debug_using_mono_debugger);
220
221         mono_debugger_lock ();
222
223         mono_symbol_table = g_new0 (MonoSymbolTable, 1);
224         mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
225         mono_symbol_table->version = MONO_DEBUGGER_MAJOR_VERSION;
226         mono_symbol_table->total_size = sizeof (MonoSymbolTable);
227
228         mono_debug_handles = g_hash_table_new_full
229                 (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle);
230
231         data_table_hash = g_hash_table_new_full (
232                 NULL, NULL, NULL, (GDestroyNotify) free_data_table);
233
234         mono_debugger_class_init_func = mono_debug_add_type;
235         mono_debugger_class_loaded_methods_func = mono_debugger_class_initialized;
236         mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
237
238         mono_symbol_table->global_data_table = create_data_table (NULL);
239
240         mono_debugger_unlock ();
241 }
242
243 /*
244  * INTERNAL USE ONLY !
245  */
246 void
247 _mono_debug_init_corlib (MonoDomain *domain)
248 {
249         if (!mono_debug_initialized)
250                 return;
251
252         mono_symbol_table->corlib = mono_debug_open_image (mono_defaults.corlib, NULL, 0);
253         mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_CORLIB,
254                              (guint64) (gsize) mono_symbol_table->corlib, 0);
255 }
256
257 void
258 mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
259 {
260         mono_debug_open_image (image, raw_contents, size);
261 }
262
263
264 gboolean
265 mono_debug_using_mono_debugger (void)
266 {
267         return _mono_debug_using_mono_debugger;
268 }
269
270 void
271 mono_debug_cleanup (void)
272 {
273         if (mono_debug_handles)
274                 g_hash_table_destroy (mono_debug_handles);
275         mono_debug_handles = NULL;
276
277         if (data_table_hash) {
278                 g_hash_table_destroy (data_table_hash);
279                 data_table_hash = NULL;
280         }
281
282         g_free (mono_symbol_table);
283         mono_symbol_table = NULL;
284 }
285
286 void
287 mono_debug_domain_create (MonoDomain *domain)
288 {
289         MonoDebugDataTable *table;
290
291         if (!mono_debug_initialized)
292                 return;
293
294         mono_debugger_lock ();
295
296         table = create_data_table (domain);
297
298         mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_CREATE, (guint64) (gsize) table,
299                              mono_domain_get_id (domain));
300
301         mono_debugger_unlock ();
302 }
303
304 void
305 mono_debug_domain_unload (MonoDomain *domain)
306 {
307         MonoDebugDataTable *table;
308
309         if (!mono_debug_initialized)
310                 return;
311
312         mono_debugger_lock ();
313
314         table = g_hash_table_lookup (data_table_hash, domain);
315         if (!table) {
316                 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
317                            domain, mono_domain_get_id (domain));
318                 mono_debugger_unlock ();
319                 return;
320         }
321
322         mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_UNLOAD, (guint64) (gsize) table,
323                              mono_domain_get_id (domain));
324
325         g_hash_table_remove (data_table_hash, domain);
326
327         mono_debugger_unlock ();
328 }
329
330 static MonoDebugHandle *
331 _mono_debug_get_image (MonoImage *image)
332 {
333         return g_hash_table_lookup (mono_debug_handles, image);
334 }
335
336 void
337 mono_debug_close_image (MonoImage *image)
338 {
339         MonoDebugHandle *handle;
340
341         if (!mono_debug_initialized)
342                 return;
343
344         handle = _mono_debug_get_image (image);
345         if (!handle)
346                 return;
347
348         mono_debugger_lock ();
349
350         mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
351                              handle->index);
352
353         mono_debug_list_remove (&mono_symbol_table->symbol_files, handle);
354         g_hash_table_remove (mono_debug_handles, image);
355
356         mono_debugger_unlock ();
357 }
358
359 static MonoDebugHandle *
360 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
361 {
362         MonoDebugHandle *handle;
363
364         if (mono_image_is_dynamic (image))
365                 return NULL;
366
367         handle = _mono_debug_get_image (image);
368         if (handle != NULL)
369                 return handle;
370
371         mono_debugger_lock ();
372
373         handle = g_new0 (MonoDebugHandle, 1);
374         handle->index = ++next_symbol_file_id;
375
376         handle->image = image;
377         mono_image_addref (image);
378         handle->image_file = g_strdup (mono_image_get_filename (image));
379
380         handle->type_table = create_data_table (NULL);
381
382         handle->symfile = mono_debug_open_mono_symbols (
383                 handle, raw_contents, size, _mono_debug_using_mono_debugger);
384
385         mono_debug_list_add (&mono_symbol_table->symbol_files, handle);
386
387         g_hash_table_insert (mono_debug_handles, image, handle);
388
389         if (mono_symbol_table->corlib)
390                 mono_debugger_event (MONO_DEBUGGER_EVENT_LOAD_MODULE,
391                                      (guint64) (gsize) handle, 0);
392
393         mono_debugger_unlock ();
394
395         return handle;
396 }
397
398 static void
399 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
400 {
401         mono_debugger_lock ();
402         mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
403         mono_debugger_unlock ();
404 }
405
406 static guint8 *
407 allocate_data_item (MonoDebugDataTable *table, MonoDebugDataItemType type, guint32 size)
408 {
409         guint32 chunk_size;
410         guint8 *data;
411
412         size = ALIGN_TO (size, sizeof (gpointer));
413
414         if (size + 16 < DATA_TABLE_CHUNK_SIZE)
415                 chunk_size = DATA_TABLE_CHUNK_SIZE;
416         else
417                 chunk_size = size + 16;
418
419         g_assert (table->current_chunk->current_offset == table->current_chunk->allocated_size);
420
421         if (table->current_chunk->allocated_size + size + 8 >= table->current_chunk->total_size) {
422                 MonoDebugDataChunk *new_chunk;
423
424                 new_chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + chunk_size);
425                 new_chunk->total_size = chunk_size;
426
427                 table->current_chunk->next = new_chunk;
428                 table->current_chunk = new_chunk;
429         }
430
431         data = &table->current_chunk->data [table->current_chunk->allocated_size];
432         table->current_chunk->allocated_size += size + 8;
433
434         * ((guint32 *) data) = size;
435         data += 4;
436         * ((guint32 *) data) = type;
437         data += 4;
438         return data;
439 }
440
441 static void
442 write_data_item (MonoDebugDataTable *table, const guint8 *data)
443 {
444         MonoDebugDataChunk *current_chunk = table->current_chunk;
445         guint32 size = * ((guint32 *) (data - 8));
446
447         g_assert (current_chunk->current_offset + size + 8 == current_chunk->allocated_size);
448         current_chunk->current_offset = current_chunk->allocated_size;
449 }
450
451 struct LookupMethodData
452 {
453         MonoDebugMethodInfo *minfo;
454         MonoMethod *method;
455 };
456
457 static void
458 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
459 {
460         MonoDebugHandle *handle = (MonoDebugHandle *) value;
461         struct LookupMethodData *data = (struct LookupMethodData *) user_data;
462
463         if (data->minfo)
464                 return;
465
466         if (handle->symfile)
467                 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
468 }
469
470 static MonoDebugMethodInfo *
471 _mono_debug_lookup_method (MonoMethod *method)
472 {
473         struct LookupMethodData data;
474
475         data.minfo = NULL;
476         data.method = method;
477
478         if (!mono_debug_handles)
479                 return NULL;
480
481         g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
482         return data.minfo;
483 }
484
485 /**
486  * mono_debug_lookup_method:
487  *
488  * Lookup symbol file information for the method @method.  The returned
489  * `MonoDebugMethodInfo' is a private structure, but it can be passed to
490  * mono_debug_symfile_lookup_location().
491  */
492 MonoDebugMethodInfo *
493 mono_debug_lookup_method (MonoMethod *method)
494 {
495         MonoDebugMethodInfo *minfo;
496
497         mono_debugger_lock ();
498         minfo = _mono_debug_lookup_method (method);
499         mono_debugger_unlock ();
500         return minfo;
501 }
502
503 static inline void
504 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
505 {
506         do {
507                 guint8 byte = value & 0x7f;
508                 value >>= 7;
509                 if (value)
510                         byte |= 0x80;
511                 *ptr++ = byte;
512         } while (value);
513
514         *rptr = ptr;
515 }
516
517 static inline void
518 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
519 {
520         gboolean more = 1;
521
522         while (more) {
523                 guint8 byte = value & 0x7f;
524                 value >>= 7;
525
526                 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
527                         more = 0;
528                 else
529                         byte |= 0x80;
530                 *ptr++ = byte;
531         }
532
533         *rptr = ptr;
534 }
535
536 static void
537 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
538 {
539         write_leb128 (var->index, ptr, &ptr);
540         write_sleb128 (var->offset, ptr, &ptr);
541         write_leb128 (var->size, ptr, &ptr);
542         write_leb128 (var->begin_scope, ptr, &ptr);
543         write_leb128 (var->end_scope, ptr, &ptr);
544         WRITE_UNALIGNED (gpointer, ptr, var->type);
545         ptr += sizeof (gpointer);
546         *rptr = ptr;
547 }
548
549 MonoDebugMethodAddress *
550 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
551 {
552         MonoMethod *declaring;
553         MonoDebugDataTable *table;
554         MonoDebugMethodHeader *header;
555         MonoDebugMethodAddress *address;
556         MonoDebugMethodInfo *minfo;
557         MonoDebugHandle *handle;
558         guint8 buffer [BUFSIZ];
559         guint8 *ptr, *oldptr;
560         guint32 i, size, total_size, max_size;
561         gboolean is_wrapper = FALSE;
562
563         mono_debugger_lock ();
564
565         table = lookup_data_table (domain);
566
567         handle = _mono_debug_get_image (method->klass->image);
568         minfo = _mono_debug_lookup_method (method);
569
570         if (!minfo || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
571             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
572             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
573             (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
574             (method->wrapper_type != MONO_WRAPPER_NONE)) {
575                 is_wrapper = TRUE;
576         }
577
578         max_size = 24 + 8 * jit->num_line_numbers +
579                 (20 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
580
581         if (max_size > BUFSIZ)
582                 ptr = oldptr = g_malloc (max_size);
583         else
584                 ptr = oldptr = buffer;
585
586         write_leb128 (jit->prologue_end, ptr, &ptr);
587         write_leb128 (jit->epilogue_begin, ptr, &ptr);
588
589         write_leb128 (jit->num_line_numbers, ptr, &ptr);
590         for (i = 0; i < jit->num_line_numbers; i++) {
591                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
592
593                 write_sleb128 (lne->il_offset, ptr, &ptr);
594                 write_sleb128 (lne->native_offset, ptr, &ptr);
595         }
596
597         *ptr++ = jit->this_var ? 1 : 0;
598         if (jit->this_var)
599                 write_variable (jit->this_var, ptr, &ptr);
600
601         write_leb128 (jit->num_params, ptr, &ptr);
602         for (i = 0; i < jit->num_params; i++)
603                 write_variable (&jit->params [i], ptr, &ptr);
604
605         write_leb128 (jit->num_locals, ptr, &ptr);
606         for (i = 0; i < jit->num_locals; i++)
607                 write_variable (&jit->locals [i], ptr, &ptr);
608
609         size = ptr - oldptr;
610         g_assert (size < max_size);
611         total_size = size + sizeof (MonoDebugMethodAddress);
612
613         address = (MonoDebugMethodAddress *) allocate_data_item (
614                 table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
615
616         address->header.size = total_size;
617         address->header.symfile_id = handle ? handle->index : 0;
618         address->header.domain_id = mono_domain_get_id (domain);
619         address->header.method_id = is_wrapper ? 0 : minfo->index;
620         address->header.method = method;
621
622         address->code_start = jit->code_start;
623         address->code_size = jit->code_size;
624
625         memcpy (&address->data, oldptr, size);
626         if (max_size > BUFSIZ)
627                 g_free (oldptr);
628
629         declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
630         header = g_hash_table_lookup (table->method_hash, declaring);
631
632         if (!header) {
633                 header = &address->header;
634                 g_hash_table_insert (table->method_hash, declaring, header);
635
636                 if (is_wrapper) {
637                         const unsigned char* il_code;
638                         MonoMethodHeader *mheader;
639                         MonoDebugWrapperData *wrapper;
640                         guint32 il_codesize;
641
642                         mheader = mono_method_get_header (declaring);
643                         il_code = mono_method_header_get_code (mheader, &il_codesize, NULL);
644
645                         header->wrapper_data = wrapper = g_new0 (MonoDebugWrapperData, 1);
646
647                         wrapper->wrapper_type = method->wrapper_type;
648                         wrapper->method_name = mono_method_full_name (declaring, TRUE);
649                         wrapper->cil_code = mono_disasm_code (
650                                 NULL, declaring, il_code, il_code + il_codesize);
651                 }
652         } else {
653                 address->header.wrapper_data = header->wrapper_data;
654                 header->address_list = g_slist_prepend (header->address_list, address);
655         }
656
657         g_hash_table_insert (table->method_address_hash, method, address);
658
659         write_data_item (table, (guint8 *) address);
660
661         mono_debugger_unlock ();
662         return address;
663 }
664
665 void
666 mono_debug_add_delegate_trampoline (gpointer code, int size)
667 {
668         MonoDebugDelegateTrampolineEntry *entry;
669
670         if (!mono_debug_initialized)
671                 return;
672
673         mono_debugger_lock ();
674
675         entry = (MonoDebugDelegateTrampolineEntry *) allocate_data_item (
676                 mono_symbol_table->global_data_table, MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE,
677                 sizeof (MonoDebugDelegateTrampolineEntry));
678         entry->code = code;
679         entry->size = size;
680
681         write_data_item (mono_symbol_table->global_data_table, (guint8 *) entry);
682
683         mono_debugger_unlock ();
684 }
685
686 static inline guint32
687 read_leb128 (guint8 *ptr, guint8 **rptr)
688 {
689         guint32 result = 0, shift = 0;
690
691         while (TRUE) {
692                 guint8 byte = *ptr++;
693
694                 result |= (byte & 0x7f) << shift;
695                 if ((byte & 0x80) == 0)
696                         break;
697                 shift += 7;
698         }
699
700         *rptr = ptr;
701         return result;
702 }
703
704 static inline gint32
705 read_sleb128 (guint8 *ptr, guint8 **rptr)
706 {
707         gint32 result = 0;
708         guint32 shift = 0;
709
710         while (TRUE) {
711                 guint8 byte = *ptr++;
712
713                 result |= (byte & 0x7f) << shift;
714                 shift += 7;
715
716                 if (byte & 0x80)
717                         continue;
718
719                 if ((shift < 32) && (byte & 0x40))
720                         result |= - (1 << shift);
721                 break;
722         }
723
724         *rptr = ptr;
725         return result;
726 }
727
728 static void
729 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
730 {
731         var->index = read_leb128 (ptr, &ptr);
732         var->offset = read_sleb128 (ptr, &ptr);
733         var->size = read_leb128 (ptr, &ptr);
734         var->begin_scope = read_leb128 (ptr, &ptr);
735         var->end_scope = read_leb128 (ptr, &ptr);
736         READ_UNALIGNED (gpointer, ptr, var->type);
737         ptr += sizeof (gpointer);
738         *rptr = ptr;
739 }
740
741 void
742 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
743 {
744         if (!jit)
745                 return;
746         g_free (jit->line_numbers);
747         g_free (jit->this_var);
748         g_free (jit->params);
749         g_free (jit->locals);
750         g_free (jit);
751 }
752
753 static MonoDebugMethodJitInfo *
754 mono_debug_read_method (MonoDebugMethodAddress *address)
755 {
756         MonoDebugMethodJitInfo *jit;
757         guint32 i;
758         guint8 *ptr;
759
760         jit = g_new0 (MonoDebugMethodJitInfo, 1);
761         jit->code_start = address->code_start;
762         jit->code_size = address->code_size;
763         jit->wrapper_addr = address->wrapper_addr;
764
765         ptr = (guint8 *) &address->data;
766
767         jit->prologue_end = read_leb128 (ptr, &ptr);
768         jit->epilogue_begin = read_leb128 (ptr, &ptr);
769
770         jit->num_line_numbers = read_leb128 (ptr, &ptr);
771         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
772         for (i = 0; i < jit->num_line_numbers; i++) {
773                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
774
775                 lne->il_offset = read_sleb128 (ptr, &ptr);
776                 lne->native_offset = read_sleb128 (ptr, &ptr);
777         }
778
779         if (*ptr++) {
780                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
781                 read_variable (jit->this_var, ptr, &ptr);
782         }
783
784         jit->num_params = read_leb128 (ptr, &ptr);
785         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
786         for (i = 0; i < jit->num_params; i++)
787                 read_variable (&jit->params [i], ptr, &ptr);
788
789         jit->num_locals = read_leb128 (ptr, &ptr);
790         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
791         for (i = 0; i < jit->num_locals; i++)
792                 read_variable (&jit->locals [i], ptr, &ptr);
793
794         return jit;
795 }
796
797 static void
798 mono_debug_add_type (MonoClass *klass)
799 {
800         MonoDebugHandle *handle;
801         MonoDebugClassEntry *entry;
802         guint8 buffer [BUFSIZ];
803         guint8 *ptr, *oldptr;
804         guint32 size, total_size, max_size;
805         int base_offset = 0;
806
807         handle = _mono_debug_get_image (klass->image);
808         if (!handle)
809                 return;
810
811         if (klass->generic_class || klass->rank ||
812             (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
813                 return;
814
815         mono_debugger_lock ();
816
817         max_size = 12 + sizeof (gpointer);
818         if (max_size > BUFSIZ)
819                 ptr = oldptr = g_malloc (max_size);
820         else
821                 ptr = oldptr = buffer;
822
823         if (klass->valuetype)
824                 base_offset = - (int)(sizeof (MonoObject));
825
826         write_leb128 (klass->type_token, ptr, &ptr);
827         write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
828         WRITE_UNALIGNED (gpointer, ptr, klass);
829         ptr += sizeof (gpointer);
830
831         size = ptr - oldptr;
832         g_assert (size < max_size);
833         total_size = size + sizeof (MonoDebugClassEntry);
834
835         g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE);
836
837         entry = (MonoDebugClassEntry *) allocate_data_item (
838                 handle->type_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size);
839
840         entry->size = total_size;
841
842         memcpy (&entry->data, oldptr, size);
843
844         write_data_item (handle->type_table, (guint8 *) entry);
845
846         if (max_size > BUFSIZ)
847                 g_free (oldptr);
848
849         mono_debugger_unlock ();
850 }
851
852 static MonoDebugMethodJitInfo *
853 find_method (MonoMethod *method, MonoDomain *domain)
854 {
855         MonoDebugDataTable *table;
856         MonoDebugMethodAddress *address;
857
858         table = lookup_data_table (domain);
859         address = g_hash_table_lookup (table->method_address_hash, method);
860
861         if (!address)
862                 return NULL;
863
864         return mono_debug_read_method (address);
865 }
866
867 MonoDebugMethodJitInfo *
868 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
869 {
870         MonoDebugMethodJitInfo *res;
871
872         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
873                 return NULL;
874
875         mono_debugger_lock ();
876         res = find_method (method, domain);
877         mono_debugger_unlock ();
878         return res;
879 }
880
881 struct LookupMethodAddressData
882 {
883         MonoMethod *method;
884         MonoDebugMethodHeader *result;
885 };
886
887 static void
888 lookup_method_address_func (gpointer key, gpointer value, gpointer user_data)
889 {
890         MonoDebugDataTable *table = (MonoDebugDataTable *) value;
891         struct LookupMethodAddressData *data = (struct LookupMethodAddressData *) user_data;
892         MonoDebugMethodHeader *header;
893
894         header = g_hash_table_lookup (table->method_hash, data->method);
895         if (header)
896                 data->result = header;
897 }
898
899 MonoDebugMethodAddressList *
900 mono_debug_lookup_method_addresses (MonoMethod *method)
901 {
902         MonoDebugMethodAddressList *info;
903         MonoDebugMethodHeader *header = NULL;
904         struct LookupMethodAddressData data;
905         MonoMethod *declaring;
906         int count, size;
907         GSList *list;
908         guint8 *ptr;
909
910         g_assert (mono_debug_debugger_version == 4);
911
912         mono_debugger_lock ();
913
914         declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
915
916         data.method = declaring;
917         data.result = NULL;
918
919         g_hash_table_foreach (data_table_hash, lookup_method_address_func, &data);
920         header = data.result;
921
922         if (!header) {
923                 mono_debugger_unlock ();
924                 return NULL;
925         }
926
927         count = g_slist_length (header->address_list) + 1;
928         size = sizeof (MonoDebugMethodAddressList) + count * sizeof (gpointer);
929
930         info = g_malloc0 (size);
931         info->size = size;
932         info->count = count;
933
934         ptr = info->data;
935
936         WRITE_UNALIGNED (gpointer, ptr, header);
937         ptr += sizeof (gpointer);
938
939         for (list = header->address_list; list; list = list->next) {
940                 WRITE_UNALIGNED (gpointer, ptr, list->data);
941                 ptr += sizeof (gpointer);
942         }
943
944         mono_debugger_unlock ();
945         return info;
946 }
947
948 static gint32
949 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
950 {
951         MonoDebugMethodJitInfo *jit;
952         int i;
953
954         jit = find_method (method, domain);
955         if (!jit || !jit->line_numbers)
956                 goto cleanup_and_fail;
957
958         for (i = jit->num_line_numbers - 1; i >= 0; i--) {
959                 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
960
961                 if (lne.native_offset <= native_offset) {
962                         mono_debug_free_method_jit_info (jit);
963                         return lne.il_offset;
964                 }
965         }
966
967 cleanup_and_fail:
968         mono_debug_free_method_jit_info (jit);
969         return -1;
970 }
971
972 /**
973  * mono_debug_lookup_source_location:
974  * @address: Native offset within the @method's machine code.
975  *
976  * Lookup the source code corresponding to the machine instruction located at
977  * native offset @address within @method.
978  *
979  * The returned `MonoDebugSourceLocation' contains both file / line number
980  * information and the corresponding IL offset.  It must be freed by
981  * mono_debug_free_source_location().
982  */
983 MonoDebugSourceLocation *
984 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
985 {
986         MonoDebugMethodInfo *minfo;
987         MonoDebugSourceLocation *location;
988         gint32 offset;
989
990         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
991                 return NULL;
992
993         mono_debugger_lock ();
994         minfo = _mono_debug_lookup_method (method);
995         if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
996                 mono_debugger_unlock ();
997                 return NULL;
998         }
999
1000         offset = il_offset_from_address (method, domain, address);
1001         if (offset < 0) {
1002                 mono_debugger_unlock ();
1003                 return NULL;
1004         }
1005
1006         location = mono_debug_symfile_lookup_location (minfo, offset);
1007         mono_debugger_unlock ();
1008         return location;
1009 }
1010
1011 /**
1012  * mono_debug_free_source_location:
1013  * @location: A `MonoDebugSourceLocation'.
1014  *
1015  * Frees the @location.
1016  */
1017 void
1018 mono_debug_free_source_location (MonoDebugSourceLocation *location)
1019 {
1020         if (location) {
1021                 g_free (location->source_file);
1022                 g_free (location);
1023         }
1024 }
1025
1026 /**
1027  * mono_debug_print_stack_frame:
1028  * @native_offset: Native offset within the @method's machine code.
1029  *
1030  * Conventient wrapper around mono_debug_lookup_source_location() which can be
1031  * used if you only want to use the location to print a stack frame.
1032  */
1033 gchar *
1034 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
1035 {
1036         MonoDebugSourceLocation *location;
1037         gchar *fname, *ptr, *res;
1038
1039         fname = mono_method_full_name (method, TRUE);
1040         for (ptr = fname; *ptr; ptr++) {
1041                 if (*ptr == ':') *ptr = '.';
1042         }
1043
1044         location = mono_debug_lookup_source_location (method, native_offset, domain);
1045
1046         if (!location) {
1047                 res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
1048                 g_free (fname);
1049                 return res;
1050         }
1051
1052         res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
1053                                location->source_file, location->row);
1054
1055         g_free (fname);
1056         mono_debug_free_source_location (location);
1057         return res;
1058 }
1059
1060 void
1061 mono_debug_list_add (MonoDebugList **list, gconstpointer data)
1062 {
1063         MonoDebugList *element, **ptr;
1064
1065         element = g_new0 (MonoDebugList, 1);
1066         element->data = data;
1067
1068         for (ptr = list; *ptr; ptr = &(*ptr)->next)
1069                 ;
1070
1071         *ptr = element;
1072 }
1073
1074 void
1075 mono_debug_list_remove (MonoDebugList **list, gconstpointer data)
1076 {
1077         MonoDebugList **ptr;
1078         MonoDebugList *next;
1079
1080         for (ptr = list; *ptr; ptr = &(*ptr)->next) {
1081                 if ((*ptr)->data != data)
1082                         continue;
1083
1084                 next = (*ptr)->next;
1085                 g_free ((*ptr));
1086                 *ptr = next;
1087                 break;
1088         }
1089 }