2003-06-17 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / debug-mono-symfile.c
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/rawbuffer.h>
8 #include <mono/metadata/tokentype.h>
9 #include <mono/metadata/appdomain.h>
10 #include <mono/metadata/exception.h>
11 #include <mono/metadata/debug-helpers.h>
12 #include <mono/metadata/mono-debug.h>
13 #include <mono/metadata/debug-mono-symfile.h>
14
15 #include <fcntl.h>
16 #include <unistd.h>
17
18 #define RANGE_TABLE_CHUNK_SIZE          256
19 #define CLASS_TABLE_CHUNK_SIZE          256
20 #define TYPE_TABLE_PTR_CHUNK_SIZE       256
21 #define TYPE_TABLE_CHUNK_SIZE           65536
22
23 static void
24 free_method_info (MonoDebugMethodInfo *minfo)
25 {
26         g_free (minfo);
27 }
28
29 static gchar *
30 get_class_name (MonoClass *klass)
31 {
32         if (klass->nested_in) {
33                 gchar *parent_name = get_class_name (klass->nested_in);
34                 gchar *name = g_strdup_printf ("%s.%s", parent_name, klass->name);
35                 g_free (parent_name);
36                 return name;
37         }
38
39         return g_strdup_printf ("%s%s%s", klass->name_space,
40                                 klass->name_space [0] ? "." : "", klass->name);
41 }
42
43 static int
44 load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile)
45 {
46         MonoSymbolFileMethodEntry *me;
47         MonoSymbolFileMethodIndexEntry *ie;
48         const char *ptr, *start;
49         guint64 magic;
50         long version;
51         int i;
52
53         ptr = start = symfile->raw_contents;
54         if (!ptr)
55                 return FALSE;
56
57         magic = *((guint64 *) ptr);
58         ptr += sizeof(guint64);
59         if (magic != MONO_SYMBOL_FILE_MAGIC) {
60                 g_warning ("Symbol file %s has is not a mono symbol file", handle->image_file);
61                 return FALSE;
62         }
63
64         version = *((guint32 *) ptr);
65         ptr += sizeof(guint32);
66         if (version != MONO_SYMBOL_FILE_VERSION) {
67                 g_warning ("Symbol file %s has incorrect version "
68                            "(expected %d, got %ld)", handle->image_file,
69                            MONO_SYMBOL_FILE_VERSION, version);
70                 return FALSE;
71         }
72
73         symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
74
75         /*
76          * Read method table.
77          *
78          */
79
80         symfile->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
81                                                              (GDestroyNotify) free_method_info);
82
83         ie = (MonoSymbolFileMethodIndexEntry *)
84                 (symfile->raw_contents + symfile->offset_table->method_table_offset);
85
86         for (i = 0; i < symfile->offset_table->method_count; i++, me++, ie++) {
87                 MonoMethod *method;
88                 MonoDebugMethodInfo *minfo;
89
90                 me = (MonoSymbolFileMethodEntry *) (symfile->raw_contents + ie->file_offset);
91
92                 method = mono_get_method (handle->image, me->token, NULL);
93
94                 if (!method)
95                         continue;
96
97                 minfo = g_new0 (MonoDebugMethodInfo, 1);
98                 minfo->index = i + 1;
99                 minfo->method = method;
100                 minfo->handle = handle;
101                 minfo->num_il_offsets = me->num_line_numbers;
102                 minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
103                         (symfile->raw_contents + me->line_number_table_offset);
104                 minfo->entry = me;
105
106                 g_hash_table_insert (symfile->method_hash, method, minfo);
107         }
108
109         return TRUE;
110 }
111
112 static gconstpointer
113 open_symfile (MonoImage *image, guint32 *size)
114 {
115         MonoTableInfo *table = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
116         guint32 i;
117         guint32 cols [MONO_MANIFEST_SIZE];
118         const char *val;
119
120         for (i = 0; i < table->rows; ++i) {
121                 mono_metadata_decode_row (table, i, cols, MONO_MANIFEST_SIZE);
122                 val = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
123                 if (!strcmp (val, "MonoSymbolFile"))
124                         break;
125         }
126         if (i == table->rows)
127                 return NULL;
128         g_assert (!cols [MONO_MANIFEST_IMPLEMENTATION]);
129
130         return mono_image_get_resource (image, cols [MONO_MANIFEST_OFFSET], size);
131 }
132
133 MonoSymbolFile *
134 mono_debug_open_mono_symbol_file (MonoDebugHandle *handle, gboolean create_symfile)
135 {
136         MonoSymbolFile *symfile;
137
138         symfile = g_new0 (MonoSymbolFile, 1);
139
140         symfile->raw_contents = open_symfile (handle->image, &symfile->raw_contents_size);
141
142         if (load_symfile (handle, symfile))
143                 return symfile;
144         else if (!create_symfile) {
145                 mono_debug_close_mono_symbol_file (symfile);
146                 return NULL;
147         }
148
149         return symfile;
150 }
151
152 void
153 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
154 {
155         if (!symfile)
156                 return;
157
158         if (symfile->method_hash)
159                 g_hash_table_destroy (symfile->method_hash);
160
161         g_free (symfile);
162 }
163
164 static gchar *
165 read_string (const char *ptr)
166 {
167         int len = *((guint32 *) ptr);
168         ptr += sizeof(guint32);
169         return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
170 }
171
172 gchar *
173 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
174                                  guint32 *line_number)
175 {
176         MonoSymbolFileLineNumberEntry *lne;
177         MonoDebugMethodInfo *minfo;
178         gchar *source_file = NULL;
179         const char *ptr;
180         int i;
181
182         if (!symfile->method_hash)
183                 return NULL;
184
185         minfo = g_hash_table_lookup (symfile->method_hash, method);
186         if (!minfo)
187                 return NULL;
188
189         if (minfo->entry->source_index) {
190                 int offset = symfile->offset_table->source_table_offset +
191                         (minfo->entry->source_index - 1) * sizeof (MonoSymbolFileSourceEntry);
192                 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *) (symfile->raw_contents + offset);
193
194                 source_file = read_string (symfile->raw_contents + se->name_offset);
195         }
196
197         ptr = symfile->raw_contents + minfo->entry->line_number_table_offset;
198
199         lne = (MonoSymbolFileLineNumberEntry *) ptr;
200
201         for (i = 0; i < minfo->entry->num_line_numbers; i++, lne++) {
202                 if (lne->offset < offset)
203                         continue;
204
205                 if (line_number) {
206                         *line_number = lne->row;
207                         if (source_file)
208                                 return source_file;
209                         else
210                                 return NULL;
211                 } else if (source_file) {
212                         gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
213                         g_free (source_file);
214                         return retval;
215                 } else
216                         return g_strdup_printf ("%d", lne->row);
217         }
218
219         return NULL;
220 }
221
222 gint32
223 _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offset)
224 {
225         int i;
226
227         if (!jit || !jit->line_numbers)
228                 return -1;
229
230         for (i = jit->line_numbers->len - 1; i >= 0; i--) {
231                 MonoDebugLineNumberEntry lne = g_array_index (
232                         jit->line_numbers, MonoDebugLineNumberEntry, i);
233
234                 if (lne.offset <= il_offset)
235                         return lne.address;
236         }
237
238         return -1;
239 }
240
241 MonoDebugMethodInfo *
242 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
243 {
244         if (!symfile->method_hash)
245                 return NULL;
246         else
247                 return g_hash_table_lookup (symfile->method_hash, method);
248 }