This is the mail archive of the
gdb@sourceware.org
mailing list for the GDB project.
jit interface and jit reader
- From: Frank Tetzel <s1445051 at mail dot zih dot tu-dresden dot de>
- To: gdb at sourceware dot org
- Date: Fri, 18 Jan 2019 11:50:04 +0100
- Subject: jit interface and jit reader
Hi,
I have trouble getting GDB's jit interface to work. I'm trying to make
application using AsmJit [1] easier to debug by being able to break
when entering jitted code. As AsmJit is just an assembler returning a
function pointer to the generated code, I do not want to create an
object file for it. That is why I'm trying to use jit-reader, but the
symbol does not seem to show up in GDB and a pending breakpoint is
never hit.
What am I doing wrong? I attached two files: gdbjit.cpp is talking to
GDB via the jit interface. gdbjit-reader.c is the jit reader for GDB
which I compile to a shared object and load in GDB with jit-reader-load.
It does not implement unwind and get_frame_id. Do I need these
functions? unwind is called sometimes. Is there a minimal example
somewhere which implements jit reader?
Best regards,
Frank
[1] https://github.com/asmjit/asmjit
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cstdint>
extern "C" {
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 char *symfile_addr;
uint64_t symfile_size;
};
struct jit_descriptor {
uint32_t version;
// This type should be jit_actions_t, but we use uint32_t
// to be explicit about the bitwidth.
uint32_t action_flag;
struct jit_code_entry *relevant_entry;
struct jit_code_entry *first_entry;
};
// GDB puts a breakpoint in this function.
void __attribute__((noinline)) __jit_debug_register_code() {}
// 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 };
} // extern "C"
void register_code(const char *name, uint64_t addr, uint64_t size){
puts("register_code called");
printf("name: %s; addr: %lu; size: %lu\n", name, addr, size);
uint64_t name_size = strlen(name)+1; // including null terminator
uint64_t symfile_size = name_size + 2*sizeof(uint64_t);
char *symfile = (char*)malloc(symfile_size);
char *ptr = symfile;
// begin address
*(uint64_t*)ptr = addr;
ptr += sizeof(uint64_t);
// end address
*(uint64_t*)ptr = addr + size;
ptr += sizeof(uint64_t);
// function/symbol name
(void)memcpy(ptr, name, name_size);
// create entry
jit_code_entry *n = new jit_code_entry; //FIXME: memory leak currently
n->next_entry = nullptr;
n->prev_entry = nullptr;
n->symfile_addr = symfile;
n->symfile_size = symfile_size;
// insert into linked list
jit_code_entry *entry = __jit_debug_descriptor.first_entry;
n->next_entry = entry;
if(entry){
entry->prev_entry = n;
}
__jit_debug_descriptor.first_entry = n;
// let GDB know about the new entry
__jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
__jit_debug_descriptor.relevant_entry = n;
puts("calling GDB");
__jit_debug_register_code();
}
#include <gdb/jit-reader.h>
#include <stdlib.h>
#include <stdio.h>
GDB_DECLARE_GPL_COMPATIBLE_READER
enum gdb_status read_debug_info(struct gdb_reader_funcs *self, struct gdb_symbol_callbacks *cb, void *memory, long memory_sz){
puts("reader read_debug_info called");
// get begin and end of code segment
GDB_CORE_ADDR begin = *(GDB_CORE_ADDR*)memory;
memory += sizeof(GDB_CORE_ADDR);
GDB_CORE_ADDR end = *(GDB_CORE_ADDR*)memory;
memory += sizeof(GDB_CORE_ADDR);
// get name of function, just a single one per file
const char *name = (const char*)memory;
printf("creating symbol %s at %lu - %lu (size=%lu)\n", name, begin, end, end - begin);
struct gdb_object *obj = cb->object_open(cb);
struct gdb_symtab *symtab = cb->symtab_open(cb, obj, NULL);
struct gdb_block *block = cb->block_open(cb, symtab, NULL, begin, end, name);
cb->symtab_close(cb, symtab);
cb->object_close(cb, obj);
return GDB_SUCCESS;
}
enum gdb_status unwind(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cb){
puts("reader unwind called");
//TODO
return GDB_FAIL;
}
struct gdb_frame_id get_frame_id(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cb){
puts("reader get_frame_id called");
//TODO
struct gdb_frame_id frame = {0, 0};
return frame;
}
void destroy(struct gdb_reader_funcs *self){
puts("reader destroy called");
free(self);
}
struct gdb_reader_funcs *gdb_init_reader(void){
puts("gdb_init_reader called");
struct gdb_reader_funcs *funcs = malloc(sizeof(struct gdb_reader_funcs));
funcs->reader_version = GDB_READER_INTERFACE_VERSION;
funcs->priv_data = NULL;
funcs->read = read_debug_info;
funcs->unwind = unwind;
funcs->get_frame_id = get_frame_id;
funcs->destroy = destroy;
return funcs;
}