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 load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_debugger)
44 const char *ptr, *start;
49 ptr = start = (const char*)symfile->raw_contents;
54 ptr += sizeof(guint64);
55 if (magic != MONO_SYMBOL_FILE_MAGIC) {
57 g_warning ("Symbol file %s is not a mono symbol file", symfile->filename);
62 ptr += sizeof(guint32);
64 ptr += sizeof(guint32);
67 * 50.0 is the frozen version for Mono 2.0.
69 * Nobody except me (Martin) is allowed to check the minor version.
71 if (major != MONO_SYMBOL_FILE_MAJOR_VERSION) {
73 g_warning ("Symbol file %s has incorrect version (expected %d.%d, got %d)",
74 symfile->filename, MONO_SYMBOL_FILE_MAJOR_VERSION,
75 MONO_SYMBOL_FILE_MINOR_VERSION, major);
79 guid = mono_guid_to_string ((const guint8 *) ptr);
82 if (strcmp (handle->image->guid, guid)) {
84 g_warning ("Symbol file %s doesn't match image %s", symfile->filename,
91 symfile->major_version = major;
92 symfile->minor_version = minor;
94 symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
96 symfile->method_hash = g_hash_table_new_full (
97 g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) free_method_info);
104 mono_debug_open_mono_symbols (MonoDebugHandle *handle, const guint8 *raw_contents,
105 int size, gboolean in_the_debugger)
107 MonoSymbolFile *symfile;
110 mono_debugger_lock ();
111 symfile = g_new0 (MonoSymbolFile, 1);
113 if (raw_contents != NULL) {
115 symfile->raw_contents_size = size;
116 symfile->raw_contents = p = g_malloc (size);
117 memcpy (p, raw_contents, size);
118 symfile->filename = g_strdup_printf ("LoadedFromMemory");
120 symfile->filename = g_strdup_printf ("%s.mdb", mono_image_get_filename (handle->image));
122 if ((f = fopen (symfile->filename, "rb"))) {
123 struct stat stat_buf;
125 if (fstat (fileno (f), &stat_buf) < 0) {
126 if (!in_the_debugger)
127 g_warning ("stat of %s failed: %s",
128 symfile->filename, g_strerror (errno));
130 symfile->raw_contents_size = stat_buf.st_size;
131 symfile->raw_contents = mono_raw_buffer_load (fileno (f), FALSE, 0, stat_buf.st_size);
138 if (load_symfile (handle, symfile, in_the_debugger)) {
139 mono_debugger_unlock ();
141 } else if (!in_the_debugger) {
142 mono_debug_close_mono_symbol_file (symfile);
143 mono_debugger_unlock ();
147 mono_debugger_unlock ();
152 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
157 mono_debugger_lock ();
158 if (symfile->method_hash)
159 g_hash_table_destroy (symfile->method_hash);
161 if (symfile->raw_contents)
162 mono_raw_buffer_free ((gpointer) symfile->raw_contents);
164 if (symfile->filename)
165 g_free (symfile->filename);
167 mono_debugger_unlock ();
171 read_leb128 (const guint8 *ptr, const guint8 **rptr)
180 ret = ret | ((b & 0x7f) << shift);
182 } while ((b & 0x80) == 0x80);
191 read_string (const guint8 *ptr)
193 int len = read_leb128 (ptr, &ptr);
194 return g_filename_from_utf8 ((const char *) ptr, len, NULL, NULL, NULL);
198 MonoSymbolFile *symfile;
199 int line_base, line_range, max_address_incr;
201 guint32 last_line, last_file, last_offset;
202 guint32 line, file, offset;
206 check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **location)
208 gchar *source_file = NULL;
210 if ((offset > 0) && (stm->offset <= offset)) {
211 stm->last_offset = stm->offset;
212 stm->last_file = stm->file;
213 if (stm->line != 0xfeefee)
214 stm->last_line = stm->line;
218 if (stm->last_file) {
219 int offset = read32(&(stm->symfile->offset_table->_source_table_offset)) +
220 (stm->last_file - 1) * sizeof (MonoSymbolFileSourceEntry);
221 MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *)
222 (stm->symfile->raw_contents + offset);
224 source_file = read_string (stm->symfile->raw_contents + read32(&(se->_data_offset)));
227 *location = g_new0 (MonoDebugSourceLocation, 1);
228 (*location)->source_file = source_file;
229 (*location)->row = stm->last_line;
230 (*location)->il_offset = stm->last_offset;
235 * mono_debug_symfile_lookup_location:
236 * @minfo: A `MonoDebugMethodInfo' which can be retrieved by
237 * mono_debug_lookup_method().
238 * @offset: IL offset within the corresponding method's CIL code.
240 * This function is similar to mono_debug_lookup_location(), but we
241 * already looked up the method and also already did the
242 * `native address -> IL offset' mapping.
244 MonoDebugSourceLocation *
245 mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset)
247 MonoDebugSourceLocation *location = NULL;
248 MonoSymbolFile *symfile;
249 const unsigned char *ptr;
250 StatementMachine stm;
252 #define DW_LNS_copy 1
253 #define DW_LNS_advance_pc 2
254 #define DW_LNS_advance_line 3
255 #define DW_LNS_set_file 4
256 #define DW_LNS_const_add_pc 8
258 #define DW_LNE_end_sequence 1
259 #define DW_LNE_MONO_negate_is_hidden 0x40
261 if ((symfile = minfo->handle->symfile) == NULL)
264 stm.line_base = symfile->offset_table->_line_number_table_line_base;
265 stm.line_range = symfile->offset_table->_line_number_table_line_range;
266 stm.opcode_base = (guint8) symfile->offset_table->_line_number_table_opcode_base;
267 stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range;
269 mono_debugger_lock ();
271 ptr = symfile->raw_contents + minfo->lnt_offset;
273 stm.symfile = symfile;
274 stm.offset = stm.last_offset = 0;
275 stm.file = stm.last_file = 1;
276 stm.line = stm.last_line = 1;
279 guint8 opcode = *ptr++;
282 guint8 size = *ptr++;
283 const unsigned char *end_ptr = ptr + size;
287 if (opcode == DW_LNE_end_sequence) {
288 if (check_line (&stm, -1, &location))
291 } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
294 g_warning ("Unknown extended opcode %x in LNT", opcode);
299 } else if (opcode < stm.opcode_base) {
302 if (check_line (&stm, offset, &location))
305 case DW_LNS_advance_pc:
306 stm.offset += read_leb128 (ptr, &ptr);
308 case DW_LNS_advance_line:
309 stm.line += read_leb128 (ptr, &ptr);
311 case DW_LNS_set_file:
312 stm.file = read_leb128 (ptr, &ptr);
314 case DW_LNS_const_add_pc:
315 stm.offset += stm.max_address_incr;
318 g_warning ("Unknown standard opcode %x in LNT", opcode);
322 opcode -= stm.opcode_base;
324 stm.offset += opcode / stm.line_range;
325 stm.line += stm.line_base + (opcode % stm.line_range);
327 if (check_line (&stm, offset, &location))
333 mono_debugger_unlock ();
337 mono_debugger_unlock ();
342 _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offset)
346 if (!jit || !jit->line_numbers)
349 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
350 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
352 if (lne.il_offset < 0)
354 if (lne.il_offset <= il_offset)
355 return lne.native_offset;
362 compare_method (const void *key, const void *object)
364 guint32 token = GPOINTER_TO_UINT (key);
365 MonoSymbolFileMethodEntry *me = (MonoSymbolFileMethodEntry*)object;
367 return token - read32(&(me->_token));
370 MonoDebugMethodInfo *
371 mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
373 MonoSymbolFileMethodEntry *first_ie, *ie;
374 MonoDebugMethodInfo *minfo;
375 MonoSymbolFile *symfile = handle->symfile;
377 if (!symfile->method_hash)
380 if (handle->image != mono_class_get_image (mono_method_get_class (method)))
383 mono_debugger_lock ();
384 first_ie = (MonoSymbolFileMethodEntry *)
385 (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset)));
387 ie = bsearch (GUINT_TO_POINTER (mono_method_get_token (method)), first_ie,
388 read32(&(symfile->offset_table->_method_count)),
389 sizeof (MonoSymbolFileMethodEntry), compare_method);
392 mono_debugger_unlock ();
396 minfo = g_new0 (MonoDebugMethodInfo, 1);
397 minfo->index = (ie - first_ie) + 1;
398 minfo->method = method;
399 minfo->handle = handle;
401 minfo->data_offset = read32 (&(ie->_data_offset));
402 minfo->lnt_offset = read32 (&(ie->_line_number_table));
404 g_hash_table_insert (symfile->method_hash, method, minfo);
406 mono_debugger_unlock ();