X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=tcg%2Ftcg.c;h=8386b70abd24a4f67f4b46848dc8f56c6f49ae4d;hb=3eea5498ca501922520b3447ba94815bfc109743;hp=ad2e983c2baef31a94206975fcc36abdfc3c29fb;hpb=103f9af2a1ad6427533ae2c92d9e1e721b2ae902;p=mirror_qemu.git diff --git a/tcg/tcg.c b/tcg/tcg.c index ad2e983c2b..8386b70abd 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, @@ -594,9 +613,6 @@ void tcg_register_helper(void *func, const char *name) void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, int sizemask, TCGArg ret, int nargs, TCGArg *args) { -#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64 - int call_type; -#endif int i; int real_args; int nb_rets; @@ -621,9 +637,6 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, *gen_opc_ptr++ = INDEX_op_call; nparam = gen_opparam_ptr++; -#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64 - call_type = (flags & TCG_CALL_TYPE_MASK); -#endif if (ret != TCG_CALL_DUMMY_ARG) { #if TCG_TARGET_REG_BITS < 64 if (sizemask & 1) { @@ -649,14 +662,6 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, #if TCG_TARGET_REG_BITS < 64 int is_64bit = sizemask & (1 << (i+1)*2); if (is_64bit) { -#ifdef TCG_TARGET_I386 - /* REGPARM case: if the third parameter is 64 bit, it is - allocated on the stack */ - if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) { - call_type = TCG_CALL_TYPE_REGPARM_2; - flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; - } -#endif #ifdef TCG_TARGET_CALL_ALIGN_ARGS /* some targets want aligned 64 bit args */ if (real_args & 1) { @@ -868,7 +873,7 @@ static const char * const cond_name[] = [TCG_COND_GTU] = "gtu" }; -void tcg_dump_ops(TCGContext *s, FILE *outfile) +void tcg_dump_ops(TCGContext *s) { const uint16_t *opc_ptr; const TCGArg *args; @@ -891,9 +896,10 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) #else pc = args[0]; #endif - if (!first_insn) - fprintf(outfile, "\n"); - fprintf(outfile, " ---- 0x%" PRIx64, pc); + if (!first_insn) { + qemu_log("\n"); + } + qemu_log(" ---- 0x%" PRIx64, pc); first_insn = 0; nb_oargs = def->nb_oargs; nb_iargs = def->nb_iargs; @@ -907,28 +913,28 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) nb_iargs = arg & 0xffff; nb_cargs = def->nb_cargs; - fprintf(outfile, " %s ", def->name); + qemu_log(" %s ", def->name); /* function name */ - fprintf(outfile, "%s", - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1])); + qemu_log("%s", + tcg_get_arg_str_idx(s, buf, sizeof(buf), + args[nb_oargs + nb_iargs - 1])); /* flags */ - fprintf(outfile, ",$0x%" TCG_PRIlx, - args[nb_oargs + nb_iargs]); + qemu_log(",$0x%" TCG_PRIlx, args[nb_oargs + nb_iargs]); /* nb out args */ - fprintf(outfile, ",$%d", nb_oargs); + qemu_log(",$%d", nb_oargs); for(i = 0; i < nb_oargs; i++) { - fprintf(outfile, ","); - fprintf(outfile, "%s", - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); + qemu_log(","); + qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), + args[i])); } for(i = 0; i < (nb_iargs - 1); i++) { - fprintf(outfile, ","); + qemu_log(","); if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { - fprintf(outfile, ""); + qemu_log(""); } else { - fprintf(outfile, "%s", - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); + qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), + args[nb_oargs + i])); } } } else if (c == INDEX_op_movi_i32 @@ -942,20 +948,21 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) nb_oargs = def->nb_oargs; nb_iargs = def->nb_iargs; nb_cargs = def->nb_cargs; - fprintf(outfile, " %s %s,$", def->name, - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); + qemu_log(" %s %s,$", def->name, + tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); val = args[1]; th = tcg_find_helper(s, val); if (th) { - fprintf(outfile, "%s", th->name); + qemu_log("%s", th->name); } else { - if (c == INDEX_op_movi_i32) - fprintf(outfile, "0x%x", (uint32_t)val); - else - fprintf(outfile, "0x%" PRIx64 , (uint64_t)val); + if (c == INDEX_op_movi_i32) { + qemu_log("0x%x", (uint32_t)val); + } else { + qemu_log("0x%" PRIx64 , (uint64_t)val); + } } } else { - fprintf(outfile, " %s ", def->name); + qemu_log(" %s ", def->name); if (c == INDEX_op_nopn) { /* variable number of arguments */ nb_cargs = *args; @@ -969,16 +976,18 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) k = 0; for(i = 0; i < nb_oargs; i++) { - if (k != 0) - fprintf(outfile, ","); - fprintf(outfile, "%s", - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + if (k != 0) { + qemu_log(","); + } + qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), + args[k++])); } for(i = 0; i < nb_iargs; i++) { - if (k != 0) - fprintf(outfile, ","); - fprintf(outfile, "%s", - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++])); + if (k != 0) { + qemu_log(","); + } + qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), + args[k++])); } switch (c) { case INDEX_op_brcond_i32: @@ -993,10 +1002,11 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) #elif TCG_TARGET_REG_BITS == 64 case INDEX_op_setcond_i64: #endif - if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) - fprintf(outfile, ",%s", cond_name[args[k++]]); - else - fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]); + if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) { + qemu_log(",%s", cond_name[args[k++]]); + } else { + qemu_log(",$0x%" TCG_PRIlx, args[k++]); + } i = 1; break; default: @@ -1004,13 +1014,14 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) break; } for(; i < nb_cargs; i++) { - if (k != 0) - fprintf(outfile, ","); + if (k != 0) { + qemu_log(","); + } arg = args[k++]; - fprintf(outfile, "$0x%" TCG_PRIlx, arg); + qemu_log("$0x%" TCG_PRIlx, arg); } } - fprintf(outfile, "\n"); + qemu_log("\n"); args += nb_iargs + nb_oargs + nb_cargs; } } @@ -2043,7 +2054,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { qemu_log("OP:\n"); - tcg_dump_ops(s, logfile); + tcg_dump_ops(s); qemu_log("\n"); } #endif @@ -2064,7 +2075,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) { qemu_log("OP after liveness analysis:\n"); - tcg_dump_ops(s, logfile); + tcg_dump_ops(s); qemu_log("\n"); } #endif @@ -2245,3 +2256,267 @@ 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, +#ifdef ELF_HOST_FLAGS + .e_flags = ELF_HOST_FLAGS, +#endif +#ifdef ELF_OSABI + .e_ident[EI_OSABI] = ELF_OSABI, +#endif + }, + .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 */