X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fdebug-mono-symfile.c;h=4f7c086edaa2a9c159a2031b69a8b2acb505322d;hb=8bee07fc5845602eb65d07df83d82e8e150fb96b;hp=bb8ef4e0b96a9a83fb3c88518c15bb1766650612;hpb=8efe5cab3eab18bef5ac682dc66904c4da1f7b9b;p=mono.git diff --git a/mono/metadata/debug-mono-symfile.c b/mono/metadata/debug-mono-symfile.c index bb8ef4e0b96..4f7c086edaa 100644 --- a/mono/metadata/debug-mono-symfile.c +++ b/mono/metadata/debug-mono-symfile.c @@ -1,16 +1,23 @@ +/* + * debug-mono-symfile.c: + * + * Author: + * Mono Project (http://www.mono-project.com) + * + * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com) + */ + #include #include #include #include #include -#include #ifdef HAVE_SYS_PARAM_H #include #endif #include #include #include -#include #include #include #include @@ -21,6 +28,7 @@ #include #include #include +#include #include #ifdef HAVE_UNISTD_H @@ -32,6 +40,18 @@ #define TYPE_TABLE_PTR_CHUNK_SIZE 256 #define TYPE_TABLE_CHUNK_SIZE 65536 +struct _MonoSymbolFile { + const uint8_t *raw_contents; + int raw_contents_size; + void *raw_contents_handle; + int major_version; + int minor_version; + char *filename; + GHashTable *method_hash; + MonoSymbolFileOffsetTable *offset_table; + gboolean was_loaded_from_memory; +}; + static void free_method_info (MonoDebugMethodInfo *minfo) { @@ -39,11 +59,11 @@ free_method_info (MonoDebugMethodInfo *minfo) } static int -load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_debugger) +load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, mono_bool in_the_debugger) { const char *ptr, *start; gchar *guid; - guint64 magic; + uint64_t magic; int minor, major; ptr = start = (const char*)symfile->raw_contents; @@ -51,7 +71,7 @@ load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_ return FALSE; magic = read64(ptr); - ptr += sizeof(guint64); + ptr += sizeof(uint64_t); if (magic != MONO_SYMBOL_FILE_MAGIC) { if (!in_the_debugger) g_warning ("Symbol file %s is not a mono symbol file", symfile->filename); @@ -59,9 +79,9 @@ load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_ } major = read32(ptr); - ptr += sizeof(guint32); + ptr += sizeof(uint32_t); minor = read32(ptr); - ptr += sizeof(guint32); + ptr += sizeof(uint32_t); /* * 50.0 is the frozen version for Mono 2.0. @@ -76,7 +96,7 @@ load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_ return FALSE; } - guid = mono_guid_to_string ((const guint8 *) ptr); + guid = mono_guid_to_string ((const uint8_t *) ptr); ptr += 16; if (strcmp (handle->image->guid, guid)) { @@ -94,18 +114,17 @@ load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_ symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr; symfile->method_hash = g_hash_table_new_full ( - g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) free_method_info); + NULL, NULL, NULL, (GDestroyNotify) free_method_info); g_free (guid); return TRUE; } MonoSymbolFile * -mono_debug_open_mono_symbols (MonoDebugHandle *handle, const guint8 *raw_contents, +mono_debug_open_mono_symbols (MonoDebugHandle *handle, const uint8_t *raw_contents, int size, gboolean in_the_debugger) { MonoSymbolFile *symfile; - FILE* f; mono_debugger_lock (); symfile = g_new0 (MonoSymbolFile, 1); @@ -116,22 +135,22 @@ mono_debug_open_mono_symbols (MonoDebugHandle *handle, const guint8 *raw_content symfile->raw_contents = p = g_malloc (size); memcpy (p, raw_contents, size); symfile->filename = g_strdup_printf ("LoadedFromMemory"); + symfile->was_loaded_from_memory = TRUE; } else { + MonoFileMap *f; symfile->filename = g_strdup_printf ("%s.mdb", mono_image_get_filename (handle->image)); - - if ((f = fopen (symfile->filename, "rb"))) { - struct stat stat_buf; - - if (fstat (fileno (f), &stat_buf) < 0) { + symfile->was_loaded_from_memory = FALSE; + if ((f = mono_file_map_open (symfile->filename))) { + symfile->raw_contents_size = mono_file_map_size (f); + if (symfile->raw_contents_size == 0) { if (!in_the_debugger) g_warning ("stat of %s failed: %s", symfile->filename, g_strerror (errno)); } else { - symfile->raw_contents_size = stat_buf.st_size; - symfile->raw_contents = mono_raw_buffer_load (fileno (f), FALSE, 0, stat_buf.st_size); + 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); } - fclose (f); + mono_file_map_close (f); } } @@ -158,8 +177,12 @@ mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile) if (symfile->method_hash) g_hash_table_destroy (symfile->method_hash); - if (symfile->raw_contents) - mono_raw_buffer_free ((gpointer) symfile->raw_contents); + if (symfile->raw_contents) { + if (symfile->was_loaded_from_memory) + g_free ((gpointer)symfile->raw_contents); + else + mono_file_unmap ((gpointer) symfile->raw_contents, symfile->raw_contents_handle); + } if (symfile->filename) g_free (symfile->filename); @@ -167,8 +190,15 @@ mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile) mono_debugger_unlock (); } +mono_bool +mono_debug_symfile_is_loaded (MonoSymbolFile *symfile) +{ + return symfile && symfile->offset_table; +} + + static int -read_leb128 (const guint8 *ptr, const guint8 **rptr) +read_leb128 (const uint8_t *ptr, const uint8_t **rptr) { int ret = 0; int shift = 0; @@ -188,7 +218,7 @@ read_leb128 (const guint8 *ptr, const guint8 **rptr) } static gchar * -read_string (const guint8 *ptr) +read_string (const uint8_t *ptr) { int len = read_leb128 (ptr, &ptr); return g_filename_from_utf8 ((const char *) ptr, len, NULL, NULL, NULL); @@ -197,9 +227,11 @@ read_string (const guint8 *ptr) typedef struct { MonoSymbolFile *symfile; int line_base, line_range, max_address_incr; - guint8 opcode_base; - guint32 last_line, last_file, last_offset; - guint32 line, file, offset; + uint8_t opcode_base; + uint32_t last_line, last_file, last_offset; + uint32_t first_file; + int line, file, offset; + gboolean is_hidden; } StatementMachine; static gboolean @@ -207,7 +239,7 @@ check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **locatio { gchar *source_file = NULL; - if ((offset > 0) && (stm->offset <= offset)) { + if (stm->offset <= offset) { stm->last_offset = stm->offset; stm->last_file = stm->file; if (stm->line != 0xfeefee) @@ -224,6 +256,15 @@ check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **locatio source_file = read_string (stm->symfile->raw_contents + read32(&(se->_data_offset))); } + if (stm->last_line == 0) { + /* + * The IL offset is less than the first IL offset which has a corresponding + * source line. + */ + *location = NULL; + return TRUE; + } + *location = g_new0 (MonoDebugSourceLocation, 1); (*location)->source_file = source_file; (*location)->row = stm->last_line; @@ -242,7 +283,7 @@ check_line (StatementMachine *stm, int offset, MonoDebugSourceLocation **locatio * `native address -> IL offset' mapping. */ MonoDebugSourceLocation * -mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset) +mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset) { MonoDebugSourceLocation *location = NULL; MonoSymbolFile *symfile; @@ -258,12 +299,15 @@ mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset) #define DW_LNE_end_sequence 1 #define DW_LNE_MONO_negate_is_hidden 0x40 +#define DW_LNE_MONO__extensions_start 0x40 +#define DW_LNE_MONO__extensions_end 0x7f + if ((symfile = minfo->handle->symfile) == NULL) return NULL; - stm.line_base = symfile->offset_table->_line_number_table_line_base; - stm.line_range = symfile->offset_table->_line_number_table_line_range; - stm.opcode_base = (guint8) symfile->offset_table->_line_number_table_opcode_base; + stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base); + stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range); + stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base); stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range; mono_debugger_lock (); @@ -272,14 +316,18 @@ mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset) stm.symfile = symfile; stm.offset = stm.last_offset = 0; - stm.file = stm.last_file = 1; - stm.line = stm.last_line = 1; + stm.last_file = 0; + stm.last_line = 0; + stm.first_file = 0; + stm.file = 1; + stm.line = 1; + stm.is_hidden = FALSE; while (TRUE) { - guint8 opcode = *ptr++; + uint8_t opcode = *ptr++; if (opcode == 0) { - guint8 size = *ptr++; + uint8_t size = *ptr++; const unsigned char *end_ptr = ptr + size; opcode = *ptr++; @@ -289,7 +337,10 @@ mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset) goto out_success; break; } else if (opcode == DW_LNE_MONO_negate_is_hidden) { - ; + stm.is_hidden = !stm.is_hidden; + } else if ((opcode >= DW_LNE_MONO__extensions_start) && + (opcode <= DW_LNE_MONO__extensions_end)) { + ; // reserved for future extensions } else { g_warning ("Unknown extended opcode %x in LNT", opcode); } @@ -338,8 +389,161 @@ mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset) return location; } -gint32 -_mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offset) +static void +add_line (StatementMachine *stm, GPtrArray *il_offset_array, GPtrArray *line_number_array) +{ + if (stm->line > 0) { + g_ptr_array_add (il_offset_array, GUINT_TO_POINTER (stm->offset)); + g_ptr_array_add (line_number_array, GUINT_TO_POINTER (stm->line)); + } + + if (!stm->is_hidden && !stm->first_file) + stm->first_file = stm->file; +} + +/* + * mono_debug_symfile_free_location: + * + * Free a MonoDebugSourceLocation returned by + * mono_debug_symfile_lookup_location + */ +void +mono_debug_symfile_free_location (MonoDebugSourceLocation *location) +{ + g_free (location->source_file); + g_free (location); +} + +/* + * mono_debug_symfile_get_line_numbers: + * + * All the output parameters can be NULL. + */ +void +mono_debug_symfile_get_line_numbers (MonoDebugMethodInfo *minfo, char **source_file, int *n_il_offsets, int **il_offsets, int **line_numbers) +{ + // FIXME: Unify this with mono_debug_symfile_lookup_location + MonoSymbolFile *symfile; + const unsigned char *ptr; + StatementMachine stm; + uint32_t i; + GPtrArray *il_offset_array, *line_number_array; + + if (source_file) + *source_file = NULL; + if (n_il_offsets) + *n_il_offsets = 0; + + if ((symfile = minfo->handle->symfile) == NULL) + return; + + il_offset_array = g_ptr_array_new (); + line_number_array = g_ptr_array_new (); + + stm.line_base = read32 (&symfile->offset_table->_line_number_table_line_base); + stm.line_range = read32 (&symfile->offset_table->_line_number_table_line_range); + stm.opcode_base = (uint8_t) read32 (&symfile->offset_table->_line_number_table_opcode_base); + stm.max_address_incr = (255 - stm.opcode_base) / stm.line_range; + + mono_debugger_lock (); + + ptr = symfile->raw_contents + minfo->lnt_offset; + + stm.symfile = symfile; + stm.offset = stm.last_offset = 0; + stm.last_file = 0; + stm.last_line = 0; + stm.first_file = 0; + stm.file = 1; + stm.line = 1; + stm.is_hidden = FALSE; + + while (TRUE) { + uint8_t opcode = *ptr++; + + if (opcode == 0) { + uint8_t size = *ptr++; + const unsigned char *end_ptr = ptr + size; + + opcode = *ptr++; + + if (opcode == DW_LNE_end_sequence) { + add_line (&stm, il_offset_array, line_number_array); + break; + } else if (opcode == DW_LNE_MONO_negate_is_hidden) { + stm.is_hidden = !stm.is_hidden; + } else if ((opcode >= DW_LNE_MONO__extensions_start) && + (opcode <= DW_LNE_MONO__extensions_end)) { + ; // reserved for future extensions + } else { + g_warning ("Unknown extended opcode %x in LNT", opcode); + } + + ptr = end_ptr; + continue; + } else if (opcode < stm.opcode_base) { + switch (opcode) { + case DW_LNS_copy: + add_line (&stm, il_offset_array, line_number_array); + break; + case DW_LNS_advance_pc: + stm.offset += read_leb128 (ptr, &ptr); + break; + case DW_LNS_advance_line: + stm.line += read_leb128 (ptr, &ptr); + break; + case DW_LNS_set_file: + stm.file = read_leb128 (ptr, &ptr); + break; + case DW_LNS_const_add_pc: + stm.offset += stm.max_address_incr; + break; + default: + g_warning ("Unknown standard opcode %x in LNT", opcode); + g_assert_not_reached (); + } + } else { + opcode -= stm.opcode_base; + + stm.offset += opcode / stm.line_range; + stm.line += stm.line_base + (opcode % stm.line_range); + + add_line (&stm, il_offset_array, line_number_array); + } + } + + if (!stm.file && stm.first_file) + stm.file = stm.first_file; + + if (stm.file) { + int offset = read32(&(stm.symfile->offset_table->_source_table_offset)) + + (stm.file - 1) * sizeof (MonoSymbolFileSourceEntry); + MonoSymbolFileSourceEntry *se = (MonoSymbolFileSourceEntry *) + (stm.symfile->raw_contents + offset); + + if (source_file) + *source_file = read_string (stm.symfile->raw_contents + read32(&(se->_data_offset))); + } + + if (n_il_offsets) + *n_il_offsets = il_offset_array->len; + if (il_offsets && line_numbers) { + *il_offsets = g_malloc (il_offset_array->len * sizeof (int)); + *line_numbers = g_malloc (il_offset_array->len * sizeof (int)); + for (i = 0; i < il_offset_array->len; ++i) { + (*il_offsets) [i] = GPOINTER_TO_UINT (g_ptr_array_index (il_offset_array, i)); + (*line_numbers) [i] = GPOINTER_TO_UINT (g_ptr_array_index (line_number_array, i)); + } + } + g_ptr_array_free (il_offset_array, TRUE); + g_ptr_array_free (line_number_array, TRUE); + + mono_debugger_unlock (); + return; +} + +int32_t +_mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, uint32_t il_offset) { int i; @@ -361,7 +565,7 @@ _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offs static int compare_method (const void *key, const void *object) { - guint32 token = GPOINTER_TO_UINT (key); + uint32_t token = GPOINTER_TO_UINT (key); MonoSymbolFileMethodEntry *me = (MonoSymbolFileMethodEntry*)object; return token - read32(&(me->_token)); @@ -381,6 +585,13 @@ mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method) return NULL; mono_debugger_lock (); + + minfo = g_hash_table_lookup (symfile->method_hash, method); + if (minfo) { + mono_debugger_unlock (); + return minfo; + } + first_ie = (MonoSymbolFileMethodEntry *) (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset))); @@ -406,3 +617,79 @@ mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method) mono_debugger_unlock (); return minfo; } + +/* + * mono_debug_symfile_lookup_locals: + * + * Return information about the local variables of MINFO from the symbol file. + * Return NULL if no information can be found. + * The result should be freed using mono_debug_symfile_free_locals (). + */ +MonoDebugLocalsInfo* +mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo) +{ + MonoSymbolFile *symfile = minfo->handle->symfile; + const uint8_t *p; + int i, len, compile_unit_index, locals_offset, num_locals, block_index; + int namespace_id, code_block_table_offset; + MonoDebugLocalsInfo *res; + + if (!symfile) + return NULL; + + p = symfile->raw_contents + minfo->data_offset; + + compile_unit_index = read_leb128 (p, &p); + locals_offset = read_leb128 (p, &p); + namespace_id = read_leb128 (p, &p); + code_block_table_offset = read_leb128 (p, &p); + + res = g_new0 (MonoDebugLocalsInfo, 1); + + p = symfile->raw_contents + code_block_table_offset; + res->num_blocks = read_leb128 (p, &p); + res->code_blocks = g_new0 (MonoDebugCodeBlock, res->num_blocks); + for (i = 0; i < res->num_blocks; ++i) { + res->code_blocks [i].type = read_leb128 (p, &p); + res->code_blocks [i].parent = read_leb128 (p, &p); + res->code_blocks [i].start_offset = read_leb128 (p, &p); + res->code_blocks [i].end_offset = read_leb128 (p, &p); + } + + p = symfile->raw_contents + locals_offset; + num_locals = read_leb128 (p, &p); + + res->num_locals = num_locals; + res->locals = g_new0 (MonoDebugLocalVar, num_locals); + + for (i = 0; i < num_locals; ++i) { + res->locals [i].index = read_leb128 (p, &p); + len = read_leb128 (p, &p); + res->locals [i].name = g_malloc (len + 1); + memcpy (res->locals [i].name, p, len); + res->locals [i].name [len] = '\0'; + p += len; + block_index = read_leb128 (p, &p); + if (block_index >= 1 && block_index <= res->num_blocks) + res->locals [i].block = &res->code_blocks [block_index - 1]; + } + + return res; +} + +/* + * mono_debug_symfile_free_locals: + * + * Free all the data allocated by mono_debug_symfile_lookup_locals (). + */ +void +mono_debug_symfile_free_locals (MonoDebugLocalsInfo *info) +{ + int i; + + for (i = 0; i < info->num_locals; ++i) + g_free (info->locals [i].name); + g_free (info->locals); + g_free (info->code_blocks); + g_free (info); +}