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