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