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