Patchwork [1/4] tcg: Add debug_info to JIT ELF image.

login
register
mail settings
Submitter Richard Henderson
Date March 24, 2012, 5:47 p.m.
Message ID <1332611259-14940-2-git-send-email-rth@twiddle.net>
Download mbox | patch
Permalink /patch/148529/
State New
Headers show

Comments

Richard Henderson - March 24, 2012, 5:47 p.m.
This allows us to actually supply a function name in softmmu builds;
gdb doesn't pick up the minimal symbol table otherwise.  Also add a
bit of documentation and statically generate more of the ELF image.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 tcg/tcg.c |  233 +++++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 158 insertions(+), 75 deletions(-)
Avi Kivity - April 16, 2012, 4:28 p.m.
On 03/24/2012 07:47 PM, Richard Henderson wrote:
> This allows us to actually supply a function name in softmmu builds;
> gdb doesn't pick up the minimal symbol table otherwise.  Also add a
> bit of documentation and statically generate more of the ELF image.
>
>

Looks like this is the cause of

# file /usr/local/bin/qemu-system-x86_64
/usr/local/bin/qemu-system-x86_64: ELF 64-bit LSB shared object, x86-64,
version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux
2.6.32, not stripped
# gdb -p `pgrep qemu`
<blurb>
Attaching to process 2119
Reading symbols from /usr/local/bin/qemu-system-x86_64...done.
Unable to read JIT descriptor from remote memory!
(gdb) bt
#0  0x00007f4a1257cae5 in ?? ()
#1  0x0000000000000000 in ?? ()
(gdb)
Richard Henderson - April 16, 2012, 7:46 p.m.
On 04/16/2012 11:28 AM, Avi Kivity wrote:
> Unable to read JIT descriptor from remote memory!
> (gdb) bt
> #0  0x00007f4a1257cae5 in ?? ()
> #1  0x0000000000000000 in ?? ()
> (gdb)

set debug jit 1


r~
Avi Kivity - April 17, 2012, 7:46 a.m.
On 04/16/2012 10:46 PM, Richard Henderson wrote:
> On 04/16/2012 11:28 AM, Avi Kivity wrote:
> > Unable to read JIT descriptor from remote memory!
> > (gdb) bt
> > #0  0x00007f4a1257cae5 in ?? ()
> > #1  0x0000000000000000 in ?? ()
> > (gdb)
>
> set debug jit 1

Added to .gdbinit:

GNU gdb (GDB) Fedora (7.3.50.20110722-13.fc16)
...
Attaching to process 2119
jit_inferior_init
Reading symbols from /usr/local/bin/qemu-system-x86_64...done.
jit_inferior_init
jit_inferior_init, descriptor_addr = 0x6f7560
Unable to read JIT descriptor from remote memory!
(gdb) bt
#0  0x00007f4a1257cae5 in ?? ()
#1  0x0000000000000000 in ?? ()
(gdb)
Richard Henderson - April 17, 2012, 1:35 p.m.
On 04/17/2012 02:46 AM, Avi Kivity wrote:
> Attaching to process 2119
> jit_inferior_init
> Reading symbols from /usr/local/bin/qemu-system-x86_64...done.
> jit_inferior_init
> jit_inferior_init, descriptor_addr = 0x6f7560
> Unable to read JIT descriptor from remote memory!

Hmm, yes.  You could work around this with --disable-pie for the moment,
or try to invoke the qemu process from gdb directly.  Although if you're
trying to debug the complete libvirt+qemu stack that may be a problem...

FYI: http://sourceware.org/bugzilla/show_bug.cgi?id=13987


r~

Patch

diff --git a/tcg/tcg.c b/tcg/tcg.c
index eb595ce..df4edc0 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2252,8 +2252,17 @@  void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf)
 #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.  */
+/* 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 {
@@ -2300,96 +2309,169 @@  static int find_string(const char *strtab, const char *str)
     }
 }
 
-static void tcg_register_jit_int(void *buf, size_t buf_size,
+static void tcg_register_jit_int(void *buf_ptr, 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 __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[5];
-        ElfW(Sym)  sym[1];
-        char       str[64];
+        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;
-    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 = g_malloc(img_size);
+    *img = img_template;
+    memcpy(img + 1, debug_frame, debug_frame_size);
 
-    img->shdr[0].sh_type = SHT_NULL;
+    img->phdr.p_vaddr = buf;
+    img->phdr.p_paddr = buf;
+    img->phdr.p_memsz = buf_size;
 
-    /* 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_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[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->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;
+    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.
@@ -2397,7 +2479,7 @@  static void tcg_register_jit_int(void *buf, size_t buf_size,
     {
         FILE *f = fopen("/tmp/qemu.jit", "w+b");
         if (f) {
-            if (fwrite(img, img_size, 1, f) != buf_size) {
+            if (fwrite(img, img_size, 1, f) != img_size) {
                 /* Avoid stupid unused return value warning for fwrite.  */
             }
             fclose(f);
@@ -2414,7 +2496,8 @@  static void tcg_register_jit_int(void *buf, size_t buf_size,
     __jit_debug_register_code();
 }
 #else
-/* No support for the feature.  Provide the entry point expected by exec.c.  */
+/* 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)