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