This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

JIT custom reader


Hi,

I was experimenting with the new JIT interface of GDB, in particular
with the custom jit-reader interface.

My goal was to load the native code application and step through in GDB
just using jit interface using fopen to fread it to the memory as flat
binary code (not containing any references symbols, fully relocatable -
just single pure function).

First of all I tried to load the executable using fopen and fread to put
into the buffer and then use the jit interface, which worked fine, I was
able to enter the source code associated with that executable, and have
an expected seg fault when I jumped into - because I was not able to
relocate the symbols to a different location than the executable got -
and GDB associated. I used proxy approach - having a jit-host that loads
a file and a executable file being jitted into the process space of
jit-host.

Then, happy with the result, I tried gdb-reader interface, I wrote a
plugin, which pretty much just registers symbol "foobar123" and
associated that with the buffer debugee address. Full line information
was not provided - but I could extract it from objdump of the binary. I
was able to execute the buffer of course and return from the callee, but
"b foobar123" does not seem to find the symbol, also I am not able to
see the code listing too - even when the line information was there. So
I had completely opposite problem - executing the code, but no debugging
information.

I'm using gdb trunk.

So I have a couple of questions:

- I am copying the example the code [1],[2], could you tell if there is
  anything obviously wrong with how gdb jit reader is used?

- I know of limitation of jit reader plugins - only one at a time, then
  question is what if I want to use several jit readers? Do I need to
  fallback to ELF and DWARF in memory or tag the code with extra
  information for the plugin to make an action (certainly that's not
  flexible enough). How to differentiate which reader shall be called -
  I could imagine where I want to debug, js JIT, regex JIT and some
  other jit possibly, at the same time but from different vendors, and
  all of them using different jit reader plugins.

Thanks for your help in advance!
Wojciech

[1] host-jit.c
================================================================================

#include <sys/mman.h>
#include <libelf.h>
#include "jit-reader.h"
#include "defs.h"
#include "jit.h"

/* On X86 page size is always 4096 */
char buffer[10*4096] __attribute__((aligned (4096)));

struct gdb_reader_funcs
reader_func_struct = { GDB_READER_INTERFACE_VERSION, 
                       0, 
                       0, 
                       0, 
                       0 };

/* Make sure to specify the version statically, because the
   debugger may check the version before we can set it.  */
struct jit_descriptor __jit_debug_descriptor = {1,0,0,0};
struct jit_code_entry entry = { 0, 0, 0, 0 };

typedef int (*func)();

/* GDB puts a breakpoint in this function.  */
void __attribute__((noinline)) __jit_debug_register_code()
{
  __asm("");
};

int main (int argc, char* argv[])
{
  FILE *f;
  int size;

  if (2 != argc) {
    fprintf (stderr, "Wrong number of arguments. Usage: jit-host <flat_binary_file>");
    exit (1);
  }

  f = fopen (argv[1], "rb");
  if (NULL == f) {
    fprintf (stderr, "Can't open file %s", argv[1]);
    exit (2);
  }

  int pagesize = sysconf(_SC_PAGE_SIZE);

  if (0 != mprotect(buffer, pagesize, PROT_WRITE|PROT_READ|PROT_EXEC)) {
    perror(NULL);
    exit(3);
  }
    
  size = fread(buffer, 1, 10*pagesize, f);
  fclose(f);

  /* Just in case if you want to JIT "ret" instruction */
  //  buffer[0] = 0xc3;

  entry.symfile_addr = (GDB_CORE_ADDR)buffer;
  entry.symfile_size = size;
  __jit_debug_descriptor.first_entry =
    __jit_debug_descriptor.relevant_entry = (GDB_CORE_ADDR)&entry;
  __jit_debug_descriptor.action_flag = JIT_REGISTER;
  __jit_debug_descriptor.version = 1;
  __jit_debug_register_code();

  /* Either works */
  //  __asm("callq  0x603000");
  (((func)(buffer)))();
  return 0;
}

[2] jit-reading.c
================================================================================
#include "jit-reader.h"
#include "defs.h"
#include "jit.h"
#include "command.h"
#include "gdb-dlfcn.h"

GDB_DECLARE_GPL_COMPATIBLE_READER;

static enum gdb_status read_debug_info (struct gdb_reader_funcs *self,
                                        struct gdb_symbol_callbacks *cb,
                                        void *memory, long memory_sz)
{
  //  struct gdb_line_mapping line_mapping[1]; 
  struct gdb_object * object = cb->object_open(cb);
  struct gdb_symtab * symtab = cb->symtab_open(cb, object, "/home/wmeyer/testmyjit.c");
  /* This debuggee addresses are fixed, but there are 100% correct during testing */
  struct gdb_block * block = cb->block_open(cb, symtab, NULL, 0x0603000, 0x603000 + 1024, "foobar123");

  /* Here I am loading the line numbers, but I am skipping it for time
  being, either ways not working */

  /* line_mapping[0].pc = 0x0603000; */
  /* line_mapping[0].line = 0; */
  /* cb->line_mapping_add (cb, symtab, 1, line_mapping); */

  /* This prints out the message when the function is registered in jit-host */
  printf("Reading debug info");

  cb->symtab_close (cb, symtab);
  cb->object_close (cb, object);
  return GDB_SUCCESS; /* cb->target_read(0x603000, memory, memory_sz); */
};

 enum gdb_status unwind_frame (struct gdb_reader_funcs *self,
                               struct gdb_unwind_callbacks *cb)
{
  return GDB_SUCCESS;
}

struct gdb_frame_id get_frame_id (struct gdb_reader_funcs *self,
                                  struct gdb_unwind_callbacks *c)
{
  struct gdb_frame_id frame =
  {
    0x603000, // GDB_CORE_ADDR code_address; 
    0x603000+1024,  // GDB_CORE_ADDR stack_address;
  };

  return frame;
}

void destroy_reader (struct gdb_reader_funcs *self)
{
}

static void jit_file_command (char *args, int from_tty) {
  
}

extern struct gdb_reader_funcs *gdb_init_reader (void) {
  static struct gdb_reader_funcs funcs = {
    GDB_READER_INTERFACE_VERSION,
    NULL,
    read_debug_info,
    unwind_frame,
    get_frame_id,
    destroy_reader
  };
  return &funcs;
}




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]