[interp] Fix interp logging (#17636)
[mono-project.git] / mono / mini / xdebug.c
blob607db2e1e9967335fecf85d02bc107f8fdb3cb85
1 /**
2 * \file
3 * Support for emitting gdb debug info for JITted code.
5 * Author:
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2010 Novell, Inc.
9 */
12 * This works as follows:
13 * - the runtime writes out an xdb.s file containing DWARF debug info.
14 * - the user calls a gdb macro
15 * - the macro compiles and loads this shared library using add-symbol-file.
17 * This is based on the xdebug functionality in the Kaffe Java VM.
19 * We emit assembly code instead of using the ELF writer, so we can emit debug info
20 * incrementally as each method is JITted, and the debugger doesn't have to call
21 * into the runtime to emit the shared library, which would cause all kinds of
22 * complications, like threading issues, and the fact that the ELF writer's
23 * emit_writeout () function cannot be called more than once.
24 * GDB 7.0 and later has a JIT interface.
27 #include "config.h"
28 #include <glib.h>
29 #include "mini.h"
30 #include "mini-runtime.h"
32 #include <sys/types.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #ifdef HAVE_STDINT_H
37 #include <stdint.h>
38 #endif
39 #include <fcntl.h>
40 #include <ctype.h>
41 #include <string.h>
42 #ifndef HOST_WIN32
43 #include <sys/time.h>
44 #else
45 #include <winsock2.h>
46 #include <windows.h>
47 #endif
49 #include <errno.h>
50 #include <sys/stat.h>
52 #include "image-writer.h"
54 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) && USE_BIN_WRITER
56 #include "dwarfwriter.h"
58 #include "mono/utils/mono-compiler.h"
60 #define USE_GDB_JIT_INTERFACE
62 /* The recommended gdb macro is: */
64 define xdb
65 shell rm -f xdb.so && as --64 -o xdb.o xdb.s && ld -shared -o xdb.so xdb.o
66 add-symbol-file xdb.so 0
67 end
71 * GDB JIT interface definitions.
73 * http://sources.redhat.com/gdb/onlinedocs/gdb_30.html
75 typedef enum
77 JIT_NOACTION = 0,
78 JIT_REGISTER_FN,
79 JIT_UNREGISTER_FN
80 } jit_actions_t;
82 struct jit_code_entry;
83 typedef struct jit_code_entry jit_code_entry;
85 struct jit_code_entry
87 jit_code_entry *next_entry;
88 jit_code_entry *prev_entry;
89 const char *symfile_addr;
91 * The gdb code in gdb/jit.c which reads this structure ignores alignment
92 * requirements, so use two 32 bit fields.
94 guint32 symfile_size1, symfile_size2;
97 typedef struct jit_descriptor
99 guint32 version;
100 /* This type should be jit_actions_t, but we use guint32
101 to be explicit about the bitwidth. */
102 guint32 action_flag;
103 jit_code_entry *relevant_entry;
104 jit_code_entry *first_entry;
105 } jit_descriptor;
107 G_BEGIN_DECLS
109 /* GDB puts a breakpoint in this function. */
110 void MONO_NEVER_INLINE __jit_debug_register_code(void);
112 #if !defined(MONO_LLVM_LOADED) && defined(ENABLE_LLVM) && !defined(MONO_CROSS_COMPILE)
114 /* LLVM already defines these */
116 extern jit_descriptor __jit_debug_descriptor;
118 #else
120 /* gcc seems to inline/eliminate calls to noinline functions, thus the asm () */
121 void MONO_NEVER_INLINE __jit_debug_register_code(void) {
122 #if defined(__GNUC__)
123 asm ("");
124 #endif
127 /* Make sure to specify the version statically, because the
128 debugger may check the version before we can set it. */
129 jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
131 #endif
133 G_END_DECLS
135 static MonoImageWriter *xdebug_w;
136 static MonoDwarfWriter *xdebug_writer;
137 static FILE *xdebug_fp, *il_file;
138 static gboolean use_gdb_interface, save_symfiles;
139 static int il_file_line_index;
140 static GHashTable *xdebug_syms;
142 void
143 mono_xdebug_init (const char *options)
145 MonoImageWriter *w;
146 char **args, **ptr;
148 args = g_strsplit (options, ",", -1);
149 for (ptr = args; ptr && *ptr; ptr ++) {
150 char *arg = *ptr;
152 if (!strcmp (arg, "gdb"))
153 use_gdb_interface = TRUE;
154 if (!strcmp (arg, "save-symfiles"))
155 save_symfiles = TRUE;
158 /* This file will contain the IL code for methods which don't have debug info */
159 il_file = fopen ("xdb.il", "w");
160 if (il_file == NULL) {
161 use_gdb_interface = FALSE;
162 g_warning ("** Unable to create xdb.il. Managed symbol names won't be available.");
163 return;
166 if (use_gdb_interface)
167 return;
169 unlink ("xdb.s");
170 xdebug_fp = fopen ("xdb.s", "w");
172 w = mono_img_writer_create (xdebug_fp, FALSE);
174 mono_img_writer_emit_start (w);
176 xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE);
178 /* Emit something so the file has a text segment */
179 mono_img_writer_emit_section_change (w, ".text", 0);
180 mono_img_writer_emit_string (w, "");
182 mono_dwarf_writer_emit_base_info (xdebug_writer, "JITted code", mono_unwind_get_cie_program ());
185 static void
186 xdebug_begin_emit (MonoImageWriter **out_w, MonoDwarfWriter **out_dw)
188 MonoImageWriter *w;
189 MonoDwarfWriter *dw;
191 w = mono_img_writer_create (NULL, TRUE);
193 mono_img_writer_emit_start (w);
195 /* This file will contain the IL code for methods which don't have debug info */
196 if (!il_file)
197 il_file = fopen ("xdb.il", "w");
199 dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, TRUE);
201 mono_dwarf_writer_emit_base_info (dw, "JITted code", mono_unwind_get_cie_program ());
203 *out_w = w;
204 *out_dw = dw;
207 static void
208 xdebug_end_emit (MonoImageWriter *w, MonoDwarfWriter *dw, MonoMethod *method)
210 guint8 *img;
211 guint32 img_size;
212 jit_code_entry *entry;
213 guint64 *psize;
215 il_file_line_index = mono_dwarf_writer_get_il_file_line_index (dw);
216 mono_dwarf_writer_close (dw);
218 mono_img_writer_emit_writeout (w);
220 img = mono_img_writer_get_output (w, &img_size);
222 mono_img_writer_destroy (w);
224 if (FALSE) {
225 /* Save the symbol files to help debugging */
226 FILE *fp;
227 char *file_name;
228 static int file_counter;
230 file_counter ++;
231 file_name = g_strdup_printf ("xdb-%d.o", file_counter);
232 printf ("%s %p %d\n", file_name, img, img_size);
234 fp = fopen (file_name, "w");
235 fwrite (img, img_size, 1, fp);
236 fclose (fp);
237 g_free (file_name);
240 /* Register the image with GDB */
242 entry = g_malloc0 (sizeof (jit_code_entry));
244 entry->symfile_addr = (const char*)img;
245 psize = (guint64*)&entry->symfile_size1;
246 *psize = img_size;
248 entry->next_entry = __jit_debug_descriptor.first_entry;
249 if (__jit_debug_descriptor.first_entry)
250 __jit_debug_descriptor.first_entry->prev_entry = entry;
251 __jit_debug_descriptor.first_entry = entry;
253 __jit_debug_descriptor.relevant_entry = entry;
254 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
256 __jit_debug_register_code ();
260 * mono_xdebug_flush:
262 * This could be called from inside gdb to flush the debugging information not yet
263 * registered with gdb.
265 void
266 mono_xdebug_flush (void)
268 if (xdebug_w)
269 xdebug_end_emit (xdebug_w, xdebug_writer, NULL);
271 xdebug_begin_emit (&xdebug_w, &xdebug_writer);
274 static int xdebug_method_count;
277 * mono_save_xdebug_info:
279 * Emit debugging info for METHOD into an assembly file which can be assembled
280 * and loaded into gdb to provide debugging info for JITted code.
281 * LOCKING: Acquires the loader lock.
283 void
284 mono_save_xdebug_info (MonoCompile *cfg)
286 MonoDebugMethodJitInfo *dmji;
288 if (use_gdb_interface) {
289 mono_loader_lock ();
291 if (!xdebug_syms)
292 xdebug_syms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
295 * gdb is not designed to handle 1000s of symbol files (one per method). So we
296 * group them into groups of 100.
298 if ((xdebug_method_count % 100) == 0)
299 mono_xdebug_flush ();
301 xdebug_method_count ++;
303 dmji = mono_debug_find_method (jinfo_get_method (cfg->jit_info), mono_domain_get ());
304 mono_dwarf_writer_emit_method (xdebug_writer, cfg, jinfo_get_method (cfg->jit_info), NULL, NULL, NULL,
305 (guint8*)cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, dmji);
306 mono_debug_free_method_jit_info (dmji);
308 #if 0
310 * Emit a symbol for the code by emitting it at the beginning of the text
311 * segment, and setting the text segment to have an absolute address.
312 * This symbol can be used to set breakpoints in gdb.
313 * FIXME: This doesn't work when multiple methods are emitted into the same file.
315 sym = get_debug_sym (cfg->jit_info->method, "", xdebug_syms);
316 mono_img_writer_emit_section_change (w, ".text", 0);
317 if (!xdebug_text_addr) {
318 xdebug_text_addr = cfg->jit_info->code_start;
319 mono_img_writer_set_section_addr (w, (gssize)xdebug_text_addr);
321 mono_img_writer_emit_global_with_size (w, sym, cfg->jit_info->code_size, TRUE);
322 mono_img_writer_emit_label (w, sym);
323 mono_img_writer_emit_bytes (w, cfg->jit_info->code_start, cfg->jit_info->code_size);
324 g_free (sym);
325 #endif
327 mono_loader_unlock ();
328 } else {
329 if (!xdebug_writer)
330 return;
332 mono_loader_lock ();
333 dmji = mono_debug_find_method (jinfo_get_method (cfg->jit_info), mono_domain_get ());
334 mono_dwarf_writer_emit_method (xdebug_writer, cfg, jinfo_get_method (cfg->jit_info), NULL, NULL, NULL,
335 (guint8*)cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, dmji);
336 mono_debug_free_method_jit_info (dmji);
337 fflush (xdebug_fp);
338 mono_loader_unlock ();
344 * mono_save_trampoline_xdebug_info:
346 * Same as mono_save_xdebug_info, but for trampolines.
347 * LOCKING: Acquires the loader lock.
349 void
350 mono_save_trampoline_xdebug_info (MonoTrampInfo *info)
352 const char *info_name = info->name;
353 if (info_name == NULL)
354 info_name = "";
356 if (use_gdb_interface) {
357 MonoImageWriter *w;
358 MonoDwarfWriter *dw;
360 /* This can be called before the loader lock is initialized */
361 mono_loader_lock_if_inited ();
363 xdebug_begin_emit (&w, &dw);
365 mono_dwarf_writer_emit_trampoline (dw, info_name, NULL, NULL, info->code, info->code_size, info->unwind_ops);
367 xdebug_end_emit (w, dw, NULL);
369 mono_loader_unlock_if_inited ();
370 } else {
371 if (!xdebug_writer)
372 return;
374 mono_loader_lock_if_inited ();
375 mono_dwarf_writer_emit_trampoline (xdebug_writer, info_name, NULL, NULL, info->code, info->code_size, info->unwind_ops);
376 fflush (xdebug_fp);
377 mono_loader_unlock_if_inited ();
381 #else /* !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */
383 void
384 mono_xdebug_init (const char *options)
388 void
389 mono_save_xdebug_info (MonoCompile *cfg)
393 void
394 mono_save_trampoline_xdebug_info (MonoTrampInfo *info)
398 #endif