2004-05-25 Atsushi Enomoto <atsushi@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 = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
84         guint32 i;
85         guint32 cols [MONO_MANIFEST_SIZE];
86         const char *val;
87
88         for (i = 0; i < table->rows; ++i) {
89                 mono_metadata_decode_row (table, i, cols, MONO_MANIFEST_SIZE);
90                 val = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
91                 if (!strcmp (val, "MonoSymbolFile"))
92                         break;
93         }
94         if (i == table->rows)
95                 return NULL;
96         g_assert (!cols [MONO_MANIFEST_IMPLEMENTATION]);
97
98         return mono_image_get_resource (image, cols [MONO_MANIFEST_OFFSET], size);
99 }
100
101 MonoSymbolFile *
102 mono_debug_open_mono_symbol_file (MonoDebugHandle *handle, gboolean create_symfile)
103 {
104         MonoSymbolFile *symfile;
105
106         symfile = g_new0 (MonoSymbolFile, 1);
107
108         symfile->raw_contents = open_symfile (handle->image, &symfile->raw_contents_size);
109
110         if (load_symfile (handle, symfile))
111                 return symfile;
112         else if (!create_symfile) {
113                 mono_debug_close_mono_symbol_file (symfile);
114                 return NULL;
115         }
116
117         return symfile;
118 }
119
120 void
121 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
122 {
123         if (!symfile)
124                 return;
125
126         if (symfile->method_hash)
127                 g_hash_table_destroy (symfile->method_hash);
128
129         g_free (symfile);
130 }
131
132 static gchar *
133 read_string (const char *ptr)
134 {
135         int len = *((guint32 *) ptr);
136         ptr += sizeof(guint32);
137         return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
138 }
139
140 gchar *
141 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
142                                  guint32 *line_number)
143 {
144         MonoSymbolFileLineNumberEntry *lne;
145         MonoDebugMethodInfo *minfo;
146         gchar *source_file = NULL;
147         const char *ptr;
148         int i;
149
150         if (!symfile->method_hash)
151                 return NULL;
152
153         minfo = g_hash_table_lookup (symfile->method_hash, method);
154         if (!minfo)
155                 return NULL;
156
157         if (read32(&(minfo->entry->_source_index))) {
158                 int offset = read32(&(symfile->offset_table->_source_table_offset)) +
159                         (read32(&(minfo->entry->_source_index)) - 1) * sizeof (MonoSymbolFileSourceEntry);
160                 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *) (symfile->raw_contents + offset);
161
162                 source_file = read_string (symfile->raw_contents + read32(&(se->_name_offset)));
163         }
164
165         ptr = symfile->raw_contents + read32(&(minfo->entry->_line_number_table_offset));
166
167         lne = (MonoSymbolFileLineNumberEntry *) ptr;
168
169         for (i = 0; i < read32(&(minfo->entry->_num_line_numbers)); i++, lne++) {
170                 if (read32(&(lne->_offset)) < offset)
171                         continue;
172
173                 if (line_number) {
174                         *line_number = read32(&(lne->_row));
175                         if (source_file)
176                                 return source_file;
177                         else
178                                 return NULL;
179                 } else if (source_file) {
180                         gchar *retval = g_strdup_printf ("%s:%d", source_file, read32(&(lne->_row)));
181                         g_free (source_file);
182                         return retval;
183                 } else
184                         return g_strdup_printf ("%d", read32(&(lne->_row)));
185         }
186
187         return NULL;
188 }
189
190 gint32
191 _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offset)
192 {
193         int i;
194
195         if (!jit || !jit->line_numbers)
196                 return -1;
197
198         for (i = jit->line_numbers->len - 1; i >= 0; i--) {
199                 MonoDebugLineNumberEntry lne = g_array_index (
200                         jit->line_numbers, MonoDebugLineNumberEntry, i);
201
202                 if (lne.offset <= il_offset)
203                         return lne.address;
204         }
205
206         return -1;
207 }
208
209 static int
210 compare_method (const void *key, const void *object)
211 {
212         guint32 token = GPOINTER_TO_UINT (key);
213         MonoSymbolFileMethodIndexEntry *me = (MonoSymbolFileMethodIndexEntry*)object;
214
215         return token - read32(&(me->_token));
216 }
217
218 MonoDebugMethodInfo *
219 mono_debug_find_method (MonoDebugHandle *handle, MonoMethod *method)
220 {
221         MonoSymbolFileMethodEntry *me;
222         MonoSymbolFileMethodIndexEntry *first_ie, *ie;
223         MonoDebugMethodInfo *minfo;
224         MonoSymbolFile *symfile = handle->symfile;
225
226         if (!symfile->method_hash)
227                 return NULL;
228
229         if (handle->image != method->klass->image)
230                 return NULL;
231
232         first_ie = (MonoSymbolFileMethodIndexEntry *)
233                 (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset)));
234
235         ie = bsearch (GUINT_TO_POINTER (method->token), first_ie,
236                                    read32(&(symfile->offset_table->_method_count)),
237                                    sizeof (MonoSymbolFileMethodIndexEntry), compare_method);
238
239         if (!ie)
240                 return NULL;
241
242         me = (MonoSymbolFileMethodEntry *) (symfile->raw_contents + read32(&(ie->_file_offset)));
243
244         minfo = g_new0 (MonoDebugMethodInfo, 1);
245         minfo->index = (ie - first_ie) + 1;
246         minfo->method = method;
247         minfo->handle = handle;
248         minfo->num_il_offsets = read32(&(me->_num_line_numbers));
249         minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
250                 (symfile->raw_contents + read32(&(me->_line_number_table_offset)));
251         minfo->entry = me;
252
253         g_hash_table_insert (symfile->method_hash, method, minfo);
254
255         return minfo;
256 }