7 #ifdef HAVE_SYS_PARAM_H
11 #include <mono/metadata/metadata.h>
12 #include <mono/metadata/tabledefs.h>
13 #include <mono/metadata/rawbuffer.h>
14 #include <mono/metadata/tokentype.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/exception.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/metadata/mono-debug.h>
19 #include <mono/metadata/debug-mono-symfile.h>
20 #include <mono/metadata/mono-debug-debugger.h>
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/class-internals.h>
30 #define RANGE_TABLE_CHUNK_SIZE 256
31 #define CLASS_TABLE_CHUNK_SIZE 256
32 #define TYPE_TABLE_PTR_CHUNK_SIZE 256
33 #define TYPE_TABLE_CHUNK_SIZE 65536
36 free_method_info (MonoDebugMethodInfo *minfo)
42 get_class_name (MonoClass *klass)
44 MonoClass *nested_in = mono_class_get_nesting_type (klass);
45 const char *name_space;
47 gchar *parent_name = get_class_name (nested_in);
48 gchar *name = g_strdup_printf ("%s.%s", parent_name, mono_class_get_name (klass));
53 name_space = mono_class_get_namespace (klass);
54 return g_strdup_printf ("%s%s%s", name_space,
55 name_space [0] ? "." : "", mono_class_get_name (klass));
59 load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_debugger)
61 const char *ptr, *start;
66 ptr = start = (const char*)symfile->raw_contents;
71 ptr += sizeof(guint64);
72 if (magic != MONO_SYMBOL_FILE_MAGIC) {
74 g_warning ("Symbol file %s is not a mono symbol file", symfile->filename);
79 ptr += sizeof(guint32);
81 ptr += sizeof(guint32);
83 if (major != MONO_SYMBOL_FILE_MAJOR_VERSION) {
85 g_warning ("Symbol file %s has incorrect version (expected %d, got %d)",
86 symfile->filename, MONO_SYMBOL_FILE_MAJOR_VERSION, major);
90 if (minor != MONO_SYMBOL_FILE_MINOR_VERSION) {
92 g_warning ("Symbol file %s has incorrect version "
93 "(expected %d.%d, got %d.%d)", symfile->filename,
94 MONO_SYMBOL_FILE_MAJOR_VERSION, MONO_SYMBOL_FILE_MINOR_VERSION,
99 guid = mono_guid_to_string ((const guint8 *) ptr);
102 if (strcmp (handle->image->guid, guid)) {
103 if (!in_the_debugger)
104 g_warning ("Symbol file %s doesn't match image %s", symfile->filename,
111 symfile->major_version = major;
112 symfile->minor_version = minor;
114 symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
116 symfile->method_hash = g_hash_table_new_full (
117 g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) free_method_info);
124 mono_debug_open_mono_symbols (MonoDebugHandle *handle, const guint8 *raw_contents,
125 int size, gboolean in_the_debugger)
127 MonoSymbolFile *symfile;
130 mono_debugger_lock ();
131 symfile = g_new0 (MonoSymbolFile, 1);
133 if (raw_contents != NULL) {
135 symfile->raw_contents_size = size;
136 symfile->raw_contents = p = g_malloc (size);
137 memcpy (p, raw_contents, size);
138 symfile->filename = g_strdup_printf ("LoadedFromMemory");
140 symfile->filename = g_strdup_printf ("%s.mdb", mono_image_get_filename (handle->image));
142 if ((f = fopen (symfile->filename, "rb"))) {
143 struct stat stat_buf;
145 if (fstat (fileno (f), &stat_buf) < 0) {
146 if (!in_the_debugger)
147 g_warning ("stat of %s failed: %s",
148 symfile->filename, g_strerror (errno));
150 symfile->raw_contents_size = stat_buf.st_size;
151 symfile->raw_contents = mono_raw_buffer_load (fileno (f), FALSE, 0, stat_buf.st_size);
158 if (load_symfile (handle, symfile, in_the_debugger)) {
159 mono_debugger_unlock ();
161 } else if (!in_the_debugger) {
162 mono_debug_close_mono_symbol_file (symfile);
163 mono_debugger_unlock ();
167 mono_debugger_unlock ();
172 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
177 mono_debugger_lock ();
178 if (symfile->method_hash)
179 g_hash_table_destroy (symfile->method_hash);
181 if (symfile->raw_contents)
182 mono_raw_buffer_free ((gpointer) symfile->raw_contents);
184 if (symfile->filename)
185 g_free (symfile->filename);
187 mono_debugger_unlock ();
191 read_leb128 (const guint8 *ptr, const guint8 **rptr)
200 ret = ret | ((b & 0x7f) << shift);
202 } while ((b & 0x80) == 0x80);
211 read_string (const guint8 *ptr)
213 int len = read_leb128 (ptr, &ptr);
214 return g_filename_from_utf8 ((const char *) ptr, len, NULL, NULL, NULL);
218 MonoSymbolFile *symfile;
219 int line_base, line_range, max_address_incr;
221 guint32 last_line, last_file, last_offset;
222 guint32 line, file, offset;
226 check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **location)
228 gchar *source_file = NULL;
230 if ((offset > 0) && (stm->offset <= offset)) {
231 stm->last_offset = stm->offset;
232 stm->last_file = stm->file;
233 if (stm->line != 0xfeefee)
234 stm->last_line = stm->line;
238 if (stm->last_file) {
239 int offset = read32(&(stm->symfile->offset_table->_source_table_offset)) +
240 (stm->last_file - 1) * sizeof (MonoSymbolFileSourceEntry);
241 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
242 (stm->symfile->raw_contents + offset);
244 source_file = read_string (stm->symfile->raw_contents + read32(&(se->_data_offset)));
247 *location = g_new0 (MonoDebugSourceLocation, 1);
248 (*location)->source_file = source_file;
249 (*location)->row = stm->last_line;
250 (*location)->il_offset = stm->last_offset;
255 * mono_debug_symfile_lookup_location:
256 * @minfo: A `MonoDebugMethodInfo' which can be retrieved by
257 * mono_debug_lookup_method().
258 * @offset: IL offset within the corresponding method's CIL code.
260 * This function is similar to mono_debug_lookup_location(), but we
261 * already looked up the method and also already did the
262 * `native address -> IL offset' mapping.
264 MonoDebugSourceLocation *
265 mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset)
267 MonoDebugSourceLocation *location = NULL;
268 MonoSymbolFile *symfile;
269 const unsigned char *ptr;
270 StatementMachine stm;
272 #define DW_LNS_copy 1
273 #define DW_LNS_advance_pc 2
274 #define DW_LNS_advance_line 3
275 #define DW_LNS_set_file 4
276 #define DW_LNS_const_add_pc 8
278 #define DW_LNE_end_sequence 1
279 #define DW_LNE_MONO_negate_is_hidden 0x40
281 if ((symfile = minfo->handle->symfile) == NULL)
284 stm.line_base = symfile->offset_table->_line_number_table_line_base;
285 stm.line_range = symfile->offset_table->_line_number_table_line_range;
286 stm.opcode_base = (guint8) symfile->offset_table->_line_number_table_opcode_base;
287 stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;
289 mono_debugger_lock ();
291 ptr = symfile->raw_contents + minfo->lnt_offset;
293 stm.symfile = symfile;
294 stm.offset = stm.last_offset = 0;
295 stm.file = stm.last_file = 1;
296 stm.line = stm.last_line = 1;
299 guint8 opcode = *ptr++;
302 guint8 size = *ptr++;
303 const unsigned char *end_ptr = ptr + size;
307 if (opcode == DW_LNE_end_sequence) {
308 if (check_line (&stm, -1, &location))
311 } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
314 g_warning ("Unknown extended opcode %x in LNT", opcode);
319 } else if (opcode < stm.opcode_base) {
322 if (check_line (&stm, offset, &location))
325 case DW_LNS_advance_pc:
326 stm.offset += read_leb128 (ptr, &ptr);
328 case DW_LNS_advance_line:
329 stm.line += read_leb128 (ptr, &ptr);
331 case DW_LNS_set_file:
332 stm.file = read_leb128 (ptr, &ptr);
334 case DW_LNS_const_add_pc:
335 stm.offset += stm.max_address_incr;
338 g_warning ("Unknown standard opcode %x in LNT", opcode);
342 opcode -= stm.opcode_base;
344 stm.offset += opcode / stm.line_range;
345 stm.line += stm.line_base + (opcode % stm.line_range);
347 if (check_line (&stm, offset, &location))
353 mono_debugger_unlock ();
357 mono_debugger_unlock ();
362 _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offset)
366 if (!jit || !jit->line_numbers)
369 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
370 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
372 if (lne.il_offset < 0)
374 if (lne.il_offset <= il_offset)
375 return lne.native_offset;
382 compare_method (const void *key, const void *object)
384 guint32 token = GPOINTER_TO_UINT (key);
385 MonoSymbolFileMethodEntry *me = (MonoSymbolFileMethodEntry*)object;
387 return token - read32(&(me->_token));
390 MonoDebugMethodInfo *
391 mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
393 MonoSymbolFileMethodEntry *first_ie, *ie;
394 MonoDebugMethodInfo *minfo;
395 MonoSymbolFile *symfile = handle->symfile;
397 if (!symfile->method_hash)
400 if (handle->image != mono_class_get_image (mono_method_get_class (method)))
403 mono_debugger_lock ();
404 first_ie = (MonoSymbolFileMethodEntry *)
405 (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset)));
407 ie = bsearch (GUINT_TO_POINTER (mono_method_get_token (method)), first_ie,
408 read32(&(symfile->offset_table->_method_count)),
409 sizeof (MonoSymbolFileMethodEntry), compare_method);
412 mono_debugger_unlock ();
416 minfo = g_new0 (MonoDebugMethodInfo, 1);
417 minfo->index = (ie - first_ie) + 1;
418 minfo->method = method;
419 minfo->handle = handle;
421 minfo->data_offset = read32 (&(ie->_data_offset));
422 minfo->lnt_offset = read32 (&(ie->_line_number_table));
424 g_hash_table_insert (symfile->method_hash, method, minfo);
426 mono_debugger_unlock ();