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