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 <blauwir...@gmail.com> wrote: > Thanks, applied. > > On Mon, Mar 19, 2012 at 19:25, Richard Henderson <r...@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 <r...@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