Merge pull request #4169 from evincarofautumn/fix-xmm-scanning-mac-x86
[mono.git] / mono / metadata / debug-mono-symfile.c
1 /*
2  * debug-mono-symfile.c: 
3  *
4  *   Support for reading debug info from .mdb files.
5  *
6  * Author:
7  *      Mono Project (http://www.mono-project.com)
8  *
9  * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
10  * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <errno.h>
18 #include <string.h>
19 #ifdef HAVE_SYS_PARAM_H
20 #include <sys/param.h>
21 #endif
22 #include <sys/stat.h>
23 #include <mono/metadata/metadata.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/tokentype.h>
26 #include <mono/metadata/appdomain.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/debug-helpers.h>
29 #include <mono/metadata/mono-debug.h>
30 #include <mono/metadata/debug-mono-symfile.h>
31 #include <mono/metadata/mono-debug-debugger.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/metadata-internals.h>
34 #include <mono/metadata/class-internals.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/bsearch.h>
37
38 #ifndef DISABLE_MDB
39
40 #include <fcntl.h>
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45 #define RANGE_TABLE_CHUNK_SIZE          256
46 #define CLASS_TABLE_CHUNK_SIZE          256
47 #define TYPE_TABLE_PTR_CHUNK_SIZE       256
48 #define TYPE_TABLE_CHUNK_SIZE           65536
49
50 struct _MonoSymbolFile {
51         const uint8_t *raw_contents;
52         int raw_contents_size;
53         void *raw_contents_handle;
54         int major_version;
55         int minor_version;
56         char *filename;
57         GHashTable *method_hash;
58         GHashTable *source_hash;
59         MonoSymbolFileOffsetTable *offset_table;
60         gboolean was_loaded_from_memory;
61 };
62
63 static void
64 free_method_info (MonoDebugMethodInfo *minfo)
65 {
66         g_free (minfo);
67 }
68
69 static void
70 free_source_info (MonoDebugSourceInfo *sinfo)
71 {
72         g_free (sinfo->source_file);
73         g_free (sinfo->guid);
74         g_free (sinfo->hash);
75         g_free (sinfo);
76 }
77
78 static int
79 load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, mono_bool in_the_debugger)
80 {
81         const char *ptr, *start;
82         gchar *guid;
83         uint64_t magic;
84         int minor, major;
85
86         ptr = start = (const char*)symfile->raw_contents;
87         if (!ptr)
88                 return FALSE;
89
90         magic = read64(ptr);
91         ptr += sizeof(uint64_t);
92         if (magic != MONO_SYMBOL_FILE_MAGIC) {
93                 if (!in_the_debugger)
94                         g_warning ("Symbol file %s is not a mono symbol file", symfile->filename);
95                 return FALSE;
96         }
97
98         major = read32(ptr);
99         ptr += sizeof(uint32_t);
100         minor = read32(ptr);
101         ptr += sizeof(uint32_t);
102
103         /*
104          * 50.0 is the frozen version for Mono 2.0.
105          *
106          * Nobody except me (Martin) is allowed to check the minor version.
107          */
108         if (major != MONO_SYMBOL_FILE_MAJOR_VERSION) {
109                 if (!in_the_debugger)
110                         g_warning ("Symbol file %s has incorrect version (expected %d.%d, got %d)",
111                                    symfile->filename, MONO_SYMBOL_FILE_MAJOR_VERSION,
112                                    MONO_SYMBOL_FILE_MINOR_VERSION, major);
113                 return FALSE;
114         }
115
116         guid = mono_guid_to_string ((const uint8_t *) ptr);
117         ptr += 16;
118
119         if (strcmp (handle->image->guid, guid)) {
120                 if (!in_the_debugger)
121                         g_warning ("Symbol file %s doesn't match image %s", symfile->filename,
122                                    handle->image->name);
123                 if (guid)
124                         g_free (guid);
125                 return FALSE;
126         }
127
128         symfile->major_version = major;
129         symfile->minor_version = minor;
130
131         symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
132
133         symfile->method_hash = g_hash_table_new_full (
134                 NULL, NULL, NULL, (GDestroyNotify) free_method_info);
135
136         symfile->source_hash = g_hash_table_new_full (
137                 NULL, NULL, NULL, (GDestroyNotify) free_source_info);
138
139         g_free (guid);
140         return TRUE;
141 }
142
143 MonoSymbolFile *
144 mono_debug_open_mono_symbols (MonoDebugHandle *handle, const uint8_t *raw_contents,
145                               int size, gboolean in_the_debugger)
146 {
147         MonoSymbolFile *symfile;
148
149         mono_debugger_lock ();
150         symfile = g_new0 (MonoSymbolFile, 1);
151
152         if (raw_contents != NULL) {
153                 unsigned char *p;
154                 symfile->raw_contents_size = size;
155                 symfile->raw_contents = p = (unsigned char *)g_malloc (size);
156                 memcpy (p, raw_contents, size);
157                 symfile->filename = g_strdup_printf ("LoadedFromMemory");
158                 symfile->was_loaded_from_memory = TRUE;
159         } else {
160                 MonoFileMap *f;
161
162                 symfile->filename = g_strdup_printf ("%s.mdb", mono_image_get_filename (handle->image));
163                 symfile->was_loaded_from_memory = FALSE;
164                 if ((f = mono_file_map_open (symfile->filename))) {
165                         symfile->raw_contents_size = mono_file_map_size (f);
166                         if (symfile->raw_contents_size == 0) {
167                                 if (!in_the_debugger)
168                                         g_warning ("stat of %s failed: %s",
169                                                    symfile->filename,  g_strerror (errno));
170                         } else {
171                                 symfile->raw_contents = (const unsigned char *)mono_file_map (symfile->raw_contents_size, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (f), 0, &symfile->raw_contents_handle);
172                         }
173
174                         mono_file_map_close (f);
175                 }
176         }
177         
178         if (load_symfile (handle, symfile, in_the_debugger)) {
179                 mono_debugger_unlock ();
180                 return symfile;
181         } else if (!in_the_debugger) {
182                 mono_debug_close_mono_symbol_file (symfile);
183                 mono_debugger_unlock ();
184                 return NULL;
185         }
186
187         mono_debugger_unlock ();
188         return symfile;
189 }
190
191 void
192 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
193 {
194         if (!symfile)
195                 return;
196
197         mono_debugger_lock ();
198         if (symfile->method_hash)
199                 g_hash_table_destroy (symfile->method_hash);
200
201         if (symfile->raw_contents) {
202                 if (symfile->was_loaded_from_memory)
203                         g_free ((gpointer)symfile->raw_contents);
204                 else
205                         mono_file_unmap ((gpointer) symfile->raw_contents, symfile->raw_contents_handle);
206         }
207
208         if (symfile->filename)
209                 g_free (symfile->filename);
210         g_free (symfile);
211         mono_debugger_unlock ();
212 }
213
214 mono_bool
215 mono_debug_symfile_is_loaded (MonoSymbolFile *symfile)
216 {
217         return symfile && symfile->offset_table;
218 }
219
220 static int
221 read_leb128 (const uint8_t *ptr, const uint8_t **rptr)
222 {
223         int ret = 0;
224         int shift = 0;
225         char b;
226
227         do {
228                 b = *ptr++;
229                                 
230                 ret = ret | ((b & 0x7f) << shift);
231                 shift += 7;
232         } while ((b & 0x80) == 0x80);
233
234         if (rptr)
235                 *rptr = ptr;
236
237         return ret;
238 }
239
240 static gchar *
241 read_string (const uint8_t *ptr, const uint8_t **endp)
242 {
243         gchar *s;
244         int len = read_leb128 (ptr, &ptr);
245
246         s = g_filename_from_utf8 ((const char *) ptr, len, NULL, NULL, NULL);
247         ptr += len;
248         if (endp)
249                 *endp = ptr;
250         return s;
251 }
252
253 typedef struct {
254         MonoSymbolFile *symfile;
255         int line_base, line_range, max_address_incr;
256         uint8_t opcode_base;
257         uint32_t last_line, last_file, last_offset;
258         uint32_t first_file;
259         int line, file, offset;
260         gboolean is_hidden;
261 } StatementMachine;
262
263 static gboolean
264 check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **location)
265 {
266         gchar *source_file = NULL;
267
268         if (stm->offset <= offset) {
269                 stm->last_offset = stm->offset;
270                 stm->last_file = stm->file;
271                 if (stm->line != 0xfeefee)
272                         stm->last_line = stm->line;
273                 return FALSE;
274         }
275
276         if (stm->last_file) {
277                 int offset = read32(&(stm->symfile->offset_table->_source_table_offset)) +
278                         (stm->last_file - 1) * sizeof (MonoSymbolFileSourceEntry);
279                 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
280                         (stm->symfile->raw_contents + offset);
281
282                 source_file = read_string (stm->symfile->raw_contents + read32(&(se->_data_offset)), NULL);
283         }
284
285         if (stm->last_line == 0) {
286                 /* 
287                  * The IL offset is less than the first IL offset which has a corresponding
288                  * source line.
289                  */
290                 *location = NULL;
291                 return TRUE;
292         }
293
294         *location = g_new0 (MonoDebugSourceLocation, 1);
295         (*location)->source_file = source_file;
296         (*location)->row = stm->last_line;
297         (*location)->il_offset = stm->last_offset;
298         return TRUE;
299 }
300
301 /**
302  * mono_debug_symfile_lookup_location:
303  * @minfo: A `MonoDebugMethodInfo' which can be retrieved by
304  *         mono_debug_lookup_method().
305  * @offset: IL offset within the corresponding method's CIL code.
306  *
307  * This function is similar to mono_debug_lookup_location(), but we
308  * already looked up the method and also already did the
309  * `native address -> IL offset' mapping.
310  */
311 MonoDebugSourceLocation *
312 mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset)
313 {
314         MonoDebugSourceLocation *location = NULL;
315         MonoSymbolFile *symfile;
316         const unsigned char *ptr;
317         StatementMachine stm;
318
319 #define DW_LNS_copy 1
320 #define DW_LNS_advance_pc 2
321 #define DW_LNS_advance_line 3
322 #define DW_LNS_set_file 4
323 #define DW_LNS_const_add_pc 8
324
325 #define DW_LNE_end_sequence 1
326 #define DW_LNE_MONO_negate_is_hidden 0x40
327
328 #define DW_LNE_MONO__extensions_start 0x40
329 #define DW_LNE_MONO__extensions_end 0x7f
330
331         if ((symfile = minfo->handle->symfile) == NULL)
332                 return NULL;
333
334         stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base);
335         stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range);
336         stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base);
337         stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;
338
339         mono_debugger_lock ();
340
341         ptr = symfile->raw_contents + minfo->lnt_offset;
342
343         stm.symfile = symfile;
344         stm.offset = stm.last_offset = 0;
345         stm.last_file = 0;
346         stm.last_line = 0;
347         stm.first_file = 0;
348         stm.file = 1;
349         stm.line = 1;
350         stm.is_hidden = FALSE;
351
352         while (TRUE) {
353                 uint8_t opcode = *ptr++;
354
355                 if (opcode == 0) {
356                         uint8_t size = *ptr++;
357                         const unsigned char *end_ptr = ptr + size;
358
359                         opcode = *ptr++;
360
361                         if (opcode == DW_LNE_end_sequence) {
362                                 if (check_line (&stm, -1, &location))
363                                         goto out_success;
364                                 break;
365                         } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
366                                 stm.is_hidden = !stm.is_hidden;
367                         } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
368                                    (opcode <= DW_LNE_MONO__extensions_end)) {
369                                 ; // reserved for future extensions
370                         } else {
371                                 g_warning ("Unknown extended opcode %x in LNT", opcode);
372                         }
373
374                         ptr = end_ptr;
375                         continue;
376                 } else if (opcode < stm.opcode_base) {
377                         switch (opcode) {
378                         case DW_LNS_copy:
379                                 if (check_line (&stm, offset, &location))
380                                         goto out_success;
381                                 break;
382                         case DW_LNS_advance_pc:
383                                 stm.offset += read_leb128 (ptr, &ptr);
384                                 break;
385                         case DW_LNS_advance_line:
386                                 stm.line += read_leb128 (ptr, &ptr);
387                                 break;
388                         case DW_LNS_set_file:
389                                 stm.file = read_leb128 (ptr, &ptr);
390                                 break;
391                         case DW_LNS_const_add_pc:
392                                 stm.offset += stm.max_address_incr;
393                                 break;
394                         default:
395                                 g_warning ("Unknown standard opcode %x in LNT", opcode);
396                                 goto error_out;
397                         }
398                 } else {
399                         opcode -= stm.opcode_base;
400
401                         stm.offset += opcode / stm.line_range;
402                         stm.line += stm.line_base + (opcode % stm.line_range);
403
404                         if (check_line (&stm, offset, &location))
405                                 goto out_success;
406                 }
407         }
408
409  error_out:
410         mono_debugger_unlock ();
411         return NULL;
412
413  out_success:
414         mono_debugger_unlock ();
415         return location;
416 }
417
418 static void
419 add_line (StatementMachine *stm, GPtrArray *il_offset_array, GPtrArray *line_number_array, GPtrArray *source_file_array, GPtrArray *hidden_array)
420 {
421         g_ptr_array_add (il_offset_array, GUINT_TO_POINTER (stm->offset));
422         g_ptr_array_add (line_number_array, GUINT_TO_POINTER (stm->line));
423         g_ptr_array_add (source_file_array, GUINT_TO_POINTER (stm->file));
424         g_ptr_array_add (hidden_array, GUINT_TO_POINTER (stm->is_hidden || stm->line <= 0));
425
426         if (!stm->is_hidden && !stm->first_file)
427                 stm->first_file = stm->file;
428 }
429
430 /*
431  * mono_debug_symfile_free_location:
432  *
433  *   Free a MonoDebugSourceLocation returned by
434  *   mono_debug_symfile_lookup_location
435  */
436 void
437 mono_debug_symfile_free_location (MonoDebugSourceLocation  *location)
438 {
439         g_free (location->source_file);
440         g_free (location);
441 }
442
443 /*
444  * LOCKING: Assumes the debugger lock is held.
445  */
446 static MonoDebugSourceInfo*
447 get_source_info (MonoSymbolFile *symfile, int index)
448 {
449         MonoDebugSourceInfo *info;
450
451         info = (MonoDebugSourceInfo *)g_hash_table_lookup (symfile->source_hash, GUINT_TO_POINTER (index));
452         if (!info) {
453                 int offset = read32(&(symfile->offset_table->_source_table_offset)) +
454                         (index - 1) * sizeof (MonoSymbolFileSourceEntry);
455                 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
456                         (symfile->raw_contents + offset);
457                 const uint8_t *ptr = symfile->raw_contents + read32(&(se->_data_offset));
458
459                 info = g_new0 (MonoDebugSourceInfo, 1);
460                 info->source_file = read_string (ptr, &ptr);
461                 info->guid = (guint8 *)g_malloc0 (16);
462                 memcpy (info->guid, ptr, 16);
463                 ptr += 16;
464                 info->hash = (guint8 *)g_malloc0 (16);
465                 memcpy (info->hash, ptr, 16);
466                 ptr += 16;
467                 g_hash_table_insert (symfile->source_hash, GUINT_TO_POINTER (index), info);
468         }
469         return info;
470 }
471
472 typedef enum {
473         LNT_FLAG_HAS_COLUMN_INFO = 1 << 1,
474         LNT_FLAG_HAS_END_INFO = 1 << 2,
475 } LineNumberTableFlags;
476
477 static LineNumberTableFlags
478 method_get_lnt_flags (MonoDebugMethodInfo *minfo)
479 {
480         MonoSymbolFile *symfile;
481         const unsigned char *ptr;
482         guint32 flags;
483
484         if ((symfile = minfo->handle->symfile) == NULL)
485                 return (LineNumberTableFlags)0;
486
487         ptr = symfile->raw_contents + minfo->data_offset;
488
489         /* Has to read 'flags' which is preceeded by a bunch of other data */
490         /* compile_unit_index */
491         read_leb128 (ptr, &ptr);
492         /* local variable table offset */
493         read_leb128 (ptr, &ptr);
494         /* namespace id */
495         read_leb128 (ptr, &ptr);
496         /* code block table offset */
497         read_leb128 (ptr, &ptr);
498         /* scope variable table offset */
499         read_leb128 (ptr, &ptr);
500         /* real name offset */
501         read_leb128 (ptr, &ptr);
502
503         flags = read_leb128 (ptr, &ptr);
504         return (LineNumberTableFlags)flags;
505 }
506
507 /*
508  * mono_debug_symfile_get_seq_points:
509  *
510  * On return, SOURCE_FILE_LIST will point to a GPtrArray of MonoDebugSourceFile
511  * structures, and SOURCE_FILES will contain indexes into this array.
512  * The MonoDebugSourceFile structures are owned by this module.
513  */
514 void
515 mono_debug_symfile_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points)
516 {
517         // FIXME: Unify this with mono_debug_symfile_lookup_location
518         MonoSymbolFile *symfile;
519         const unsigned char *ptr;
520         StatementMachine stm;
521         uint32_t i, j, n;
522         LineNumberTableFlags flags;
523         GPtrArray *il_offset_array, *line_number_array, *source_file_array, *hidden_array;
524         gboolean has_column_info, has_end_info;
525         MonoSymSeqPoint *sps;
526
527         if (source_file_list)
528                 *source_file_list = NULL;
529         if (seq_points)
530                 *seq_points = NULL;
531         if (n_seq_points)
532                 *n_seq_points = 0;
533         if (source_files)
534                 *source_files = NULL;
535         if (source_file)
536                 *source_file = NULL;
537
538         if ((symfile = minfo->handle->symfile) == NULL)
539                 return;
540
541         flags = method_get_lnt_flags (minfo);
542         has_column_info = (flags & LNT_FLAG_HAS_COLUMN_INFO) > 0;
543         has_end_info = (flags & LNT_FLAG_HAS_END_INFO) > 0;
544
545         il_offset_array = g_ptr_array_new ();
546         line_number_array = g_ptr_array_new ();
547         source_file_array = g_ptr_array_new ();
548         hidden_array = g_ptr_array_new();
549
550         stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base);
551         stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range);
552         stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base);
553         stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;
554
555         mono_debugger_lock ();
556
557         ptr = symfile->raw_contents + minfo->lnt_offset;
558
559         stm.symfile = symfile;
560         stm.offset = stm.last_offset = 0;
561         stm.last_file = 0;
562         stm.last_line = 0;
563         stm.first_file = 0;
564         stm.file = 1;
565         stm.line = 1;
566         stm.is_hidden = FALSE;
567
568         while (TRUE) {
569                 uint8_t opcode = *ptr++;
570
571                 if (opcode == 0) {
572                         uint8_t size = *ptr++;
573                         const unsigned char *end_ptr = ptr + size;
574
575                         opcode = *ptr++;
576
577                         if (opcode == DW_LNE_end_sequence) {
578                                 if (il_offset_array->len == 0)
579                                         /* Empty table */
580                                         break;
581                                 break;
582                         } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
583                                 stm.is_hidden = !stm.is_hidden;
584                         } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
585                                    (opcode <= DW_LNE_MONO__extensions_end)) {
586                                 ; // reserved for future extensions
587                         } else {
588                                 g_warning ("Unknown extended opcode %x in LNT", opcode);
589                         }
590
591                         ptr = end_ptr;
592                         continue;
593                 } else if (opcode < stm.opcode_base) {
594                         switch (opcode) {
595                         case DW_LNS_copy:
596                                 add_line (&stm, il_offset_array, line_number_array, source_file_array, hidden_array);
597                                 break;
598                         case DW_LNS_advance_pc:
599                                 stm.offset += read_leb128 (ptr, &ptr);
600                                 break;
601                         case DW_LNS_advance_line:
602                                 stm.line += read_leb128 (ptr, &ptr);
603                                 break;
604                         case DW_LNS_set_file:
605                                 stm.file = read_leb128 (ptr, &ptr);
606                                 break;
607                         case DW_LNS_const_add_pc:
608                                 stm.offset += stm.max_address_incr;
609                                 break;
610                         default:
611                                 g_warning ("Unknown standard opcode %x in LNT", opcode);
612                                 g_assert_not_reached ();
613                         }
614                 } else {
615                         opcode -= stm.opcode_base;
616
617                         stm.offset += opcode / stm.line_range;
618                         stm.line += stm.line_base + (opcode % stm.line_range);
619
620                         add_line (&stm, il_offset_array, line_number_array, source_file_array, hidden_array);
621                 }
622         }
623
624         if (!stm.file && stm.first_file)
625                 stm.file = stm.first_file;
626
627         if (stm.file && source_file) {
628                 int offset = read32(&(stm.symfile->offset_table->_source_table_offset)) +
629                         (stm.file - 1) * sizeof (MonoSymbolFileSourceEntry);
630                 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
631                         (stm.symfile->raw_contents + offset);
632
633                 if (source_file)
634                         *source_file = read_string (stm.symfile->raw_contents + read32(&(se->_data_offset)), NULL);
635         }
636
637         if (source_file_list) {
638                 int file, last_file = 0;
639
640                 *source_file_list = g_ptr_array_new ();
641                 if (source_files)
642                         *source_files = (int *)g_malloc (il_offset_array->len * sizeof (int));
643
644                 for (i = 0; i < il_offset_array->len; ++i) {
645                         file = GPOINTER_TO_UINT (g_ptr_array_index (source_file_array, i));
646                         if (file && file != last_file) {
647                                 MonoDebugSourceInfo *info = get_source_info (symfile, file);
648
649                                 g_ptr_array_add (*source_file_list, info);
650                         }
651                         last_file = file;
652                         if (source_files)
653                                 (*source_files) [i] = (*source_file_list)->len - 1;
654                 }
655         }                               
656
657         if (n_seq_points) {
658                 g_assert (seq_points);
659
660                 n = il_offset_array->len;
661                 for (i = 0; i < il_offset_array->len; i++) {
662                         if (GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
663                                 n --;
664                         }
665                 }
666
667                 *n_seq_points = n;
668                 *seq_points = sps = g_new0 (MonoSymSeqPoint, n);
669                 j = 0;
670                 for (i = 0; i < il_offset_array->len; ++i) {
671                         MonoSymSeqPoint *sp = &(sps [j]);
672                         if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
673                                 sp->il_offset = GPOINTER_TO_UINT (g_ptr_array_index (il_offset_array, i));
674                                 sp->line = GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i));
675                                 sp->column = -1;
676                                 sp->end_line = -1;
677                                 sp->end_column = -1;
678                                 j ++;
679                         }
680                 }
681
682                 if (has_column_info) {
683                         j = 0;
684                         for (i = 0; i < il_offset_array->len; ++i) {
685                                 MonoSymSeqPoint *sp = &(sps [j]);
686                                 int column = read_leb128 (ptr, &ptr);
687                                 if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
688                                         sp->column = column;
689                                         j++;
690                                 }
691                         }
692                 }
693
694                 if (has_end_info) {
695                         j = 0;
696                         for (i = 0; i < il_offset_array->len; ++i) {
697                                 MonoSymSeqPoint *sp = &(sps [j]);
698                                 int end_row, end_column = -1;
699
700                                 end_row = read_leb128 (ptr, &ptr);
701                                 if (end_row != 0xffffff) {
702                                         end_row += GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i));
703                                         end_column = read_leb128 (ptr, &ptr);
704                                         if (!GPOINTER_TO_UINT (g_ptr_array_index (hidden_array, i))) {
705                                                 sp->end_line = end_row;
706                                                 sp->end_column = end_column;
707                                                 j++;
708                                         }
709                                 }
710                         }
711                 }
712         }
713
714         g_ptr_array_free (il_offset_array, TRUE);
715         g_ptr_array_free (line_number_array, TRUE);
716         g_ptr_array_free (hidden_array, TRUE);
717
718         mono_debugger_unlock ();
719         return;
720 }
721
722 static int
723 compare_method (const void *key, const void *object)
724 {
725         uint32_t token = GPOINTER_TO_UINT (key);
726         MonoSymbolFileMethodEntry *me = (MonoSymbolFileMethodEntry*)object;
727
728         return token - read32(&(me->_token));
729 }
730
731 MonoDebugMethodInfo *
732 mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
733 {
734         MonoSymbolFileMethodEntry *first_ie, *ie;
735         MonoDebugMethodInfo *minfo;
736         MonoSymbolFile *symfile = handle->symfile;
737
738         if (!symfile->method_hash)
739                 return NULL;
740
741         if (handle->image != mono_class_get_image (mono_method_get_class (method)))
742                 return NULL;
743
744         mono_debugger_lock ();
745
746         minfo = (MonoDebugMethodInfo *)g_hash_table_lookup (symfile->method_hash, method);
747         if (minfo) {
748                 mono_debugger_unlock ();
749                 return minfo;
750         }
751
752         first_ie = (MonoSymbolFileMethodEntry *)
753                 (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset)));
754
755         ie = (MonoSymbolFileMethodEntry *)mono_binary_search (GUINT_TO_POINTER (mono_method_get_token (method)), first_ie,
756                                    read32(&(symfile->offset_table->_method_count)),
757                                    sizeof (MonoSymbolFileMethodEntry), compare_method);
758
759         if (!ie) {
760                 mono_debugger_unlock ();
761                 return NULL;
762         }
763
764         minfo = g_new0 (MonoDebugMethodInfo, 1);
765         minfo->index = (ie - first_ie) + 1;
766         minfo->method = method;
767         minfo->handle = handle;
768
769         minfo->data_offset = read32 (&(ie->_data_offset));
770         minfo->lnt_offset = read32 (&(ie->_line_number_table));
771
772         g_hash_table_insert (symfile->method_hash, method, minfo);
773
774         mono_debugger_unlock ();
775         return minfo;
776 }
777
778 /*
779  * mono_debug_symfile_lookup_locals:
780  *
781  *   Return information about the local variables of MINFO from the symbol file.
782  * Return NULL if no information can be found.
783  * The result should be freed using mono_debug_symfile_free_locals ().
784  */
785 MonoDebugLocalsInfo*
786 mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo)
787 {
788         MonoSymbolFile *symfile = minfo->handle->symfile;
789         const uint8_t *p;
790         int i, len, locals_offset, num_locals, block_index;
791         int code_block_table_offset;
792         MonoDebugLocalsInfo *res;
793
794         if (!symfile)
795                 return NULL;
796
797         p = symfile->raw_contents + minfo->data_offset;
798
799         /* compile_unit_index = */ read_leb128 (p, &p);
800         locals_offset = read_leb128 (p, &p);
801         /* namespace_id = */ read_leb128 (p, &p);
802         code_block_table_offset = read_leb128 (p, &p);
803
804         res = g_new0 (MonoDebugLocalsInfo, 1);
805
806         p = symfile->raw_contents + code_block_table_offset;
807         res->num_blocks = read_leb128 (p, &p);
808         res->code_blocks = g_new0 (MonoDebugCodeBlock, res->num_blocks);
809         for (i = 0; i < res->num_blocks; ++i) {
810                 res->code_blocks [i].type = read_leb128 (p, &p);
811                 res->code_blocks [i].parent = read_leb128 (p, &p);
812                 res->code_blocks [i].start_offset = read_leb128 (p, &p);
813                 res->code_blocks [i].end_offset = read_leb128 (p, &p);
814         }
815
816         p = symfile->raw_contents + locals_offset;
817         num_locals = read_leb128 (p, &p);
818
819         res->num_locals = num_locals;
820         res->locals = g_new0 (MonoDebugLocalVar, num_locals);
821
822         for (i = 0; i < num_locals; ++i) {
823                 res->locals [i].index = read_leb128 (p, &p);
824                 len = read_leb128 (p, &p);
825                 res->locals [i].name = (char *)g_malloc (len + 1);
826                 memcpy (res->locals [i].name, p, len);
827                 res->locals [i].name [len] = '\0';
828                 p += len;
829                 block_index = read_leb128 (p, &p);
830                 if (block_index >= 1 && block_index <= res->num_blocks)
831                         res->locals [i].block = &res->code_blocks [block_index - 1];
832         }
833
834         return res;
835 }
836
837 #else /* DISABLE_MDB */
838
839 MonoSymbolFile *
840 mono_debug_open_mono_symbols (MonoDebugHandle *handle, const uint8_t *raw_contents,
841                               int size, gboolean in_the_debugger)
842 {
843         return NULL;
844 }
845
846 void
847 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
848 {
849 }
850
851 mono_bool
852 mono_debug_symfile_is_loaded (MonoSymbolFile *symfile)
853 {
854         return FALSE;
855 }
856
857 MonoDebugMethodInfo *
858 mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
859 {
860         return NULL;
861 }
862
863 void
864 mono_debug_symfile_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points)
865 {
866         g_assert_not_reached ();
867 }
868
869 MonoDebugSourceLocation *
870 mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset)
871 {
872         return NULL;
873 }
874
875 MonoDebugLocalsInfo*
876 mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo)
877 {
878         return NULL;
879 }
880
881 void
882 mono_debug_symfile_free_location (MonoDebugSourceLocation  *location)
883 {
884 }
885
886 #endif