Skip to content

Commit 450dae6

Browse files
garazdawijhogbergdgudbjorng
committed
erts: Implement the BeamAsm JIT
Co-authored-by: John Högberg <[email protected]> Co-authored-by: Dan Gudmundsson <[email protected]> Co-authored-by: Björn Gustavsson <[email protected]>
1 parent e25d966 commit 450dae6

File tree

2 files changed

+528
-0
lines changed

2 files changed

+528
-0
lines changed

jit-reader.c

+182
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#include "jit-reader.h"
2+
3+
#include <stdlib.h>
4+
#include <stdio.h>
5+
#include <stdint.h>
6+
#include <string.h>
7+
8+
/* Useful links
9+
* - https://pwparchive.wordpress.com/2011/11/20/new-jit-interface-for-gdb/
10+
* - https://sourceware.org/gdb/current/onlinedocs/gdb/Custom-Debug-Info.html
11+
* - https://github.com/tetzank/asmjit-utilities
12+
* - https://github.com/bminor/binutils-gdb/blob/master/gdb/testsuite/gdb.base/jitreader.c
13+
*/
14+
15+
GDB_DECLARE_GPL_COMPATIBLE_READER
16+
17+
/* #define HARD_DEBUG */
18+
19+
typedef struct range {
20+
GDB_CORE_ADDR start;
21+
GDB_CORE_ADDR end;
22+
} range;
23+
24+
typedef struct priv {
25+
range *ranges;
26+
int num_ranges;
27+
} priv;
28+
29+
static enum gdb_status read_debug_info(struct gdb_reader_funcs *self,
30+
struct gdb_symbol_callbacks *cb,
31+
void *memory, long memory_sz) {
32+
priv *priv = self->priv_data;
33+
uint64_t num_functions = *(uint64_t*)memory;
34+
GDB_CORE_ADDR mod_start = *(GDB_CORE_ADDR *)(memory + sizeof(uint64_t));
35+
GDB_CORE_ADDR mod_end = mod_start + *(uint64_t*)(memory + sizeof(uint64_t)*2);
36+
char* module = memory + sizeof(uint64_t)*3;
37+
char* curr = module + strlen(module) + 1;
38+
int i;
39+
struct gdb_object *obj = cb->object_open(cb);
40+
41+
priv->ranges = realloc(priv->ranges, sizeof(range) * ++priv->num_ranges);
42+
priv->ranges[priv->num_ranges-1].start = mod_start;
43+
priv->ranges[priv->num_ranges-1].end = mod_end;
44+
45+
#ifdef HARD_DEBUG
46+
fprintf(stderr,"Add module %s (%lx, %lx)\r\n", module, mod_start, mod_end);
47+
#endif
48+
49+
for (i = 0; i < num_functions; i++) {
50+
// get begin and end of code segment
51+
// A bug in GDB < 9 forces us to open and close the symtab for each iteration
52+
struct gdb_symtab *symtab = cb->symtab_open(cb, obj, module);
53+
GDB_CORE_ADDR begin = *(GDB_CORE_ADDR*)curr;
54+
GDB_CORE_ADDR end = *(GDB_CORE_ADDR*)(curr + sizeof(GDB_CORE_ADDR));
55+
// get name of function
56+
const char *name = (const char*)(curr + sizeof(GDB_CORE_ADDR) * 2);
57+
curr += strlen(name) + 1 + sizeof(GDB_CORE_ADDR) * 2;
58+
59+
#ifdef HARD_DEBUG
60+
fprintf(stderr,"Add %s (%lx, %lx)\r\n", name, begin, end);
61+
#endif
62+
63+
// returned value has no use
64+
cb->block_open(cb, symtab, NULL, begin, end, name);
65+
cb->symtab_close(cb, symtab);
66+
}
67+
68+
cb->object_close(cb, obj);
69+
return GDB_SUCCESS;
70+
}
71+
72+
static void regfree(struct gdb_reg_value *reg) {
73+
free(reg);
74+
}
75+
76+
static enum gdb_status unwind(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cb) {
77+
int i;
78+
priv *priv = self->priv_data;
79+
GDB_CORE_ADDR rip = *(GDB_CORE_ADDR*)cb->reg_get(cb,16)->value;
80+
#ifdef HARD_DEBUG
81+
GDB_CORE_ADDR rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb,7)->value;
82+
#endif
83+
GDB_CORE_ADDR rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb,6)->value;
84+
85+
/* Check that rip points to one of the addresses that we handle */
86+
for (i = 0; i < priv->num_ranges; i++) {
87+
if (rip >= priv->ranges[i].start && rip < priv->ranges[i].end) {
88+
struct gdb_reg_value *prev_rsp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)),
89+
*prev_rip = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)),
90+
*prev_rbp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*));
91+
92+
#ifdef HARD_DEBUG
93+
fprintf(stderr,"UNWIND match: rip: %lx rsp: %lx rbp: %lx \r\n", rip, rsp, rbp);
94+
#endif
95+
/* We use the normal frame-pointer logic to unwind the stack, which means
96+
that rbp will point to where we stored the previous frames rbp. Also
97+
the previous frames address will be at rbp + 1 and the previous frames
98+
rsp will be rbp + 2.
99+
100+
0x00: <- prev_rsp
101+
0x80: prev call addr
102+
0x10: prev rbp <- curr rbp
103+
0x18: current frame
104+
0x20: <- curr rip
105+
106+
*/
107+
108+
prev_rsp->free = &regfree;
109+
prev_rsp->defined = 1;
110+
prev_rsp->size = sizeof(char*);
111+
((GDB_CORE_ADDR*)prev_rsp->value)[0] = rbp + sizeof(char*) * 2;
112+
113+
cb->target_read(rbp + 0 * sizeof(char*), &prev_rbp->value, sizeof(char*));
114+
prev_rbp->free = &regfree;
115+
prev_rbp->defined = 1;
116+
prev_rbp->size = sizeof(char*);
117+
118+
cb->target_read(rbp + 1 * sizeof(char*), &prev_rip->value, sizeof(char*));
119+
prev_rip->free = &regfree;
120+
prev_rip->defined = 1;
121+
prev_rip->size = sizeof(char*);
122+
123+
#ifdef HARD_DEBUG
124+
fprintf(stderr,"UNWIND prev: rip: %lx rsp: %lx rbp: %lx\r\n",
125+
*(GDB_CORE_ADDR*)prev_rip->value,
126+
*(GDB_CORE_ADDR*)prev_rsp->value,
127+
*(GDB_CORE_ADDR*)prev_rbp->value);
128+
#endif
129+
130+
cb->reg_set(cb, 16, prev_rip);
131+
cb->reg_set(cb, 7, prev_rsp);
132+
cb->reg_set(cb, 6, prev_rbp);
133+
return GDB_SUCCESS;
134+
}
135+
}
136+
#ifdef HARD_DEBUG
137+
fprintf(stderr,"UNWIND no match: rip: %lx rsp: %lx rbp: %lx\r\n", rip, rsp, rbp);
138+
#endif
139+
return GDB_FAIL;
140+
}
141+
142+
static struct gdb_frame_id get_frame_id(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cb){
143+
int i;
144+
priv *priv = self->priv_data;
145+
struct gdb_frame_id frame = {0, 0};
146+
GDB_CORE_ADDR rip = *(GDB_CORE_ADDR*)cb->reg_get(cb,16)->value;
147+
GDB_CORE_ADDR rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb,6)->value;
148+
#ifdef HARD_DEBUG
149+
GDB_CORE_ADDR rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb,7)->value;
150+
fprintf(stderr,"FRAME: rip: %lx rsp: %lx rbp: %lx \r\n", rip, rsp, rbp);
151+
#endif
152+
for (i = 0; i < priv->num_ranges; i++) {
153+
if (rip >= priv->ranges[i].start && rip < priv->ranges[i].end) {
154+
frame.code_address = priv->ranges[i].start;
155+
frame.stack_address = rbp + sizeof(char*);
156+
}
157+
}
158+
return frame;
159+
}
160+
161+
static void destroy(struct gdb_reader_funcs *self){
162+
free(self);
163+
}
164+
165+
struct gdb_reader_funcs *gdb_init_reader(void){
166+
struct gdb_reader_funcs *funcs = malloc(sizeof(struct gdb_reader_funcs));
167+
priv *priv = malloc(sizeof(priv));
168+
priv->num_ranges = 1;
169+
priv->ranges = malloc(sizeof(range));
170+
priv->ranges[0].start = 0;
171+
priv->ranges[0].end = 0;
172+
173+
funcs->reader_version = GDB_READER_INTERFACE_VERSION;
174+
funcs->priv_data = priv;
175+
176+
funcs->read = read_debug_info;
177+
funcs->unwind = unwind;
178+
funcs->get_frame_id = get_frame_id;
179+
funcs->destroy = destroy;
180+
181+
return funcs;
182+
}

0 commit comments

Comments
 (0)