diff options
Diffstat (limited to 'src/lj_gdbjit.c')
-rw-r--r-- | src/lj_gdbjit.c | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/src/lj_gdbjit.c b/src/lj_gdbjit.c new file mode 100644 index 00000000..dfec188a --- /dev/null +++ b/src/lj_gdbjit.c | |||
@@ -0,0 +1,739 @@ | |||
1 | /* | ||
2 | ** Client for the GDB JIT API. | ||
3 | ** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #define lj_gdbjit_c | ||
7 | #define LUA_CORE | ||
8 | |||
9 | #include "lj_obj.h" | ||
10 | |||
11 | #if LJ_HASJIT | ||
12 | |||
13 | #include "lj_gc.h" | ||
14 | #include "lj_err.h" | ||
15 | #include "lj_str.h" | ||
16 | #include "lj_frame.h" | ||
17 | #include "lj_jit.h" | ||
18 | #include "lj_dispatch.h" | ||
19 | |||
20 | /* This is not compiled in by default. | ||
21 | ** Enable with -DLUAJIT_USE_GDBJIT in the Makefile and recompile everything. | ||
22 | */ | ||
23 | #ifdef LUAJIT_USE_GDBJIT | ||
24 | |||
25 | /* The GDB JIT API allows JIT compilers to pass debug information about | ||
26 | ** JIT-compiled code back to GDB. You need at least GDB 7.0 or higher | ||
27 | ** to see it in action. | ||
28 | ** | ||
29 | ** This is a passive API, so it works even when not running under GDB | ||
30 | ** or when attaching to an already running process. Alas, this implies | ||
31 | ** enabling it always has a non-negligible overhead -- do not use in | ||
32 | ** release mode! | ||
33 | ** | ||
34 | ** The LuaJIT GDB JIT client is rather minimal at the moment. It gives | ||
35 | ** each trace a symbol name and adds a source location and frame unwind | ||
36 | ** information. Obviously LuaJIT itself and any embedding C application | ||
37 | ** should be compiled with debug symbols, too (see the Makefile). | ||
38 | ** | ||
39 | ** Traces are named TRACE_1, TRACE_2, ... these correspond to the trace | ||
40 | ** numbers from -jv or -jdump. Use "break TRACE_1" or "tbreak TRACE_1" etc. | ||
41 | ** to set breakpoints on specific traces (even ahead of their creation). | ||
42 | ** | ||
43 | ** The source location for each trace allows listing the corresponding | ||
44 | ** source lines with the GDB command "list" (but only if the Lua source | ||
45 | ** has been loaded from a file). Currently this is always set to the | ||
46 | ** location where the trace has been started. | ||
47 | ** | ||
48 | ** Frame unwind information can be inspected with the GDB command | ||
49 | ** "info frame". This also allows proper backtraces across JIT-compiled | ||
50 | ** code with the GDB command "bt". | ||
51 | ** | ||
52 | ** You probably want to add the following settings to a .gdbinit file | ||
53 | ** (or add them to ~/.gdbinit): | ||
54 | ** set disassembly-flavor intel | ||
55 | ** set breakpoint pending on | ||
56 | ** | ||
57 | ** Here's a sample GDB session: | ||
58 | ** ------------------------------------------------------------------------ | ||
59 | |||
60 | $ cat >x.lua | ||
61 | for outer=1,100 do | ||
62 | for inner=1,100 do end | ||
63 | end | ||
64 | ^D | ||
65 | |||
66 | $ luajit -jv x.lua | ||
67 | [TRACE 1 x.lua:2] | ||
68 | [TRACE 2 (1/3) x.lua:1 -> 1] | ||
69 | |||
70 | $ gdb --quiet --args luajit x.lua | ||
71 | (gdb) tbreak TRACE_1 | ||
72 | Function "TRACE_1" not defined. | ||
73 | Temporary breakpoint 1 (TRACE_1) pending. | ||
74 | (gdb) run | ||
75 | Starting program: luajit x.lua | ||
76 | |||
77 | Temporary breakpoint 1, TRACE_1 () at x.lua:2 | ||
78 | 2 for inner=1,100 do end | ||
79 | (gdb) list | ||
80 | 1 for outer=1,100 do | ||
81 | 2 for inner=1,100 do end | ||
82 | 3 end | ||
83 | (gdb) bt | ||
84 | #0 TRACE_1 () at x.lua:2 | ||
85 | #1 0x08053690 in lua_pcall [...] | ||
86 | [...] | ||
87 | #7 0x0806ff90 in main [...] | ||
88 | (gdb) disass TRACE_1 | ||
89 | Dump of assembler code for function TRACE_1: | ||
90 | 0xf7fd9fba <TRACE_1+0>: mov DWORD PTR ds:0xf7e0e2a0,0x1 | ||
91 | 0xf7fd9fc4 <TRACE_1+10>: movsd xmm7,QWORD PTR [edx+0x20] | ||
92 | [...] | ||
93 | 0xf7fd9ff8 <TRACE_1+62>: jmp 0xf7fd2014 | ||
94 | End of assembler dump. | ||
95 | (gdb) tbreak TRACE_2 | ||
96 | Function "TRACE_2" not defined. | ||
97 | Temporary breakpoint 2 (TRACE_2) pending. | ||
98 | (gdb) cont | ||
99 | Continuing. | ||
100 | |||
101 | Temporary breakpoint 2, TRACE_2 () at x.lua:1 | ||
102 | 1 for outer=1,100 do | ||
103 | (gdb) info frame | ||
104 | Stack level 0, frame at 0xffffd7c0: | ||
105 | eip = 0xf7fd9f60 in TRACE_2 (x.lua:1); saved eip 0x8053690 | ||
106 | called by frame at 0xffffd7e0 | ||
107 | source language unknown. | ||
108 | Arglist at 0xffffd78c, args: | ||
109 | Locals at 0xffffd78c, Previous frame's sp is 0xffffd7c0 | ||
110 | Saved registers: | ||
111 | ebx at 0xffffd7ac, ebp at 0xffffd7b8, esi at 0xffffd7b0, edi at 0xffffd7b4, | ||
112 | eip at 0xffffd7bc | ||
113 | (gdb) | ||
114 | |||
115 | ** ------------------------------------------------------------------------ | ||
116 | */ | ||
117 | |||
118 | /* -- GDB JIT API --------------------------------------------------------- */ | ||
119 | |||
120 | /* GDB JIT actions. */ | ||
121 | enum { | ||
122 | GDBJIT_NOACTION = 0, | ||
123 | GDBJIT_REGISTER, | ||
124 | GDBJIT_UNREGISTER | ||
125 | }; | ||
126 | |||
127 | /* GDB JIT entry. */ | ||
128 | typedef struct GDBJITentry { | ||
129 | struct GDBJITentry *next_entry; | ||
130 | struct GDBJITentry *prev_entry; | ||
131 | const char *symfile_addr; | ||
132 | uint64_t symfile_size; | ||
133 | } GDBJITentry; | ||
134 | |||
135 | /* GDB JIT descriptor. */ | ||
136 | typedef struct GDBJITdesc { | ||
137 | uint32_t version; | ||
138 | uint32_t action_flag; | ||
139 | GDBJITentry *relevant_entry; | ||
140 | GDBJITentry *first_entry; | ||
141 | } GDBJITdesc; | ||
142 | |||
143 | GDBJITdesc __jit_debug_descriptor = { | ||
144 | 1, GDBJIT_NOACTION, NULL, NULL | ||
145 | }; | ||
146 | |||
147 | /* GDB sets a breakpoint at this function. */ | ||
148 | void LJ_NOINLINE __jit_debug_register_code() | ||
149 | { | ||
150 | __asm__ __volatile__(""); | ||
151 | }; | ||
152 | |||
153 | /* -- In-memory ELF object definitions ------------------------------------ */ | ||
154 | |||
155 | /* ELF definitions. */ | ||
156 | typedef struct ELFheader { | ||
157 | uint8_t emagic[4]; | ||
158 | uint8_t eclass; | ||
159 | uint8_t eendian; | ||
160 | uint8_t eversion; | ||
161 | uint8_t eosabi; | ||
162 | uint8_t eabiversion; | ||
163 | uint8_t epad[7]; | ||
164 | uint16_t type; | ||
165 | uint16_t machine; | ||
166 | uint32_t version; | ||
167 | uintptr_t entry; | ||
168 | uintptr_t phofs; | ||
169 | uintptr_t shofs; | ||
170 | uint32_t flags; | ||
171 | uint16_t ehsize; | ||
172 | uint16_t phentsize; | ||
173 | uint16_t phnum; | ||
174 | uint16_t shentsize; | ||
175 | uint16_t shnum; | ||
176 | uint16_t shstridx; | ||
177 | } ELFheader; | ||
178 | |||
179 | typedef struct ELFsectheader { | ||
180 | uint32_t name; | ||
181 | uint32_t type; | ||
182 | uintptr_t flags; | ||
183 | uintptr_t addr; | ||
184 | uintptr_t ofs; | ||
185 | uintptr_t size; | ||
186 | uint32_t link; | ||
187 | uint32_t info; | ||
188 | uintptr_t align; | ||
189 | uintptr_t entsize; | ||
190 | } ELFsectheader; | ||
191 | |||
192 | #define ELFSECT_IDX_ABS 0xfff1 | ||
193 | |||
194 | enum { | ||
195 | ELFSECT_TYPE_PROGBITS = 1, | ||
196 | ELFSECT_TYPE_SYMTAB = 2, | ||
197 | ELFSECT_TYPE_STRTAB = 3, | ||
198 | ELFSECT_TYPE_NOBITS = 8 | ||
199 | }; | ||
200 | |||
201 | #define ELFSECT_FLAGS_WRITE 1 | ||
202 | #define ELFSECT_FLAGS_ALLOC 2 | ||
203 | #define ELFSECT_FLAGS_EXEC 4 | ||
204 | |||
205 | typedef struct ELFsymbol { | ||
206 | #if LJ_64 | ||
207 | uint32_t name; | ||
208 | uint8_t info; | ||
209 | uint8_t other; | ||
210 | uint16_t sectidx; | ||
211 | uintptr_t value; | ||
212 | uint64_t size; | ||
213 | #else | ||
214 | uint32_t name; | ||
215 | uintptr_t value; | ||
216 | uint32_t size; | ||
217 | uint8_t info; | ||
218 | uint8_t other; | ||
219 | uint16_t sectidx; | ||
220 | #endif | ||
221 | } ELFsymbol; | ||
222 | |||
223 | enum { | ||
224 | ELFSYM_TYPE_FUNC = 2, | ||
225 | ELFSYM_TYPE_FILE = 4, | ||
226 | ELFSYM_BIND_LOCAL = 0 << 4, | ||
227 | ELFSYM_BIND_GLOBAL = 1 << 4, | ||
228 | }; | ||
229 | |||
230 | /* DWARF definitions. */ | ||
231 | #define DW_CIE_VERSION 1 | ||
232 | |||
233 | enum { | ||
234 | DW_CFA_nop = 0x0, | ||
235 | DW_CFA_def_cfa = 0xc, | ||
236 | DW_CFA_def_cfa_offset = 0xe, | ||
237 | DW_CFA_advance_loc = 0x40, | ||
238 | DW_CFA_offset = 0x80 | ||
239 | }; | ||
240 | |||
241 | enum { | ||
242 | DW_EH_PE_udata4 = 3, | ||
243 | DW_EH_PE_textrel = 0x20 | ||
244 | }; | ||
245 | |||
246 | enum { | ||
247 | DW_TAG_compile_unit = 0x11 | ||
248 | }; | ||
249 | |||
250 | enum { | ||
251 | DW_children_no = 0, | ||
252 | DW_children_yes = 1 | ||
253 | }; | ||
254 | |||
255 | enum { | ||
256 | DW_AT_name = 0x03, | ||
257 | DW_AT_stmt_list = 0x10, | ||
258 | DW_AT_low_pc = 0x11, | ||
259 | DW_AT_high_pc = 0x12 | ||
260 | }; | ||
261 | |||
262 | enum { | ||
263 | DW_FORM_addr = 0x01, | ||
264 | DW_FORM_data4 = 0x06, | ||
265 | DW_FORM_string = 0x08 | ||
266 | }; | ||
267 | |||
268 | enum { | ||
269 | DW_LNS_extended_op = 0, | ||
270 | DW_LNS_copy = 1, | ||
271 | DW_LNS_advance_pc = 2, | ||
272 | DW_LNS_advance_line = 3 | ||
273 | }; | ||
274 | |||
275 | enum { | ||
276 | DW_LNE_end_sequence = 1, | ||
277 | DW_LNE_set_address = 2 | ||
278 | }; | ||
279 | |||
280 | enum { | ||
281 | #if LJ_TARGET_X86 | ||
282 | DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX, | ||
283 | DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI, | ||
284 | DW_REG_RA, | ||
285 | #elif LJ_TARGET_X64 | ||
286 | /* Yes, the order is strange, but correct. */ | ||
287 | DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX, | ||
288 | DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP, | ||
289 | DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11, | ||
290 | DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15, | ||
291 | DW_REG_RA, | ||
292 | #else | ||
293 | #error "Unsupported target architecture" | ||
294 | #endif | ||
295 | }; | ||
296 | |||
297 | /* Minimal list of sections for the in-memory ELF object. */ | ||
298 | enum { | ||
299 | GDBJIT_SECT_NULL, | ||
300 | GDBJIT_SECT_text, | ||
301 | GDBJIT_SECT_eh_frame, | ||
302 | GDBJIT_SECT_shstrtab, | ||
303 | GDBJIT_SECT_strtab, | ||
304 | GDBJIT_SECT_symtab, | ||
305 | GDBJIT_SECT_debug_info, | ||
306 | GDBJIT_SECT_debug_abbrev, | ||
307 | GDBJIT_SECT_debug_line, | ||
308 | GDBJIT_SECT__MAX | ||
309 | }; | ||
310 | |||
311 | enum { | ||
312 | GDBJIT_SYM_UNDEF, | ||
313 | GDBJIT_SYM_FILE, | ||
314 | GDBJIT_SYM_FUNC, | ||
315 | GDBJIT_SYM__MAX | ||
316 | }; | ||
317 | |||
318 | /* In-memory ELF object. */ | ||
319 | typedef struct GDBJITobj { | ||
320 | ELFheader hdr; /* ELF header. */ | ||
321 | ELFsectheader sect[GDBJIT_SECT__MAX]; /* ELF sections. */ | ||
322 | ELFsymbol sym[GDBJIT_SYM__MAX]; /* ELF symbol table. */ | ||
323 | uint8_t space[4096]; /* Space for various section data. */ | ||
324 | } GDBJITobj; | ||
325 | |||
326 | /* Combined structure for GDB JIT entry and ELF object. */ | ||
327 | typedef struct GDBJITentryobj { | ||
328 | GDBJITentry entry; | ||
329 | size_t sz; | ||
330 | GDBJITobj obj; | ||
331 | } GDBJITentryobj; | ||
332 | |||
333 | /* Template for in-memory ELF header. */ | ||
334 | static const ELFheader elfhdr_template = { | ||
335 | .emagic = { 0x7f, 'E', 'L', 'F' }, | ||
336 | .eclass = LJ_64 ? 2 : 1, | ||
337 | .eendian = LJ_ENDIAN_SELECT(1, 2), | ||
338 | .eversion = 1, | ||
339 | #if defined(__linux__) | ||
340 | .eosabi = 0, /* Nope, it's not 3. */ | ||
341 | #elif defined(__FreeBSD__) | ||
342 | .eosabi = 9, | ||
343 | #elif defined(__NetBSD__) | ||
344 | .eosabi = 2, | ||
345 | #elif defined(__OpenBSD__) | ||
346 | .eosabi = 12, | ||
347 | #elif defined(__solaris__) | ||
348 | .eosabi = 6, | ||
349 | #else | ||
350 | .eosabi = 0, | ||
351 | #endif | ||
352 | .eabiversion = 0, | ||
353 | .epad = { 0, 0, 0, 0, 0, 0, 0 }, | ||
354 | .type = 1, | ||
355 | #if LJ_TARGET_X86 | ||
356 | .machine = 3, | ||
357 | #elif LJ_TARGET_X64 | ||
358 | .machine = 62, | ||
359 | #else | ||
360 | #error "Unsupported target architecture" | ||
361 | #endif | ||
362 | .version = 1, | ||
363 | .entry = 0, | ||
364 | .phofs = 0, | ||
365 | .shofs = offsetof(GDBJITobj, sect), | ||
366 | .flags = 0, | ||
367 | .ehsize = sizeof(ELFheader), | ||
368 | .phentsize = 0, | ||
369 | .phnum = 0, | ||
370 | .shentsize = sizeof(ELFsectheader), | ||
371 | .shnum = GDBJIT_SECT__MAX, | ||
372 | .shstridx = GDBJIT_SECT_shstrtab | ||
373 | }; | ||
374 | |||
375 | /* -- In-memory ELF object generation ------------------------------------- */ | ||
376 | |||
377 | /* Context for generating the ELF object for the GDB JIT API. */ | ||
378 | typedef struct GDBJITctx { | ||
379 | uint8_t *p; /* Pointer to next address in obj.space. */ | ||
380 | uint8_t *startp; /* Pointer to start address in obj.space. */ | ||
381 | Trace *T; /* Generate symbols for this trace. */ | ||
382 | uintptr_t mcaddr; /* Machine code address. */ | ||
383 | MSize szmcode; /* Size of machine code. */ | ||
384 | MSize spadjp; /* Stack adjustment for parent trace or interpreter. */ | ||
385 | MSize spadj; /* Stack adjustment for trace itself. */ | ||
386 | BCLine lineno; /* Starting line number. */ | ||
387 | const char *filename; /* Starting file name. */ | ||
388 | const char *trname; /* Name of trace. */ | ||
389 | size_t objsize; /* Final size of ELF object. */ | ||
390 | GDBJITobj obj; /* In-memory ELF object. */ | ||
391 | } GDBJITctx; | ||
392 | |||
393 | /* Add a zero-terminated string. */ | ||
394 | static uint32_t gdbjit_strz(GDBJITctx *ctx, const char *str) | ||
395 | { | ||
396 | uint8_t *p = ctx->p; | ||
397 | uint32_t ofs = (uint32_t)(p - ctx->startp); | ||
398 | do { | ||
399 | *p++ = (uint8_t)*str; | ||
400 | } while (*str++); | ||
401 | ctx->p = p; | ||
402 | return ofs; | ||
403 | } | ||
404 | |||
405 | /* Add a ULEB128 value. */ | ||
406 | static void gdbjit_uleb128(GDBJITctx *ctx, uint32_t v) | ||
407 | { | ||
408 | uint8_t *p = ctx->p; | ||
409 | for (; v >= 0x80; v >>= 7) | ||
410 | *p++ = (uint8_t)((v & 0x7f) | 0x80); | ||
411 | *p++ = (uint8_t)v; | ||
412 | ctx->p = p; | ||
413 | } | ||
414 | |||
415 | /* Add a SLEB128 value. */ | ||
416 | static void gdbjit_sleb128(GDBJITctx *ctx, int32_t v) | ||
417 | { | ||
418 | uint8_t *p = ctx->p; | ||
419 | for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7) | ||
420 | *p++ = (uint8_t)((v & 0x7f) | 0x80); | ||
421 | *p++ = (uint8_t)(v & 0x7f); | ||
422 | ctx->p = p; | ||
423 | } | ||
424 | |||
425 | /* Shortcuts to generate DWARF structures. */ | ||
426 | #define DB(x) (*p++ = (x)) | ||
427 | #define DI8(x) (*(int8_t *)p = (x), p++) | ||
428 | #define DU16(x) (*(uint16_t *)p = (x), p += 2) | ||
429 | #define DU32(x) (*(uint32_t *)p = (x), p += 4) | ||
430 | #define DADDR(x) (*(uintptr_t *)p = (x), p += sizeof(uintptr_t)) | ||
431 | #define DUV(x) (ctx->p = p, gdbjit_uleb128(ctx, (x)), p = ctx->p) | ||
432 | #define DSV(x) (ctx->p = p, gdbjit_sleb128(ctx, (x)), p = ctx->p) | ||
433 | #define DSTR(str) (ctx->p = p, gdbjit_strz(ctx, (str)), p = ctx->p) | ||
434 | #define DALIGNNOP(s) while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop | ||
435 | #define DSECT(name, stmt) \ | ||
436 | { uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \ | ||
437 | *szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); } \ | ||
438 | |||
439 | /* Initialize ELF section headers. */ | ||
440 | static void LJ_FASTCALL gdbjit_secthdr(GDBJITctx *ctx) | ||
441 | { | ||
442 | ELFsectheader *sect; | ||
443 | |||
444 | *ctx->p++ = '\0'; /* Empty string at start of string table. */ | ||
445 | |||
446 | #define SECTDEF(id, tp, al) \ | ||
447 | sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \ | ||
448 | sect->name = gdbjit_strz(ctx, "." #id); \ | ||
449 | sect->type = ELFSECT_TYPE_##tp; \ | ||
450 | sect->align = (al) | ||
451 | |||
452 | SECTDEF(text, NOBITS, 16); | ||
453 | sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC; | ||
454 | sect->addr = ctx->mcaddr; | ||
455 | sect->ofs = 0; | ||
456 | sect->size = ctx->szmcode; | ||
457 | |||
458 | SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t)); | ||
459 | sect->flags = ELFSECT_FLAGS_ALLOC; | ||
460 | |||
461 | SECTDEF(shstrtab, STRTAB, 1); | ||
462 | SECTDEF(strtab, STRTAB, 1); | ||
463 | |||
464 | SECTDEF(symtab, SYMTAB, sizeof(uintptr_t)); | ||
465 | sect->ofs = offsetof(GDBJITobj, sym); | ||
466 | sect->size = sizeof(ctx->obj.sym); | ||
467 | sect->link = GDBJIT_SECT_strtab; | ||
468 | sect->entsize = sizeof(ELFsymbol); | ||
469 | sect->info = GDBJIT_SYM_FUNC; | ||
470 | |||
471 | SECTDEF(debug_info, PROGBITS, 1); | ||
472 | SECTDEF(debug_abbrev, PROGBITS, 1); | ||
473 | SECTDEF(debug_line, PROGBITS, 1); | ||
474 | |||
475 | #undef SECTDEF | ||
476 | } | ||
477 | |||
478 | /* Initialize symbol table. */ | ||
479 | static void LJ_FASTCALL gdbjit_symtab(GDBJITctx *ctx) | ||
480 | { | ||
481 | ELFsymbol *sym; | ||
482 | |||
483 | *ctx->p++ = '\0'; /* Empty string at start of string table. */ | ||
484 | |||
485 | sym = &ctx->obj.sym[GDBJIT_SYM_FILE]; | ||
486 | sym->name = gdbjit_strz(ctx, "JIT mcode"); | ||
487 | sym->sectidx = ELFSECT_IDX_ABS; | ||
488 | sym->info = ELFSYM_TYPE_FILE|ELFSYM_BIND_LOCAL; | ||
489 | |||
490 | sym = &ctx->obj.sym[GDBJIT_SYM_FUNC]; | ||
491 | sym->name = gdbjit_strz(ctx, ctx->trname); | ||
492 | sym->sectidx = GDBJIT_SECT_text; | ||
493 | sym->value = 0; | ||
494 | sym->size = ctx->szmcode; | ||
495 | sym->info = ELFSYM_TYPE_FUNC|ELFSYM_BIND_GLOBAL; | ||
496 | } | ||
497 | |||
498 | /* Initialize .eh_frame section. */ | ||
499 | static void LJ_FASTCALL gdbjit_ehframe(GDBJITctx *ctx) | ||
500 | { | ||
501 | uint8_t *p = ctx->p; | ||
502 | uint8_t *framep = p; | ||
503 | |||
504 | /* Emit DWARF EH CIE. */ | ||
505 | DSECT(CIE, | ||
506 | DU32(0); /* Offset to CIE itself. */ | ||
507 | DB(DW_CIE_VERSION); | ||
508 | DSTR("zR"); /* Augmentation. */ | ||
509 | DUV(1); /* Code alignment factor. */ | ||
510 | DSV(-(int32_t)sizeof(uintptr_t)); /* Data alignment factor. */ | ||
511 | DB(DW_REG_RA); /* Return address register. */ | ||
512 | DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4); /* Augmentation data. */ | ||
513 | DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t)); | ||
514 | DB(DW_CFA_offset|DW_REG_RA); DUV(1); | ||
515 | DALIGNNOP(sizeof(uintptr_t)); | ||
516 | ) | ||
517 | |||
518 | /* Emit DWARF EH FDE. */ | ||
519 | DSECT(FDE, | ||
520 | DU32((uint32_t)(p-framep)); /* Offset to CIE. */ | ||
521 | DU32(0); /* Machine code offset relative to .text. */ | ||
522 | DU32(ctx->szmcode); /* Machine code length. */ | ||
523 | DB(0); /* Augmentation data. */ | ||
524 | /* Registers saved in CFRAME. */ | ||
525 | #if LJ_TARGET_X86 | ||
526 | DB(DW_CFA_offset|DW_REG_BP); DUV(2); | ||
527 | DB(DW_CFA_offset|DW_REG_DI); DUV(3); | ||
528 | DB(DW_CFA_offset|DW_REG_SI); DUV(4); | ||
529 | DB(DW_CFA_offset|DW_REG_BX); DUV(5); | ||
530 | #elif LJ_TARGET_X64 | ||
531 | /* Add saved registers for x64 CFRAME. */ | ||
532 | #else | ||
533 | #error "Unsupported target architecture" | ||
534 | #endif | ||
535 | if (ctx->spadjp != ctx->spadj) { /* Parent/interpreter stack frame size. */ | ||
536 | DB(DW_CFA_def_cfa_offset); DUV(ctx->spadjp); | ||
537 | DB(DW_CFA_advance_loc|1); /* Only an approximation. */ | ||
538 | } | ||
539 | DB(DW_CFA_def_cfa_offset); DUV(ctx->spadj); /* Trace stack frame size. */ | ||
540 | DALIGNNOP(sizeof(uintptr_t)); | ||
541 | ) | ||
542 | |||
543 | ctx->p = p; | ||
544 | } | ||
545 | |||
546 | /* Initialize .debug_info section. */ | ||
547 | static void LJ_FASTCALL gdbjit_debuginfo(GDBJITctx *ctx) | ||
548 | { | ||
549 | uint8_t *p = ctx->p; | ||
550 | |||
551 | DSECT(info, | ||
552 | DU16(2); /* DWARF version. */ | ||
553 | DU32(0); /* Abbrev offset. */ | ||
554 | DB(sizeof(uintptr_t)); /* Pointer size. */ | ||
555 | |||
556 | DUV(1); /* Abbrev #1: DW_TAG_compile_unit. */ | ||
557 | DSTR(ctx->filename); /* DW_AT_name. */ | ||
558 | DADDR(ctx->mcaddr); /* DW_AT_low_pc. */ | ||
559 | DADDR(ctx->mcaddr + ctx->szmcode); /* DW_AT_high_pc. */ | ||
560 | DU32(0); /* DW_AT_stmt_list. */ | ||
561 | ) | ||
562 | |||
563 | ctx->p = p; | ||
564 | } | ||
565 | |||
566 | /* Initialize .debug_abbrev section. */ | ||
567 | static void LJ_FASTCALL gdbjit_debugabbrev(GDBJITctx *ctx) | ||
568 | { | ||
569 | uint8_t *p = ctx->p; | ||
570 | |||
571 | /* Abbrev #1: DW_TAG_compile_unit. */ | ||
572 | DUV(1); DUV(DW_TAG_compile_unit); | ||
573 | DB(DW_children_no); | ||
574 | DUV(DW_AT_name); DUV(DW_FORM_string); | ||
575 | DUV(DW_AT_low_pc); DUV(DW_FORM_addr); | ||
576 | DUV(DW_AT_high_pc); DUV(DW_FORM_addr); | ||
577 | DUV(DW_AT_stmt_list); DUV(DW_FORM_data4); | ||
578 | DB(0); DB(0); | ||
579 | |||
580 | ctx->p = p; | ||
581 | } | ||
582 | |||
583 | #define DLNE(op, s) (DB(DW_LNS_extended_op), DUV(1+(s)), DB((op))) | ||
584 | |||
585 | /* Initialize .debug_line section. */ | ||
586 | static void LJ_FASTCALL gdbjit_debugline(GDBJITctx *ctx) | ||
587 | { | ||
588 | uint8_t *p = ctx->p; | ||
589 | |||
590 | DSECT(line, | ||
591 | DU16(2); /* DWARF version. */ | ||
592 | DSECT(header, | ||
593 | DB(1); /* Minimum instruction length. */ | ||
594 | DB(1); /* is_stmt. */ | ||
595 | DI8(0); /* Line base for special opcodes. */ | ||
596 | DB(2); /* Line range for special opcodes. */ | ||
597 | DB(3+1); /* Opcode base at DW_LNS_advance_line+1. */ | ||
598 | DB(0); DB(1); DB(1); /* Standard opcode lengths. */ | ||
599 | /* Directory table. */ | ||
600 | DB(0); | ||
601 | /* File name table. */ | ||
602 | DSTR(ctx->filename); DUV(0); DUV(0); DUV(0); | ||
603 | DB(0); | ||
604 | ) | ||
605 | |||
606 | DLNE(DW_LNE_set_address, sizeof(uintptr_t)); DADDR(ctx->mcaddr); | ||
607 | if (ctx->lineno) { | ||
608 | DB(DW_LNS_advance_line); DSV(ctx->lineno-1); | ||
609 | } | ||
610 | DB(DW_LNS_copy); | ||
611 | DB(DW_LNS_advance_pc); DUV(ctx->szmcode); | ||
612 | DLNE(DW_LNE_end_sequence, 0); | ||
613 | ) | ||
614 | |||
615 | ctx->p = p; | ||
616 | } | ||
617 | |||
618 | #undef DLNE | ||
619 | |||
620 | /* Undef shortcuts. */ | ||
621 | #undef DB | ||
622 | #undef DI8 | ||
623 | #undef DU16 | ||
624 | #undef DU32 | ||
625 | #undef DADDR | ||
626 | #undef DUV | ||
627 | #undef DSV | ||
628 | #undef DSTR | ||
629 | #undef DALIGNNOP | ||
630 | #undef DSECT | ||
631 | |||
632 | /* Type of a section initializer callback. */ | ||
633 | typedef void (LJ_FASTCALL *GDBJITinitf)(GDBJITctx *ctx); | ||
634 | |||
635 | /* Call section initializer and set the section offset and size. */ | ||
636 | static void gdbjit_initsect(GDBJITctx *ctx, int sect, GDBJITinitf initf) | ||
637 | { | ||
638 | ctx->startp = ctx->p; | ||
639 | ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj); | ||
640 | initf(ctx); | ||
641 | ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp); | ||
642 | } | ||
643 | |||
644 | #define SECTALIGN(p, a) \ | ||
645 | ((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1))) | ||
646 | |||
647 | /* Build in-memory ELF object. */ | ||
648 | static void gdbjit_buildobj(GDBJITctx *ctx) | ||
649 | { | ||
650 | GDBJITobj *obj = &ctx->obj; | ||
651 | /* Fill in ELF header and clear structures. */ | ||
652 | memcpy(&obj->hdr, &elfhdr_template, sizeof(ELFheader)); | ||
653 | memset(&obj->sect, 0, sizeof(ELFsectheader)*GDBJIT_SECT__MAX); | ||
654 | memset(&obj->sym, 0, sizeof(ELFsymbol)*GDBJIT_SYM__MAX); | ||
655 | /* Initialize sections. */ | ||
656 | ctx->p = obj->space; | ||
657 | gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab, gdbjit_secthdr); | ||
658 | gdbjit_initsect(ctx, GDBJIT_SECT_strtab, gdbjit_symtab); | ||
659 | gdbjit_initsect(ctx, GDBJIT_SECT_debug_info, gdbjit_debuginfo); | ||
660 | gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev, gdbjit_debugabbrev); | ||
661 | gdbjit_initsect(ctx, GDBJIT_SECT_debug_line, gdbjit_debugline); | ||
662 | SECTALIGN(ctx->p, sizeof(uintptr_t)); | ||
663 | gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame, gdbjit_ehframe); | ||
664 | ctx->objsize = (size_t)((char *)ctx->p - (char *)obj); | ||
665 | lua_assert(ctx->objsize < sizeof(GDBJITobj)); | ||
666 | } | ||
667 | |||
668 | #undef SECTALIGN | ||
669 | |||
670 | /* -- Interface to GDB JIT API -------------------------------------------- */ | ||
671 | |||
672 | /* Add new entry to GDB JIT symbol chain. */ | ||
673 | static void gdbjit_newentry(lua_State *L, GDBJITctx *ctx) | ||
674 | { | ||
675 | /* Allocate memory for GDB JIT entry and ELF object. */ | ||
676 | MSize sz = (MSize)(sizeof(GDBJITentryobj) - sizeof(GDBJITobj) + ctx->objsize); | ||
677 | GDBJITentryobj *eo = lj_mem_newt(L, sz, GDBJITentryobj); | ||
678 | memcpy(&eo->obj, &ctx->obj, ctx->objsize); /* Copy ELF object. */ | ||
679 | eo->sz = sz; | ||
680 | ctx->T->gdbjit_entry = (void *)eo; | ||
681 | /* Link new entry to chain and register it. */ | ||
682 | eo->entry.prev_entry = NULL; | ||
683 | eo->entry.next_entry = __jit_debug_descriptor.first_entry; | ||
684 | if (eo->entry.next_entry) | ||
685 | eo->entry.next_entry->prev_entry = &eo->entry; | ||
686 | eo->entry.symfile_addr = (const char *)&eo->obj; | ||
687 | eo->entry.symfile_size = ctx->objsize; | ||
688 | __jit_debug_descriptor.first_entry = &eo->entry; | ||
689 | __jit_debug_descriptor.relevant_entry = &eo->entry; | ||
690 | __jit_debug_descriptor.action_flag = GDBJIT_REGISTER; | ||
691 | __jit_debug_register_code(); | ||
692 | } | ||
693 | |||
694 | /* Add debug info for newly compiled trace and notify GDB. */ | ||
695 | void lj_gdbjit_addtrace(jit_State *J, Trace *T, TraceNo traceno) | ||
696 | { | ||
697 | GDBJITctx ctx; | ||
698 | lua_State *L = J->L; | ||
699 | GCproto *pt = &gcref(T->startpt)->pt; | ||
700 | TraceNo parent = T->ir[REF_BASE].op1; | ||
701 | uintptr_t pcofs = (uintptr_t)(T->snap[0].mapofs+T->snap[0].nslots); | ||
702 | const BCIns *startpc = (const BCIns *)(uintptr_t)T->snapmap[pcofs]; | ||
703 | ctx.T = T; | ||
704 | ctx.mcaddr = (uintptr_t)T->mcode; | ||
705 | ctx.szmcode = T->szmcode; | ||
706 | ctx.spadjp = CFRAME_SIZE + (MSize)(parent ? J->trace[parent]->spadjust : 0); | ||
707 | ctx.spadj = CFRAME_SIZE + T->spadjust; | ||
708 | ctx.lineno = pt->lineinfo ? pt->lineinfo[startpc - pt->bc] : 0; | ||
709 | ctx.filename = strdata(pt->chunkname); | ||
710 | if (*ctx.filename == '@' || *ctx.filename == '=') | ||
711 | ctx.filename++; | ||
712 | else | ||
713 | ctx.filename = "(string)"; | ||
714 | ctx.trname = lj_str_pushf(L, "TRACE_%d", traceno); | ||
715 | L->top--; | ||
716 | gdbjit_buildobj(&ctx); | ||
717 | gdbjit_newentry(L, &ctx); | ||
718 | } | ||
719 | |||
720 | /* Delete debug info for trace and notify GDB. */ | ||
721 | void lj_gdbjit_deltrace(jit_State *J, Trace *T) | ||
722 | { | ||
723 | GDBJITentryobj *eo = (GDBJITentryobj *)T->gdbjit_entry; | ||
724 | if (eo) { | ||
725 | if (eo->entry.prev_entry) | ||
726 | eo->entry.prev_entry->next_entry = eo->entry.next_entry; | ||
727 | else | ||
728 | __jit_debug_descriptor.first_entry = eo->entry.next_entry; | ||
729 | if (eo->entry.next_entry) | ||
730 | eo->entry.next_entry->prev_entry = eo->entry.prev_entry; | ||
731 | __jit_debug_descriptor.relevant_entry = &eo->entry; | ||
732 | __jit_debug_descriptor.action_flag = GDBJIT_UNREGISTER; | ||
733 | __jit_debug_register_code(); | ||
734 | lj_mem_free(J2G(J), eo, eo->sz); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | #endif | ||
739 | #endif | ||