3 #include <mono/metadata/class.h>
4 #include <mono/metadata/tabledefs.h>
5 #include <mono/metadata/tokentype.h>
6 #include <mono/jit/codegen.h>
7 #include <mono/jit/debug.h>
9 #include "debug-private.h"
12 mono_debug_open_file (const char *filename, MonoDebugFormat format)
14 MonoDebugHandle *debug;
16 debug = g_new0 (MonoDebugHandle, 1);
17 debug->name = g_strdup (filename);
18 debug->default_format = format;
23 debug_load_method_lines (AssemblyDebugInfo* info)
28 char *name = g_strdup_printf ("%s.il", info->name);
31 /* use an env var with directories for searching. */
32 if (!(f = fopen (name, "r"))) {
33 g_warning ("cannot open IL assembly file %s", name);
38 info->total_lines = 100;
39 info->moffsets = g_malloc (info->total_lines * sizeof (int));
43 while (fgets (buf, sizeof (buf), f)) {
46 info->moffsets [i++] = offset;
47 if (i + 2 >= info->total_lines) {
48 info->total_lines += 100;
49 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
50 g_assert (info->moffsets);
53 if (!sscanf (buf, " // method line %d", &mnum))
58 if (mnum >= info->nmethods)
61 while (fgets (buf, sizeof (buf), f)) {
65 if (i + 2 >= info->total_lines) {
66 info->total_lines += 100;
67 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
68 g_assert (info->moffsets);
71 if (strstr (buf, "}")) {
76 if (sscanf (buf, " IL_%x:", &newoffset)) {
82 info->moffsets [i] = offset;
84 /* g_print ("method %d found at %d\n", mnum, pos); */
85 info->mlines [mnum] = pos;
91 record_line_number (DebugMethodInfo *minfo, gpointer address, guint32 line, int is_basic_block)
93 DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);
95 lni->address = address;
97 lni->is_basic_block = is_basic_block;
100 g_ptr_array_add (minfo->line_numbers, lni);
104 record_il_offset (GPtrArray *array, guint32 offset, guint32 address)
106 MonoDebugILOffsetInfo *info = g_new0 (MonoDebugILOffsetInfo, 1);
108 info->offset = offset;
109 info->address = address;
111 g_ptr_array_add (array, info);
115 debug_generate_method_lines (AssemblyDebugInfo *info, DebugMethodInfo *minfo, MonoFlowGraph* cfg)
117 guint32 st_address, st_line;
118 GPtrArray *il_offsets;
121 il_offsets = g_ptr_array_new ();
122 minfo->line_numbers = g_ptr_array_new ();
124 st_line = minfo->first_line;
125 st_address = minfo->method_info.prologue_end;
127 /* record_line_number takes absolute memory addresses. */
128 record_line_number (minfo, minfo->method_info.code_start, minfo->start_line, FALSE);
129 /* record_il_offsets uses offsets relative to minfo->method_info.code_start. */
130 record_il_offset (il_offsets, 0, st_address);
132 /* This is the first actual code line of the method. */
133 record_line_number (minfo, minfo->method_info.code_start + st_address, st_line, TRUE);
135 /* start lines of basic blocks */
136 for (i = 0; i < cfg->block_count; ++i) {
139 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
140 MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
141 gint32 line_inc = 0, addr_inc;
144 st_line = minfo->first_line;
145 st_address = t->addr - 1;
147 record_line_number (minfo, cfg->start + st_address, st_line, TRUE);
150 addr_inc = t->addr - st_address - 1;
151 st_address += addr_inc;
153 if (t->cli_addr != -1)
154 record_il_offset (il_offsets, t->cli_addr, st_address);
160 if (t->cli_addr != -1) {
161 int *lines = info->moffsets + st_line;
164 while ((*k != -1) && (*k < t->cli_addr))
167 line_inc = k - lines;
172 record_line_number (minfo, minfo->method_info.code_start + st_address,
177 minfo->method_info.num_il_offsets = il_offsets->len;
178 minfo->method_info.il_offsets = g_new0 (MonoDebugILOffsetInfo, il_offsets->len);
179 for (i = 0; i < il_offsets->len; i++) {
180 MonoDebugILOffsetInfo *il = (MonoDebugILOffsetInfo *) g_ptr_array_index (il_offsets, i);
182 minfo->method_info.il_offsets [i] = *il;
185 g_ptr_array_free (il_offsets, TRUE);
189 free_method_info (DebugMethodInfo *minfo)
191 if (minfo->line_numbers)
192 g_ptr_array_free (minfo->line_numbers, TRUE);
193 g_free (minfo->method_info.params);
194 g_free (minfo->method_info.locals);
198 static AssemblyDebugInfo*
199 mono_debug_open_assembly (MonoDebugHandle* handle, MonoImage *image)
202 AssemblyDebugInfo* info;
204 for (tmp = handle->info; tmp; tmp = tmp->next) {
205 info = (AssemblyDebugInfo*)tmp->data;
206 if (strcmp (info->name, image->assembly_name) == 0)
209 info = g_new0 (AssemblyDebugInfo, 1);
210 info->format = handle->default_format;
211 switch (handle->default_format) {
212 case MONO_DEBUG_FORMAT_STABS:
213 info->filename = g_strdup_printf ("%s-stabs.s", image->assembly_name);
215 case MONO_DEBUG_FORMAT_DWARF2:
216 info->filename = g_strdup_printf ("%s-dwarf.s", image->assembly_name);
218 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
219 info->filename = g_strdup_printf ("%s-debug.o", image->assembly_name);
221 g_message (G_STRLOC ": %s - %s", image->assembly_name, image->name);
223 /* Fall back to dwarf if we can't find the symbol file. */
224 if (!g_file_test (info->filename, G_FILE_TEST_EXISTS)) {
225 gchar *fname = g_strdup_printf ("%s-dwarf.s", image->assembly_name);
227 if (g_file_test (fname, G_FILE_TEST_EXISTS)) {
228 g_warning ("Can't open symbol file `%s', falling back to DWARF 2.",
230 g_free (info->filename);
231 info->filename = fname;
232 info->format = MONO_DEBUG_FORMAT_DWARF2;
240 info->image->ref_count++;
241 info->name = g_strdup (image->assembly_name);
242 info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
243 NULL, (GDestroyNotify) free_method_info);
244 info->source_files = g_ptr_array_new ();
245 info->type_hash = g_hash_table_new (NULL, NULL);
247 g_ptr_array_add (info->source_files, g_strdup_printf ("%s.il", image->assembly_name));
248 info->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
250 mono_debug_get_type (info, mono_defaults.void_class);
251 mono_debug_get_type (info, mono_defaults.object_class);
252 mono_debug_get_type (info, mono_defaults.void_class);
253 mono_debug_get_type (info, mono_defaults.boolean_class);
254 mono_debug_get_type (info, mono_defaults.char_class);
255 mono_debug_get_type (info, mono_defaults.sbyte_class);
256 mono_debug_get_type (info, mono_defaults.byte_class);
257 mono_debug_get_type (info, mono_defaults.int16_class);
258 mono_debug_get_type (info, mono_defaults.uint16_class);
259 mono_debug_get_type (info, mono_defaults.int32_class);
260 mono_debug_get_type (info, mono_defaults.uint32_class);
261 mono_debug_get_type (info, mono_defaults.int_class);
262 mono_debug_get_type (info, mono_defaults.uint_class);
263 mono_debug_get_type (info, mono_defaults.int64_class);
264 mono_debug_get_type (info, mono_defaults.uint64_class);
265 mono_debug_get_type (info, mono_defaults.single_class);
266 mono_debug_get_type (info, mono_defaults.double_class);
267 mono_debug_get_type (info, mono_defaults.string_class);
269 switch (info->format) {
270 case MONO_DEBUG_FORMAT_STABS:
271 mono_debug_open_assembly_stabs (info);
273 case MONO_DEBUG_FORMAT_DWARF2:
274 mono_debug_open_assembly_dwarf2 (info);
276 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
277 mono_debug_open_assembly_dwarf2_plus (info);
281 info->next_idx = 100;
282 handle->info = g_list_prepend (handle->info, info);
284 info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
285 info->mlines = g_new0 (int, info->nmethods);
287 if (info->format != MONO_DEBUG_FORMAT_DWARF2_PLUS)
288 debug_load_method_lines (info);
294 mono_debug_make_symbols (void)
297 AssemblyDebugInfo* info;
299 if (!mono_debug_handle)
302 for (tmp = mono_debug_handle->info; tmp; tmp = tmp->next) {
303 info = (AssemblyDebugInfo*)tmp->data;
305 switch (info->format) {
306 case MONO_DEBUG_FORMAT_STABS:
307 mono_debug_write_assembly_stabs (info);
309 case MONO_DEBUG_FORMAT_DWARF2:
310 mono_debug_write_assembly_dwarf2 (info);
312 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
313 mono_debug_write_assembly_dwarf2_plus (info);
320 mono_debug_close_assembly (AssemblyDebugInfo* info)
322 g_free (info->mlines);
323 g_free (info->moffsets);
325 g_free (info->filename);
326 g_ptr_array_free (info->source_files, TRUE);
327 g_hash_table_destroy (info->type_hash);
328 g_hash_table_destroy (info->methods);
329 g_free (info->producer_name);
334 mono_debug_close (MonoDebugHandle* debug)
337 AssemblyDebugInfo* info;
339 mono_debug_make_symbols ();
341 for (tmp = debug->info; tmp; tmp = tmp->next) {
342 info = (AssemblyDebugInfo*)tmp->data;
344 switch (info->format) {
345 case MONO_DEBUG_FORMAT_STABS:
346 mono_debug_close_assembly_stabs (info);
348 case MONO_DEBUG_FORMAT_DWARF2:
349 mono_debug_close_assembly_dwarf2 (info);
351 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
352 mono_debug_close_assembly_dwarf2_plus (info);
356 mono_debug_close_assembly (info);
359 g_free (debug->name);
364 mono_debug_get_type (AssemblyDebugInfo* info, MonoClass *klass)
368 mono_class_init (klass);
370 index = GPOINTER_TO_INT (g_hash_table_lookup (info->type_hash, klass));
374 index = ++info->next_klass_idx;
375 g_hash_table_insert (info->type_hash, klass, GINT_TO_POINTER (index));
380 switch (klass->byval_arg.type) {
381 case MONO_TYPE_CLASS:
383 mono_debug_get_type (info, klass->parent);
385 for (i = 0; i < klass->method.count; i++) {
386 MonoMethod *method = klass->methods [i];
387 MonoType *ret_type = NULL;
390 if (method->signature->ret->type != MONO_TYPE_VOID)
391 ret_type = method->signature->ret;
394 MonoClass *ret_klass = mono_class_from_mono_type (ret_type);
395 mono_debug_get_type (info, ret_klass);
398 for (j = 0; j < method->signature->param_count; j++) {
399 MonoType *sub_type = method->signature->params [j];
400 MonoClass *sub_klass = mono_class_from_mono_type (sub_type);
401 mono_debug_get_type (info, sub_klass);
405 case MONO_TYPE_VALUETYPE:
406 for (i = 0; i < klass->field.count; i++) {
407 MonoClass *subclass = mono_class_from_mono_type (klass->fields [i].type);
408 mono_debug_get_type (info, subclass);
411 case MONO_TYPE_ARRAY:
412 case MONO_TYPE_SZARRAY:
413 mono_debug_get_type (info, klass->element_class);
423 mono_debug_add_type (MonoDebugHandle* debug, MonoClass *klass)
425 AssemblyDebugInfo* info = mono_debug_open_assembly (debug, klass->image);
427 mono_debug_get_type (info, klass);
431 mono_debug_add_method (MonoDebugHandle* debug, MonoFlowGraph *cfg)
433 MonoMethod *method = cfg->method;
434 MonoClass *klass = method->klass;
435 AssemblyDebugInfo* info = mono_debug_open_assembly (debug, klass->image);
436 int method_number = 0, line = 0, start_line = 0, end_line = 0, i;
437 DebugMethodInfo *minfo;
440 mono_class_init (klass);
442 * Find the method index in the image.
444 for (i = 0; klass->methods && i < klass->method.count; ++i) {
445 if (klass->methods [i] == method) {
446 method_number = klass->method.first + i + 1;
447 line = info->mlines [method_number];
452 if (g_hash_table_lookup (info->methods, method))
455 if (info->moffsets) {
456 /* info->moffsets contains -1 "outside" of functions. */
457 for (i = line; (i > 0) && (info->moffsets [i] == 0); i--)
461 for (i = start_line; info->moffsets [i] != -1; i++)
466 name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
467 klass->name, method->name);
469 minfo = g_new0 (DebugMethodInfo, 1);
471 minfo->start_line = start_line;
472 minfo->first_line = line;
473 minfo->last_line = end_line;
474 minfo->method_info.code_start = cfg->start + 1;
475 minfo->method_info.code_size = cfg->epilogue_end - 1;
476 minfo->method_number = method_number;
477 minfo->method_info.method = method;
478 minfo->method_info.num_params = method->signature->param_count;
479 minfo->method_info.params = g_new0 (MonoDebugVarInfo, minfo->method_info.num_params);
480 minfo->method_info.prologue_end = cfg->prologue_end - 1;
481 minfo->method_info.epilogue_begin = cfg->epilog - 1;
483 if (method->signature->hasthis) {
484 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
486 minfo->method_info.this_var = g_new0 (MonoDebugVarInfo, 1);
487 minfo->method_info.this_var->offset = ptr->offset;
490 for (i = 0; i < minfo->method_info.num_params; i++) {
491 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
492 method->signature->hasthis;
494 minfo->method_info.params [i].offset = ptr [i].offset;
497 if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
498 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
499 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
501 minfo->method_info.num_locals = header->num_locals;
502 minfo->method_info.locals = g_new0 (MonoDebugVarInfo, header->num_locals);
503 for (i = 0; i < minfo->method_info.num_locals; i++) {
504 minfo->method_info.locals [i].offset = ptr [i].offset;
505 minfo->method_info.locals [i].begin_scope = minfo->method_info.prologue_end;
506 minfo->method_info.locals [i].end_scope = minfo->method_info.epilogue_begin;
510 debug_generate_method_lines (info, minfo, cfg);
512 g_hash_table_insert (info->methods, method, minfo);