Remove docs from mono-1-0 branch
[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         mono_loader_lock ();
111         symfile = g_new0 (MonoSymbolFile, 1);
112
113         symfile->raw_contents = open_symfile (handle->image, &symfile->raw_contents_size);
114
115         if (load_symfile (handle, symfile)) {
116                 mono_loader_unlock ();
117                 return symfile;
118         } else if (!create_symfile) {
119                 mono_debug_close_mono_symbol_file (symfile);
120                 mono_loader_unlock ();
121                 return NULL;
122         }
123
124         mono_loader_unlock ();
125         return symfile;
126 }
127
128 void
129 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
130 {
131         if (!symfile)
132                 return;
133
134         mono_loader_lock ();
135         if (symfile->method_hash)
136                 g_hash_table_destroy (symfile->method_hash);
137
138         g_free (symfile);
139         mono_loader_unlock ();
140 }
141
142 static gchar *
143 read_string (const char *ptr)
144 {
145         int len = read32 (ptr);
146         ptr += sizeof(guint32);
147         return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
148 }
149
150 gchar *
151 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
152                                  guint32 *line_number)
153 {
154         MonoSymbolFileLineNumberEntry *lne;
155         MonoDebugMethodInfo *minfo;
156         gchar *source_file = NULL;
157         const char *ptr;
158         int i;
159
160         mono_loader_lock ();
161         if (!symfile->method_hash) {
162                 mono_loader_unlock ();
163                 return NULL;
164         }
165
166         minfo = g_hash_table_lookup (symfile->method_hash, method);
167         if (!minfo) {
168                 mono_loader_unlock ();
169                 return NULL;
170         }
171
172         if (read32(&(minfo->entry->_source_index))) {
173                 int offset = read32(&(symfile->offset_table->_source_table_offset)) +
174                         (read32(&(minfo->entry->_source_index)) - 1) * sizeof (MonoSymbolFileSourceEntry);
175                 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *) (symfile->raw_contents + offset);
176
177                 source_file = read_string (symfile->raw_contents + read32(&(se->_name_offset)));
178         }
179
180         ptr = symfile->raw_contents + read32(&(minfo->entry->_line_number_table_offset));
181
182         lne = (MonoSymbolFileLineNumberEntry *) ptr;
183
184         for (i = 0; i < read32(&(minfo->entry->_num_line_numbers)); i++, lne++) {
185                 if (read32(&(lne->_offset)) < offset)
186                         continue;
187
188                 if (line_number) {
189                         *line_number = read32(&(lne->_row));
190                         mono_loader_unlock ();
191                         if (source_file)
192                                 return source_file;
193                         else
194                                 return NULL;
195                 } else if (source_file) {
196                         gchar *retval = g_strdup_printf ("%s:%d", source_file, read32(&(lne->_row)));
197                         g_free (source_file);
198                         mono_loader_unlock ();
199                         return retval;
200                 } else {
201                         gchar* retval = g_strdup_printf ("%d", read32(&(lne->_row)));
202                         mono_loader_unlock ();
203                         return retval;
204                 }
205         }
206
207         mono_loader_unlock ();
208         return NULL;
209 }
210
211 gint32
212 _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offset)
213 {
214         int i;
215
216         if (!jit || !jit->line_numbers)
217                 return -1;
218
219         for (i = jit->line_numbers->len - 1; i >= 0; i--) {
220                 MonoDebugLineNumberEntry lne = g_array_index (
221                         jit->line_numbers, MonoDebugLineNumberEntry, i);
222
223                 if (lne.offset <= il_offset)
224                         return lne.address;
225         }
226
227         return -1;
228 }
229
230 static int
231 compare_method (const void *key, const void *object)
232 {
233         guint32 token = GPOINTER_TO_UINT (key);
234         MonoSymbolFileMethodIndexEntry *me = (MonoSymbolFileMethodIndexEntry*)object;
235
236         return token - read32(&(me->_token));
237 }
238
239 MonoDebugMethodInfo *
240 mono_debug_find_method (MonoDebugHandle *handle, MonoMethod *method)
241 {
242         MonoSymbolFileMethodEntry *me;
243         MonoSymbolFileMethodIndexEntry *first_ie, *ie;
244         MonoDebugMethodInfo *minfo;
245         MonoSymbolFile *symfile = handle->symfile;
246
247         if (!symfile->method_hash)
248                 return NULL;
249
250         if (handle->image != mono_class_get_image (mono_method_get_class (method)))
251                 return NULL;
252
253         mono_loader_lock ();
254         first_ie = (MonoSymbolFileMethodIndexEntry *)
255                 (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset)));
256
257         ie = bsearch (GUINT_TO_POINTER (mono_method_get_token (method)), first_ie,
258                                    read32(&(symfile->offset_table->_method_count)),
259                                    sizeof (MonoSymbolFileMethodIndexEntry), compare_method);
260
261         if (!ie) {
262                 mono_loader_unlock ();
263                 return NULL;
264         }
265
266         me = (MonoSymbolFileMethodEntry *) (symfile->raw_contents + read32(&(ie->_file_offset)));
267
268         minfo = g_new0 (MonoDebugMethodInfo, 1);
269         minfo->index = (ie - first_ie) + 1;
270         minfo->method = method;
271         minfo->handle = handle;
272         minfo->num_il_offsets = read32(&(me->_num_line_numbers));
273         minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
274                 (symfile->raw_contents + read32(&(me->_line_number_table_offset)));
275         minfo->entry = me;
276
277         g_hash_table_insert (symfile->method_hash, method, minfo);
278
279         mono_loader_unlock ();
280         return minfo;
281 }