#include <mono/metadata/verify.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/mono-debug.h>
-/* mono-debug-debugger.h nneds config.h to work... */
+#include <mono/metadata/appdomain.h>
+/* mono-debug-debugger.h needs config.h to work... */
#include "config.h"
#include <mono/metadata/mono-debug-debugger.h>
+#ifdef HAVE_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
+
static inline void
record_line_number (MonoDebugMethodJitInfo *jit, guint32 address, guint32 offset)
{
MonoDebugLineNumberEntry lne;
- lne.address = address;
- lne.offset = offset;
+ lne.native_offset = address;
+ lne.il_offset = offset;
g_array_append_val (jit->line_numbers, lne);
}
if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
- (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
- (method->wrapper_type != MONO_WRAPPER_NONE))
+ (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ return;
+ if ((method->wrapper_type != MONO_WRAPPER_NONE) &&
+ (method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE))
return;
info = g_new0 (MiniDebugMethodInfo, 1);
mono_class_init (cfg->method->klass);
- g_assert (((MonoMethodNormal*)cfg->method)->header);
- header = ((MonoMethodNormal*)cfg->method)->header;
-
+ header = mono_method_get_header (cfg->method);
+ g_assert (header);
+
info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
jit->num_locals = header->num_locals;
}
}
+/*
+ * mono_debug_add_vg_method:
+ *
+ * Register symbol information for the method with valgrind
+ */
+static void
+mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit)
+{
+#ifdef VALGRIND_ADD_LINE_INFO
+ MonoMethodHeader *header;
+ int i;
+ char *filename = NULL;
+ guint32 address, line_number;
+ const char *full_name;
+ guint32 *addresses;
+ guint32 *lines;
+
+ if (!RUNNING_ON_VALGRIND)
+ return;
+
+ header = mono_method_get_header (method);
+
+ full_name = mono_method_full_name (method, TRUE);
+
+ addresses = g_new0 (guint32, header->code_size + 1);
+ lines = g_new0 (guint32, header->code_size + 1);
+
+ /*
+ * Very simple code to convert the addr->offset mappings that mono has
+ * into [addr-addr] ->line number mappings.
+ */
+
+ /* Create offset->line number mapping */
+ for (i = 0; i < header->code_size; ++i) {
+ char *fname;
+
+ fname = mono_debug_source_location_from_il_offset (method, i, &lines [i]);
+ if (!filename)
+ filename = fname;
+ }
+
+ /* Create address->offset mapping */
+ for (i = 0; i < jit->line_numbers->len; ++i) {
+ MonoDebugLineNumberEntry *lne = &g_array_index (jit->line_numbers, MonoDebugLineNumberEntry, i);
+
+ g_assert (lne->offset <= header->code_size);
+
+ if ((addresses [lne->offset] == 0) || (lne->address < addresses [lne->offset]))
+ addresses [lne->offset] = lne->address;
+ }
+ /* Fill out missing addresses */
+ address = 0;
+ for (i = 0; i < header->code_size; ++i) {
+ if (addresses [i] == 0)
+ addresses [i] = address;
+ else
+ address = addresses [i];
+ }
+
+ address = 0;
+ line_number = 0;
+ i = 0;
+ while (i < header->code_size) {
+ if (lines [i] == line_number)
+ i ++;
+ else {
+ if (line_number > 0) {
+ //g_assert (addresses [i] - 1 >= address);
+
+ if (addresses [i] - 1 >= address) {
+ VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + addresses [i] - 1, filename, line_number);
+ //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number);
+ }
+ }
+ address = addresses [i];
+ line_number = lines [i];
+ }
+ }
+
+ if (line_number > 0) {
+ VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + jit->code_size - 1, filename, line_number);
+ //printf ("[%d-%d] -> %d.\n", address, jit->code_size - 1, line_number);
+ }
+
+ VALGRIND_ADD_SYMBOL (jit->code_start, jit->code_size, full_name);
+
+ g_free (addresses);
+ g_free (lines);
+#endif /* VALGRIND_ADD_LINE_INFO */
+}
+
void
mono_debug_close_method (MonoCompile *cfg)
{
return;
method = cfg->method;
- header = ((MonoMethodNormal*)method)->header;
+ header = mono_method_get_header (method);
jit = info->jit;
jit->code_start = cfg->native_code;
mono_debug_add_method (method, jit, cfg->domain);
+ mono_debug_add_vg_method (method, jit);
+
if (info->breakpoint_id)
mono_debugger_breakpoint_callback (method, info->breakpoint_id);
}
if (!info || !info->jit || !ins->cil_code)
return;
- g_assert (((MonoMethodNormal*)cfg->method)->header);
- header = ((MonoMethodNormal*)cfg->method)->header;
+ header = mono_method_get_header (cfg->method);
+ g_assert (header);
if ((ins->cil_code < header->code) ||
(ins->cil_code > header->code + header->code_size))
}
static inline void
-encode_value (guint32 value, char *buf, char **endbuf)
+encode_value (gint32 value, char *buf, char **endbuf)
{
char *p = buf;
* Same encoding as the one used in the metadata, extended to handle values
* greater than 0x1fffffff.
*/
- if (value <= 127)
+ if ((value >= 0) && (value <= 127))
*p++ = value;
- else if (value <= 16384) {
+ else if ((value >= 0) && (value <= 16383)) {
p [0] = 0x80 | (value >> 8);
p [1] = value & 0xff;
p += 2;
- } else if (value <= 0x1fffffff) {
+ } else if ((value >= 0) && (value <= 0x1fffffff)) {
p [0] = (value >> 24) | 0xc0;
p [1] = (value >> 16) & 0xff;
p [2] = (value >> 8) & 0xff;
*endbuf = p;
}
-static inline guint32
+static inline gint32
decode_value (char *_ptr, char **rptr)
{
unsigned char *ptr = (unsigned char *) _ptr;
unsigned char b = *ptr;
- guint32 len;
+ gint32 len;
if ((b & 0x80) == 0){
len = b;
ptr += 4;
}
else {
- len = (ptr [0] << 24) | (ptr [1] << 16) | (ptr [2] << 8) | ptr [3];
+ len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
ptr += 5;
}
if (rptr)
prev_offset = 0;
prev_native_offset = 0;
for (i = 0; i < jit->line_numbers->len; ++i) {
+ /* Sometimes, the offset values are not in increasing order */
MonoDebugLineNumberEntry *lne = &g_array_index (jit->line_numbers,
MonoDebugLineNumberEntry,
i);
- encode_value (lne->offset - prev_offset, p, &p);
- encode_value (lne->address - prev_native_offset, p, &p);
- prev_offset = lne->offset;
- prev_native_offset = lne->address;
+ encode_value (lne->il_offset - prev_offset, p, &p);
+ encode_value (lne->native_offset - prev_native_offset, p, &p);
+ prev_offset = lne->il_offset;
+ prev_native_offset = lne->native_offset;
}
g_assert (p - buf < size);
{
MonoMethodHeader *header;
MonoDebugMethodJitInfo *jit;
- guint32 offset, native_offset, prev_offset, prev_native_offset, len;
+ gint32 offset, native_offset, prev_offset, prev_native_offset, len;
char *p;
int i;
- g_assert (((MonoMethodNormal*)method)->header);
- header = ((MonoMethodNormal*)method)->header;
+ header = mono_method_get_header (method);
+ g_assert (header);
jit = g_new0 (MonoDebugMethodJitInfo, 1);
jit->code_start = code_start;
debug_info_len);
mono_debug_add_method (method, jit, domain);
+
+ mono_debug_add_vg_method (method, jit);
}
MonoDomain *
mono_init_debugger (const char *file, const char *opt_flags)
{
MonoDomain *domain;
- const char *error;
+ const guchar *error;
int opt;
g_set_prgname (file);
mono_config_parse (NULL);
- error = mono_verify_corlib ();
+ error = mono_check_corlib_version ();
if (error) {
fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
+ fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
exit (1);
}
return domain;
}
+
+void
+mono_debug_add_icall_wrapper (MonoMethod *method, MonoJitICallInfo* callinfo)
+{
+ if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+ return;
+
+ mono_debug_add_wrapper (method, callinfo->func, mono_get_root_domain ());
+}