diff mbox

tcg: Use the GDB JIT debugging interface.

Message ID 1332185111-20739-2-git-send-email-rth@twiddle.net
State New
Headers show

Commit Message

Richard Henderson March 19, 2012, 7:25 p.m. UTC
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(-)

Comments

Blue Swirl March 24, 2012, 4:11 p.m. UTC | #1
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
>
>
Peter Maydell March 24, 2012, 5:04 p.m. UTC | #2
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
>>
>>
>
diff mbox

Patch

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);