2 * debug-mono-symfile.c:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
16 #ifdef HAVE_SYS_PARAM_H
17 #include <sys/param.h>
20 #include <mono/metadata/metadata.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/appdomain.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/debug-helpers.h>
26 #include <mono/metadata/mono-debug.h>
27 #include <mono/metadata/debug-mono-symfile.h>
28 #include <mono/metadata/mono-debug-debugger.h>
29 #include <mono/metadata/mono-endian.h>
30 #include <mono/metadata/metadata-internals.h>
31 #include <mono/metadata/class-internals.h>
32 #include <mono/utils/mono-mmap.h>
39 #define RANGE_TABLE_CHUNK_SIZE 256
40 #define CLASS_TABLE_CHUNK_SIZE 256
41 #define TYPE_TABLE_PTR_CHUNK_SIZE 256
42 #define TYPE_TABLE_CHUNK_SIZE 65536
45 free_method_info (MonoDebugMethodInfo *minfo)
51 load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_debugger)
53 const char *ptr, *start;
58 ptr = start = (const char*)symfile->raw_contents;
63 ptr += sizeof(guint64);
64 if (magic != MONO_SYMBOL_FILE_MAGIC) {
66 g_warning ("Symbol file %s is not a mono symbol file", symfile->filename);
71 ptr += sizeof(guint32);
73 ptr += sizeof(guint32);
76 * 50.0 is the frozen version for Mono 2.0.
78 * Nobody except me (Martin) is allowed to check the minor version.
80 if (major != MONO_SYMBOL_FILE_MAJOR_VERSION) {
82 g_warning ("Symbol file %s has incorrect version (expected %d.%d, got %d)",
83 symfile->filename, MONO_SYMBOL_FILE_MAJOR_VERSION,
84 MONO_SYMBOL_FILE_MINOR_VERSION, major);
88 guid = mono_guid_to_string ((const guint8 *) ptr);
91 if (strcmp (handle->image->guid, guid)) {
93 g_warning ("Symbol file %s doesn't match image %s", symfile->filename,
100 symfile->major_version = major;
101 symfile->minor_version = minor;
103 symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
105 symfile->method_hash = g_hash_table_new_full (
106 g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) free_method_info);
113 mono_debug_open_mono_symbols (MonoDebugHandle *handle, const guint8 *raw_contents,
114 int size, gboolean in_the_debugger)
116 MonoSymbolFile *symfile;
118 mono_debugger_lock ();
119 symfile = g_new0 (MonoSymbolFile, 1);
121 if (raw_contents != NULL) {
123 symfile->raw_contents_size = size;
124 symfile->raw_contents = p = g_malloc (size);
125 memcpy (p, raw_contents, size);
126 symfile->filename = g_strdup_printf ("LoadedFromMemory");
129 symfile->filename = g_strdup_printf ("%s.mdb", mono_image_get_filename (handle->image));
131 if ((f = mono_file_map_open (symfile->filename))) {
132 symfile->raw_contents_size = mono_file_map_size (f);
133 if (symfile->raw_contents_size == 0) {
134 if (!in_the_debugger)
135 g_warning ("stat of %s failed: %s",
136 symfile->filename, g_strerror (errno));
138 symfile->raw_contents = mono_file_map (symfile->raw_contents_size, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (f), 0, &symfile->raw_contents_handle);
141 mono_file_map_close (f);
145 if (load_symfile (handle, symfile, in_the_debugger)) {
146 mono_debugger_unlock ();
148 } else if (!in_the_debugger) {
149 mono_debug_close_mono_symbol_file (symfile);
150 mono_debugger_unlock ();
154 mono_debugger_unlock ();
159 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
164 mono_debugger_lock ();
165 if (symfile->method_hash)
166 g_hash_table_destroy (symfile->method_hash);
168 if (symfile->raw_contents)
169 mono_file_unmap ((gpointer) symfile->raw_contents, symfile->raw_contents_handle);
171 if (symfile->filename)
172 g_free (symfile->filename);
174 mono_debugger_unlock ();
178 read_leb128 (const guint8 *ptr, const guint8 **rptr)
187 ret = ret | ((b & 0x7f) << shift);
189 } while ((b & 0x80) == 0x80);
198 read_string (const guint8 *ptr)
200 int len = read_leb128 (ptr, &ptr);
201 return g_filename_from_utf8 ((const char *) ptr, len, NULL, NULL, NULL);
205 MonoSymbolFile *symfile;
206 int line_base, line_range, max_address_incr;
208 guint32 last_line, last_file, last_offset;
209 guint32 line, file, offset;
213 check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **location)
215 gchar *source_file = NULL;
217 if ((offset > 0) && (stm->offset <= offset)) {
218 stm->last_offset = stm->offset;
219 stm->last_file = stm->file;
220 if (stm->line != 0xfeefee)
221 stm->last_line = stm->line;
225 if (stm->last_file) {
226 int offset = read32(&(stm->symfile->offset_table->_source_table_offset)) +
227 (stm->last_file - 1) * sizeof (MonoSymbolFileSourceEntry);
228 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
229 (stm->symfile->raw_contents + offset);
231 source_file = read_string (stm->symfile->raw_contents + read32(&(se->_data_offset)));
234 if (stm->last_line == 0) {
236 * The IL offset is less than the first IL offset which has a corresponding
243 *location = g_new0 (MonoDebugSourceLocation, 1);
244 (*location)->source_file = source_file;
245 (*location)->row = stm->last_line;
246 (*location)->il_offset = stm->last_offset;
251 * mono_debug_symfile_lookup_location:
252 * @minfo: A `MonoDebugMethodInfo' which can be retrieved by
253 * mono_debug_lookup_method().
254 * @offset: IL offset within the corresponding method's CIL code.
256 * This function is similar to mono_debug_lookup_location(), but we
257 * already looked up the method and also already did the
258 * `native address -> IL offset' mapping.
260 MonoDebugSourceLocation *
261 mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset)
263 MonoDebugSourceLocation *location = NULL;
264 MonoSymbolFile *symfile;
265 const unsigned char *ptr;
266 StatementMachine stm;
268 #define DW_LNS_copy 1
269 #define DW_LNS_advance_pc 2
270 #define DW_LNS_advance_line 3
271 #define DW_LNS_set_file 4
272 #define DW_LNS_const_add_pc 8
274 #define DW_LNE_end_sequence 1
275 #define DW_LNE_MONO_negate_is_hidden 0x40
277 if ((symfile = minfo->handle->symfile) == NULL)
280 stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base);
281 stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range);
282 stm.opcode_base = (guint8) read32 (&symfile->offset_table->_line_number_table_opcode_base);
283 stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;
285 mono_debugger_lock ();
287 ptr = symfile->raw_contents + minfo->lnt_offset;
289 stm.symfile = symfile;
290 stm.offset = stm.last_offset = 0;
297 guint8 opcode = *ptr++;
300 guint8 size = *ptr++;
301 const unsigned char *end_ptr = ptr + size;
305 if (opcode == DW_LNE_end_sequence) {
306 if (check_line (&stm, -1, &location))
309 } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
312 g_warning ("Unknown extended opcode %x in LNT", opcode);
317 } else if (opcode < stm.opcode_base) {
320 if (check_line (&stm, offset, &location))
323 case DW_LNS_advance_pc:
324 stm.offset += read_leb128 (ptr, &ptr);
326 case DW_LNS_advance_line:
327 stm.line += read_leb128 (ptr, &ptr);
329 case DW_LNS_set_file:
330 stm.file = read_leb128 (ptr, &ptr);
332 case DW_LNS_const_add_pc:
333 stm.offset += stm.max_address_incr;
336 g_warning ("Unknown standard opcode %x in LNT", opcode);
340 opcode -= stm.opcode_base;
342 stm.offset += opcode / stm.line_range;
343 stm.line += stm.line_base + (opcode % stm.line_range);
345 if (check_line (&stm, offset, &location))
351 mono_debugger_unlock ();
355 mono_debugger_unlock ();
360 _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offset)
364 if (!jit || !jit->line_numbers)
367 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
368 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
370 if (lne.il_offset < 0)
372 if (lne.il_offset <= il_offset)
373 return lne.native_offset;
380 compare_method (const void *key, const void *object)
382 guint32 token = GPOINTER_TO_UINT (key);
383 MonoSymbolFileMethodEntry *me = (MonoSymbolFileMethodEntry*)object;
385 return token - read32(&(me->_token));
388 MonoDebugMethodInfo *
389 mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
391 MonoSymbolFileMethodEntry *first_ie, *ie;
392 MonoDebugMethodInfo *minfo;
393 MonoSymbolFile *symfile = handle->symfile;
395 if (!symfile->method_hash)
398 if (handle->image != mono_class_get_image (mono_method_get_class (method)))
401 mono_debugger_lock ();
403 minfo = g_hash_table_lookup (symfile->method_hash, method);
405 mono_debugger_unlock ();
409 first_ie = (MonoSymbolFileMethodEntry *)
410 (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset)));
412 ie = bsearch (GUINT_TO_POINTER (mono_method_get_token (method)), first_ie,
413 read32(&(symfile->offset_table->_method_count)),
414 sizeof (MonoSymbolFileMethodEntry), compare_method);
417 mono_debugger_unlock ();
421 minfo = g_new0 (MonoDebugMethodInfo, 1);
422 minfo->index = (ie - first_ie) + 1;
423 minfo->method = method;
424 minfo->handle = handle;
426 minfo->data_offset = read32 (&(ie->_data_offset));
427 minfo->lnt_offset = read32 (&(ie->_line_number_table));
429 g_hash_table_insert (symfile->method_hash, method, minfo);
431 mono_debugger_unlock ();
436 * mono_debug_symfile_lookup_locals:
438 * Return information about the local variables of MINFO from the symbol file.
439 * NAMES and INDEXES are set to g_malloc-ed arrays containing the local names and
441 * Returns: the number of elements placed into the arrays, or -1 if there is no
442 * local variable info.
445 mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo, char ***names, int **indexes)
447 MonoSymbolFile *symfile = minfo->handle->symfile;
449 int i, len, compile_unit_index, locals_offset, num_locals, index, block_index;
457 p = symfile->raw_contents + minfo->data_offset;
459 compile_unit_index = read_leb128 (p, &p);
460 locals_offset = read_leb128 (p, &p);
462 p = symfile->raw_contents + locals_offset;
463 num_locals = read_leb128 (p, &p);
465 *names = g_new0 (char*, num_locals);
466 *indexes = g_new0 (int, num_locals);
468 for (i = 0; i < num_locals; ++i) {
469 index = read_leb128 (p, &p);
470 (*indexes) [i] = index;
471 len = read_leb128 (p, &p);
472 (*names) [i] = g_malloc (len + 1);
473 memcpy ((*names) [i], p, len);
474 (*names) [i][len] = '\0';
476 block_index = read_leb128 (p, &p);