/src/php-src/ext/opcache/jit/ir/ir_gdb.c
Line | Count | Source |
1 | | /* |
2 | | * IR - Lightweight JIT Compilation Framework |
3 | | * (GDB interface) |
4 | | * Copyright (C) 2022 Zend by Perforce. |
5 | | * Authors: Dmitry Stogov <dmitry@php.net> |
6 | | * |
7 | | * Based on Mike Pall's implementation of GDB interface for LuaJIT. |
8 | | */ |
9 | | |
10 | | #include <stddef.h> |
11 | | #include <stdlib.h> |
12 | | #include <unistd.h> |
13 | | #include <fcntl.h> |
14 | | |
15 | | #ifdef __FreeBSD__ |
16 | | # include <sys/types.h> |
17 | | # include <sys/sysctl.h> |
18 | | # include <sys/user.h> |
19 | | #endif |
20 | | |
21 | | #include "ir.h" |
22 | | #include "ir_private.h" |
23 | | #include "ir_elf.h" |
24 | | |
25 | | /* DWARF definitions. */ |
26 | | #define DW_CIE_VERSION 1 |
27 | | |
28 | | /* CFA (Canonical frame address) */ |
29 | | enum { |
30 | | DW_CFA_nop = 0x0, |
31 | | DW_CFA_offset_extended = 0x5, |
32 | | DW_CFA_def_cfa = 0xc, |
33 | | DW_CFA_def_cfa_offset = 0xe, |
34 | | DW_CFA_offset_extended_sf = 0x11, |
35 | | DW_CFA_advance_loc = 0x40, |
36 | | DW_CFA_offset = 0x80 |
37 | | }; |
38 | | |
39 | | enum { |
40 | | DW_EH_PE_udata4 = 0x03, |
41 | | DW_EH_PE_textrel = 0x20 |
42 | | }; |
43 | | |
44 | | enum { |
45 | | DW_TAG_compile_unit = 0x11 |
46 | | }; |
47 | | |
48 | | enum { |
49 | | DW_children_no = 0, |
50 | | DW_children_yes = 1 |
51 | | }; |
52 | | |
53 | | enum { |
54 | | DW_AT_name = 0x03, |
55 | | DW_AT_stmt_list = 0x10, |
56 | | DW_AT_low_pc = 0x11, |
57 | | DW_AT_high_pc = 0x12 |
58 | | }; |
59 | | |
60 | | enum { |
61 | | DW_FORM_addr = 0x01, |
62 | | DW_FORM_data4 = 0x06, |
63 | | DW_FORM_string = 0x08 |
64 | | }; |
65 | | |
66 | | enum { |
67 | | DW_LNS_extended_op = 0, |
68 | | DW_LNS_copy = 1, |
69 | | DW_LNS_advance_pc = 2, |
70 | | DW_LNS_advance_line = 3 |
71 | | }; |
72 | | |
73 | | enum { |
74 | | DW_LNE_end_sequence = 1, |
75 | | DW_LNE_set_address = 2 |
76 | | }; |
77 | | |
78 | | enum { |
79 | | #if defined(IR_TARGET_X86) |
80 | | DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX, |
81 | | DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI, |
82 | | DW_REG_RA, |
83 | | #elif defined(IR_TARGET_X64) |
84 | | /* Yes, the order is strange, but correct. */ |
85 | | DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX, |
86 | | DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP, |
87 | | DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11, |
88 | | DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15, |
89 | | DW_REG_RA, |
90 | | #elif defined(IR_TARGET_AARCH64) |
91 | | DW_REG_SP = 31, |
92 | | DW_REG_RA = 30, |
93 | | DW_REG_X29 = 29, |
94 | | #else |
95 | | #error "Unsupported target architecture" |
96 | | #endif |
97 | | }; |
98 | | |
99 | | enum { |
100 | | GDBJIT_SECT_NULL, |
101 | | GDBJIT_SECT_text, |
102 | | GDBJIT_SECT_eh_frame, |
103 | | GDBJIT_SECT_shstrtab, |
104 | | GDBJIT_SECT_strtab, |
105 | | GDBJIT_SECT_symtab, |
106 | | GDBJIT_SECT_debug_info, |
107 | | GDBJIT_SECT_debug_abbrev, |
108 | | GDBJIT_SECT_debug_line, |
109 | | GDBJIT_SECT__MAX |
110 | | }; |
111 | | |
112 | | enum { |
113 | | GDBJIT_SYM_UNDEF, |
114 | | GDBJIT_SYM_FILE, |
115 | | GDBJIT_SYM_FUNC, |
116 | | GDBJIT_SYM__MAX |
117 | | }; |
118 | | |
119 | | typedef struct _ir_gdbjit_obj { |
120 | | ir_elf_header hdr; |
121 | | ir_elf_sectheader sect[GDBJIT_SECT__MAX]; |
122 | | ir_elf_symbol sym[GDBJIT_SYM__MAX]; |
123 | | uint8_t space[4096]; |
124 | | } ir_gdbjit_obj; |
125 | | |
126 | | static const ir_elf_header ir_elfhdr_template = { |
127 | | .emagic = { 0x7f, 'E', 'L', 'F' }, |
128 | | #ifdef ELF64 |
129 | | .eclass = 2, |
130 | | #else |
131 | | .eclass = 1, |
132 | | #endif |
133 | | #ifdef WORDS_BIGENDIAN |
134 | | .eendian = 2, |
135 | | #else |
136 | | .eendian = 1, |
137 | | #endif |
138 | | .eversion = 1, |
139 | | #if defined(Linux) |
140 | | .eosabi = 0, /* TODO: Nope, it's not 3. ??? */ |
141 | | #elif defined(__FreeBSD__) |
142 | | .eosabi = 9, |
143 | | #elif defined(__OpenBSD__) |
144 | | .eosabi = 12, |
145 | | #elif defined(__NetBSD__) |
146 | | .eosabi = 2, |
147 | | #elif defined(__DragonFly__) |
148 | | .eosabi = 0, |
149 | | #elif (defined(__sun__) && defined(__svr4__)) |
150 | | .eosabi = 6, |
151 | | #else |
152 | | .eosabi = 0, |
153 | | #endif |
154 | | .eabiversion = 0, |
155 | | .epad = { 0, 0, 0, 0, 0, 0, 0 }, |
156 | | .type = 1, |
157 | | #if defined(IR_TARGET_X86) |
158 | | .machine = 3, |
159 | | #elif defined(IR_TARGET_X64) |
160 | | .machine = 62, |
161 | | #elif defined(IR_TARGET_AARCH64) |
162 | | .machine = 183, |
163 | | #else |
164 | | # error "Unsupported target architecture" |
165 | | #endif |
166 | | .version = 1, |
167 | | .entry = 0, |
168 | | .phofs = 0, |
169 | | .shofs = offsetof(ir_gdbjit_obj, sect), |
170 | | .flags = 0, |
171 | | .ehsize = sizeof(ir_elf_header), |
172 | | .phentsize = 0, |
173 | | .phnum = 0, |
174 | | .shentsize = sizeof(ir_elf_sectheader), |
175 | | .shnum = GDBJIT_SECT__MAX, |
176 | | .shstridx = GDBJIT_SECT_shstrtab |
177 | | }; |
178 | | |
179 | | /* Context for generating the ELF object for the GDB JIT API. */ |
180 | | typedef struct _ir_gdbjit_ctx { |
181 | | uint8_t *p; /* Pointer to next address in obj.space. */ |
182 | | uint8_t *startp; /* Pointer to start address in obj.space. */ |
183 | | uintptr_t mcaddr; /* Machine code address. */ |
184 | | uint32_t szmcode; /* Size of machine code. */ |
185 | | int32_t lineno; /* Starting line number. */ |
186 | | const char *name; /* JIT function name */ |
187 | | const char *filename; /* Starting file name. */ |
188 | | size_t objsize; /* Final size of ELF object. */ |
189 | | ir_gdbjit_obj obj; /* In-memory ELF object. */ |
190 | | } ir_gdbjit_ctx; |
191 | | |
192 | | /* Add a zero-terminated string */ |
193 | | static uint32_t ir_gdbjit_strz(ir_gdbjit_ctx *ctx, const char *str) |
194 | 0 | { |
195 | 0 | uint8_t *p = ctx->p; |
196 | 0 | uint32_t ofs = (uint32_t)(p - ctx->startp); |
197 | 0 | do { |
198 | 0 | *p++ = (uint8_t)*str; |
199 | 0 | } while (*str++); |
200 | 0 | ctx->p = p; |
201 | 0 | return ofs; |
202 | 0 | } |
203 | | |
204 | | /* Add a ULEB128 value */ |
205 | | static void ir_gdbjit_uleb128(ir_gdbjit_ctx *ctx, uint32_t v) |
206 | 0 | { |
207 | 0 | uint8_t *p = ctx->p; |
208 | 0 | for (; v >= 0x80; v >>= 7) |
209 | 0 | *p++ = (uint8_t)((v & 0x7f) | 0x80); |
210 | 0 | *p++ = (uint8_t)v; |
211 | 0 | ctx->p = p; |
212 | 0 | } |
213 | | |
214 | | /* Add a SLEB128 value */ |
215 | | static void ir_gdbjit_sleb128(ir_gdbjit_ctx *ctx, int32_t v) |
216 | 0 | { |
217 | 0 | uint8_t *p = ctx->p; |
218 | 0 | for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7) |
219 | 0 | *p++ = (uint8_t)((v & 0x7f) | 0x80); |
220 | 0 | *p++ = (uint8_t)(v & 0x7f); |
221 | 0 | ctx->p = p; |
222 | 0 | } |
223 | | |
224 | | static void ir_gdbjit_secthdr(ir_gdbjit_ctx *ctx) |
225 | 0 | { |
226 | 0 | ir_elf_sectheader *sect; |
227 | |
|
228 | 0 | *ctx->p++ = '\0'; |
229 | |
|
230 | 0 | #define SECTDEF(id, tp, al) \ |
231 | 0 | sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \ |
232 | 0 | sect->name = ir_gdbjit_strz(ctx, "." #id); \ |
233 | 0 | sect->type = ELFSECT_TYPE_##tp; \ |
234 | 0 | sect->align = (al) |
235 | |
|
236 | 0 | SECTDEF(text, NOBITS, 16); |
237 | 0 | sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC; |
238 | 0 | sect->addr = ctx->mcaddr; |
239 | 0 | sect->ofs = 0; |
240 | 0 | sect->size = ctx->szmcode; |
241 | |
|
242 | 0 | SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t)); |
243 | 0 | sect->flags = ELFSECT_FLAGS_ALLOC; |
244 | |
|
245 | 0 | SECTDEF(shstrtab, STRTAB, 1); |
246 | 0 | SECTDEF(strtab, STRTAB, 1); |
247 | |
|
248 | 0 | SECTDEF(symtab, SYMTAB, sizeof(uintptr_t)); |
249 | 0 | sect->ofs = offsetof(ir_gdbjit_obj, sym); |
250 | 0 | sect->size = sizeof(ctx->obj.sym); |
251 | 0 | sect->link = GDBJIT_SECT_strtab; |
252 | 0 | sect->entsize = sizeof(ir_elf_symbol); |
253 | 0 | sect->info = GDBJIT_SYM_FUNC; |
254 | |
|
255 | 0 | SECTDEF(debug_info, PROGBITS, 1); |
256 | 0 | SECTDEF(debug_abbrev, PROGBITS, 1); |
257 | 0 | SECTDEF(debug_line, PROGBITS, 1); |
258 | |
|
259 | 0 | #undef SECTDEF |
260 | 0 | } |
261 | | |
262 | | static void ir_gdbjit_symtab(ir_gdbjit_ctx *ctx) |
263 | 0 | { |
264 | 0 | ir_elf_symbol *sym; |
265 | |
|
266 | 0 | *ctx->p++ = '\0'; |
267 | |
|
268 | 0 | sym = &ctx->obj.sym[GDBJIT_SYM_FILE]; |
269 | 0 | sym->name = ir_gdbjit_strz(ctx, "JIT code"); |
270 | 0 | sym->sectidx = ELFSECT_IDX_ABS; |
271 | 0 | sym->info = ELFSYM_INFO(ELFSYM_BIND_LOCAL, ELFSYM_TYPE_FILE); |
272 | |
|
273 | 0 | sym = &ctx->obj.sym[GDBJIT_SYM_FUNC]; |
274 | 0 | sym->name = ir_gdbjit_strz(ctx, ctx->name); |
275 | 0 | sym->sectidx = GDBJIT_SECT_text; |
276 | 0 | sym->value = 0; |
277 | 0 | sym->size = ctx->szmcode; |
278 | 0 | sym->info = ELFSYM_INFO(ELFSYM_BIND_GLOBAL, ELFSYM_TYPE_FUNC); |
279 | 0 | } |
280 | | |
281 | | typedef IR_SET_ALIGNED(1, uint16_t unaligned_uint16_t); |
282 | | typedef IR_SET_ALIGNED(1, uint32_t unaligned_uint32_t); |
283 | | typedef IR_SET_ALIGNED(1, uintptr_t unaligned_uintptr_t); |
284 | | |
285 | | #define SECTALIGN(p, a) \ |
286 | 0 | ((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1))) |
287 | | |
288 | | /* Shortcuts to generate DWARF structures. */ |
289 | 0 | #define DB(x) (*p++ = (x)) |
290 | | #define DI8(x) (*(int8_t *)p = (x), p++) |
291 | | #define DU16(x) (*(unaligned_uint16_t *)p = (x), p += 2) |
292 | | #define DU32(x) (*(unaligned_uint32_t *)p = (x), p += 4) |
293 | | #define DADDR(x) (*(unaligned_uintptr_t *)p = (x), p += sizeof(uintptr_t)) |
294 | 0 | #define DUV(x) (ctx->p = p, ir_gdbjit_uleb128(ctx, (x)), p = ctx->p) |
295 | | #define DSV(x) (ctx->p = p, ir_gdbjit_sleb128(ctx, (x)), p = ctx->p) |
296 | | #define DSTR(str) (ctx->p = p, ir_gdbjit_strz(ctx, (str)), p = ctx->p) |
297 | | #define DALIGNNOP(s) while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop |
298 | | #define DSECT(name, stmt) \ |
299 | 0 | { unaligned_uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \ |
300 | 0 | *szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); } |
301 | | |
302 | | static void ir_gdbjit_ehframe(ir_gdbjit_ctx *ctx, uint32_t sp_offset, uint32_t sp_adjustment) |
303 | 0 | { |
304 | 0 | uint8_t *p = ctx->p; |
305 | 0 | uint8_t *framep = p; |
306 | | |
307 | | /* DWARF EH CIE (Common Information Entry) */ |
308 | 0 | DSECT(CIE, |
309 | 0 | DU32(0); /* CIE ID. */ |
310 | 0 | DB(DW_CIE_VERSION); /* Version */ |
311 | 0 | DSTR("zR"); /* Augmentation String. */ |
312 | 0 | DUV(1); /* Code alignment factor. */ |
313 | 0 | DSV(-(int32_t)sizeof(uintptr_t)); /* Data alignment factor. */ |
314 | 0 | DB(DW_REG_RA); /* Return address register. */ |
315 | 0 | DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4); /* Augmentation data. */ |
316 | 0 | #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) |
317 | 0 | DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t)); |
318 | 0 | DB(DW_CFA_offset|DW_REG_RA); DUV(1); |
319 | | #elif defined(IR_TARGET_AARCH64) |
320 | | DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(0); |
321 | | #endif |
322 | 0 | DALIGNNOP(sizeof(uintptr_t)); |
323 | 0 | ) |
324 | | |
325 | | /* DWARF EH FDE (Frame Description Entry). */ |
326 | 0 | DSECT(FDE, |
327 | 0 | DU32((uint32_t)(p-framep)); /* Offset to CIE Pointer. */ |
328 | 0 | DU32(0); /* Machine code offset relative to .text. */ |
329 | 0 | DU32(ctx->szmcode); /* Machine code length. */ |
330 | 0 | DB(0); /* Augmentation data. */ |
331 | 0 | DB(DW_CFA_def_cfa_offset); DUV(sp_offset); |
332 | | #if defined(IR_TARGET_AARCH64) |
333 | | if (sp_offset) { |
334 | | if (sp_adjustment && sp_adjustment < sp_offset) { |
335 | | DB(DW_CFA_offset|DW_REG_X29); DUV(sp_adjustment / sizeof(uintptr_t)); |
336 | | DB(DW_CFA_offset|DW_REG_RA); DUV((sp_adjustment / sizeof(uintptr_t)) - 1); |
337 | | } else { |
338 | | DB(DW_CFA_offset|DW_REG_X29); DUV(sp_offset / sizeof(uintptr_t)); |
339 | | DB(DW_CFA_offset|DW_REG_RA); DUV((sp_offset / sizeof(uintptr_t)) - 1); |
340 | | } |
341 | | } |
342 | | #endif |
343 | 0 | if (sp_adjustment && sp_adjustment > sp_offset) { |
344 | 0 | DB(DW_CFA_advance_loc|1); DB(DW_CFA_def_cfa_offset); DUV(sp_adjustment); |
345 | | #if defined(IR_TARGET_AARCH64) |
346 | | if (!sp_offset) { |
347 | | DB(DW_CFA_offset|DW_REG_X29); DUV(sp_adjustment / sizeof(uintptr_t)); |
348 | | DB(DW_CFA_offset|DW_REG_RA); DUV((sp_adjustment / sizeof(uintptr_t)) - 1); |
349 | | } |
350 | | #endif |
351 | 0 | } |
352 | 0 | DALIGNNOP(sizeof(uintptr_t)); |
353 | 0 | ) |
354 | |
|
355 | 0 | ctx->p = p; |
356 | 0 | } |
357 | | |
358 | | static void ir_gdbjit_debuginfo(ir_gdbjit_ctx *ctx) |
359 | 0 | { |
360 | 0 | uint8_t *p = ctx->p; |
361 | |
|
362 | 0 | DSECT(info, |
363 | 0 | DU16(2); /* DWARF version. */ |
364 | 0 | DU32(0); /* Abbrev offset. */ |
365 | 0 | DB(sizeof(uintptr_t)); /* Pointer size. */ |
366 | |
|
367 | 0 | DUV(1); /* Abbrev #1: DW_TAG_compile_unit. */ |
368 | 0 | DSTR(ctx->filename); /* DW_AT_name. */ |
369 | 0 | DADDR(ctx->mcaddr); /* DW_AT_low_pc. */ |
370 | 0 | DADDR(ctx->mcaddr + ctx->szmcode); /* DW_AT_high_pc. */ |
371 | 0 | DU32(0); /* DW_AT_stmt_list. */ |
372 | 0 | ); |
373 | |
|
374 | 0 | ctx->p = p; |
375 | 0 | } |
376 | | |
377 | | static void ir_gdbjit_debugabbrev(ir_gdbjit_ctx *ctx) |
378 | 0 | { |
379 | 0 | uint8_t *p = ctx->p; |
380 | | |
381 | | /* Abbrev #1: DW_TAG_compile_unit. */ |
382 | 0 | DUV(1); |
383 | 0 | DUV(DW_TAG_compile_unit); |
384 | 0 | DB(DW_children_no); |
385 | 0 | DUV(DW_AT_name); |
386 | 0 | DUV(DW_FORM_string); |
387 | 0 | DUV(DW_AT_low_pc); |
388 | 0 | DUV(DW_FORM_addr); |
389 | 0 | DUV(DW_AT_high_pc); |
390 | 0 | DUV(DW_FORM_addr); |
391 | 0 | DUV(DW_AT_stmt_list); |
392 | 0 | DUV(DW_FORM_data4); |
393 | 0 | DB(0); |
394 | 0 | DB(0); |
395 | 0 | DB(0); |
396 | |
|
397 | 0 | ctx->p = p; |
398 | 0 | } |
399 | | |
400 | | #define DLNE(op, s) (DB(DW_LNS_extended_op), DUV(1+(s)), DB((op))) |
401 | | |
402 | | static void ir_gdbjit_debugline(ir_gdbjit_ctx *ctx) |
403 | 0 | { |
404 | 0 | uint8_t *p = ctx->p; |
405 | |
|
406 | 0 | DSECT(line, |
407 | 0 | DU16(2); /* DWARF version. */ |
408 | 0 | DSECT(header, |
409 | 0 | DB(1); /* Minimum instruction length. */ |
410 | 0 | DB(1); /* is_stmt. */ |
411 | 0 | DI8(0); /* Line base for special opcodes. */ |
412 | 0 | DB(2); /* Line range for special opcodes. */ |
413 | 0 | DB(3+1); /* Opcode base at DW_LNS_advance_line+1. */ |
414 | 0 | DB(0); DB(1); DB(1); /* Standard opcode lengths. */ |
415 | | /* Directory table. */ |
416 | 0 | DB(0); |
417 | | /* File name table. */ |
418 | 0 | DSTR(ctx->filename); DUV(0); DUV(0); DUV(0); |
419 | 0 | DB(0); |
420 | 0 | ); |
421 | 0 | DLNE(DW_LNE_set_address, sizeof(uintptr_t)); |
422 | 0 | DADDR(ctx->mcaddr); |
423 | 0 | if (ctx->lineno) (DB(DW_LNS_advance_line), DSV(ctx->lineno-1)); |
424 | 0 | DB(DW_LNS_copy); |
425 | 0 | DB(DW_LNS_advance_pc); DUV(ctx->szmcode); |
426 | 0 | DLNE(DW_LNE_end_sequence, 0); |
427 | 0 | ); |
428 | |
|
429 | 0 | ctx->p = p; |
430 | 0 | } |
431 | | |
432 | | |
433 | | #undef DLNE |
434 | | |
435 | | /* Undef shortcuts. */ |
436 | | #undef DB |
437 | | #undef DI8 |
438 | | #undef DU16 |
439 | | #undef DU32 |
440 | | #undef DADDR |
441 | | #undef DUV |
442 | | #undef DSV |
443 | | #undef DSTR |
444 | | #undef DALIGNNOP |
445 | | #undef DSECT |
446 | | |
447 | | typedef void (*ir_gdbjit_initf) (ir_gdbjit_ctx *ctx); |
448 | | |
449 | | static void ir_gdbjit_initsect(ir_gdbjit_ctx *ctx, int sect) |
450 | 0 | { |
451 | 0 | ctx->startp = ctx->p; |
452 | 0 | ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj); |
453 | 0 | } |
454 | | |
455 | | static void ir_gdbjit_initsect_done(ir_gdbjit_ctx *ctx, int sect) |
456 | 0 | { |
457 | 0 | ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp); |
458 | 0 | } |
459 | | |
460 | | static void ir_gdbjit_buildobj(ir_gdbjit_ctx *ctx, uint32_t sp_offset, uint32_t sp_adjustment) |
461 | 0 | { |
462 | 0 | ir_gdbjit_obj *obj = &ctx->obj; |
463 | | |
464 | | /* Fill in ELF header and clear structures. */ |
465 | 0 | memcpy(&obj->hdr, &ir_elfhdr_template, sizeof(ir_elf_header)); |
466 | 0 | memset(&obj->sect, 0, sizeof(ir_elf_sectheader) * GDBJIT_SECT__MAX); |
467 | 0 | memset(&obj->sym, 0, sizeof(ir_elf_symbol) * GDBJIT_SYM__MAX); |
468 | | |
469 | | /* Initialize sections. */ |
470 | 0 | ctx->p = obj->space; |
471 | 0 | ir_gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab); ir_gdbjit_secthdr(ctx); ir_gdbjit_initsect_done(ctx, GDBJIT_SECT_shstrtab); |
472 | 0 | ir_gdbjit_initsect(ctx, GDBJIT_SECT_strtab); ir_gdbjit_symtab(ctx); ir_gdbjit_initsect_done(ctx, GDBJIT_SECT_strtab); |
473 | 0 | ir_gdbjit_initsect(ctx, GDBJIT_SECT_debug_info); ir_gdbjit_debuginfo(ctx); ir_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_info); |
474 | 0 | ir_gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev); ir_gdbjit_debugabbrev(ctx); ir_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_abbrev); |
475 | 0 | ir_gdbjit_initsect(ctx, GDBJIT_SECT_debug_line); ir_gdbjit_debugline(ctx); ir_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_line); |
476 | 0 | SECTALIGN(ctx->p, sizeof(uintptr_t)); |
477 | 0 | ir_gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame); ir_gdbjit_ehframe(ctx, sp_offset, sp_adjustment); ir_gdbjit_initsect_done(ctx, GDBJIT_SECT_eh_frame); |
478 | 0 | ctx->objsize = (size_t)((char *)ctx->p - (char *)obj); |
479 | |
|
480 | 0 | IR_ASSERT(ctx->objsize < sizeof(ir_gdbjit_obj)); |
481 | 0 | } |
482 | | |
483 | | enum { |
484 | | IR_GDBJIT_NOACTION, |
485 | | IR_GDBJIT_REGISTER, |
486 | | IR_GDBJIT_UNREGISTER |
487 | | }; |
488 | | |
489 | | typedef struct _ir_gdbjit_code_entry { |
490 | | struct _ir_gdbjit_code_entry *next_entry; |
491 | | struct _ir_gdbjit_code_entry *prev_entry; |
492 | | const char *symfile_addr; |
493 | | uint64_t symfile_size; |
494 | | } ir_gdbjit_code_entry; |
495 | | |
496 | | typedef struct _ir_gdbjit_descriptor { |
497 | | uint32_t version; |
498 | | uint32_t action_flag; |
499 | | struct _ir_gdbjit_code_entry *relevant_entry; |
500 | | struct _ir_gdbjit_code_entry *first_entry; |
501 | | } ir_gdbjit_descriptor; |
502 | | |
503 | | #ifdef IR_EXTERNAL_GDB_ENTRY |
504 | | extern ir_gdbjit_descriptor __jit_debug_descriptor; |
505 | | void __jit_debug_register_code(void); |
506 | | #else |
507 | | ir_gdbjit_descriptor __jit_debug_descriptor = { |
508 | | 1, IR_GDBJIT_NOACTION, NULL, NULL |
509 | | }; |
510 | | |
511 | | IR_NEVER_INLINE void __jit_debug_register_code(void) |
512 | | { |
513 | | __asm__ __volatile__(""); |
514 | | } |
515 | | #endif |
516 | | |
517 | | static bool ir_gdb_register_code(const void *object, size_t size) |
518 | 0 | { |
519 | 0 | ir_gdbjit_code_entry *entry; |
520 | |
|
521 | 0 | entry = malloc(sizeof(ir_gdbjit_code_entry) + size); |
522 | 0 | if (entry == NULL) { |
523 | 0 | return 0; |
524 | 0 | } |
525 | | |
526 | 0 | entry->symfile_addr = ((char*)entry) + sizeof(ir_gdbjit_code_entry); |
527 | 0 | entry->symfile_size = size; |
528 | |
|
529 | 0 | memcpy((char *)entry->symfile_addr, object, size); |
530 | |
|
531 | 0 | entry->prev_entry = NULL; |
532 | 0 | entry->next_entry = __jit_debug_descriptor.first_entry; |
533 | |
|
534 | 0 | if (entry->next_entry) { |
535 | 0 | entry->next_entry->prev_entry = entry; |
536 | 0 | } |
537 | 0 | __jit_debug_descriptor.first_entry = entry; |
538 | | |
539 | | /* Notify GDB */ |
540 | 0 | __jit_debug_descriptor.relevant_entry = entry; |
541 | 0 | __jit_debug_descriptor.action_flag = IR_GDBJIT_REGISTER; |
542 | 0 | __jit_debug_register_code(); |
543 | |
|
544 | 0 | return 1; |
545 | 0 | } |
546 | | |
547 | | void ir_gdb_unregister_all(void) |
548 | 0 | { |
549 | 0 | ir_gdbjit_code_entry *entry; |
550 | |
|
551 | 0 | __jit_debug_descriptor.action_flag = IR_GDBJIT_UNREGISTER; |
552 | 0 | while ((entry = __jit_debug_descriptor.first_entry)) { |
553 | 0 | __jit_debug_descriptor.first_entry = entry->next_entry; |
554 | 0 | if (entry->next_entry) { |
555 | 0 | entry->next_entry->prev_entry = NULL; |
556 | 0 | } |
557 | | /* Notify GDB */ |
558 | 0 | __jit_debug_descriptor.relevant_entry = entry; |
559 | 0 | __jit_debug_register_code(); |
560 | |
|
561 | 0 | free(entry); |
562 | 0 | } |
563 | 0 | } |
564 | | |
565 | | #if defined(__FreeBSD__) |
566 | | static bool ir_gdb_info_proc(pid_t pid, struct kinfo_proc *proc) |
567 | | { |
568 | | size_t len, plen; |
569 | | len = plen = sizeof(*proc); |
570 | | int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; |
571 | | |
572 | | if (sysctl(mib, 4, proc, &len, NULL, 0) < 0 || len != plen || |
573 | | proc->ki_structsize != (int)plen || proc->ki_pid != pid) { |
574 | | return false; |
575 | | } |
576 | | |
577 | | return true; |
578 | | } |
579 | | #endif |
580 | | |
581 | | bool ir_gdb_present(void) |
582 | 0 | { |
583 | 0 | bool ret = 0; |
584 | 0 | #if defined(__linux__) /* netbsd while having this procfs part, does not hold the tracer pid */ |
585 | 0 | int fd = open("/proc/self/status", O_RDONLY); |
586 | |
|
587 | 0 | if (fd > 0) { |
588 | 0 | char buf[1024]; |
589 | 0 | ssize_t n = read(fd, buf, sizeof(buf) - 1); |
590 | 0 | char *s; |
591 | 0 | pid_t pid; |
592 | |
|
593 | 0 | if (n > 0) { |
594 | 0 | buf[n] = 0; |
595 | 0 | s = strstr(buf, "TracerPid:"); |
596 | 0 | if (s) { |
597 | 0 | s += sizeof("TracerPid:") - 1; |
598 | 0 | while (*s == ' ' || *s == '\t') { |
599 | 0 | s++; |
600 | 0 | } |
601 | 0 | pid = atoi(s); |
602 | 0 | if (pid) { |
603 | 0 | char out[1024]; |
604 | 0 | snprintf(buf, sizeof(buf), "/proc/%d/exe", (int)pid); |
605 | 0 | if (readlink(buf, out, sizeof(out) - 1) > 0) { |
606 | 0 | if (strstr(out, "gdb")) { |
607 | 0 | ret = 1; |
608 | 0 | } |
609 | 0 | } |
610 | 0 | } |
611 | 0 | } |
612 | 0 | } |
613 | |
|
614 | 0 | close(fd); |
615 | 0 | } |
616 | | #elif defined(__FreeBSD__) |
617 | | struct kinfo_proc proc, dbg; |
618 | | |
619 | | if (ir_gdb_info_proc(getpid(), &proc)) { |
620 | | if ((proc.ki_flag & P_TRACED) != 0) { |
621 | | if (ir_gdb_info_proc(proc.ki_tracer, &dbg)) { |
622 | | ret = strstr(dbg.ki_comm, "gdb"); |
623 | | } |
624 | | } |
625 | | } |
626 | | #endif |
627 | |
|
628 | 0 | return ret; |
629 | 0 | } |
630 | | |
631 | | int ir_gdb_register(const char *name, |
632 | | const void *start, |
633 | | size_t size, |
634 | | uint32_t sp_offset, |
635 | | uint32_t sp_adjustment) |
636 | 0 | { |
637 | 0 | ir_gdbjit_ctx ctx; |
638 | |
|
639 | 0 | ctx.mcaddr = (uintptr_t)start; |
640 | 0 | ctx.szmcode = (uint32_t)size; |
641 | 0 | ctx.name = name; |
642 | 0 | ctx.filename = "unknown"; |
643 | 0 | ctx.lineno = 0; |
644 | |
|
645 | 0 | ir_gdbjit_buildobj(&ctx, sp_offset, sp_adjustment); |
646 | |
|
647 | 0 | return ir_gdb_register_code(&ctx.obj, ctx.objsize); |
648 | 0 | } |
649 | | |
650 | | void ir_gdb_init(void) |
651 | 0 | { |
652 | | /* This might enable registration of all JIT-ed code, but unfortunately, |
653 | | * in case of many functions, this takes enormous time. */ |
654 | 0 | if (ir_gdb_present()) { |
655 | | #if 0 |
656 | | _debug |= IR_DEBUG_GDB; |
657 | | #endif |
658 | 0 | } |
659 | 0 | } |