jit interface and jit reader

Frank Tetzel <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <20190118115004.1a51eefc@archvm>
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
gdbjit.cpp (text/x-c++src, 2 KB)
#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();
}
gdbjit-reader.c (text/x-c++src, 1.7 KB)
#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;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.