All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
@ 2011-09-29 23:46 Richard Henderson
  2011-09-30  7:12 ` Jan Kiszka
  0 siblings, 1 reply; 8+ messages in thread
From: Richard Henderson @ 2011-09-29 23:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: gdb

This allows us to generate unwind info for the dynamicly generated
code in the code_gen_buffer.  Only i386 is converted at this point.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 elf.h                 |    1 +
 exec.c                |    9 +++
 tcg/i386/tcg-target.c |  125 +++++++++++++++++++++++++++++++---
 tcg/tcg.c             |  185 +++++++++++++++++++++++++++++++++++++++++++++++++
 tcg/tcg.h             |    2 +
 5 files changed, 313 insertions(+), 9 deletions(-)


It's somewhat unfortunate, but the GDB interface requires that we
build a contiguous ELF image.  This means we can't place the ELF
header that we generate any place except the beginning of the
code_gen_buffer.  While tedious, this isn't terribly difficult.

With this patch, I now get:

Breakpoint 1, __ldb_mmu (addr=1001716, mmu_idx=0)
    at /home/rth/work/qemu/qemu/softmmu_template.h:86
86	{
(gdb) where
#0  __ldb_mmu (addr=1001716, mmu_idx=0)
    at /home/rth/work/qemu/qemu/softmmu_template.h:86
#1  0x0000000040000afc in ?? ()
#2  0x000000000053e85c in cpu_x86_exec (env=0x1208d80)
    at /home/rth/work/qemu/qemu/cpu-exec.c:565
#3  0x0000000000542932 in tcg_cpu_exec (env=0x1208d80)
    at /home/rth/work/qemu/qemu/cpus.c:913
#4  cpu_exec_all () at /home/rth/work/qemu/qemu/cpus.c:949
#5  0x0000000000542ad5 in qemu_tcg_cpu_thread_fn (arg=<optimized out>)
    at /home/rth/work/qemu/qemu/cpus.c:688
#6  0x00000033f1a07b31 in start_thread () from /lib64/libpthread.so.0
#7  0x00000033f16dfd2d in clone () from /lib64/libc.so.6

which is nicely correct.

Comments from the gdb folk are welcome.


r~



diff --git a/elf.h b/elf.h
index 2e05d34..1e56a8c 100644
--- a/elf.h
+++ b/elf.h
@@ -216,6 +216,7 @@ typedef int64_t  Elf64_Sxword;
 
 #define ELF_ST_BIND(x)		((x) >> 4)
 #define ELF_ST_TYPE(x)		(((unsigned int) x) & 0xf)
+#define ELF_ST_INFO(bind,type)	(((bind) << 4) | (type))
 #define ELF32_ST_BIND(x)	ELF_ST_BIND(x)
 #define ELF32_ST_TYPE(x)	ELF_ST_TYPE(x)
 #define ELF64_ST_BIND(x)	ELF_ST_BIND(x)
diff --git a/exec.c b/exec.c
index 1e6f732..f6c07d5 100644
--- a/exec.c
+++ b/exec.c
@@ -464,6 +464,8 @@ static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
 
 static void code_gen_alloc(unsigned long tb_size)
 {
+    size_t grab;
+
 #ifdef USE_STATIC_CODE_GEN_BUFFER
     code_gen_buffer = static_code_gen_buffer;
     code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
@@ -558,6 +560,13 @@ static void code_gen_alloc(unsigned long tb_size)
     map_exec(code_gen_buffer, code_gen_buffer_size);
 #endif
 #endif /* !USE_STATIC_CODE_GEN_BUFFER */
+
+    /* Give GDB unwind info for the code we generate.  This grabs a small
+       amount of space from the front of the buffer.  Account for it.  */
+    grab = tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
+    code_gen_buffer += grab;
+    code_gen_buffer_size -= grab;
+
     map_exec(code_gen_prologue, sizeof(code_gen_prologue));
     code_gen_buffer_max_size = code_gen_buffer_size -
         (TCG_MAX_OP_SIZE * OPC_BUF_SIZE);
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 281f87d..462f455 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1913,22 +1913,29 @@ static int tcg_target_callee_save_regs[] = {
 #endif
 };
 
+/* Compute frame size via macros, to share between tcg_target_qemu_prologue
+   and tcg_register_jit.  */
+
+#define PUSH_SIZE \
+    ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
+     * (TCG_TARGET_REG_BITS / 8))
+
+#define FRAME_SIZE \
+    ((PUSH_SIZE \
+      + TCG_STATIC_CALL_ARGS_SIZE \
+      + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+      + TCG_TARGET_STACK_ALIGN - 1) \
+     & ~(TCG_TARGET_STACK_ALIGN - 1))
+
 /* Generate global QEMU prologue and epilogue code */
 static void tcg_target_qemu_prologue(TCGContext *s)
 {
-    int i, frame_size, push_size, stack_addend;
+    int i, stack_addend;
 
     /* TB prologue */
 
     /* Reserve some stack space, also for TCG temps.  */
-    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
-    push_size *= TCG_TARGET_REG_BITS / 8;
-
-    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
-        CPU_TEMP_BUF_NLONGS * sizeof(long);
-    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
-        ~(TCG_TARGET_STACK_ALIGN - 1);
-    stack_addend = frame_size - push_size;
+    stack_addend = FRAME_SIZE - PUSH_SIZE;
     tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
                   CPU_TEMP_BUF_NLONGS * sizeof(long));
 
@@ -1988,3 +1995,103 @@ static void tcg_target_init(TCGContext *s)
 
     tcg_add_target_add_op_defs(x86_op_defs);
 }
+
+extern char debug_frame[];
+extern char debug_frame_end[];
+extern void *debug_frame_code_start;
+extern size_t debug_frame_code_len;
+extern char debug_frame_frame_size[];
+
+#if TCG_TARGET_REG_BITS == 64
+#define ELF_HOST_MACHINE EM_X86_64
+asm(".data\n"
+"	.align 8\n"
+"debug_frame:\n"
+"	.long	99f-0f\n"	/* Length of CIE */
+"0:	.long	-1\n"		/* CIE identifier */
+"	.byte	1\n"		/* CIE version */
+"	.byte	0\n"		/* CIE augmentation (none) */
+"	.byte	1\n"		/* CIE code alignment factor */
+"	.byte	0x78\n"		/* CIE data alignment factor (sleb128 -8) */
+"	.byte	16\n"		/* CIE return address column */
+"	.align 8\n"
+"99:\n"				/* End of CIE */
+"	.long	99f-0f\n"	/* Length of FDE */
+"0:	.long	0\n"		/* FDE CIE offset (start of section) */
+"debug_frame_code_start:\n"
+"	.quad	0\n"		/* FDE start (to be filled in) */
+"debug_frame_code_len:\n"
+"	.quad	0\n"		/* FDE length (to be filled in) */
+"	.byte	12\n"		/* DW_CFA_def_cfa */
+"	.byte	7\n"		/*   %rsp */
+"debug_frame_frame_size:\n"
+"	.byte	0, 0\n"		/*   frame_size (to be filled in) */
+"	.byte	0x90, 1\n"	/* DW_CFA_offset, %rip, -8 */
+/* The following ordering must match tcg_target_callee_save_regs.  */
+"	.byte	0x86, 2\n"	/* DW_CFA_offset, %rbp, -16 */
+"	.byte	0x83, 3\n"	/* DW_CFA_offset, %rbx, -24 */
+"	.byte	0x8c, 4\n"	/* DW_CFA_offset, %r12, -32 */
+"	.byte	0x8d, 5\n"	/* DW_CFA_offset, %r13, -40 */
+"	.byte	0x8e, 6\n"	/* DW_CFA_offset, %r14, -48 */
+"	.byte	0x8f, 7\n"	/* DW_CFA_offset, %r15, -56 */
+"	.align	8\n"
+"99:\n"				/* End of FDE */
+"debug_frame_end:\n"
+".previous"
+);
+#else
+#define ELF_HOST_MACHINE EM_386
+asm(".data\n"
+"	.align 4\n"
+"debug_frame:\n"
+"	.long	99f-0f\n"	/* Length of CIE */
+"0:	.long	-1\n"		/* CIE identifier */
+"	.byte	1\n"		/* CIE version */
+"	.byte	0\n"		/* CIE augmentation (none) */
+"	.byte	1\n"		/* CIE code alignment factor */
+"	.byte	0x7c\n"		/* CIE data alignment factor (sleb128 -4) */
+"	.byte	8\n"		/* CIE return address column */
+"	.align 4\n"
+"99:\n"				/* End of CIE */
+"	.long	99f-0f\n"	/* Length of FDE */
+"0:	.long	0\n"		/* FDE CIE offset (start of section) */
+"debug_frame_code_start:\n"
+"	.long	0\n"		/* FDE start (to be filled in) */
+"debug_frame_code_len:\n"
+"	.long	0\n"		/* FDE length (to be filled in) */
+"	.byte	12\n"		/* DW_CFA_def_cfa */
+"	.byte	4\n"		/*   %rsp */
+"debug_frame_frame_size:\n"
+"	.byte	0, 0\n"		/*   frame_size (to be filled in) */
+"	.byte	0x88, 1\n"	/* DW_CFA_offset, %eip, -4 */
+/* The following ordering must match tcg_target_callee_save_regs.  */
+"	.byte	0x85, 2\n"	/* DW_CFA_offset, %ebp, -8 */
+"	.byte	0x83, 3\n"	/* DW_CFA_offset, %ebx, -12 */
+"	.byte	0x86, 4\n"	/* DW_CFA_offset, %esi, -16 */
+"	.byte	0x87, 5\n"	/* DW_CFA_offset, %edi, -20 */
+"	.align	4\n"
+"99:\n"				/* End of FDE */
+"debug_frame_end:\n"
+".previous"
+);
+#endif
+
+size_t tcg_register_jit(void *buf, size_t buf_size)
+{
+    const unsigned int frame_size = FRAME_SIZE;
+    unsigned int f_lo, f_hi;
+
+    /* ??? These could be filled in generically via reading the debug data.  */
+    debug_frame_code_start = buf;
+    debug_frame_code_len = buf_size;
+
+    /* ??? We're expecting a 2 byte uleb128 encoded value.  */
+    f_lo = (frame_size & 0x7f) | 0x80;
+    f_hi = frame_size >> 7;
+    assert(frame_size >> 14 == 0);
+    debug_frame_frame_size[0] = f_lo;
+    debug_frame_frame_size[1] = f_hi;
+
+    return tcg_register_jit_int(buf, buf_size, debug_frame,
+                                debug_frame_end - debug_frame);
+}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 411f971..63d81f9 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -57,6 +57,18 @@
 #include "cpu.h"
 
 #include "tcg-op.h"
+
+#if TCG_TARGET_REG_BITS == 64
+# define ELF_CLASS  ELFCLASS64
+#else
+# define ELF_CLASS  ELFCLASS32
+#endif
+#ifdef HOST_WORDS_BIGENDIAN
+# define ELF_DATA   ELFDATA2MSB
+#else
+# define ELF_DATA   ELFDATA2LSB
+#endif
+
 #include "elf.h"
 
 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
@@ -68,6 +80,9 @@ static void tcg_target_qemu_prologue(TCGContext *s);
 static void patch_reloc(uint8_t *code_ptr, int type, 
                         tcg_target_long value, tcg_target_long addend);
 
+static size_t tcg_register_jit_int(void *buf, size_t size,
+                                   void *debug_frame, size_t debug_frame_size);
+
 TCGOpDef tcg_op_defs[] = {
 #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
 #include "tcg-opc.h"
@@ -2233,3 +2248,173 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
     cpu_fprintf(f, "[TCG profiler not compiled]\n");
 }
 #endif
+
+#ifdef ELF_HOST_MACHINE
+/* The backend should define ELF_HOST_MACHINE to indicate both what value to
+   put into the ELF image and to indicate support for the feature.  */
+
+/* Begin GDB interface.  The following must match the docs.  */
+typedef enum
+{
+    JIT_NOACTION = 0,
+    JIT_REGISTER_FN,
+    JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry {
+    struct jit_code_entry *next_entry;
+    struct jit_code_entry *prev_entry;
+    const char *symfile_addr;
+    uint64_t symfile_size;
+};
+
+struct jit_descriptor {
+    uint32_t version;
+    uint32_t action_flag;
+    struct jit_code_entry *relevant_entry;
+    struct jit_code_entry *first_entry;
+};
+
+void __jit_debug_register_code(void);
+void __attribute__((noinline)) __jit_debug_register_code(void)
+{
+    asm("");
+}
+
+/* Must statically initialize the version, because GDB may check
+   the version before we can set it.  */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+/* End GDB interface.  */
+
+static int find_string(const char *strtab, const char *str)
+{
+    const char *p = strtab + 1;
+
+    while (1) {
+        if (strcmp(p, str) == 0) {
+            return p - strtab;
+        }
+        p += strlen(p) + 1;
+    }
+}
+
+static size_t tcg_register_jit_int(void *buf, size_t buf_size,
+                                   void *debug_frame, size_t debug_frame_size)
+{
+    static const char strings[64] =
+        "\0"
+        ".text\0"
+        ".debug_frame\0"
+        ".symtab\0"
+        ".strtab\0"
+        "code_gen_buffer";
+
+    struct ElfImage {
+        ElfW(Ehdr) ehdr;
+        ElfW(Phdr) phdr;
+        ElfW(Shdr) shdr[5];
+        ElfW(Sym)  sym[1];
+        char       str[64];
+    };
+
+    /* We only need a single jit entry; statically allocate it.  */
+    static struct jit_code_entry one_entry;
+
+    struct ElfImage *img = buf;
+    size_t grab = sizeof(*img) + debug_frame_size;
+
+    img->ehdr.e_ident[EI_MAG0] = ELFMAG0;
+    img->ehdr.e_ident[EI_MAG1] = ELFMAG1;
+    img->ehdr.e_ident[EI_MAG2] = ELFMAG2;
+    img->ehdr.e_ident[EI_MAG3] = ELFMAG3;
+    img->ehdr.e_ident[EI_CLASS] = ELF_CLASS;
+    img->ehdr.e_ident[EI_DATA] = ELF_DATA;
+    img->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+    img->ehdr.e_type = ET_EXEC;
+    img->ehdr.e_machine = ELF_HOST_MACHINE;
+    img->ehdr.e_version = EV_CURRENT;
+    img->ehdr.e_phoff = offsetof(struct ElfImage, phdr);
+    img->ehdr.e_shoff = offsetof(struct ElfImage, shdr);
+    img->ehdr.e_ehsize = sizeof(ElfW(Shdr));
+    img->ehdr.e_phentsize = sizeof(ElfW(Phdr));
+    img->ehdr.e_phnum = 1;
+    img->ehdr.e_shentsize = sizeof(img->shdr[0]);
+    img->ehdr.e_shnum = ARRAY_SIZE(img->shdr);
+    img->ehdr.e_shstrndx = ARRAY_SIZE(img->shdr) - 1;
+
+    img->phdr.p_type = PT_LOAD;
+    img->phdr.p_offset = (char *)buf - (char *)img;
+    img->phdr.p_vaddr = (ElfW(Addr))buf;
+    img->phdr.p_paddr = img->phdr.p_vaddr;
+    img->phdr.p_filesz = buf_size;
+    img->phdr.p_memsz = buf_size;
+    img->phdr.p_flags = PF_X;
+
+    memcpy(img->str, strings, sizeof(img->str));
+
+    img->shdr[0].sh_type = SHT_NULL;
+
+    img->shdr[1].sh_name = find_string(img->str, ".text");
+    img->shdr[1].sh_type = SHT_PROGBITS;
+    img->shdr[1].sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+    img->shdr[1].sh_addr = (ElfW(Addr))buf + grab;
+    img->shdr[1].sh_offset = grab;
+    img->shdr[1].sh_size = buf_size - grab;
+
+    img->shdr[2].sh_name = find_string(img->str, ".debug_frame");
+    img->shdr[2].sh_type = SHT_PROGBITS;
+    img->shdr[2].sh_offset = sizeof(*img);
+    img->shdr[2].sh_size = debug_frame_size;
+    memcpy(img + 1, debug_frame, debug_frame_size);
+
+    img->shdr[3].sh_name = find_string(img->str, ".symtab");
+    img->shdr[3].sh_type = SHT_SYMTAB;
+    img->shdr[3].sh_offset = offsetof(struct ElfImage, sym);
+    img->shdr[3].sh_size = sizeof(img->sym);
+    img->shdr[3].sh_info = ARRAY_SIZE(img->sym);
+    img->shdr[3].sh_link = img->ehdr.e_shstrndx;
+    img->shdr[3].sh_entsize = sizeof(ElfW(Sym));
+
+    img->shdr[4].sh_name = find_string(img->str, ".strtab");
+    img->shdr[4].sh_type = SHT_STRTAB;
+    img->shdr[4].sh_offset = offsetof(struct ElfImage, str);
+    img->shdr[4].sh_size = sizeof(img->str);
+
+    img->sym[0].st_name = find_string(img->str, "code_gen_buffer");
+    img->sym[0].st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
+    img->sym[0].st_shndx = 1;
+    img->sym[0].st_value = (ElfW(Addr))buf + grab;
+    img->sym[0].st_size = buf_size - grab;
+
+#if 0
+    /* Enable this block to be able to debug the ELF image file creation.
+       One can use readelf, objdump, or other inspection utilities.  */
+    {
+        FILE *f = fopen("/tmp/qemu.jit", "w+b");
+        if (f) {
+            if (fwrite(buf, buf_size, 1, f) != buf_size) {
+                /* Avoid stupid unused return value warning for fwrite.  */
+            }
+            fclose(f);
+        }
+    }
+#endif
+
+    one_entry.symfile_addr = buf;
+    one_entry.symfile_size = buf_size;
+
+    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+    __jit_debug_descriptor.relevant_entry = &one_entry;
+    __jit_debug_descriptor.first_entry = &one_entry;
+    __jit_debug_register_code();
+
+    return grab;
+}
+#else
+/* No support for the feature.  Provide the entry point expected by exec.c.  */
+size_t tcg_register_jit(void *buf, size_t buf_size)
+{
+    return 0;
+}
+#endif /* ELF_HOST_MACHINE */
diff --git a/tcg/tcg.h b/tcg/tcg.h
index dc5e9c9..3d2e5d0 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -574,3 +574,5 @@ extern uint8_t code_gen_prologue[];
 #define tcg_qemu_tb_exec(env, tb_ptr)                                    \
     ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
 #endif
+
+size_t tcg_register_jit(void *, size_t);
-- 
1.7.6.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
  2011-09-29 23:46 [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface Richard Henderson
@ 2011-09-30  7:12 ` Jan Kiszka
  2011-09-30 14:36   ` Richard Henderson
  0 siblings, 1 reply; 8+ messages in thread
From: Jan Kiszka @ 2011-09-30  7:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gdb, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 16690 bytes --]

On 2011-09-30 01:46, Richard Henderson wrote:
> This allows us to generate unwind info for the dynamicly generated
> code in the code_gen_buffer.  Only i386 is converted at this point.
> 
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  elf.h                 |    1 +
>  exec.c                |    9 +++
>  tcg/i386/tcg-target.c |  125 +++++++++++++++++++++++++++++++---
>  tcg/tcg.c             |  185 +++++++++++++++++++++++++++++++++++++++++++++++++
>  tcg/tcg.h             |    2 +
>  5 files changed, 313 insertions(+), 9 deletions(-)
> 
> 
> It's somewhat unfortunate, but the GDB interface requires that we
> build a contiguous ELF image.  This means we can't place the ELF
> header that we generate any place except the beginning of the
> code_gen_buffer.  While tedious, this isn't terribly difficult.
> 
> With this patch, I now get:
> 
> Breakpoint 1, __ldb_mmu (addr=1001716, mmu_idx=0)
>     at /home/rth/work/qemu/qemu/softmmu_template.h:86
> 86	{
> (gdb) where
> #0  __ldb_mmu (addr=1001716, mmu_idx=0)
>     at /home/rth/work/qemu/qemu/softmmu_template.h:86
> #1  0x0000000040000afc in ?? ()
> #2  0x000000000053e85c in cpu_x86_exec (env=0x1208d80)
>     at /home/rth/work/qemu/qemu/cpu-exec.c:565
> #3  0x0000000000542932 in tcg_cpu_exec (env=0x1208d80)
>     at /home/rth/work/qemu/qemu/cpus.c:913
> #4  cpu_exec_all () at /home/rth/work/qemu/qemu/cpus.c:949
> #5  0x0000000000542ad5 in qemu_tcg_cpu_thread_fn (arg=<optimized out>)
>     at /home/rth/work/qemu/qemu/cpus.c:688
> #6  0x00000033f1a07b31 in start_thread () from /lib64/libpthread.so.0
> #7  0x00000033f16dfd2d in clone () from /lib64/libc.so.6
> 
> which is nicely correct.

Cool.

Would it be possible to tag translated code as well? At TB or maybe even
input instruction level? Only in debugging mode of course.

> 
> Comments from the gdb folk are welcome.
> 
> 
> r~
> 
> 
> 
> diff --git a/elf.h b/elf.h
> index 2e05d34..1e56a8c 100644
> --- a/elf.h
> +++ b/elf.h
> @@ -216,6 +216,7 @@ typedef int64_t  Elf64_Sxword;
>  
>  #define ELF_ST_BIND(x)		((x) >> 4)
>  #define ELF_ST_TYPE(x)		(((unsigned int) x) & 0xf)
> +#define ELF_ST_INFO(bind,type)	(((bind) << 4) | (type))
>  #define ELF32_ST_BIND(x)	ELF_ST_BIND(x)
>  #define ELF32_ST_TYPE(x)	ELF_ST_TYPE(x)
>  #define ELF64_ST_BIND(x)	ELF_ST_BIND(x)
> diff --git a/exec.c b/exec.c
> index 1e6f732..f6c07d5 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -464,6 +464,8 @@ static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
>  
>  static void code_gen_alloc(unsigned long tb_size)
>  {
> +    size_t grab;
> +
>  #ifdef USE_STATIC_CODE_GEN_BUFFER
>      code_gen_buffer = static_code_gen_buffer;
>      code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
> @@ -558,6 +560,13 @@ static void code_gen_alloc(unsigned long tb_size)
>      map_exec(code_gen_buffer, code_gen_buffer_size);
>  #endif
>  #endif /* !USE_STATIC_CODE_GEN_BUFFER */
> +
> +    /* Give GDB unwind info for the code we generate.  This grabs a small
> +       amount of space from the front of the buffer.  Account for it.  */
> +    grab = tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
> +    code_gen_buffer += grab;
> +    code_gen_buffer_size -= grab;
> +
>      map_exec(code_gen_prologue, sizeof(code_gen_prologue));
>      code_gen_buffer_max_size = code_gen_buffer_size -
>          (TCG_MAX_OP_SIZE * OPC_BUF_SIZE);
> diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
> index 281f87d..462f455 100644
> --- a/tcg/i386/tcg-target.c
> +++ b/tcg/i386/tcg-target.c
> @@ -1913,22 +1913,29 @@ static int tcg_target_callee_save_regs[] = {
>  #endif
>  };
>  
> +/* Compute frame size via macros, to share between tcg_target_qemu_prologue
> +   and tcg_register_jit.  */
> +
> +#define PUSH_SIZE \
> +    ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
> +     * (TCG_TARGET_REG_BITS / 8))
> +
> +#define FRAME_SIZE \
> +    ((PUSH_SIZE \
> +      + TCG_STATIC_CALL_ARGS_SIZE \
> +      + CPU_TEMP_BUF_NLONGS * sizeof(long) \
> +      + TCG_TARGET_STACK_ALIGN - 1) \
> +     & ~(TCG_TARGET_STACK_ALIGN - 1))
> +
>  /* Generate global QEMU prologue and epilogue code */
>  static void tcg_target_qemu_prologue(TCGContext *s)
>  {
> -    int i, frame_size, push_size, stack_addend;
> +    int i, stack_addend;
>  
>      /* TB prologue */
>  
>      /* Reserve some stack space, also for TCG temps.  */
> -    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
> -    push_size *= TCG_TARGET_REG_BITS / 8;
> -
> -    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
> -        CPU_TEMP_BUF_NLONGS * sizeof(long);
> -    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
> -        ~(TCG_TARGET_STACK_ALIGN - 1);
> -    stack_addend = frame_size - push_size;
> +    stack_addend = FRAME_SIZE - PUSH_SIZE;
>      tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
>                    CPU_TEMP_BUF_NLONGS * sizeof(long));
>  
> @@ -1988,3 +1995,103 @@ static void tcg_target_init(TCGContext *s)
>  
>      tcg_add_target_add_op_defs(x86_op_defs);
>  }
> +
> +extern char debug_frame[];
> +extern char debug_frame_end[];
> +extern void *debug_frame_code_start;
> +extern size_t debug_frame_code_len;
> +extern char debug_frame_frame_size[];
> +
> +#if TCG_TARGET_REG_BITS == 64
> +#define ELF_HOST_MACHINE EM_X86_64
> +asm(".data\n"
> +"	.align 8\n"
> +"debug_frame:\n"
> +"	.long	99f-0f\n"	/* Length of CIE */
> +"0:	.long	-1\n"		/* CIE identifier */
> +"	.byte	1\n"		/* CIE version */
> +"	.byte	0\n"		/* CIE augmentation (none) */
> +"	.byte	1\n"		/* CIE code alignment factor */
> +"	.byte	0x78\n"		/* CIE data alignment factor (sleb128 -8) */
> +"	.byte	16\n"		/* CIE return address column */
> +"	.align 8\n"
> +"99:\n"				/* End of CIE */
> +"	.long	99f-0f\n"	/* Length of FDE */
> +"0:	.long	0\n"		/* FDE CIE offset (start of section) */
> +"debug_frame_code_start:\n"
> +"	.quad	0\n"		/* FDE start (to be filled in) */
> +"debug_frame_code_len:\n"
> +"	.quad	0\n"		/* FDE length (to be filled in) */
> +"	.byte	12\n"		/* DW_CFA_def_cfa */
> +"	.byte	7\n"		/*   %rsp */
> +"debug_frame_frame_size:\n"
> +"	.byte	0, 0\n"		/*   frame_size (to be filled in) */
> +"	.byte	0x90, 1\n"	/* DW_CFA_offset, %rip, -8 */
> +/* The following ordering must match tcg_target_callee_save_regs.  */
> +"	.byte	0x86, 2\n"	/* DW_CFA_offset, %rbp, -16 */
> +"	.byte	0x83, 3\n"	/* DW_CFA_offset, %rbx, -24 */
> +"	.byte	0x8c, 4\n"	/* DW_CFA_offset, %r12, -32 */
> +"	.byte	0x8d, 5\n"	/* DW_CFA_offset, %r13, -40 */
> +"	.byte	0x8e, 6\n"	/* DW_CFA_offset, %r14, -48 */
> +"	.byte	0x8f, 7\n"	/* DW_CFA_offset, %r15, -56 */
> +"	.align	8\n"
> +"99:\n"				/* End of FDE */
> +"debug_frame_end:\n"
> +".previous"
> +);
> +#else
> +#define ELF_HOST_MACHINE EM_386
> +asm(".data\n"
> +"	.align 4\n"
> +"debug_frame:\n"
> +"	.long	99f-0f\n"	/* Length of CIE */
> +"0:	.long	-1\n"		/* CIE identifier */
> +"	.byte	1\n"		/* CIE version */
> +"	.byte	0\n"		/* CIE augmentation (none) */
> +"	.byte	1\n"		/* CIE code alignment factor */
> +"	.byte	0x7c\n"		/* CIE data alignment factor (sleb128 -4) */
> +"	.byte	8\n"		/* CIE return address column */
> +"	.align 4\n"
> +"99:\n"				/* End of CIE */
> +"	.long	99f-0f\n"	/* Length of FDE */
> +"0:	.long	0\n"		/* FDE CIE offset (start of section) */
> +"debug_frame_code_start:\n"
> +"	.long	0\n"		/* FDE start (to be filled in) */
> +"debug_frame_code_len:\n"
> +"	.long	0\n"		/* FDE length (to be filled in) */
> +"	.byte	12\n"		/* DW_CFA_def_cfa */
> +"	.byte	4\n"		/*   %rsp */
> +"debug_frame_frame_size:\n"
> +"	.byte	0, 0\n"		/*   frame_size (to be filled in) */
> +"	.byte	0x88, 1\n"	/* DW_CFA_offset, %eip, -4 */
> +/* The following ordering must match tcg_target_callee_save_regs.  */
> +"	.byte	0x85, 2\n"	/* DW_CFA_offset, %ebp, -8 */
> +"	.byte	0x83, 3\n"	/* DW_CFA_offset, %ebx, -12 */
> +"	.byte	0x86, 4\n"	/* DW_CFA_offset, %esi, -16 */
> +"	.byte	0x87, 5\n"	/* DW_CFA_offset, %edi, -20 */
> +"	.align	4\n"
> +"99:\n"				/* End of FDE */
> +"debug_frame_end:\n"
> +".previous"
> +);
> +#endif
> +
> +size_t tcg_register_jit(void *buf, size_t buf_size)
> +{
> +    const unsigned int frame_size = FRAME_SIZE;
> +    unsigned int f_lo, f_hi;
> +
> +    /* ??? These could be filled in generically via reading the debug data.  */
> +    debug_frame_code_start = buf;
> +    debug_frame_code_len = buf_size;
> +
> +    /* ??? We're expecting a 2 byte uleb128 encoded value.  */
> +    f_lo = (frame_size & 0x7f) | 0x80;
> +    f_hi = frame_size >> 7;
> +    assert(frame_size >> 14 == 0);
> +    debug_frame_frame_size[0] = f_lo;
> +    debug_frame_frame_size[1] = f_hi;
> +
> +    return tcg_register_jit_int(buf, buf_size, debug_frame,
> +                                debug_frame_end - debug_frame);
> +}
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index 411f971..63d81f9 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -57,6 +57,18 @@
>  #include "cpu.h"
>  
>  #include "tcg-op.h"
> +
> +#if TCG_TARGET_REG_BITS == 64
> +# define ELF_CLASS  ELFCLASS64
> +#else
> +# define ELF_CLASS  ELFCLASS32
> +#endif
> +#ifdef HOST_WORDS_BIGENDIAN
> +# define ELF_DATA   ELFDATA2MSB
> +#else
> +# define ELF_DATA   ELFDATA2LSB
> +#endif
> +
>  #include "elf.h"
>  
>  #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
> @@ -68,6 +80,9 @@ static void tcg_target_qemu_prologue(TCGContext *s);
>  static void patch_reloc(uint8_t *code_ptr, int type, 
>                          tcg_target_long value, tcg_target_long addend);
>  
> +static size_t tcg_register_jit_int(void *buf, size_t size,
> +                                   void *debug_frame, size_t debug_frame_size);
> +
>  TCGOpDef tcg_op_defs[] = {
>  #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
>  #include "tcg-opc.h"
> @@ -2233,3 +2248,173 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
>      cpu_fprintf(f, "[TCG profiler not compiled]\n");
>  }
>  #endif
> +
> +#ifdef ELF_HOST_MACHINE
> +/* The backend should define ELF_HOST_MACHINE to indicate both what value to
> +   put into the ELF image and to indicate support for the feature.  */
> +
> +/* Begin GDB interface.  The following must match the docs.  */
> +typedef enum
> +{
> +    JIT_NOACTION = 0,
> +    JIT_REGISTER_FN,
> +    JIT_UNREGISTER_FN
> +} jit_actions_t;
> +
> +struct jit_code_entry {
> +    struct jit_code_entry *next_entry;
> +    struct jit_code_entry *prev_entry;
> +    const char *symfile_addr;
> +    uint64_t symfile_size;
> +};
> +
> +struct jit_descriptor {
> +    uint32_t version;
> +    uint32_t action_flag;
> +    struct jit_code_entry *relevant_entry;
> +    struct jit_code_entry *first_entry;
> +};
> +
> +void __jit_debug_register_code(void);
> +void __attribute__((noinline)) __jit_debug_register_code(void)

Leading '_' are reserved for the system and tabu for the application (we
have some other violations, yes).

> +{
> +    asm("");
> +}
> +
> +/* Must statically initialize the version, because GDB may check
> +   the version before we can set it.  */
> +struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
> +
> +/* End GDB interface.  */
> +
> +static int find_string(const char *strtab, const char *str)
> +{
> +    const char *p = strtab + 1;
> +
> +    while (1) {
> +        if (strcmp(p, str) == 0) {
> +            return p - strtab;
> +        }
> +        p += strlen(p) + 1;
> +    }
> +}
> +
> +static size_t tcg_register_jit_int(void *buf, size_t buf_size,
> +                                   void *debug_frame, size_t debug_frame_size)
> +{
> +    static const char strings[64] =
> +        "\0"
> +        ".text\0"
> +        ".debug_frame\0"
> +        ".symtab\0"
> +        ".strtab\0"
> +        "code_gen_buffer";
> +
> +    struct ElfImage {
> +        ElfW(Ehdr) ehdr;
> +        ElfW(Phdr) phdr;
> +        ElfW(Shdr) shdr[5];
> +        ElfW(Sym)  sym[1];
> +        char       str[64];
> +    };
> +
> +    /* We only need a single jit entry; statically allocate it.  */
> +    static struct jit_code_entry one_entry;
> +
> +    struct ElfImage *img = buf;
> +    size_t grab = sizeof(*img) + debug_frame_size;
> +
> +    img->ehdr.e_ident[EI_MAG0] = ELFMAG0;
> +    img->ehdr.e_ident[EI_MAG1] = ELFMAG1;
> +    img->ehdr.e_ident[EI_MAG2] = ELFMAG2;
> +    img->ehdr.e_ident[EI_MAG3] = ELFMAG3;
> +    img->ehdr.e_ident[EI_CLASS] = ELF_CLASS;
> +    img->ehdr.e_ident[EI_DATA] = ELF_DATA;
> +    img->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
> +    img->ehdr.e_type = ET_EXEC;
> +    img->ehdr.e_machine = ELF_HOST_MACHINE;
> +    img->ehdr.e_version = EV_CURRENT;
> +    img->ehdr.e_phoff = offsetof(struct ElfImage, phdr);
> +    img->ehdr.e_shoff = offsetof(struct ElfImage, shdr);
> +    img->ehdr.e_ehsize = sizeof(ElfW(Shdr));
> +    img->ehdr.e_phentsize = sizeof(ElfW(Phdr));
> +    img->ehdr.e_phnum = 1;
> +    img->ehdr.e_shentsize = sizeof(img->shdr[0]);
> +    img->ehdr.e_shnum = ARRAY_SIZE(img->shdr);
> +    img->ehdr.e_shstrndx = ARRAY_SIZE(img->shdr) - 1;
> +
> +    img->phdr.p_type = PT_LOAD;
> +    img->phdr.p_offset = (char *)buf - (char *)img;
> +    img->phdr.p_vaddr = (ElfW(Addr))buf;
> +    img->phdr.p_paddr = img->phdr.p_vaddr;
> +    img->phdr.p_filesz = buf_size;
> +    img->phdr.p_memsz = buf_size;
> +    img->phdr.p_flags = PF_X;
> +
> +    memcpy(img->str, strings, sizeof(img->str));
> +
> +    img->shdr[0].sh_type = SHT_NULL;
> +
> +    img->shdr[1].sh_name = find_string(img->str, ".text");
> +    img->shdr[1].sh_type = SHT_PROGBITS;
> +    img->shdr[1].sh_flags = SHF_EXECINSTR | SHF_ALLOC;
> +    img->shdr[1].sh_addr = (ElfW(Addr))buf + grab;
> +    img->shdr[1].sh_offset = grab;
> +    img->shdr[1].sh_size = buf_size - grab;
> +
> +    img->shdr[2].sh_name = find_string(img->str, ".debug_frame");
> +    img->shdr[2].sh_type = SHT_PROGBITS;
> +    img->shdr[2].sh_offset = sizeof(*img);
> +    img->shdr[2].sh_size = debug_frame_size;
> +    memcpy(img + 1, debug_frame, debug_frame_size);
> +
> +    img->shdr[3].sh_name = find_string(img->str, ".symtab");
> +    img->shdr[3].sh_type = SHT_SYMTAB;
> +    img->shdr[3].sh_offset = offsetof(struct ElfImage, sym);
> +    img->shdr[3].sh_size = sizeof(img->sym);
> +    img->shdr[3].sh_info = ARRAY_SIZE(img->sym);
> +    img->shdr[3].sh_link = img->ehdr.e_shstrndx;
> +    img->shdr[3].sh_entsize = sizeof(ElfW(Sym));
> +
> +    img->shdr[4].sh_name = find_string(img->str, ".strtab");
> +    img->shdr[4].sh_type = SHT_STRTAB;
> +    img->shdr[4].sh_offset = offsetof(struct ElfImage, str);
> +    img->shdr[4].sh_size = sizeof(img->str);
> +
> +    img->sym[0].st_name = find_string(img->str, "code_gen_buffer");
> +    img->sym[0].st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
> +    img->sym[0].st_shndx = 1;
> +    img->sym[0].st_value = (ElfW(Addr))buf + grab;
> +    img->sym[0].st_size = buf_size - grab;
> +
> +#if 0

#ifdef DEBUG_ELF_GENERATION or so?

> +    /* Enable this block to be able to debug the ELF image file creation.
> +       One can use readelf, objdump, or other inspection utilities.  */
> +    {
> +        FILE *f = fopen("/tmp/qemu.jit", "w+b");
> +        if (f) {
> +            if (fwrite(buf, buf_size, 1, f) != buf_size) {
> +                /* Avoid stupid unused return value warning for fwrite.  */
> +            }
> +            fclose(f);
> +        }
> +    }
> +#endif
> +
> +    one_entry.symfile_addr = buf;
> +    one_entry.symfile_size = buf_size;
> +
> +    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
> +    __jit_debug_descriptor.relevant_entry = &one_entry;
> +    __jit_debug_descriptor.first_entry = &one_entry;
> +    __jit_debug_register_code();
> +
> +    return grab;
> +}
> +#else
> +/* No support for the feature.  Provide the entry point expected by exec.c.  */
> +size_t tcg_register_jit(void *buf, size_t buf_size)
> +{
> +    return 0;
> +}
> +#endif /* ELF_HOST_MACHINE */
> diff --git a/tcg/tcg.h b/tcg/tcg.h
> index dc5e9c9..3d2e5d0 100644
> --- a/tcg/tcg.h
> +++ b/tcg/tcg.h
> @@ -574,3 +574,5 @@ extern uint8_t code_gen_prologue[];
>  #define tcg_qemu_tb_exec(env, tb_ptr)                                    \
>      ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
>  #endif
> +
> +size_t tcg_register_jit(void *, size_t);

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
  2011-09-30  7:12 ` Jan Kiszka
@ 2011-09-30 14:36   ` Richard Henderson
  2011-10-02  2:04     ` Daniel Jacobowitz
  0 siblings, 1 reply; 8+ messages in thread
From: Richard Henderson @ 2011-09-30 14:36 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: gdb, qemu-devel

On 09/30/2011 12:12 AM, Jan Kiszka wrote:
>> Breakpoint 1, __ldb_mmu (addr=1001716, mmu_idx=0)
>>     at /home/rth/work/qemu/qemu/softmmu_template.h:86
>> 86	{
>> (gdb) where
>> #0  __ldb_mmu (addr=1001716, mmu_idx=0)
>>     at /home/rth/work/qemu/qemu/softmmu_template.h:86
>> #1  0x0000000040000afc in ?? ()
...
> Would it be possible to tag translated code as well? At TB or maybe even
> input instruction level? Only in debugging mode of course.

I don't know.  A couple of points on that:

(1) I was rather expecting frame 1 above to be marked "code_gen_buffer"
    rather than "??".  I *did* install that symbol in the generated 
    ELF image as a function covering the entire buffer.  So I'm not
    quite sure why GDB didn't use it.

(2) If we wanted to mark stuff individually, then we would have to
    manipulate the symbol table presented to GDB.  One could do this
    either via separate ELF images for each TB (overhead ~600 bytes
    per TB, more if we mark input insns), or via un-registering and
    re-registering the "main" ELF image after having manipulated the
    symbol table.  Of course, in the later case the layout of the ELF
    image would get tricky, as the symbol table expands and overruns
    existing TBs.

So, "probably not" is my answer.

>> +/* Begin GDB interface.  The following must match the docs.  */
...
>> +void __jit_debug_register_code(void);
>> +void __attribute__((noinline)) __jit_debug_register_code(void)
> 
> Leading '_' are reserved for the system and tabu for the application (we
> have some other violations, yes).

We have no choice here -- we must use exactly what GDB documents.

>> +#if 0
> 
> #ifdef DEBUG_ELF_GENERATION or so?

Sure.


r~

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
  2011-09-30 14:36   ` Richard Henderson
@ 2011-10-02  2:04     ` Daniel Jacobowitz
  0 siblings, 0 replies; 8+ messages in thread
From: Daniel Jacobowitz @ 2011-10-02  2:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gdb, Jan Kiszka, qemu-devel

On Fri, Sep 30, 2011 at 10:36 AM, Richard Henderson <rth@twiddle.net> wrote:
> On 09/30/2011 12:12 AM, Jan Kiszka wrote:
>>> Breakpoint 1, __ldb_mmu (addr=1001716, mmu_idx=0)
>>>     at /home/rth/work/qemu/qemu/softmmu_template.h:86
>>> 86   {
>>> (gdb) where
>>> #0  __ldb_mmu (addr=1001716, mmu_idx=0)
>>>     at /home/rth/work/qemu/qemu/softmmu_template.h:86
>>> #1  0x0000000040000afc in ?? ()
> ...
>> Would it be possible to tag translated code as well? At TB or maybe even
>> input instruction level? Only in debugging mode of course.
>
> I don't know.  A couple of points on that:
>
> (1) I was rather expecting frame 1 above to be marked "code_gen_buffer"
>    rather than "??".  I *did* install that symbol in the generated
>    ELF image as a function covering the entire buffer.  So I'm not
>    quite sure why GDB didn't use it.

Totally wild guess: associated with the wrong section?  I don't
remember what we do w.r.t. ABS in shared libraries, but for non-ABS we
do validate what section we think things are in.  And I'm not sure if
we load section info in the JIT loader, either.

-- 
Thanks,
Daniel

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
  2012-03-24 16:11   ` Blue Swirl
@ 2012-03-24 17:04     ` Peter Maydell
  0 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2012-03-24 17:04 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel, Richard Henderson

Er, this is the v2 patch, which Richard updated based on review
comments, can you apply the later v3 one instead?

thanks
-- PMM

On 24 March 2012 16:11, Blue Swirl <blauwirbel@gmail.com> wrote:
> Thanks, applied.
>
> On Mon, Mar 19, 2012 at 19:25, Richard Henderson <rth@twiddle.net> wrote:
>> This allows us to generate unwind info for the dynamicly generated
>> code in the code_gen_buffer.  Only i386 is converted at this point.
>>
>> Signed-off-by: Richard Henderson <rth@twiddle.net>
>> ---
>>  elf.h                 |    1 +
>>  exec.c                |    1 +
>>  tcg/i386/tcg-target.c |  114 ++++++++++++++++++++++++++--
>>  tcg/tcg.c             |  194 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  tcg/tcg.h             |    2 +
>>  5 files changed, 303 insertions(+), 9 deletions(-)
>>
>> diff --git a/elf.h b/elf.h
>> index 2e05d34..310e05a 100644
>> --- a/elf.h
>> +++ b/elf.h
>> @@ -216,6 +216,7 @@ typedef int64_t  Elf64_Sxword;
>>
>>  #define ELF_ST_BIND(x)         ((x) >> 4)
>>  #define ELF_ST_TYPE(x)         (((unsigned int) x) & 0xf)
>> +#define ELF_ST_INFO(bind, type) (((bind) << 4) | ((type) & 0xf))
>>  #define ELF32_ST_BIND(x)       ELF_ST_BIND(x)
>>  #define ELF32_ST_TYPE(x)       ELF_ST_TYPE(x)
>>  #define ELF64_ST_BIND(x)       ELF_ST_BIND(x)
>> diff --git a/exec.c b/exec.c
>> index be392e2..dd24939 100644
>> --- a/exec.c
>> +++ b/exec.c
>> @@ -636,6 +636,7 @@ void tcg_exec_init(unsigned long tb_size)
>>     cpu_gen_init();
>>     code_gen_alloc(tb_size);
>>     code_gen_ptr = code_gen_buffer;
>> +    tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
>>     page_init();
>>  #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
>>     /* There's no guest base to take into account, so go ahead and
>> diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
>> index 43a51a1..871a7e7 100644
>> --- a/tcg/i386/tcg-target.c
>> +++ b/tcg/i386/tcg-target.c
>> @@ -1989,22 +1989,29 @@ static int tcg_target_callee_save_regs[] = {
>>  #endif
>>  };
>>
>> +/* Compute frame size via macros, to share between tcg_target_qemu_prologue
>> +   and tcg_register_jit.  */
>> +
>> +#define PUSH_SIZE \
>> +    ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
>> +     * (TCG_TARGET_REG_BITS / 8))
>> +
>> +#define FRAME_SIZE \
>> +    ((PUSH_SIZE \
>> +      + TCG_STATIC_CALL_ARGS_SIZE \
>> +      + CPU_TEMP_BUF_NLONGS * sizeof(long) \
>> +      + TCG_TARGET_STACK_ALIGN - 1) \
>> +     & ~(TCG_TARGET_STACK_ALIGN - 1))
>> +
>>  /* Generate global QEMU prologue and epilogue code */
>>  static void tcg_target_qemu_prologue(TCGContext *s)
>>  {
>> -    int i, frame_size, push_size, stack_addend;
>> +    int i, stack_addend;
>>
>>     /* TB prologue */
>>
>>     /* Reserve some stack space, also for TCG temps.  */
>> -    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
>> -    push_size *= TCG_TARGET_REG_BITS / 8;
>> -
>> -    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
>> -        CPU_TEMP_BUF_NLONGS * sizeof(long);
>> -    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
>> -        ~(TCG_TARGET_STACK_ALIGN - 1);
>> -    stack_addend = frame_size - push_size;
>> +    stack_addend = FRAME_SIZE - PUSH_SIZE;
>>     tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
>>                   CPU_TEMP_BUF_NLONGS * sizeof(long));
>>
>> @@ -2070,3 +2077,92 @@ static void tcg_target_init(TCGContext *s)
>>
>>     tcg_add_target_add_op_defs(x86_op_defs);
>>  }
>> +
>> +typedef struct {
>> +    uint32_t len __attribute__((aligned((sizeof(void *)))));
>> +    uint32_t id;
>> +    uint8_t version;
>> +    char augmentation[1];
>> +    uint8_t code_align;
>> +    uint8_t data_align;
>> +    uint8_t return_column;
>> +} DebugFrameCIE;
>> +
>> +typedef struct {
>> +    uint32_t len __attribute__((aligned((sizeof(void *)))));
>> +    uint32_t cie_offset;
>> +    tcg_target_long func_start __attribute__((packed));
>> +    tcg_target_long func_len __attribute__((packed));
>> +    uint8_t def_cfa[4];
>> +    uint8_t reg_ofs[14];
>> +} DebugFrameFDE;
>> +
>> +typedef struct {
>> +    DebugFrameCIE cie;
>> +    DebugFrameFDE fde;
>> +} DebugFrame;
>> +
>> +#if TCG_TARGET_REG_BITS == 64
>> +#define ELF_HOST_MACHINE EM_X86_64
>> +static DebugFrame debug_frame = {
>> +    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
>> +    .cie.id = -1,
>> +    .cie.version = 1,
>> +    .cie.code_align = 1,
>> +    .cie.data_align = 0x78,             /* sleb128 -8 */
>> +    .cie.return_column = 16,
>> +
>> +    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
>> +    .fde.def_cfa = {
>> +        12, 7,                          /* DW_CFA_def_cfa %rsp, ... */
>> +        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
>> +        (FRAME_SIZE >> 7)
>> +    },
>> +    .fde.reg_ofs = {
>> +        0x90, 1,                        /* DW_CFA_offset, %rip, -8 */
>> +        /* The following ordering must match tcg_target_callee_save_regs.  */
>> +        0x86, 2,                        /* DW_CFA_offset, %rbp, -16 */
>> +        0x83, 3,                        /* DW_CFA_offset, %rbx, -24 */
>> +        0x8c, 4,                        /* DW_CFA_offset, %r12, -32 */
>> +        0x8d, 5,                        /* DW_CFA_offset, %r13, -40 */
>> +        0x8e, 6,                        /* DW_CFA_offset, %r14, -48 */
>> +        0x8f, 7,                        /* DW_CFA_offset, %r15, -56 */
>> +    }
>> +};
>> +#else
>> +#define ELF_HOST_MACHINE EM_386
>> +static DebugFrame debug_frame = {
>> +    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
>> +    .cie.id = -1,
>> +    .cie.version = 1,
>> +    .cie.code_align = 1,
>> +    .cie.data_align = 0x7c,             /* sleb128 -4 */
>> +    .cie.return_column = 8,
>> +
>> +    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
>> +    .fde.def_cfa = {
>> +        12, 4,                          /* DW_CFA_def_cfa %esp, ... */
>> +        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
>> +        (FRAME_SIZE >> 7)
>> +    },
>> +    .fde.reg_ofs = {
>> +        0x88, 1,                        /* DW_CFA_offset, %eip, -4 */
>> +        /* The following ordering must match tcg_target_callee_save_regs.  */
>> +        0x85, 2,                        /* DW_CFA_offset, %ebp, -8 */
>> +        0x83, 3,                        /* DW_CFA_offset, %ebx, -12 */
>> +        0x86, 4,                        /* DW_CFA_offset, %esi, -16 */
>> +        0x87, 5,                        /* DW_CFA_offset, %edi, -20 */
>> +    }
>> +};
>> +#endif
>> +
>> +void tcg_register_jit(void *buf, size_t buf_size)
>> +{
>> +    /* We're expecting a 2 byte uleb128 encoded value.  */
>> +    assert(FRAME_SIZE >> 14 == 0);
>> +
>> +    debug_frame.fde.func_start = (tcg_target_long) buf;
>> +    debug_frame.fde.func_len = buf_size;
>> +
>> +    tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
>> +}
>> diff --git a/tcg/tcg.c b/tcg/tcg.c
>> index ccfcd1a..eb595ce 100644
>> --- a/tcg/tcg.c
>> +++ b/tcg/tcg.c
>> @@ -28,6 +28,9 @@
>>
>>  #include "config.h"
>>
>> +/* Define to jump the ELF file used to communicate with GDB.  */
>> +#undef DEBUG_JIT
>> +
>>  #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
>>  /* define it to suppress various consistency checks (faster) */
>>  #define NDEBUG
>> @@ -45,6 +48,18 @@
>>  #include "cpu.h"
>>
>>  #include "tcg-op.h"
>> +
>> +#if TCG_TARGET_REG_BITS == 64
>> +# define ELF_CLASS  ELFCLASS64
>> +#else
>> +# define ELF_CLASS  ELFCLASS32
>> +#endif
>> +#ifdef HOST_WORDS_BIGENDIAN
>> +# define ELF_DATA   ELFDATA2MSB
>> +#else
>> +# define ELF_DATA   ELFDATA2LSB
>> +#endif
>> +
>>  #include "elf.h"
>>
>>  #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
>> @@ -57,6 +72,10 @@ static void tcg_target_qemu_prologue(TCGContext *s);
>>  static void patch_reloc(uint8_t *code_ptr, int type,
>>                         tcg_target_long value, tcg_target_long addend);
>>
>> +static void tcg_register_jit_int(void *buf, size_t size,
>> +                                 void *debug_frame, size_t debug_frame_size)
>> +    __attribute__((unused));
>> +
>>  /* Forward declarations for functions declared and used in tcg-target.c. */
>>  static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
>>  static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
>> @@ -2231,3 +2250,178 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
>>     cpu_fprintf(f, "[TCG profiler not compiled]\n");
>>  }
>>  #endif
>> +
>> +#ifdef ELF_HOST_MACHINE
>> +/* The backend should define ELF_HOST_MACHINE to indicate both what value to
>> +   put into the ELF image and to indicate support for the feature.  */
>> +
>> +/* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
>> +typedef enum {
>> +    JIT_NOACTION = 0,
>> +    JIT_REGISTER_FN,
>> +    JIT_UNREGISTER_FN
>> +} jit_actions_t;
>> +
>> +struct jit_code_entry {
>> +    struct jit_code_entry *next_entry;
>> +    struct jit_code_entry *prev_entry;
>> +    const void *symfile_addr;
>> +    uint64_t symfile_size;
>> +};
>> +
>> +struct jit_descriptor {
>> +    uint32_t version;
>> +    uint32_t action_flag;
>> +    struct jit_code_entry *relevant_entry;
>> +    struct jit_code_entry *first_entry;
>> +};
>> +
>> +void __jit_debug_register_code(void) __attribute__((noinline));
>> +void __jit_debug_register_code(void)
>> +{
>> +    asm("");
>> +}
>> +
>> +/* Must statically initialize the version, because GDB may check
>> +   the version before we can set it.  */
>> +struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
>> +
>> +/* End GDB interface.  */
>> +
>> +static int find_string(const char *strtab, const char *str)
>> +{
>> +    const char *p = strtab + 1;
>> +
>> +    while (1) {
>> +        if (strcmp(p, str) == 0) {
>> +            return p - strtab;
>> +        }
>> +        p += strlen(p) + 1;
>> +    }
>> +}
>> +
>> +static void tcg_register_jit_int(void *buf, size_t buf_size,
>> +                                 void *debug_frame, size_t debug_frame_size)
>> +{
>> +    static const char strings[64] =
>> +        "\0"
>> +        ".text\0"
>> +        ".debug_frame\0"
>> +        ".symtab\0"
>> +        ".strtab\0"
>> +        "code_gen_buffer";
>> +
>> +    struct ElfImage {
>> +        ElfW(Ehdr) ehdr;
>> +        ElfW(Phdr) phdr;
>> +        ElfW(Shdr) shdr[5];
>> +        ElfW(Sym)  sym[1];
>> +        char       str[64];
>> +    };
>> +
>> +    /* We only need a single jit entry; statically allocate it.  */
>> +    static struct jit_code_entry one_entry;
>> +
>> +    size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
>> +    struct ElfImage *img = g_malloc0(img_size);
>> +
>> +    img->ehdr.e_ident[EI_MAG0] = ELFMAG0;
>> +    img->ehdr.e_ident[EI_MAG1] = ELFMAG1;
>> +    img->ehdr.e_ident[EI_MAG2] = ELFMAG2;
>> +    img->ehdr.e_ident[EI_MAG3] = ELFMAG3;
>> +    img->ehdr.e_ident[EI_CLASS] = ELF_CLASS;
>> +    img->ehdr.e_ident[EI_DATA] = ELF_DATA;
>> +    img->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
>> +    img->ehdr.e_type = ET_EXEC;
>> +    img->ehdr.e_machine = ELF_HOST_MACHINE;
>> +    img->ehdr.e_version = EV_CURRENT;
>> +    img->ehdr.e_phoff = offsetof(struct ElfImage, phdr);
>> +    img->ehdr.e_shoff = offsetof(struct ElfImage, shdr);
>> +    img->ehdr.e_ehsize = sizeof(ElfW(Shdr));
>> +    img->ehdr.e_phentsize = sizeof(ElfW(Phdr));
>> +    img->ehdr.e_phnum = 1;
>> +    img->ehdr.e_shentsize = sizeof(img->shdr[0]);
>> +    img->ehdr.e_shnum = ARRAY_SIZE(img->shdr);
>> +    img->ehdr.e_shstrndx = ARRAY_SIZE(img->shdr) - 1;
>> +
>> +    img->phdr.p_type = PT_LOAD;
>> +    img->phdr.p_offset = (char *)buf - (char *)img;
>> +    img->phdr.p_vaddr = (ElfW(Addr))buf;
>> +    img->phdr.p_paddr = img->phdr.p_vaddr;
>> +    img->phdr.p_filesz = 0;
>> +    img->phdr.p_memsz = buf_size;
>> +    img->phdr.p_flags = PF_X;
>> +
>> +    memcpy(img->str, strings, sizeof(img->str));
>> +
>> +    img->shdr[0].sh_type = SHT_NULL;
>> +
>> +    /* Trick: The contents of code_gen_buffer are not present in this fake
>> +       ELF file; that got allocated elsewhere, discontiguously.  Therefore
>> +       we mark .text as SHT_NOBITS (similar to .bss) so that readers will
>> +       not look for contents.  We can record any address at will.  */
>> +    img->shdr[1].sh_name = find_string(img->str, ".text");
>> +    img->shdr[1].sh_type = SHT_NOBITS;
>> +    img->shdr[1].sh_flags = SHF_EXECINSTR | SHF_ALLOC;
>> +    img->shdr[1].sh_addr = (ElfW(Addr))buf;
>> +    img->shdr[1].sh_size = buf_size;
>> +
>> +    img->shdr[2].sh_name = find_string(img->str, ".debug_frame");
>> +    img->shdr[2].sh_type = SHT_PROGBITS;
>> +    img->shdr[2].sh_offset = sizeof(*img);
>> +    img->shdr[2].sh_size = debug_frame_size;
>> +    memcpy(img + 1, debug_frame, debug_frame_size);
>> +
>> +    img->shdr[3].sh_name = find_string(img->str, ".symtab");
>> +    img->shdr[3].sh_type = SHT_SYMTAB;
>> +    img->shdr[3].sh_offset = offsetof(struct ElfImage, sym);
>> +    img->shdr[3].sh_size = sizeof(img->sym);
>> +    img->shdr[3].sh_info = ARRAY_SIZE(img->sym);
>> +    img->shdr[3].sh_link = img->ehdr.e_shstrndx;
>> +    img->shdr[3].sh_entsize = sizeof(ElfW(Sym));
>> +
>> +    img->shdr[4].sh_name = find_string(img->str, ".strtab");
>> +    img->shdr[4].sh_type = SHT_STRTAB;
>> +    img->shdr[4].sh_offset = offsetof(struct ElfImage, str);
>> +    img->shdr[4].sh_size = sizeof(img->str);
>> +
>> +    img->sym[0].st_name = find_string(img->str, "code_gen_buffer");
>> +    img->sym[0].st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
>> +    img->sym[0].st_shndx = 1;
>> +    img->sym[0].st_value = (ElfW(Addr))buf;
>> +    img->sym[0].st_size = buf_size;
>> +
>> +#ifdef DEBUG_JIT
>> +    /* Enable this block to be able to debug the ELF image file creation.
>> +       One can use readelf, objdump, or other inspection utilities.  */
>> +    {
>> +        FILE *f = fopen("/tmp/qemu.jit", "w+b");
>> +        if (f) {
>> +            if (fwrite(img, img_size, 1, f) != buf_size) {
>> +                /* Avoid stupid unused return value warning for fwrite.  */
>> +            }
>> +            fclose(f);
>> +        }
>> +    }
>> +#endif
>> +
>> +    one_entry.symfile_addr = img;
>> +    one_entry.symfile_size = img_size;
>> +
>> +    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
>> +    __jit_debug_descriptor.relevant_entry = &one_entry;
>> +    __jit_debug_descriptor.first_entry = &one_entry;
>> +    __jit_debug_register_code();
>> +}
>> +#else
>> +/* No support for the feature.  Provide the entry point expected by exec.c.  */
>> +
>> +static void tcg_register_jit_int(void *buf, size_t size,
>> +                                 void *debug_frame, size_t debug_frame_size)
>> +{
>> +}
>> +
>> +void tcg_register_jit(void *buf, size_t buf_size)
>> +{
>> +}
>> +#endif /* ELF_HOST_MACHINE */
>> diff --git a/tcg/tcg.h b/tcg/tcg.h
>> index 5f6c647..a83bddd 100644
>> --- a/tcg/tcg.h
>> +++ b/tcg/tcg.h
>> @@ -586,3 +586,5 @@ extern uint8_t code_gen_prologue[];
>>  # define tcg_qemu_tb_exec(env, tb_ptr) \
>>     ((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
>>  #endif
>> +
>> +void tcg_register_jit(void *buf, size_t buf_size);
>> --
>> 1.7.7.6
>>
>>
>



-- 
12345678901234567890123456789012345678901234567890123456789012345678901234567890
         1         2         3         4         5         6         7         8

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
  2012-03-19 19:25 ` [Qemu-devel] [PATCH] tcg: " Richard Henderson
@ 2012-03-24 16:11   ` Blue Swirl
  2012-03-24 17:04     ` Peter Maydell
  0 siblings, 1 reply; 8+ messages in thread
From: Blue Swirl @ 2012-03-24 16:11 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

Thanks, applied.

On Mon, Mar 19, 2012 at 19:25, Richard Henderson <rth@twiddle.net> wrote:
> This allows us to generate unwind info for the dynamicly generated
> code in the code_gen_buffer.  Only i386 is converted at this point.
>
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  elf.h                 |    1 +
>  exec.c                |    1 +
>  tcg/i386/tcg-target.c |  114 ++++++++++++++++++++++++++--
>  tcg/tcg.c             |  194 +++++++++++++++++++++++++++++++++++++++++++++++++
>  tcg/tcg.h             |    2 +
>  5 files changed, 303 insertions(+), 9 deletions(-)
>
> diff --git a/elf.h b/elf.h
> index 2e05d34..310e05a 100644
> --- a/elf.h
> +++ b/elf.h
> @@ -216,6 +216,7 @@ typedef int64_t  Elf64_Sxword;
>
>  #define ELF_ST_BIND(x)         ((x) >> 4)
>  #define ELF_ST_TYPE(x)         (((unsigned int) x) & 0xf)
> +#define ELF_ST_INFO(bind, type) (((bind) << 4) | ((type) & 0xf))
>  #define ELF32_ST_BIND(x)       ELF_ST_BIND(x)
>  #define ELF32_ST_TYPE(x)       ELF_ST_TYPE(x)
>  #define ELF64_ST_BIND(x)       ELF_ST_BIND(x)
> diff --git a/exec.c b/exec.c
> index be392e2..dd24939 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -636,6 +636,7 @@ void tcg_exec_init(unsigned long tb_size)
>     cpu_gen_init();
>     code_gen_alloc(tb_size);
>     code_gen_ptr = code_gen_buffer;
> +    tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
>     page_init();
>  #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
>     /* There's no guest base to take into account, so go ahead and
> diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
> index 43a51a1..871a7e7 100644
> --- a/tcg/i386/tcg-target.c
> +++ b/tcg/i386/tcg-target.c
> @@ -1989,22 +1989,29 @@ static int tcg_target_callee_save_regs[] = {
>  #endif
>  };
>
> +/* Compute frame size via macros, to share between tcg_target_qemu_prologue
> +   and tcg_register_jit.  */
> +
> +#define PUSH_SIZE \
> +    ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
> +     * (TCG_TARGET_REG_BITS / 8))
> +
> +#define FRAME_SIZE \
> +    ((PUSH_SIZE \
> +      + TCG_STATIC_CALL_ARGS_SIZE \
> +      + CPU_TEMP_BUF_NLONGS * sizeof(long) \
> +      + TCG_TARGET_STACK_ALIGN - 1) \
> +     & ~(TCG_TARGET_STACK_ALIGN - 1))
> +
>  /* Generate global QEMU prologue and epilogue code */
>  static void tcg_target_qemu_prologue(TCGContext *s)
>  {
> -    int i, frame_size, push_size, stack_addend;
> +    int i, stack_addend;
>
>     /* TB prologue */
>
>     /* Reserve some stack space, also for TCG temps.  */
> -    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
> -    push_size *= TCG_TARGET_REG_BITS / 8;
> -
> -    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
> -        CPU_TEMP_BUF_NLONGS * sizeof(long);
> -    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
> -        ~(TCG_TARGET_STACK_ALIGN - 1);
> -    stack_addend = frame_size - push_size;
> +    stack_addend = FRAME_SIZE - PUSH_SIZE;
>     tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
>                   CPU_TEMP_BUF_NLONGS * sizeof(long));
>
> @@ -2070,3 +2077,92 @@ static void tcg_target_init(TCGContext *s)
>
>     tcg_add_target_add_op_defs(x86_op_defs);
>  }
> +
> +typedef struct {
> +    uint32_t len __attribute__((aligned((sizeof(void *)))));
> +    uint32_t id;
> +    uint8_t version;
> +    char augmentation[1];
> +    uint8_t code_align;
> +    uint8_t data_align;
> +    uint8_t return_column;
> +} DebugFrameCIE;
> +
> +typedef struct {
> +    uint32_t len __attribute__((aligned((sizeof(void *)))));
> +    uint32_t cie_offset;
> +    tcg_target_long func_start __attribute__((packed));
> +    tcg_target_long func_len __attribute__((packed));
> +    uint8_t def_cfa[4];
> +    uint8_t reg_ofs[14];
> +} DebugFrameFDE;
> +
> +typedef struct {
> +    DebugFrameCIE cie;
> +    DebugFrameFDE fde;
> +} DebugFrame;
> +
> +#if TCG_TARGET_REG_BITS == 64
> +#define ELF_HOST_MACHINE EM_X86_64
> +static DebugFrame debug_frame = {
> +    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
> +    .cie.id = -1,
> +    .cie.version = 1,
> +    .cie.code_align = 1,
> +    .cie.data_align = 0x78,             /* sleb128 -8 */
> +    .cie.return_column = 16,
> +
> +    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
> +    .fde.def_cfa = {
> +        12, 7,                          /* DW_CFA_def_cfa %rsp, ... */
> +        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
> +        (FRAME_SIZE >> 7)
> +    },
> +    .fde.reg_ofs = {
> +        0x90, 1,                        /* DW_CFA_offset, %rip, -8 */
> +        /* The following ordering must match tcg_target_callee_save_regs.  */
> +        0x86, 2,                        /* DW_CFA_offset, %rbp, -16 */
> +        0x83, 3,                        /* DW_CFA_offset, %rbx, -24 */
> +        0x8c, 4,                        /* DW_CFA_offset, %r12, -32 */
> +        0x8d, 5,                        /* DW_CFA_offset, %r13, -40 */
> +        0x8e, 6,                        /* DW_CFA_offset, %r14, -48 */
> +        0x8f, 7,                        /* DW_CFA_offset, %r15, -56 */
> +    }
> +};
> +#else
> +#define ELF_HOST_MACHINE EM_386
> +static DebugFrame debug_frame = {
> +    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
> +    .cie.id = -1,
> +    .cie.version = 1,
> +    .cie.code_align = 1,
> +    .cie.data_align = 0x7c,             /* sleb128 -4 */
> +    .cie.return_column = 8,
> +
> +    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
> +    .fde.def_cfa = {
> +        12, 4,                          /* DW_CFA_def_cfa %esp, ... */
> +        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
> +        (FRAME_SIZE >> 7)
> +    },
> +    .fde.reg_ofs = {
> +        0x88, 1,                        /* DW_CFA_offset, %eip, -4 */
> +        /* The following ordering must match tcg_target_callee_save_regs.  */
> +        0x85, 2,                        /* DW_CFA_offset, %ebp, -8 */
> +        0x83, 3,                        /* DW_CFA_offset, %ebx, -12 */
> +        0x86, 4,                        /* DW_CFA_offset, %esi, -16 */
> +        0x87, 5,                        /* DW_CFA_offset, %edi, -20 */
> +    }
> +};
> +#endif
> +
> +void tcg_register_jit(void *buf, size_t buf_size)
> +{
> +    /* We're expecting a 2 byte uleb128 encoded value.  */
> +    assert(FRAME_SIZE >> 14 == 0);
> +
> +    debug_frame.fde.func_start = (tcg_target_long) buf;
> +    debug_frame.fde.func_len = buf_size;
> +
> +    tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
> +}
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index ccfcd1a..eb595ce 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -28,6 +28,9 @@
>
>  #include "config.h"
>
> +/* Define to jump the ELF file used to communicate with GDB.  */
> +#undef DEBUG_JIT
> +
>  #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
>  /* define it to suppress various consistency checks (faster) */
>  #define NDEBUG
> @@ -45,6 +48,18 @@
>  #include "cpu.h"
>
>  #include "tcg-op.h"
> +
> +#if TCG_TARGET_REG_BITS == 64
> +# define ELF_CLASS  ELFCLASS64
> +#else
> +# define ELF_CLASS  ELFCLASS32
> +#endif
> +#ifdef HOST_WORDS_BIGENDIAN
> +# define ELF_DATA   ELFDATA2MSB
> +#else
> +# define ELF_DATA   ELFDATA2LSB
> +#endif
> +
>  #include "elf.h"
>
>  #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
> @@ -57,6 +72,10 @@ static void tcg_target_qemu_prologue(TCGContext *s);
>  static void patch_reloc(uint8_t *code_ptr, int type,
>                         tcg_target_long value, tcg_target_long addend);
>
> +static void tcg_register_jit_int(void *buf, size_t size,
> +                                 void *debug_frame, size_t debug_frame_size)
> +    __attribute__((unused));
> +
>  /* Forward declarations for functions declared and used in tcg-target.c. */
>  static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
>  static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
> @@ -2231,3 +2250,178 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
>     cpu_fprintf(f, "[TCG profiler not compiled]\n");
>  }
>  #endif
> +
> +#ifdef ELF_HOST_MACHINE
> +/* The backend should define ELF_HOST_MACHINE to indicate both what value to
> +   put into the ELF image and to indicate support for the feature.  */
> +
> +/* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
> +typedef enum {
> +    JIT_NOACTION = 0,
> +    JIT_REGISTER_FN,
> +    JIT_UNREGISTER_FN
> +} jit_actions_t;
> +
> +struct jit_code_entry {
> +    struct jit_code_entry *next_entry;
> +    struct jit_code_entry *prev_entry;
> +    const void *symfile_addr;
> +    uint64_t symfile_size;
> +};
> +
> +struct jit_descriptor {
> +    uint32_t version;
> +    uint32_t action_flag;
> +    struct jit_code_entry *relevant_entry;
> +    struct jit_code_entry *first_entry;
> +};
> +
> +void __jit_debug_register_code(void) __attribute__((noinline));
> +void __jit_debug_register_code(void)
> +{
> +    asm("");
> +}
> +
> +/* Must statically initialize the version, because GDB may check
> +   the version before we can set it.  */
> +struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
> +
> +/* End GDB interface.  */
> +
> +static int find_string(const char *strtab, const char *str)
> +{
> +    const char *p = strtab + 1;
> +
> +    while (1) {
> +        if (strcmp(p, str) == 0) {
> +            return p - strtab;
> +        }
> +        p += strlen(p) + 1;
> +    }
> +}
> +
> +static void tcg_register_jit_int(void *buf, size_t buf_size,
> +                                 void *debug_frame, size_t debug_frame_size)
> +{
> +    static const char strings[64] =
> +        "\0"
> +        ".text\0"
> +        ".debug_frame\0"
> +        ".symtab\0"
> +        ".strtab\0"
> +        "code_gen_buffer";
> +
> +    struct ElfImage {
> +        ElfW(Ehdr) ehdr;
> +        ElfW(Phdr) phdr;
> +        ElfW(Shdr) shdr[5];
> +        ElfW(Sym)  sym[1];
> +        char       str[64];
> +    };
> +
> +    /* We only need a single jit entry; statically allocate it.  */
> +    static struct jit_code_entry one_entry;
> +
> +    size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
> +    struct ElfImage *img = g_malloc0(img_size);
> +
> +    img->ehdr.e_ident[EI_MAG0] = ELFMAG0;
> +    img->ehdr.e_ident[EI_MAG1] = ELFMAG1;
> +    img->ehdr.e_ident[EI_MAG2] = ELFMAG2;
> +    img->ehdr.e_ident[EI_MAG3] = ELFMAG3;
> +    img->ehdr.e_ident[EI_CLASS] = ELF_CLASS;
> +    img->ehdr.e_ident[EI_DATA] = ELF_DATA;
> +    img->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
> +    img->ehdr.e_type = ET_EXEC;
> +    img->ehdr.e_machine = ELF_HOST_MACHINE;
> +    img->ehdr.e_version = EV_CURRENT;
> +    img->ehdr.e_phoff = offsetof(struct ElfImage, phdr);
> +    img->ehdr.e_shoff = offsetof(struct ElfImage, shdr);
> +    img->ehdr.e_ehsize = sizeof(ElfW(Shdr));
> +    img->ehdr.e_phentsize = sizeof(ElfW(Phdr));
> +    img->ehdr.e_phnum = 1;
> +    img->ehdr.e_shentsize = sizeof(img->shdr[0]);
> +    img->ehdr.e_shnum = ARRAY_SIZE(img->shdr);
> +    img->ehdr.e_shstrndx = ARRAY_SIZE(img->shdr) - 1;
> +
> +    img->phdr.p_type = PT_LOAD;
> +    img->phdr.p_offset = (char *)buf - (char *)img;
> +    img->phdr.p_vaddr = (ElfW(Addr))buf;
> +    img->phdr.p_paddr = img->phdr.p_vaddr;
> +    img->phdr.p_filesz = 0;
> +    img->phdr.p_memsz = buf_size;
> +    img->phdr.p_flags = PF_X;
> +
> +    memcpy(img->str, strings, sizeof(img->str));
> +
> +    img->shdr[0].sh_type = SHT_NULL;
> +
> +    /* Trick: The contents of code_gen_buffer are not present in this fake
> +       ELF file; that got allocated elsewhere, discontiguously.  Therefore
> +       we mark .text as SHT_NOBITS (similar to .bss) so that readers will
> +       not look for contents.  We can record any address at will.  */
> +    img->shdr[1].sh_name = find_string(img->str, ".text");
> +    img->shdr[1].sh_type = SHT_NOBITS;
> +    img->shdr[1].sh_flags = SHF_EXECINSTR | SHF_ALLOC;
> +    img->shdr[1].sh_addr = (ElfW(Addr))buf;
> +    img->shdr[1].sh_size = buf_size;
> +
> +    img->shdr[2].sh_name = find_string(img->str, ".debug_frame");
> +    img->shdr[2].sh_type = SHT_PROGBITS;
> +    img->shdr[2].sh_offset = sizeof(*img);
> +    img->shdr[2].sh_size = debug_frame_size;
> +    memcpy(img + 1, debug_frame, debug_frame_size);
> +
> +    img->shdr[3].sh_name = find_string(img->str, ".symtab");
> +    img->shdr[3].sh_type = SHT_SYMTAB;
> +    img->shdr[3].sh_offset = offsetof(struct ElfImage, sym);
> +    img->shdr[3].sh_size = sizeof(img->sym);
> +    img->shdr[3].sh_info = ARRAY_SIZE(img->sym);
> +    img->shdr[3].sh_link = img->ehdr.e_shstrndx;
> +    img->shdr[3].sh_entsize = sizeof(ElfW(Sym));
> +
> +    img->shdr[4].sh_name = find_string(img->str, ".strtab");
> +    img->shdr[4].sh_type = SHT_STRTAB;
> +    img->shdr[4].sh_offset = offsetof(struct ElfImage, str);
> +    img->shdr[4].sh_size = sizeof(img->str);
> +
> +    img->sym[0].st_name = find_string(img->str, "code_gen_buffer");
> +    img->sym[0].st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
> +    img->sym[0].st_shndx = 1;
> +    img->sym[0].st_value = (ElfW(Addr))buf;
> +    img->sym[0].st_size = buf_size;
> +
> +#ifdef DEBUG_JIT
> +    /* Enable this block to be able to debug the ELF image file creation.
> +       One can use readelf, objdump, or other inspection utilities.  */
> +    {
> +        FILE *f = fopen("/tmp/qemu.jit", "w+b");
> +        if (f) {
> +            if (fwrite(img, img_size, 1, f) != buf_size) {
> +                /* Avoid stupid unused return value warning for fwrite.  */
> +            }
> +            fclose(f);
> +        }
> +    }
> +#endif
> +
> +    one_entry.symfile_addr = img;
> +    one_entry.symfile_size = img_size;
> +
> +    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
> +    __jit_debug_descriptor.relevant_entry = &one_entry;
> +    __jit_debug_descriptor.first_entry = &one_entry;
> +    __jit_debug_register_code();
> +}
> +#else
> +/* No support for the feature.  Provide the entry point expected by exec.c.  */
> +
> +static void tcg_register_jit_int(void *buf, size_t size,
> +                                 void *debug_frame, size_t debug_frame_size)
> +{
> +}
> +
> +void tcg_register_jit(void *buf, size_t buf_size)
> +{
> +}
> +#endif /* ELF_HOST_MACHINE */
> diff --git a/tcg/tcg.h b/tcg/tcg.h
> index 5f6c647..a83bddd 100644
> --- a/tcg/tcg.h
> +++ b/tcg/tcg.h
> @@ -586,3 +586,5 @@ extern uint8_t code_gen_prologue[];
>  # define tcg_qemu_tb_exec(env, tb_ptr) \
>     ((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
>  #endif
> +
> +void tcg_register_jit(void *buf, size_t buf_size);
> --
> 1.7.7.6
>
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
  2012-03-20 18:18 [Qemu-devel] [PATCH v3] Use the GDB JIT interface Richard Henderson
@ 2012-03-20 18:18 ` Richard Henderson
  0 siblings, 0 replies; 8+ messages in thread
From: Richard Henderson @ 2012-03-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

This allows us to generate unwind info for the dynamicly generated
code in the code_gen_buffer.  Only i386 is converted at this point.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 elf.h                 |    1 +
 exec.c                |    1 +
 tcg/i386/tcg-target.c |  114 +++++++++++++++++++--
 tcg/tcg.c             |  277 +++++++++++++++++++++++++++++++++++++++++++++++++
 tcg/tcg.h             |    2 +
 5 files changed, 386 insertions(+), 9 deletions(-)

diff --git a/elf.h b/elf.h
index 2e05d34..310e05a 100644
--- a/elf.h
+++ b/elf.h
@@ -216,6 +216,7 @@ typedef int64_t  Elf64_Sxword;
 
 #define ELF_ST_BIND(x)		((x) >> 4)
 #define ELF_ST_TYPE(x)		(((unsigned int) x) & 0xf)
+#define ELF_ST_INFO(bind, type) (((bind) << 4) | ((type) & 0xf))
 #define ELF32_ST_BIND(x)	ELF_ST_BIND(x)
 #define ELF32_ST_TYPE(x)	ELF_ST_TYPE(x)
 #define ELF64_ST_BIND(x)	ELF_ST_BIND(x)
diff --git a/exec.c b/exec.c
index be392e2..dd24939 100644
--- a/exec.c
+++ b/exec.c
@@ -636,6 +636,7 @@ void tcg_exec_init(unsigned long tb_size)
     cpu_gen_init();
     code_gen_alloc(tb_size);
     code_gen_ptr = code_gen_buffer;
+    tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
     page_init();
 #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
     /* There's no guest base to take into account, so go ahead and
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 43a51a1..871a7e7 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1989,22 +1989,29 @@ static int tcg_target_callee_save_regs[] = {
 #endif
 };
 
+/* Compute frame size via macros, to share between tcg_target_qemu_prologue
+   and tcg_register_jit.  */
+
+#define PUSH_SIZE \
+    ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
+     * (TCG_TARGET_REG_BITS / 8))
+
+#define FRAME_SIZE \
+    ((PUSH_SIZE \
+      + TCG_STATIC_CALL_ARGS_SIZE \
+      + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+      + TCG_TARGET_STACK_ALIGN - 1) \
+     & ~(TCG_TARGET_STACK_ALIGN - 1))
+
 /* Generate global QEMU prologue and epilogue code */
 static void tcg_target_qemu_prologue(TCGContext *s)
 {
-    int i, frame_size, push_size, stack_addend;
+    int i, stack_addend;
 
     /* TB prologue */
 
     /* Reserve some stack space, also for TCG temps.  */
-    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
-    push_size *= TCG_TARGET_REG_BITS / 8;
-
-    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
-        CPU_TEMP_BUF_NLONGS * sizeof(long);
-    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
-        ~(TCG_TARGET_STACK_ALIGN - 1);
-    stack_addend = frame_size - push_size;
+    stack_addend = FRAME_SIZE - PUSH_SIZE;
     tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
                   CPU_TEMP_BUF_NLONGS * sizeof(long));
 
@@ -2070,3 +2077,92 @@ static void tcg_target_init(TCGContext *s)
 
     tcg_add_target_add_op_defs(x86_op_defs);
 }
+
+typedef struct {
+    uint32_t len __attribute__((aligned((sizeof(void *)))));
+    uint32_t id;
+    uint8_t version;
+    char augmentation[1];
+    uint8_t code_align;
+    uint8_t data_align;
+    uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+    uint32_t len __attribute__((aligned((sizeof(void *)))));
+    uint32_t cie_offset;
+    tcg_target_long func_start __attribute__((packed));
+    tcg_target_long func_len __attribute__((packed));
+    uint8_t def_cfa[4];
+    uint8_t reg_ofs[14];
+} DebugFrameFDE;
+
+typedef struct {
+    DebugFrameCIE cie;
+    DebugFrameFDE fde;
+} DebugFrame;
+
+#if TCG_TARGET_REG_BITS == 64
+#define ELF_HOST_MACHINE EM_X86_64
+static DebugFrame debug_frame = {
+    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .cie.id = -1,
+    .cie.version = 1,
+    .cie.code_align = 1,
+    .cie.data_align = 0x78,             /* sleb128 -8 */
+    .cie.return_column = 16,
+
+    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+    .fde.def_cfa = {
+        12, 7,                          /* DW_CFA_def_cfa %rsp, ... */
+        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
+        (FRAME_SIZE >> 7)
+    },
+    .fde.reg_ofs = {
+        0x90, 1,                        /* DW_CFA_offset, %rip, -8 */
+        /* The following ordering must match tcg_target_callee_save_regs.  */
+        0x86, 2,                        /* DW_CFA_offset, %rbp, -16 */
+        0x83, 3,                        /* DW_CFA_offset, %rbx, -24 */
+        0x8c, 4,                        /* DW_CFA_offset, %r12, -32 */
+        0x8d, 5,                        /* DW_CFA_offset, %r13, -40 */
+        0x8e, 6,                        /* DW_CFA_offset, %r14, -48 */
+        0x8f, 7,                        /* DW_CFA_offset, %r15, -56 */
+    }
+};
+#else
+#define ELF_HOST_MACHINE EM_386
+static DebugFrame debug_frame = {
+    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .cie.id = -1,
+    .cie.version = 1,
+    .cie.code_align = 1,
+    .cie.data_align = 0x7c,             /* sleb128 -4 */
+    .cie.return_column = 8,
+
+    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+    .fde.def_cfa = {
+        12, 4,                          /* DW_CFA_def_cfa %esp, ... */
+        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
+        (FRAME_SIZE >> 7)
+    },
+    .fde.reg_ofs = {
+        0x88, 1,                        /* DW_CFA_offset, %eip, -4 */
+        /* The following ordering must match tcg_target_callee_save_regs.  */
+        0x85, 2,                        /* DW_CFA_offset, %ebp, -8 */
+        0x83, 3,                        /* DW_CFA_offset, %ebx, -12 */
+        0x86, 4,                        /* DW_CFA_offset, %esi, -16 */
+        0x87, 5,                        /* DW_CFA_offset, %edi, -20 */
+    }
+};
+#endif
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+    /* We're expecting a 2 byte uleb128 encoded value.  */
+    assert(FRAME_SIZE >> 14 == 0);
+
+    debug_frame.fde.func_start = (tcg_target_long) buf;
+    debug_frame.fde.func_len = buf_size;
+
+    tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ccfcd1a..df4edc0 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -28,6 +28,9 @@
 
 #include "config.h"
 
+/* Define to jump the ELF file used to communicate with GDB.  */
+#undef DEBUG_JIT
+
 #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
 /* define it to suppress various consistency checks (faster) */
 #define NDEBUG
@@ -45,6 +48,18 @@
 #include "cpu.h"
 
 #include "tcg-op.h"
+
+#if TCG_TARGET_REG_BITS == 64
+# define ELF_CLASS  ELFCLASS64
+#else
+# define ELF_CLASS  ELFCLASS32
+#endif
+#ifdef HOST_WORDS_BIGENDIAN
+# define ELF_DATA   ELFDATA2MSB
+#else
+# define ELF_DATA   ELFDATA2LSB
+#endif
+
 #include "elf.h"
 
 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
@@ -57,6 +72,10 @@ static void tcg_target_qemu_prologue(TCGContext *s);
 static void patch_reloc(uint8_t *code_ptr, int type, 
                         tcg_target_long value, tcg_target_long addend);
 
+static void tcg_register_jit_int(void *buf, size_t size,
+                                 void *debug_frame, size_t debug_frame_size)
+    __attribute__((unused));
+
 /* Forward declarations for functions declared and used in tcg-target.c. */
 static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
 static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
@@ -2231,3 +2250,261 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
     cpu_fprintf(f, "[TCG profiler not compiled]\n");
 }
 #endif
+
+#ifdef ELF_HOST_MACHINE
+/* In order to use this feature, the backend needs to do three things:
+
+   (1) Define ELF_HOST_MACHINE to indicate both what value to
+       put into the ELF image and to indicate support for the feature.
+
+   (2) Define tcg_register_jit.  This should create a buffer containing
+       the contents of a .debug_frame section that describes the post-
+       prologue unwind info for the tcg machine.
+
+   (3) Call tcg_register_jit_int, with the constructed .debug_frame.
+*/
+
+/* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
+typedef enum {
+    JIT_NOACTION = 0,
+    JIT_REGISTER_FN,
+    JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry {
+    struct jit_code_entry *next_entry;
+    struct jit_code_entry *prev_entry;
+    const void *symfile_addr;
+    uint64_t symfile_size;
+};
+
+struct jit_descriptor {
+    uint32_t version;
+    uint32_t action_flag;
+    struct jit_code_entry *relevant_entry;
+    struct jit_code_entry *first_entry;
+};
+
+void __jit_debug_register_code(void) __attribute__((noinline));
+void __jit_debug_register_code(void)
+{
+    asm("");
+}
+
+/* Must statically initialize the version, because GDB may check
+   the version before we can set it.  */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+/* End GDB interface.  */
+
+static int find_string(const char *strtab, const char *str)
+{
+    const char *p = strtab + 1;
+
+    while (1) {
+        if (strcmp(p, str) == 0) {
+            return p - strtab;
+        }
+        p += strlen(p) + 1;
+    }
+}
+
+static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
+                                 void *debug_frame, size_t debug_frame_size)
+{
+    struct __attribute__((packed)) DebugInfo {
+        uint32_t  len;
+        uint16_t  version;
+        uint32_t  abbrev;
+        uint8_t   ptr_size;
+        uint8_t   cu_die;
+        uint16_t  cu_lang;
+        uintptr_t cu_low_pc;
+        uintptr_t cu_high_pc;
+        uint8_t   fn_die;
+        char      fn_name[16];
+        uintptr_t fn_low_pc;
+        uintptr_t fn_high_pc;
+        uint8_t   cu_eoc;
+    };
+
+    struct ElfImage {
+        ElfW(Ehdr) ehdr;
+        ElfW(Phdr) phdr;
+        ElfW(Shdr) shdr[7];
+        ElfW(Sym)  sym[2];
+        struct DebugInfo di;
+        uint8_t    da[24];
+        char       str[80];
+    };
+
+    struct ElfImage *img;
+
+    static const struct ElfImage img_template = {
+        .ehdr = {
+            .e_ident[EI_MAG0] = ELFMAG0,
+            .e_ident[EI_MAG1] = ELFMAG1,
+            .e_ident[EI_MAG2] = ELFMAG2,
+            .e_ident[EI_MAG3] = ELFMAG3,
+            .e_ident[EI_CLASS] = ELF_CLASS,
+            .e_ident[EI_DATA] = ELF_DATA,
+            .e_ident[EI_VERSION] = EV_CURRENT,
+            .e_type = ET_EXEC,
+            .e_machine = ELF_HOST_MACHINE,
+            .e_version = EV_CURRENT,
+            .e_phoff = offsetof(struct ElfImage, phdr),
+            .e_shoff = offsetof(struct ElfImage, shdr),
+            .e_ehsize = sizeof(ElfW(Shdr)),
+            .e_phentsize = sizeof(ElfW(Phdr)),
+            .e_phnum = 1,
+            .e_shentsize = sizeof(ElfW(Shdr)),
+            .e_shnum = ARRAY_SIZE(img->shdr),
+            .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
+        },
+        .phdr = {
+            .p_type = PT_LOAD,
+            .p_flags = PF_X,
+        },
+        .shdr = {
+            [0] = { .sh_type = SHT_NULL },
+            /* Trick: The contents of code_gen_buffer are not present in
+               this fake ELF file; that got allocated elsewhere.  Therefore
+               we mark .text as SHT_NOBITS (similar to .bss) so that readers
+               will not look for contents.  We can record any address.  */
+            [1] = { /* .text */
+                .sh_type = SHT_NOBITS,
+                .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
+            },
+            [2] = { /* .debug_info */
+                .sh_type = SHT_PROGBITS,
+                .sh_offset = offsetof(struct ElfImage, di),
+                .sh_size = sizeof(struct DebugInfo),
+            },
+            [3] = { /* .debug_abbrev */
+                .sh_type = SHT_PROGBITS,
+                .sh_offset = offsetof(struct ElfImage, da),
+                .sh_size = sizeof(img->da),
+            },
+            [4] = { /* .debug_frame */
+                .sh_type = SHT_PROGBITS,
+                .sh_offset = sizeof(struct ElfImage),
+            },
+            [5] = { /* .symtab */
+                .sh_type = SHT_SYMTAB,
+                .sh_offset = offsetof(struct ElfImage, sym),
+                .sh_size = sizeof(img->sym),
+                .sh_info = 1,
+                .sh_link = ARRAY_SIZE(img->shdr) - 1,
+                .sh_entsize = sizeof(ElfW(Sym)),
+            },
+            [6] = { /* .strtab */
+                .sh_type = SHT_STRTAB,
+                .sh_offset = offsetof(struct ElfImage, str),
+                .sh_size = sizeof(img->str),
+            }
+        },
+        .sym = {
+            [1] = { /* code_gen_buffer */
+                .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
+                .st_shndx = 1,
+            }
+        },
+        .di = {
+            .len = sizeof(struct DebugInfo) - 4,
+            .version = 2,
+            .ptr_size = sizeof(void *),
+            .cu_die = 1,
+            .cu_lang = 0x8001,  /* DW_LANG_Mips_Assembler */
+            .fn_die = 2,
+            .fn_name = "code_gen_buffer"
+        },
+        .da = {
+            1,          /* abbrev number (the cu) */
+            0x11, 1,    /* DW_TAG_compile_unit, has children */
+            0x13, 0x5,  /* DW_AT_language, DW_FORM_data2 */
+            0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
+            0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
+            0, 0,       /* end of abbrev */
+            2,          /* abbrev number (the fn) */
+            0x2e, 0,    /* DW_TAG_subprogram, no children */
+            0x3, 0x8,   /* DW_AT_name, DW_FORM_string */
+            0x11, 0x1,  /* DW_AT_low_pc, DW_FORM_addr */
+            0x12, 0x1,  /* DW_AT_high_pc, DW_FORM_addr */
+            0, 0,       /* end of abbrev */
+            0           /* no more abbrev */
+        },
+        .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
+               ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
+    };
+
+    /* We only need a single jit entry; statically allocate it.  */
+    static struct jit_code_entry one_entry;
+
+    uintptr_t buf = (uintptr_t)buf_ptr;
+    size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
+
+    img = g_malloc(img_size);
+    *img = img_template;
+    memcpy(img + 1, debug_frame, debug_frame_size);
+
+    img->phdr.p_vaddr = buf;
+    img->phdr.p_paddr = buf;
+    img->phdr.p_memsz = buf_size;
+
+    img->shdr[1].sh_name = find_string(img->str, ".text");
+    img->shdr[1].sh_addr = buf;
+    img->shdr[1].sh_size = buf_size;
+
+    img->shdr[2].sh_name = find_string(img->str, ".debug_info");
+    img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
+
+    img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
+    img->shdr[4].sh_size = debug_frame_size;
+
+    img->shdr[5].sh_name = find_string(img->str, ".symtab");
+    img->shdr[6].sh_name = find_string(img->str, ".strtab");
+
+    img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
+    img->sym[1].st_value = buf;
+    img->sym[1].st_size = buf_size;
+
+    img->di.cu_low_pc = buf;
+    img->di.cu_high_pc = buf_size;
+    img->di.fn_low_pc = buf;
+    img->di.fn_high_pc = buf_size;
+
+#ifdef DEBUG_JIT
+    /* Enable this block to be able to debug the ELF image file creation.
+       One can use readelf, objdump, or other inspection utilities.  */
+    {
+        FILE *f = fopen("/tmp/qemu.jit", "w+b");
+        if (f) {
+            if (fwrite(img, img_size, 1, f) != img_size) {
+                /* Avoid stupid unused return value warning for fwrite.  */
+            }
+            fclose(f);
+        }
+    }
+#endif
+
+    one_entry.symfile_addr = img;
+    one_entry.symfile_size = img_size;
+
+    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+    __jit_debug_descriptor.relevant_entry = &one_entry;
+    __jit_debug_descriptor.first_entry = &one_entry;
+    __jit_debug_register_code();
+}
+#else
+/* No support for the feature.  Provide the entry point expected by exec.c,
+   and implement the internal function we declared earlier.  */
+
+static void tcg_register_jit_int(void *buf, size_t size,
+                                 void *debug_frame, size_t debug_frame_size)
+{
+}
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+}
+#endif /* ELF_HOST_MACHINE */
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 5f6c647..a83bddd 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -586,3 +586,5 @@ extern uint8_t code_gen_prologue[];
 # define tcg_qemu_tb_exec(env, tb_ptr) \
     ((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
 #endif
+
+void tcg_register_jit(void *buf, size_t buf_size);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface.
  2012-03-19 19:25 [Qemu-devel] [PATCH v2] " Richard Henderson
@ 2012-03-19 19:25 ` Richard Henderson
  2012-03-24 16:11   ` Blue Swirl
  0 siblings, 1 reply; 8+ messages in thread
From: Richard Henderson @ 2012-03-19 19:25 UTC (permalink / raw)
  To: qemu-devel

This allows us to generate unwind info for the dynamicly generated
code in the code_gen_buffer.  Only i386 is converted at this point.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 elf.h                 |    1 +
 exec.c                |    1 +
 tcg/i386/tcg-target.c |  114 ++++++++++++++++++++++++++--
 tcg/tcg.c             |  194 +++++++++++++++++++++++++++++++++++++++++++++++++
 tcg/tcg.h             |    2 +
 5 files changed, 303 insertions(+), 9 deletions(-)

diff --git a/elf.h b/elf.h
index 2e05d34..310e05a 100644
--- a/elf.h
+++ b/elf.h
@@ -216,6 +216,7 @@ typedef int64_t  Elf64_Sxword;
 
 #define ELF_ST_BIND(x)		((x) >> 4)
 #define ELF_ST_TYPE(x)		(((unsigned int) x) & 0xf)
+#define ELF_ST_INFO(bind, type) (((bind) << 4) | ((type) & 0xf))
 #define ELF32_ST_BIND(x)	ELF_ST_BIND(x)
 #define ELF32_ST_TYPE(x)	ELF_ST_TYPE(x)
 #define ELF64_ST_BIND(x)	ELF_ST_BIND(x)
diff --git a/exec.c b/exec.c
index be392e2..dd24939 100644
--- a/exec.c
+++ b/exec.c
@@ -636,6 +636,7 @@ void tcg_exec_init(unsigned long tb_size)
     cpu_gen_init();
     code_gen_alloc(tb_size);
     code_gen_ptr = code_gen_buffer;
+    tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
     page_init();
 #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
     /* There's no guest base to take into account, so go ahead and
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 43a51a1..871a7e7 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1989,22 +1989,29 @@ static int tcg_target_callee_save_regs[] = {
 #endif
 };
 
+/* Compute frame size via macros, to share between tcg_target_qemu_prologue
+   and tcg_register_jit.  */
+
+#define PUSH_SIZE \
+    ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
+     * (TCG_TARGET_REG_BITS / 8))
+
+#define FRAME_SIZE \
+    ((PUSH_SIZE \
+      + TCG_STATIC_CALL_ARGS_SIZE \
+      + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+      + TCG_TARGET_STACK_ALIGN - 1) \
+     & ~(TCG_TARGET_STACK_ALIGN - 1))
+
 /* Generate global QEMU prologue and epilogue code */
 static void tcg_target_qemu_prologue(TCGContext *s)
 {
-    int i, frame_size, push_size, stack_addend;
+    int i, stack_addend;
 
     /* TB prologue */
 
     /* Reserve some stack space, also for TCG temps.  */
-    push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
-    push_size *= TCG_TARGET_REG_BITS / 8;
-
-    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
-        CPU_TEMP_BUF_NLONGS * sizeof(long);
-    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
-        ~(TCG_TARGET_STACK_ALIGN - 1);
-    stack_addend = frame_size - push_size;
+    stack_addend = FRAME_SIZE - PUSH_SIZE;
     tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
                   CPU_TEMP_BUF_NLONGS * sizeof(long));
 
@@ -2070,3 +2077,92 @@ static void tcg_target_init(TCGContext *s)
 
     tcg_add_target_add_op_defs(x86_op_defs);
 }
+
+typedef struct {
+    uint32_t len __attribute__((aligned((sizeof(void *)))));
+    uint32_t id;
+    uint8_t version;
+    char augmentation[1];
+    uint8_t code_align;
+    uint8_t data_align;
+    uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+    uint32_t len __attribute__((aligned((sizeof(void *)))));
+    uint32_t cie_offset;
+    tcg_target_long func_start __attribute__((packed));
+    tcg_target_long func_len __attribute__((packed));
+    uint8_t def_cfa[4];
+    uint8_t reg_ofs[14];
+} DebugFrameFDE;
+
+typedef struct {
+    DebugFrameCIE cie;
+    DebugFrameFDE fde;
+} DebugFrame;
+
+#if TCG_TARGET_REG_BITS == 64
+#define ELF_HOST_MACHINE EM_X86_64
+static DebugFrame debug_frame = {
+    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .cie.id = -1,
+    .cie.version = 1,
+    .cie.code_align = 1,
+    .cie.data_align = 0x78,             /* sleb128 -8 */
+    .cie.return_column = 16,
+
+    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+    .fde.def_cfa = {
+        12, 7,                          /* DW_CFA_def_cfa %rsp, ... */
+        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
+        (FRAME_SIZE >> 7)
+    },
+    .fde.reg_ofs = {
+        0x90, 1,                        /* DW_CFA_offset, %rip, -8 */
+        /* The following ordering must match tcg_target_callee_save_regs.  */
+        0x86, 2,                        /* DW_CFA_offset, %rbp, -16 */
+        0x83, 3,                        /* DW_CFA_offset, %rbx, -24 */
+        0x8c, 4,                        /* DW_CFA_offset, %r12, -32 */
+        0x8d, 5,                        /* DW_CFA_offset, %r13, -40 */
+        0x8e, 6,                        /* DW_CFA_offset, %r14, -48 */
+        0x8f, 7,                        /* DW_CFA_offset, %r15, -56 */
+    }
+};
+#else
+#define ELF_HOST_MACHINE EM_386
+static DebugFrame debug_frame = {
+    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .cie.id = -1,
+    .cie.version = 1,
+    .cie.code_align = 1,
+    .cie.data_align = 0x7c,             /* sleb128 -4 */
+    .cie.return_column = 8,
+
+    .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+    .fde.def_cfa = {
+        12, 4,                          /* DW_CFA_def_cfa %esp, ... */
+        (FRAME_SIZE & 0x7f) | 0x80,     /* ... uleb128 FRAME_SIZE */
+        (FRAME_SIZE >> 7)
+    },
+    .fde.reg_ofs = {
+        0x88, 1,                        /* DW_CFA_offset, %eip, -4 */
+        /* The following ordering must match tcg_target_callee_save_regs.  */
+        0x85, 2,                        /* DW_CFA_offset, %ebp, -8 */
+        0x83, 3,                        /* DW_CFA_offset, %ebx, -12 */
+        0x86, 4,                        /* DW_CFA_offset, %esi, -16 */
+        0x87, 5,                        /* DW_CFA_offset, %edi, -20 */
+    }
+};
+#endif
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+    /* We're expecting a 2 byte uleb128 encoded value.  */
+    assert(FRAME_SIZE >> 14 == 0);
+
+    debug_frame.fde.func_start = (tcg_target_long) buf;
+    debug_frame.fde.func_len = buf_size;
+
+    tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ccfcd1a..eb595ce 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -28,6 +28,9 @@
 
 #include "config.h"
 
+/* Define to jump the ELF file used to communicate with GDB.  */
+#undef DEBUG_JIT
+
 #if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
 /* define it to suppress various consistency checks (faster) */
 #define NDEBUG
@@ -45,6 +48,18 @@
 #include "cpu.h"
 
 #include "tcg-op.h"
+
+#if TCG_TARGET_REG_BITS == 64
+# define ELF_CLASS  ELFCLASS64
+#else
+# define ELF_CLASS  ELFCLASS32
+#endif
+#ifdef HOST_WORDS_BIGENDIAN
+# define ELF_DATA   ELFDATA2MSB
+#else
+# define ELF_DATA   ELFDATA2LSB
+#endif
+
 #include "elf.h"
 
 #if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
@@ -57,6 +72,10 @@ static void tcg_target_qemu_prologue(TCGContext *s);
 static void patch_reloc(uint8_t *code_ptr, int type, 
                         tcg_target_long value, tcg_target_long addend);
 
+static void tcg_register_jit_int(void *buf, size_t size,
+                                 void *debug_frame, size_t debug_frame_size)
+    __attribute__((unused));
+
 /* Forward declarations for functions declared and used in tcg-target.c. */
 static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
 static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
@@ -2231,3 +2250,178 @@ void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
     cpu_fprintf(f, "[TCG profiler not compiled]\n");
 }
 #endif
+
+#ifdef ELF_HOST_MACHINE
+/* The backend should define ELF_HOST_MACHINE to indicate both what value to
+   put into the ELF image and to indicate support for the feature.  */
+
+/* Begin GDB interface.  THE FOLLOWING MUST MATCH GDB DOCS.  */
+typedef enum {
+    JIT_NOACTION = 0,
+    JIT_REGISTER_FN,
+    JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry {
+    struct jit_code_entry *next_entry;
+    struct jit_code_entry *prev_entry;
+    const void *symfile_addr;
+    uint64_t symfile_size;
+};
+
+struct jit_descriptor {
+    uint32_t version;
+    uint32_t action_flag;
+    struct jit_code_entry *relevant_entry;
+    struct jit_code_entry *first_entry;
+};
+
+void __jit_debug_register_code(void) __attribute__((noinline));
+void __jit_debug_register_code(void)
+{
+    asm("");
+}
+
+/* Must statically initialize the version, because GDB may check
+   the version before we can set it.  */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+/* End GDB interface.  */
+
+static int find_string(const char *strtab, const char *str)
+{
+    const char *p = strtab + 1;
+
+    while (1) {
+        if (strcmp(p, str) == 0) {
+            return p - strtab;
+        }
+        p += strlen(p) + 1;
+    }
+}
+
+static void tcg_register_jit_int(void *buf, size_t buf_size,
+                                 void *debug_frame, size_t debug_frame_size)
+{
+    static const char strings[64] =
+        "\0"
+        ".text\0"
+        ".debug_frame\0"
+        ".symtab\0"
+        ".strtab\0"
+        "code_gen_buffer";
+
+    struct ElfImage {
+        ElfW(Ehdr) ehdr;
+        ElfW(Phdr) phdr;
+        ElfW(Shdr) shdr[5];
+        ElfW(Sym)  sym[1];
+        char       str[64];
+    };
+
+    /* We only need a single jit entry; statically allocate it.  */
+    static struct jit_code_entry one_entry;
+
+    size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
+    struct ElfImage *img = g_malloc0(img_size);
+
+    img->ehdr.e_ident[EI_MAG0] = ELFMAG0;
+    img->ehdr.e_ident[EI_MAG1] = ELFMAG1;
+    img->ehdr.e_ident[EI_MAG2] = ELFMAG2;
+    img->ehdr.e_ident[EI_MAG3] = ELFMAG3;
+    img->ehdr.e_ident[EI_CLASS] = ELF_CLASS;
+    img->ehdr.e_ident[EI_DATA] = ELF_DATA;
+    img->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+    img->ehdr.e_type = ET_EXEC;
+    img->ehdr.e_machine = ELF_HOST_MACHINE;
+    img->ehdr.e_version = EV_CURRENT;
+    img->ehdr.e_phoff = offsetof(struct ElfImage, phdr);
+    img->ehdr.e_shoff = offsetof(struct ElfImage, shdr);
+    img->ehdr.e_ehsize = sizeof(ElfW(Shdr));
+    img->ehdr.e_phentsize = sizeof(ElfW(Phdr));
+    img->ehdr.e_phnum = 1;
+    img->ehdr.e_shentsize = sizeof(img->shdr[0]);
+    img->ehdr.e_shnum = ARRAY_SIZE(img->shdr);
+    img->ehdr.e_shstrndx = ARRAY_SIZE(img->shdr) - 1;
+
+    img->phdr.p_type = PT_LOAD;
+    img->phdr.p_offset = (char *)buf - (char *)img;
+    img->phdr.p_vaddr = (ElfW(Addr))buf;
+    img->phdr.p_paddr = img->phdr.p_vaddr;
+    img->phdr.p_filesz = 0;
+    img->phdr.p_memsz = buf_size;
+    img->phdr.p_flags = PF_X;
+
+    memcpy(img->str, strings, sizeof(img->str));
+
+    img->shdr[0].sh_type = SHT_NULL;
+
+    /* Trick: The contents of code_gen_buffer are not present in this fake
+       ELF file; that got allocated elsewhere, discontiguously.  Therefore
+       we mark .text as SHT_NOBITS (similar to .bss) so that readers will
+       not look for contents.  We can record any address at will.  */
+    img->shdr[1].sh_name = find_string(img->str, ".text");
+    img->shdr[1].sh_type = SHT_NOBITS;
+    img->shdr[1].sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+    img->shdr[1].sh_addr = (ElfW(Addr))buf;
+    img->shdr[1].sh_size = buf_size;
+
+    img->shdr[2].sh_name = find_string(img->str, ".debug_frame");
+    img->shdr[2].sh_type = SHT_PROGBITS;
+    img->shdr[2].sh_offset = sizeof(*img);
+    img->shdr[2].sh_size = debug_frame_size;
+    memcpy(img + 1, debug_frame, debug_frame_size);
+
+    img->shdr[3].sh_name = find_string(img->str, ".symtab");
+    img->shdr[3].sh_type = SHT_SYMTAB;
+    img->shdr[3].sh_offset = offsetof(struct ElfImage, sym);
+    img->shdr[3].sh_size = sizeof(img->sym);
+    img->shdr[3].sh_info = ARRAY_SIZE(img->sym);
+    img->shdr[3].sh_link = img->ehdr.e_shstrndx;
+    img->shdr[3].sh_entsize = sizeof(ElfW(Sym));
+
+    img->shdr[4].sh_name = find_string(img->str, ".strtab");
+    img->shdr[4].sh_type = SHT_STRTAB;
+    img->shdr[4].sh_offset = offsetof(struct ElfImage, str);
+    img->shdr[4].sh_size = sizeof(img->str);
+
+    img->sym[0].st_name = find_string(img->str, "code_gen_buffer");
+    img->sym[0].st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
+    img->sym[0].st_shndx = 1;
+    img->sym[0].st_value = (ElfW(Addr))buf;
+    img->sym[0].st_size = buf_size;
+
+#ifdef DEBUG_JIT
+    /* Enable this block to be able to debug the ELF image file creation.
+       One can use readelf, objdump, or other inspection utilities.  */
+    {
+        FILE *f = fopen("/tmp/qemu.jit", "w+b");
+        if (f) {
+            if (fwrite(img, img_size, 1, f) != buf_size) {
+                /* Avoid stupid unused return value warning for fwrite.  */
+            }
+            fclose(f);
+        }
+    }
+#endif
+
+    one_entry.symfile_addr = img;
+    one_entry.symfile_size = img_size;
+
+    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+    __jit_debug_descriptor.relevant_entry = &one_entry;
+    __jit_debug_descriptor.first_entry = &one_entry;
+    __jit_debug_register_code();
+}
+#else
+/* No support for the feature.  Provide the entry point expected by exec.c.  */
+
+static void tcg_register_jit_int(void *buf, size_t size,
+                                 void *debug_frame, size_t debug_frame_size)
+{
+}
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+}
+#endif /* ELF_HOST_MACHINE */
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 5f6c647..a83bddd 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -586,3 +586,5 @@ extern uint8_t code_gen_prologue[];
 # define tcg_qemu_tb_exec(env, tb_ptr) \
     ((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
 #endif
+
+void tcg_register_jit(void *buf, size_t buf_size);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-03-24 17:04 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-29 23:46 [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface Richard Henderson
2011-09-30  7:12 ` Jan Kiszka
2011-09-30 14:36   ` Richard Henderson
2011-10-02  2:04     ` Daniel Jacobowitz
2012-03-19 19:25 [Qemu-devel] [PATCH v2] " Richard Henderson
2012-03-19 19:25 ` [Qemu-devel] [PATCH] tcg: " Richard Henderson
2012-03-24 16:11   ` Blue Swirl
2012-03-24 17:04     ` Peter Maydell
2012-03-20 18:18 [Qemu-devel] [PATCH v3] Use the GDB JIT interface Richard Henderson
2012-03-20 18:18 ` [Qemu-devel] [PATCH] tcg: Use the GDB JIT debugging interface Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.