diff options
author | David Walter Seikel | 2012-01-23 23:36:30 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-01-23 23:36:30 +1000 |
commit | 6523585c66c04cea54df50013df8886b589847d8 (patch) | |
tree | 0b22aee7064166d88595eda260ca2d17c0773da5 /libraries/luajit-2.0/src/lj_gdbjit.c | |
parent | Update the EFL to what I'm actually using, coz I'm using some stuff not yet r... (diff) | |
download | SledjHamr-6523585c66c04cea54df50013df8886b589847d8.zip SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.gz SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.bz2 SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.xz |
Add luaproc and LuaJIT libraries.
Two versions of LuaJIT, the stable release, and the dev version. Try the dev version first, until ih fails badly.
Diffstat (limited to '')
-rw-r--r-- | libraries/luajit-2.0/src/lj_gdbjit.c | 783 |
1 files changed, 783 insertions, 0 deletions
diff --git a/libraries/luajit-2.0/src/lj_gdbjit.c b/libraries/luajit-2.0/src/lj_gdbjit.c new file mode 100644 index 0000000..130ab99 --- /dev/null +++ b/libraries/luajit-2.0/src/lj_gdbjit.c | |||
@@ -0,0 +1,783 @@ | |||
1 | /* | ||
2 | ** Client for the GDB JIT API. | ||
3 | ** Copyright (C) 2005-2011 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_debug.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_offset_extended = 0x5, | ||
236 | DW_CFA_def_cfa = 0xc, | ||
237 | DW_CFA_def_cfa_offset = 0xe, | ||
238 | DW_CFA_offset_extended_sf = 0x11, | ||
239 | DW_CFA_advance_loc = 0x40, | ||
240 | DW_CFA_offset = 0x80 | ||
241 | }; | ||
242 | |||
243 | enum { | ||
244 | DW_EH_PE_udata4 = 3, | ||
245 | DW_EH_PE_textrel = 0x20 | ||
246 | }; | ||
247 | |||
248 | enum { | ||
249 | DW_TAG_compile_unit = 0x11 | ||
250 | }; | ||
251 | |||
252 | enum { | ||
253 | DW_children_no = 0, | ||
254 | DW_children_yes = 1 | ||
255 | }; | ||
256 | |||
257 | enum { | ||
258 | DW_AT_name = 0x03, | ||
259 | DW_AT_stmt_list = 0x10, | ||
260 | DW_AT_low_pc = 0x11, | ||
261 | DW_AT_high_pc = 0x12 | ||
262 | }; | ||
263 | |||
264 | enum { | ||
265 | DW_FORM_addr = 0x01, | ||
266 | DW_FORM_data4 = 0x06, | ||
267 | DW_FORM_string = 0x08 | ||
268 | }; | ||
269 | |||
270 | enum { | ||
271 | DW_LNS_extended_op = 0, | ||
272 | DW_LNS_copy = 1, | ||
273 | DW_LNS_advance_pc = 2, | ||
274 | DW_LNS_advance_line = 3 | ||
275 | }; | ||
276 | |||
277 | enum { | ||
278 | DW_LNE_end_sequence = 1, | ||
279 | DW_LNE_set_address = 2 | ||
280 | }; | ||
281 | |||
282 | enum { | ||
283 | #if LJ_TARGET_X86 | ||
284 | DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX, | ||
285 | DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI, | ||
286 | DW_REG_RA, | ||
287 | #elif LJ_TARGET_X64 | ||
288 | /* Yes, the order is strange, but correct. */ | ||
289 | DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX, | ||
290 | DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP, | ||
291 | DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11, | ||
292 | DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15, | ||
293 | DW_REG_RA, | ||
294 | #elif LJ_TARGET_ARM | ||
295 | DW_REG_SP = 13, | ||
296 | DW_REG_RA = 14, | ||
297 | #elif LJ_TARGET_PPC | ||
298 | DW_REG_SP = 1, | ||
299 | DW_REG_RA = 65, | ||
300 | DW_REG_CR = 70, | ||
301 | #else | ||
302 | #error "Unsupported target architecture" | ||
303 | #endif | ||
304 | }; | ||
305 | |||
306 | /* Minimal list of sections for the in-memory ELF object. */ | ||
307 | enum { | ||
308 | GDBJIT_SECT_NULL, | ||
309 | GDBJIT_SECT_text, | ||
310 | GDBJIT_SECT_eh_frame, | ||
311 | GDBJIT_SECT_shstrtab, | ||
312 | GDBJIT_SECT_strtab, | ||
313 | GDBJIT_SECT_symtab, | ||
314 | GDBJIT_SECT_debug_info, | ||
315 | GDBJIT_SECT_debug_abbrev, | ||
316 | GDBJIT_SECT_debug_line, | ||
317 | GDBJIT_SECT__MAX | ||
318 | }; | ||
319 | |||
320 | enum { | ||
321 | GDBJIT_SYM_UNDEF, | ||
322 | GDBJIT_SYM_FILE, | ||
323 | GDBJIT_SYM_FUNC, | ||
324 | GDBJIT_SYM__MAX | ||
325 | }; | ||
326 | |||
327 | /* In-memory ELF object. */ | ||
328 | typedef struct GDBJITobj { | ||
329 | ELFheader hdr; /* ELF header. */ | ||
330 | ELFsectheader sect[GDBJIT_SECT__MAX]; /* ELF sections. */ | ||
331 | ELFsymbol sym[GDBJIT_SYM__MAX]; /* ELF symbol table. */ | ||
332 | uint8_t space[4096]; /* Space for various section data. */ | ||
333 | } GDBJITobj; | ||
334 | |||
335 | /* Combined structure for GDB JIT entry and ELF object. */ | ||
336 | typedef struct GDBJITentryobj { | ||
337 | GDBJITentry entry; | ||
338 | size_t sz; | ||
339 | GDBJITobj obj; | ||
340 | } GDBJITentryobj; | ||
341 | |||
342 | /* Template for in-memory ELF header. */ | ||
343 | static const ELFheader elfhdr_template = { | ||
344 | .emagic = { 0x7f, 'E', 'L', 'F' }, | ||
345 | .eclass = LJ_64 ? 2 : 1, | ||
346 | .eendian = LJ_ENDIAN_SELECT(1, 2), | ||
347 | .eversion = 1, | ||
348 | #if LJ_TARGET_LINUX | ||
349 | .eosabi = 0, /* Nope, it's not 3. */ | ||
350 | #elif defined(__FreeBSD__) | ||
351 | .eosabi = 9, | ||
352 | #elif defined(__NetBSD__) | ||
353 | .eosabi = 2, | ||
354 | #elif defined(__OpenBSD__) | ||
355 | .eosabi = 12, | ||
356 | #elif (defined(__sun__) && defined(__svr4__)) || defined(__solaris__) | ||
357 | .eosabi = 6, | ||
358 | #else | ||
359 | .eosabi = 0, | ||
360 | #endif | ||
361 | .eabiversion = 0, | ||
362 | .epad = { 0, 0, 0, 0, 0, 0, 0 }, | ||
363 | .type = 1, | ||
364 | #if LJ_TARGET_X86 | ||
365 | .machine = 3, | ||
366 | #elif LJ_TARGET_X64 | ||
367 | .machine = 62, | ||
368 | #elif LJ_TARGET_ARM | ||
369 | .machine = 40, | ||
370 | #elif LJ_TARGET_PPC | ||
371 | .machine = 20, | ||
372 | #else | ||
373 | #error "Unsupported target architecture" | ||
374 | #endif | ||
375 | .version = 1, | ||
376 | .entry = 0, | ||
377 | .phofs = 0, | ||
378 | .shofs = offsetof(GDBJITobj, sect), | ||
379 | .flags = 0, | ||
380 | .ehsize = sizeof(ELFheader), | ||
381 | .phentsize = 0, | ||
382 | .phnum = 0, | ||
383 | .shentsize = sizeof(ELFsectheader), | ||
384 | .shnum = GDBJIT_SECT__MAX, | ||
385 | .shstridx = GDBJIT_SECT_shstrtab | ||
386 | }; | ||
387 | |||
388 | /* -- In-memory ELF object generation ------------------------------------- */ | ||
389 | |||
390 | /* Context for generating the ELF object for the GDB JIT API. */ | ||
391 | typedef struct GDBJITctx { | ||
392 | uint8_t *p; /* Pointer to next address in obj.space. */ | ||
393 | uint8_t *startp; /* Pointer to start address in obj.space. */ | ||
394 | GCtrace *T; /* Generate symbols for this trace. */ | ||
395 | uintptr_t mcaddr; /* Machine code address. */ | ||
396 | MSize szmcode; /* Size of machine code. */ | ||
397 | MSize spadjp; /* Stack adjustment for parent trace or interpreter. */ | ||
398 | MSize spadj; /* Stack adjustment for trace itself. */ | ||
399 | BCLine lineno; /* Starting line number. */ | ||
400 | const char *filename; /* Starting file name. */ | ||
401 | size_t objsize; /* Final size of ELF object. */ | ||
402 | GDBJITobj obj; /* In-memory ELF object. */ | ||
403 | } GDBJITctx; | ||
404 | |||
405 | /* Add a zero-terminated string. */ | ||
406 | static uint32_t gdbjit_strz(GDBJITctx *ctx, const char *str) | ||
407 | { | ||
408 | uint8_t *p = ctx->p; | ||
409 | uint32_t ofs = (uint32_t)(p - ctx->startp); | ||
410 | do { | ||
411 | *p++ = (uint8_t)*str; | ||
412 | } while (*str++); | ||
413 | ctx->p = p; | ||
414 | return ofs; | ||
415 | } | ||
416 | |||
417 | /* Append a decimal number. */ | ||
418 | static void gdbjit_catnum(GDBJITctx *ctx, uint32_t n) | ||
419 | { | ||
420 | if (n >= 10) { uint32_t m = n / 10; n = n % 10; gdbjit_catnum(ctx, m); } | ||
421 | *ctx->p++ = '0' + n; | ||
422 | } | ||
423 | |||
424 | /* Add a ULEB128 value. */ | ||
425 | static void gdbjit_uleb128(GDBJITctx *ctx, uint32_t v) | ||
426 | { | ||
427 | uint8_t *p = ctx->p; | ||
428 | for (; v >= 0x80; v >>= 7) | ||
429 | *p++ = (uint8_t)((v & 0x7f) | 0x80); | ||
430 | *p++ = (uint8_t)v; | ||
431 | ctx->p = p; | ||
432 | } | ||
433 | |||
434 | /* Add a SLEB128 value. */ | ||
435 | static void gdbjit_sleb128(GDBJITctx *ctx, int32_t v) | ||
436 | { | ||
437 | uint8_t *p = ctx->p; | ||
438 | for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7) | ||
439 | *p++ = (uint8_t)((v & 0x7f) | 0x80); | ||
440 | *p++ = (uint8_t)(v & 0x7f); | ||
441 | ctx->p = p; | ||
442 | } | ||
443 | |||
444 | /* Shortcuts to generate DWARF structures. */ | ||
445 | #define DB(x) (*p++ = (x)) | ||
446 | #define DI8(x) (*(int8_t *)p = (x), p++) | ||
447 | #define DU16(x) (*(uint16_t *)p = (x), p += 2) | ||
448 | #define DU32(x) (*(uint32_t *)p = (x), p += 4) | ||
449 | #define DADDR(x) (*(uintptr_t *)p = (x), p += sizeof(uintptr_t)) | ||
450 | #define DUV(x) (ctx->p = p, gdbjit_uleb128(ctx, (x)), p = ctx->p) | ||
451 | #define DSV(x) (ctx->p = p, gdbjit_sleb128(ctx, (x)), p = ctx->p) | ||
452 | #define DSTR(str) (ctx->p = p, gdbjit_strz(ctx, (str)), p = ctx->p) | ||
453 | #define DALIGNNOP(s) while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop | ||
454 | #define DSECT(name, stmt) \ | ||
455 | { uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \ | ||
456 | *szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); } \ | ||
457 | |||
458 | /* Initialize ELF section headers. */ | ||
459 | static void LJ_FASTCALL gdbjit_secthdr(GDBJITctx *ctx) | ||
460 | { | ||
461 | ELFsectheader *sect; | ||
462 | |||
463 | *ctx->p++ = '\0'; /* Empty string at start of string table. */ | ||
464 | |||
465 | #define SECTDEF(id, tp, al) \ | ||
466 | sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \ | ||
467 | sect->name = gdbjit_strz(ctx, "." #id); \ | ||
468 | sect->type = ELFSECT_TYPE_##tp; \ | ||
469 | sect->align = (al) | ||
470 | |||
471 | SECTDEF(text, NOBITS, 16); | ||
472 | sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC; | ||
473 | sect->addr = ctx->mcaddr; | ||
474 | sect->ofs = 0; | ||
475 | sect->size = ctx->szmcode; | ||
476 | |||
477 | SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t)); | ||
478 | sect->flags = ELFSECT_FLAGS_ALLOC; | ||
479 | |||
480 | SECTDEF(shstrtab, STRTAB, 1); | ||
481 | SECTDEF(strtab, STRTAB, 1); | ||
482 | |||
483 | SECTDEF(symtab, SYMTAB, sizeof(uintptr_t)); | ||
484 | sect->ofs = offsetof(GDBJITobj, sym); | ||
485 | sect->size = sizeof(ctx->obj.sym); | ||
486 | sect->link = GDBJIT_SECT_strtab; | ||
487 | sect->entsize = sizeof(ELFsymbol); | ||
488 | sect->info = GDBJIT_SYM_FUNC; | ||
489 | |||
490 | SECTDEF(debug_info, PROGBITS, 1); | ||
491 | SECTDEF(debug_abbrev, PROGBITS, 1); | ||
492 | SECTDEF(debug_line, PROGBITS, 1); | ||
493 | |||
494 | #undef SECTDEF | ||
495 | } | ||
496 | |||
497 | /* Initialize symbol table. */ | ||
498 | static void LJ_FASTCALL gdbjit_symtab(GDBJITctx *ctx) | ||
499 | { | ||
500 | ELFsymbol *sym; | ||
501 | |||
502 | *ctx->p++ = '\0'; /* Empty string at start of string table. */ | ||
503 | |||
504 | sym = &ctx->obj.sym[GDBJIT_SYM_FILE]; | ||
505 | sym->name = gdbjit_strz(ctx, "JIT mcode"); | ||
506 | sym->sectidx = ELFSECT_IDX_ABS; | ||
507 | sym->info = ELFSYM_TYPE_FILE|ELFSYM_BIND_LOCAL; | ||
508 | |||
509 | sym = &ctx->obj.sym[GDBJIT_SYM_FUNC]; | ||
510 | sym->name = gdbjit_strz(ctx, "TRACE_"); ctx->p--; | ||
511 | gdbjit_catnum(ctx, ctx->T->traceno); *ctx->p++ = '\0'; | ||
512 | sym->sectidx = GDBJIT_SECT_text; | ||
513 | sym->value = 0; | ||
514 | sym->size = ctx->szmcode; | ||
515 | sym->info = ELFSYM_TYPE_FUNC|ELFSYM_BIND_GLOBAL; | ||
516 | } | ||
517 | |||
518 | /* Initialize .eh_frame section. */ | ||
519 | static void LJ_FASTCALL gdbjit_ehframe(GDBJITctx *ctx) | ||
520 | { | ||
521 | uint8_t *p = ctx->p; | ||
522 | uint8_t *framep = p; | ||
523 | |||
524 | /* Emit DWARF EH CIE. */ | ||
525 | DSECT(CIE, | ||
526 | DU32(0); /* Offset to CIE itself. */ | ||
527 | DB(DW_CIE_VERSION); | ||
528 | DSTR("zR"); /* Augmentation. */ | ||
529 | DUV(1); /* Code alignment factor. */ | ||
530 | DSV(-(int32_t)sizeof(uintptr_t)); /* Data alignment factor. */ | ||
531 | DB(DW_REG_RA); /* Return address register. */ | ||
532 | DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4); /* Augmentation data. */ | ||
533 | DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t)); | ||
534 | #if LJ_TARGET_PPC | ||
535 | DB(DW_CFA_offset_extended_sf); DB(DW_REG_RA); DSV(-1); | ||
536 | #else | ||
537 | DB(DW_CFA_offset|DW_REG_RA); DUV(1); | ||
538 | #endif | ||
539 | DALIGNNOP(sizeof(uintptr_t)); | ||
540 | ) | ||
541 | |||
542 | /* Emit DWARF EH FDE. */ | ||
543 | DSECT(FDE, | ||
544 | DU32((uint32_t)(p-framep)); /* Offset to CIE. */ | ||
545 | DU32(0); /* Machine code offset relative to .text. */ | ||
546 | DU32(ctx->szmcode); /* Machine code length. */ | ||
547 | DB(0); /* Augmentation data. */ | ||
548 | /* Registers saved in CFRAME. */ | ||
549 | #if LJ_TARGET_X86 | ||
550 | DB(DW_CFA_offset|DW_REG_BP); DUV(2); | ||
551 | DB(DW_CFA_offset|DW_REG_DI); DUV(3); | ||
552 | DB(DW_CFA_offset|DW_REG_SI); DUV(4); | ||
553 | DB(DW_CFA_offset|DW_REG_BX); DUV(5); | ||
554 | #elif LJ_TARGET_X64 | ||
555 | DB(DW_CFA_offset|DW_REG_BP); DUV(2); | ||
556 | DB(DW_CFA_offset|DW_REG_BX); DUV(3); | ||
557 | DB(DW_CFA_offset|DW_REG_15); DUV(4); | ||
558 | DB(DW_CFA_offset|DW_REG_14); DUV(5); | ||
559 | /* Extra registers saved for JIT-compiled code. */ | ||
560 | DB(DW_CFA_offset|DW_REG_13); DUV(9); | ||
561 | DB(DW_CFA_offset|DW_REG_12); DUV(10); | ||
562 | #elif LJ_TARGET_ARM | ||
563 | { | ||
564 | int i; | ||
565 | DB(DW_CFA_offset_extended); DB(DW_REG_CR); DUV(55); | ||
566 | for (i = 11; i >= 4; i--) { /* R4-R11. */ | ||
567 | DB(DW_CFA_offset|i); DUV(2+(11-i)); | ||
568 | } | ||
569 | } | ||
570 | #elif LJ_TARGET_PPC | ||
571 | { | ||
572 | int i; | ||
573 | for (i = 14; i <= 31; i++) { | ||
574 | DB(DW_CFA_offset|i); DUV(37+(31-i)); | ||
575 | DB(DW_CFA_offset|32|i); DUV(2+2*(31-i)); | ||
576 | } | ||
577 | } | ||
578 | #else | ||
579 | #error "Unsupported target architecture" | ||
580 | #endif | ||
581 | if (ctx->spadjp != ctx->spadj) { /* Parent/interpreter stack frame size. */ | ||
582 | DB(DW_CFA_def_cfa_offset); DUV(ctx->spadjp); | ||
583 | DB(DW_CFA_advance_loc|1); /* Only an approximation. */ | ||
584 | } | ||
585 | DB(DW_CFA_def_cfa_offset); DUV(ctx->spadj); /* Trace stack frame size. */ | ||
586 | DALIGNNOP(sizeof(uintptr_t)); | ||
587 | ) | ||
588 | |||
589 | ctx->p = p; | ||
590 | } | ||
591 | |||
592 | /* Initialize .debug_info section. */ | ||
593 | static void LJ_FASTCALL gdbjit_debuginfo(GDBJITctx *ctx) | ||
594 | { | ||
595 | uint8_t *p = ctx->p; | ||
596 | |||
597 | DSECT(info, | ||
598 | DU16(2); /* DWARF version. */ | ||
599 | DU32(0); /* Abbrev offset. */ | ||
600 | DB(sizeof(uintptr_t)); /* Pointer size. */ | ||
601 | |||
602 | DUV(1); /* Abbrev #1: DW_TAG_compile_unit. */ | ||
603 | DSTR(ctx->filename); /* DW_AT_name. */ | ||
604 | DADDR(ctx->mcaddr); /* DW_AT_low_pc. */ | ||
605 | DADDR(ctx->mcaddr + ctx->szmcode); /* DW_AT_high_pc. */ | ||
606 | DU32(0); /* DW_AT_stmt_list. */ | ||
607 | ) | ||
608 | |||
609 | ctx->p = p; | ||
610 | } | ||
611 | |||
612 | /* Initialize .debug_abbrev section. */ | ||
613 | static void LJ_FASTCALL gdbjit_debugabbrev(GDBJITctx *ctx) | ||
614 | { | ||
615 | uint8_t *p = ctx->p; | ||
616 | |||
617 | /* Abbrev #1: DW_TAG_compile_unit. */ | ||
618 | DUV(1); DUV(DW_TAG_compile_unit); | ||
619 | DB(DW_children_no); | ||
620 | DUV(DW_AT_name); DUV(DW_FORM_string); | ||
621 | DUV(DW_AT_low_pc); DUV(DW_FORM_addr); | ||
622 | DUV(DW_AT_high_pc); DUV(DW_FORM_addr); | ||
623 | DUV(DW_AT_stmt_list); DUV(DW_FORM_data4); | ||
624 | DB(0); DB(0); | ||
625 | |||
626 | ctx->p = p; | ||
627 | } | ||
628 | |||
629 | #define DLNE(op, s) (DB(DW_LNS_extended_op), DUV(1+(s)), DB((op))) | ||
630 | |||
631 | /* Initialize .debug_line section. */ | ||
632 | static void LJ_FASTCALL gdbjit_debugline(GDBJITctx *ctx) | ||
633 | { | ||
634 | uint8_t *p = ctx->p; | ||
635 | |||
636 | DSECT(line, | ||
637 | DU16(2); /* DWARF version. */ | ||
638 | DSECT(header, | ||
639 | DB(1); /* Minimum instruction length. */ | ||
640 | DB(1); /* is_stmt. */ | ||
641 | DI8(0); /* Line base for special opcodes. */ | ||
642 | DB(2); /* Line range for special opcodes. */ | ||
643 | DB(3+1); /* Opcode base at DW_LNS_advance_line+1. */ | ||
644 | DB(0); DB(1); DB(1); /* Standard opcode lengths. */ | ||
645 | /* Directory table. */ | ||
646 | DB(0); | ||
647 | /* File name table. */ | ||
648 | DSTR(ctx->filename); DUV(0); DUV(0); DUV(0); | ||
649 | DB(0); | ||
650 | ) | ||
651 | |||
652 | DLNE(DW_LNE_set_address, sizeof(uintptr_t)); DADDR(ctx->mcaddr); | ||
653 | if (ctx->lineno) { | ||
654 | DB(DW_LNS_advance_line); DSV(ctx->lineno-1); | ||
655 | } | ||
656 | DB(DW_LNS_copy); | ||
657 | DB(DW_LNS_advance_pc); DUV(ctx->szmcode); | ||
658 | DLNE(DW_LNE_end_sequence, 0); | ||
659 | ) | ||
660 | |||
661 | ctx->p = p; | ||
662 | } | ||
663 | |||
664 | #undef DLNE | ||
665 | |||
666 | /* Undef shortcuts. */ | ||
667 | #undef DB | ||
668 | #undef DI8 | ||
669 | #undef DU16 | ||
670 | #undef DU32 | ||
671 | #undef DADDR | ||
672 | #undef DUV | ||
673 | #undef DSV | ||
674 | #undef DSTR | ||
675 | #undef DALIGNNOP | ||
676 | #undef DSECT | ||
677 | |||
678 | /* Type of a section initializer callback. */ | ||
679 | typedef void (LJ_FASTCALL *GDBJITinitf)(GDBJITctx *ctx); | ||
680 | |||
681 | /* Call section initializer and set the section offset and size. */ | ||
682 | static void gdbjit_initsect(GDBJITctx *ctx, int sect, GDBJITinitf initf) | ||
683 | { | ||
684 | ctx->startp = ctx->p; | ||
685 | ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj); | ||
686 | initf(ctx); | ||
687 | ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp); | ||
688 | } | ||
689 | |||
690 | #define SECTALIGN(p, a) \ | ||
691 | ((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1))) | ||
692 | |||
693 | /* Build in-memory ELF object. */ | ||
694 | static void gdbjit_buildobj(GDBJITctx *ctx) | ||
695 | { | ||
696 | GDBJITobj *obj = &ctx->obj; | ||
697 | /* Fill in ELF header and clear structures. */ | ||
698 | memcpy(&obj->hdr, &elfhdr_template, sizeof(ELFheader)); | ||
699 | memset(&obj->sect, 0, sizeof(ELFsectheader)*GDBJIT_SECT__MAX); | ||
700 | memset(&obj->sym, 0, sizeof(ELFsymbol)*GDBJIT_SYM__MAX); | ||
701 | /* Initialize sections. */ | ||
702 | ctx->p = obj->space; | ||
703 | gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab, gdbjit_secthdr); | ||
704 | gdbjit_initsect(ctx, GDBJIT_SECT_strtab, gdbjit_symtab); | ||
705 | gdbjit_initsect(ctx, GDBJIT_SECT_debug_info, gdbjit_debuginfo); | ||
706 | gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev, gdbjit_debugabbrev); | ||
707 | gdbjit_initsect(ctx, GDBJIT_SECT_debug_line, gdbjit_debugline); | ||
708 | SECTALIGN(ctx->p, sizeof(uintptr_t)); | ||
709 | gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame, gdbjit_ehframe); | ||
710 | ctx->objsize = (size_t)((char *)ctx->p - (char *)obj); | ||
711 | lua_assert(ctx->objsize < sizeof(GDBJITobj)); | ||
712 | } | ||
713 | |||
714 | #undef SECTALIGN | ||
715 | |||
716 | /* -- Interface to GDB JIT API -------------------------------------------- */ | ||
717 | |||
718 | /* Add new entry to GDB JIT symbol chain. */ | ||
719 | static void gdbjit_newentry(lua_State *L, GDBJITctx *ctx) | ||
720 | { | ||
721 | /* Allocate memory for GDB JIT entry and ELF object. */ | ||
722 | MSize sz = (MSize)(sizeof(GDBJITentryobj) - sizeof(GDBJITobj) + ctx->objsize); | ||
723 | GDBJITentryobj *eo = lj_mem_newt(L, sz, GDBJITentryobj); | ||
724 | memcpy(&eo->obj, &ctx->obj, ctx->objsize); /* Copy ELF object. */ | ||
725 | eo->sz = sz; | ||
726 | ctx->T->gdbjit_entry = (void *)eo; | ||
727 | /* Link new entry to chain and register it. */ | ||
728 | eo->entry.prev_entry = NULL; | ||
729 | eo->entry.next_entry = __jit_debug_descriptor.first_entry; | ||
730 | if (eo->entry.next_entry) | ||
731 | eo->entry.next_entry->prev_entry = &eo->entry; | ||
732 | eo->entry.symfile_addr = (const char *)&eo->obj; | ||
733 | eo->entry.symfile_size = ctx->objsize; | ||
734 | __jit_debug_descriptor.first_entry = &eo->entry; | ||
735 | __jit_debug_descriptor.relevant_entry = &eo->entry; | ||
736 | __jit_debug_descriptor.action_flag = GDBJIT_REGISTER; | ||
737 | __jit_debug_register_code(); | ||
738 | } | ||
739 | |||
740 | /* Add debug info for newly compiled trace and notify GDB. */ | ||
741 | void lj_gdbjit_addtrace(jit_State *J, GCtrace *T) | ||
742 | { | ||
743 | GDBJITctx ctx; | ||
744 | GCproto *pt = &gcref(T->startpt)->pt; | ||
745 | TraceNo parent = T->ir[REF_BASE].op1; | ||
746 | const BCIns *startpc = mref(T->startpc, const BCIns); | ||
747 | ctx.T = T; | ||
748 | ctx.mcaddr = (uintptr_t)T->mcode; | ||
749 | ctx.szmcode = T->szmcode; | ||
750 | ctx.spadjp = CFRAME_SIZE_JIT + | ||
751 | (MSize)(parent ? traceref(J, parent)->spadjust : 0); | ||
752 | ctx.spadj = CFRAME_SIZE_JIT + T->spadjust; | ||
753 | lua_assert(startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc); | ||
754 | ctx.lineno = lj_debug_line(pt, proto_bcpos(pt, startpc)); | ||
755 | ctx.filename = proto_chunknamestr(pt); | ||
756 | if (*ctx.filename == '@' || *ctx.filename == '=') | ||
757 | ctx.filename++; | ||
758 | else | ||
759 | ctx.filename = "(string)"; | ||
760 | gdbjit_buildobj(&ctx); | ||
761 | gdbjit_newentry(J->L, &ctx); | ||
762 | } | ||
763 | |||
764 | /* Delete debug info for trace and notify GDB. */ | ||
765 | void lj_gdbjit_deltrace(jit_State *J, GCtrace *T) | ||
766 | { | ||
767 | GDBJITentryobj *eo = (GDBJITentryobj *)T->gdbjit_entry; | ||
768 | if (eo) { | ||
769 | if (eo->entry.prev_entry) | ||
770 | eo->entry.prev_entry->next_entry = eo->entry.next_entry; | ||
771 | else | ||
772 | __jit_debug_descriptor.first_entry = eo->entry.next_entry; | ||
773 | if (eo->entry.next_entry) | ||
774 | eo->entry.next_entry->prev_entry = eo->entry.prev_entry; | ||
775 | __jit_debug_descriptor.relevant_entry = &eo->entry; | ||
776 | __jit_debug_descriptor.action_flag = GDBJIT_UNREGISTER; | ||
777 | __jit_debug_register_code(); | ||
778 | lj_mem_free(J2G(J), eo, eo->sz); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | #endif | ||
783 | #endif | ||