| 1 | /* Handle JIT code generation in the inferior for GDB, the GNU Debugger. |
| 2 | |
| 3 | Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. |
| 4 | |
| 5 | This file is part of GDB. |
| 6 | |
| 7 | This program is free software; you can redistribute it and/or modify |
| 8 | it under the terms of the GNU General Public License as published by |
| 9 | the Free Software Foundation; either version 3 of the License, or |
| 10 | (at your option) any later version. |
| 11 | |
| 12 | This program is distributed in the hope that it will be useful, |
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | GNU General Public License for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU General Public License |
| 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| 19 | |
| 20 | #include "defs.h" |
| 21 | |
| 22 | #include "jit.h" |
| 23 | #include "breakpoint.h" |
| 24 | #include "command.h" |
| 25 | #include "gdbcmd.h" |
| 26 | #include "gdbcore.h" |
| 27 | #include "inferior.h" |
| 28 | #include "observer.h" |
| 29 | #include "objfiles.h" |
| 30 | #include "symfile.h" |
| 31 | #include "symtab.h" |
| 32 | #include "target.h" |
| 33 | #include "gdb_stat.h" |
| 34 | |
| 35 | static const struct objfile_data *jit_objfile_data; |
| 36 | |
| 37 | static const char *const jit_break_name = "__jit_debug_register_code"; |
| 38 | |
| 39 | static const char *const jit_descriptor_name = "__jit_debug_descriptor"; |
| 40 | |
| 41 | static const struct inferior_data *jit_inferior_data = NULL; |
| 42 | |
| 43 | /* Non-zero if we want to see trace of jit level stuff. */ |
| 44 | |
| 45 | static int jit_debug = 0; |
| 46 | |
| 47 | static void |
| 48 | show_jit_debug (struct ui_file *file, int from_tty, |
| 49 | struct cmd_list_element *c, const char *value) |
| 50 | { |
| 51 | fprintf_filtered (file, _("JIT debugging is %s.\n"), value); |
| 52 | } |
| 53 | |
| 54 | struct target_buffer |
| 55 | { |
| 56 | CORE_ADDR base; |
| 57 | ULONGEST size; |
| 58 | }; |
| 59 | |
| 60 | /* Openning the file is a no-op. */ |
| 61 | |
| 62 | static void * |
| 63 | mem_bfd_iovec_open (struct bfd *abfd, void *open_closure) |
| 64 | { |
| 65 | return open_closure; |
| 66 | } |
| 67 | |
| 68 | /* Closing the file is just freeing the base/size pair on our side. */ |
| 69 | |
| 70 | static int |
| 71 | mem_bfd_iovec_close (struct bfd *abfd, void *stream) |
| 72 | { |
| 73 | xfree (stream); |
| 74 | return 1; |
| 75 | } |
| 76 | |
| 77 | /* For reading the file, we just need to pass through to target_read_memory and |
| 78 | fix up the arguments and return values. */ |
| 79 | |
| 80 | static file_ptr |
| 81 | mem_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf, |
| 82 | file_ptr nbytes, file_ptr offset) |
| 83 | { |
| 84 | int err; |
| 85 | struct target_buffer *buffer = (struct target_buffer *) stream; |
| 86 | |
| 87 | /* If this read will read all of the file, limit it to just the rest. */ |
| 88 | if (offset + nbytes > buffer->size) |
| 89 | nbytes = buffer->size - offset; |
| 90 | |
| 91 | /* If there are no more bytes left, we've reached EOF. */ |
| 92 | if (nbytes == 0) |
| 93 | return 0; |
| 94 | |
| 95 | err = target_read_memory (buffer->base + offset, (gdb_byte *) buf, nbytes); |
| 96 | if (err) |
| 97 | return -1; |
| 98 | |
| 99 | return nbytes; |
| 100 | } |
| 101 | |
| 102 | /* For statting the file, we only support the st_size attribute. */ |
| 103 | |
| 104 | static int |
| 105 | mem_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb) |
| 106 | { |
| 107 | struct target_buffer *buffer = (struct target_buffer*) stream; |
| 108 | |
| 109 | sb->st_size = buffer->size; |
| 110 | return 0; |
| 111 | } |
| 112 | |
| 113 | /* Open a BFD from the target's memory. */ |
| 114 | |
| 115 | static struct bfd * |
| 116 | bfd_open_from_target_memory (CORE_ADDR addr, ULONGEST size, char *target) |
| 117 | { |
| 118 | const char *filename = xstrdup ("<in-memory>"); |
| 119 | struct target_buffer *buffer = xmalloc (sizeof (struct target_buffer)); |
| 120 | |
| 121 | buffer->base = addr; |
| 122 | buffer->size = size; |
| 123 | return bfd_openr_iovec (filename, target, |
| 124 | mem_bfd_iovec_open, |
| 125 | buffer, |
| 126 | mem_bfd_iovec_pread, |
| 127 | mem_bfd_iovec_close, |
| 128 | mem_bfd_iovec_stat); |
| 129 | } |
| 130 | |
| 131 | /* Per-inferior structure recording the addresses in the inferior. */ |
| 132 | |
| 133 | struct jit_inferior_data |
| 134 | { |
| 135 | CORE_ADDR breakpoint_addr; /* &__jit_debug_register_code() */ |
| 136 | CORE_ADDR descriptor_addr; /* &__jit_debug_descriptor */ |
| 137 | }; |
| 138 | |
| 139 | /* Return jit_inferior_data for current inferior. Allocate if not already |
| 140 | present. */ |
| 141 | |
| 142 | static struct jit_inferior_data * |
| 143 | get_jit_inferior_data (void) |
| 144 | { |
| 145 | struct inferior *inf; |
| 146 | struct jit_inferior_data *inf_data; |
| 147 | |
| 148 | inf = current_inferior (); |
| 149 | inf_data = inferior_data (inf, jit_inferior_data); |
| 150 | if (inf_data == NULL) |
| 151 | { |
| 152 | inf_data = XZALLOC (struct jit_inferior_data); |
| 153 | set_inferior_data (inf, jit_inferior_data, inf_data); |
| 154 | } |
| 155 | |
| 156 | return inf_data; |
| 157 | } |
| 158 | |
| 159 | static void |
| 160 | jit_inferior_data_cleanup (struct inferior *inf, void *arg) |
| 161 | { |
| 162 | xfree (arg); |
| 163 | } |
| 164 | |
| 165 | /* Helper function for reading the global JIT descriptor from remote |
| 166 | memory. */ |
| 167 | |
| 168 | static void |
| 169 | jit_read_descriptor (struct gdbarch *gdbarch, |
| 170 | struct jit_descriptor *descriptor, |
| 171 | CORE_ADDR descriptor_addr) |
| 172 | { |
| 173 | int err; |
| 174 | struct type *ptr_type; |
| 175 | int ptr_size; |
| 176 | int desc_size; |
| 177 | gdb_byte *desc_buf; |
| 178 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| 179 | |
| 180 | /* Figure out how big the descriptor is on the remote and how to read it. */ |
| 181 | ptr_type = builtin_type (gdbarch)->builtin_data_ptr; |
| 182 | ptr_size = TYPE_LENGTH (ptr_type); |
| 183 | desc_size = 8 + 2 * ptr_size; /* Two 32-bit ints and two pointers. */ |
| 184 | desc_buf = alloca (desc_size); |
| 185 | |
| 186 | /* Read the descriptor. */ |
| 187 | err = target_read_memory (descriptor_addr, desc_buf, desc_size); |
| 188 | if (err) |
| 189 | error (_("Unable to read JIT descriptor from remote memory!")); |
| 190 | |
| 191 | /* Fix the endianness to match the host. */ |
| 192 | descriptor->version = extract_unsigned_integer (&desc_buf[0], 4, byte_order); |
| 193 | descriptor->action_flag = |
| 194 | extract_unsigned_integer (&desc_buf[4], 4, byte_order); |
| 195 | descriptor->relevant_entry = extract_typed_address (&desc_buf[8], ptr_type); |
| 196 | descriptor->first_entry = |
| 197 | extract_typed_address (&desc_buf[8 + ptr_size], ptr_type); |
| 198 | } |
| 199 | |
| 200 | /* Helper function for reading a JITed code entry from remote memory. */ |
| 201 | |
| 202 | static void |
| 203 | jit_read_code_entry (struct gdbarch *gdbarch, |
| 204 | CORE_ADDR code_addr, struct jit_code_entry *code_entry) |
| 205 | { |
| 206 | int err; |
| 207 | struct type *ptr_type; |
| 208 | int ptr_size; |
| 209 | int entry_size; |
| 210 | gdb_byte *entry_buf; |
| 211 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| 212 | |
| 213 | /* Figure out how big the entry is on the remote and how to read it. */ |
| 214 | ptr_type = builtin_type (gdbarch)->builtin_data_ptr; |
| 215 | ptr_size = TYPE_LENGTH (ptr_type); |
| 216 | entry_size = 3 * ptr_size + 8; /* Three pointers and one 64-bit int. */ |
| 217 | entry_buf = alloca (entry_size); |
| 218 | |
| 219 | /* Read the entry. */ |
| 220 | err = target_read_memory (code_addr, entry_buf, entry_size); |
| 221 | if (err) |
| 222 | error (_("Unable to read JIT code entry from remote memory!")); |
| 223 | |
| 224 | /* Fix the endianness to match the host. */ |
| 225 | ptr_type = builtin_type (gdbarch)->builtin_data_ptr; |
| 226 | code_entry->next_entry = extract_typed_address (&entry_buf[0], ptr_type); |
| 227 | code_entry->prev_entry = |
| 228 | extract_typed_address (&entry_buf[ptr_size], ptr_type); |
| 229 | code_entry->symfile_addr = |
| 230 | extract_typed_address (&entry_buf[2 * ptr_size], ptr_type); |
| 231 | code_entry->symfile_size = |
| 232 | extract_unsigned_integer (&entry_buf[3 * ptr_size], 8, byte_order); |
| 233 | } |
| 234 | |
| 235 | /* This function registers code associated with a JIT code entry. It uses the |
| 236 | pointer and size pair in the entry to read the symbol file from the remote |
| 237 | and then calls symbol_file_add_from_local_memory to add it as though it were |
| 238 | a symbol file added by the user. */ |
| 239 | |
| 240 | static void |
| 241 | jit_register_code (struct gdbarch *gdbarch, |
| 242 | CORE_ADDR entry_addr, struct jit_code_entry *code_entry) |
| 243 | { |
| 244 | bfd *nbfd; |
| 245 | struct section_addr_info *sai; |
| 246 | struct bfd_section *sec; |
| 247 | struct objfile *objfile; |
| 248 | struct cleanup *old_cleanups, *my_cleanups; |
| 249 | int i; |
| 250 | const struct bfd_arch_info *b; |
| 251 | CORE_ADDR *entry_addr_ptr; |
| 252 | |
| 253 | if (jit_debug) |
| 254 | fprintf_unfiltered (gdb_stdlog, |
| 255 | "jit_register_code, symfile_addr = %s, " |
| 256 | "symfile_size = %s\n", |
| 257 | paddress (gdbarch, code_entry->symfile_addr), |
| 258 | pulongest (code_entry->symfile_size)); |
| 259 | |
| 260 | nbfd = bfd_open_from_target_memory (code_entry->symfile_addr, |
| 261 | code_entry->symfile_size, gnutarget); |
| 262 | old_cleanups = make_cleanup_bfd_close (nbfd); |
| 263 | |
| 264 | /* Check the format. NOTE: This initializes important data that GDB uses! |
| 265 | We would segfault later without this line. */ |
| 266 | if (!bfd_check_format (nbfd, bfd_object)) |
| 267 | { |
| 268 | printf_unfiltered (_("\ |
| 269 | JITed symbol file is not an object file, ignoring it.\n")); |
| 270 | do_cleanups (old_cleanups); |
| 271 | return; |
| 272 | } |
| 273 | |
| 274 | /* Check bfd arch. */ |
| 275 | b = gdbarch_bfd_arch_info (gdbarch); |
| 276 | if (b->compatible (b, bfd_get_arch_info (nbfd)) != b) |
| 277 | warning (_("JITed object file architecture %s is not compatible " |
| 278 | "with target architecture %s."), bfd_get_arch_info |
| 279 | (nbfd)->printable_name, b->printable_name); |
| 280 | |
| 281 | /* Read the section address information out of the symbol file. Since the |
| 282 | file is generated by the JIT at runtime, it should all of the absolute |
| 283 | addresses that we care about. */ |
| 284 | sai = alloc_section_addr_info (bfd_count_sections (nbfd)); |
| 285 | make_cleanup_free_section_addr_info (sai); |
| 286 | i = 0; |
| 287 | for (sec = nbfd->sections; sec != NULL; sec = sec->next) |
| 288 | if ((bfd_get_section_flags (nbfd, sec) & (SEC_ALLOC|SEC_LOAD)) != 0) |
| 289 | { |
| 290 | /* We assume that these virtual addresses are absolute, and do not |
| 291 | treat them as offsets. */ |
| 292 | sai->other[i].addr = bfd_get_section_vma (nbfd, sec); |
| 293 | sai->other[i].name = xstrdup (bfd_get_section_name (nbfd, sec)); |
| 294 | sai->other[i].sectindex = sec->index; |
| 295 | ++i; |
| 296 | } |
| 297 | |
| 298 | /* This call takes ownership of sai. */ |
| 299 | objfile = symbol_file_add_from_bfd (nbfd, 0, sai, OBJF_SHARED); |
| 300 | |
| 301 | /* Remember a mapping from entry_addr to objfile. */ |
| 302 | entry_addr_ptr = xmalloc (sizeof (CORE_ADDR)); |
| 303 | *entry_addr_ptr = entry_addr; |
| 304 | set_objfile_data (objfile, jit_objfile_data, entry_addr_ptr); |
| 305 | |
| 306 | discard_cleanups (old_cleanups); |
| 307 | } |
| 308 | |
| 309 | /* This function unregisters JITed code and frees the corresponding |
| 310 | objfile. */ |
| 311 | |
| 312 | static void |
| 313 | jit_unregister_code (struct objfile *objfile) |
| 314 | { |
| 315 | free_objfile (objfile); |
| 316 | } |
| 317 | |
| 318 | /* Look up the objfile with this code entry address. */ |
| 319 | |
| 320 | static struct objfile * |
| 321 | jit_find_objf_with_entry_addr (CORE_ADDR entry_addr) |
| 322 | { |
| 323 | struct objfile *objf; |
| 324 | CORE_ADDR *objf_entry_addr; |
| 325 | |
| 326 | ALL_OBJFILES (objf) |
| 327 | { |
| 328 | objf_entry_addr = (CORE_ADDR *) objfile_data (objf, jit_objfile_data); |
| 329 | if (objf_entry_addr != NULL && *objf_entry_addr == entry_addr) |
| 330 | return objf; |
| 331 | } |
| 332 | return NULL; |
| 333 | } |
| 334 | |
| 335 | /* (Re-)Initialize the jit breakpoint if necessary. |
| 336 | Return 0 on success. */ |
| 337 | |
| 338 | static int |
| 339 | jit_breakpoint_re_set_internal (struct gdbarch *gdbarch, |
| 340 | struct jit_inferior_data *inf_data) |
| 341 | { |
| 342 | if (inf_data->breakpoint_addr == 0) |
| 343 | { |
| 344 | struct minimal_symbol *reg_symbol; |
| 345 | |
| 346 | /* Lookup the registration symbol. If it is missing, then we assume |
| 347 | we are not attached to a JIT. */ |
| 348 | reg_symbol = lookup_minimal_symbol (jit_break_name, NULL, NULL); |
| 349 | if (reg_symbol == NULL) |
| 350 | return 1; |
| 351 | inf_data->breakpoint_addr = SYMBOL_VALUE_ADDRESS (reg_symbol); |
| 352 | if (inf_data->breakpoint_addr == 0) |
| 353 | return 2; |
| 354 | } |
| 355 | else |
| 356 | return 0; |
| 357 | |
| 358 | if (jit_debug) |
| 359 | fprintf_unfiltered (gdb_stdlog, |
| 360 | "jit_breakpoint_re_set_internal, " |
| 361 | "breakpoint_addr = %s\n", |
| 362 | paddress (gdbarch, inf_data->breakpoint_addr)); |
| 363 | |
| 364 | /* Put a breakpoint in the registration symbol. */ |
| 365 | create_jit_event_breakpoint (gdbarch, inf_data->breakpoint_addr); |
| 366 | |
| 367 | return 0; |
| 368 | } |
| 369 | |
| 370 | /* Register any already created translations. */ |
| 371 | |
| 372 | static void |
| 373 | jit_inferior_init (struct gdbarch *gdbarch) |
| 374 | { |
| 375 | struct jit_descriptor descriptor; |
| 376 | struct jit_code_entry cur_entry; |
| 377 | struct jit_inferior_data *inf_data; |
| 378 | CORE_ADDR cur_entry_addr; |
| 379 | |
| 380 | if (jit_debug) |
| 381 | fprintf_unfiltered (gdb_stdlog, "jit_inferior_init\n"); |
| 382 | |
| 383 | inf_data = get_jit_inferior_data (); |
| 384 | if (jit_breakpoint_re_set_internal (gdbarch, inf_data) != 0) |
| 385 | return; |
| 386 | |
| 387 | if (inf_data->descriptor_addr == 0) |
| 388 | { |
| 389 | struct minimal_symbol *desc_symbol; |
| 390 | |
| 391 | /* Lookup the descriptor symbol and cache the addr. If it is |
| 392 | missing, we assume we are not attached to a JIT and return early. */ |
| 393 | desc_symbol = lookup_minimal_symbol (jit_descriptor_name, NULL, NULL); |
| 394 | if (desc_symbol == NULL) |
| 395 | return; |
| 396 | |
| 397 | inf_data->descriptor_addr = SYMBOL_VALUE_ADDRESS (desc_symbol); |
| 398 | if (inf_data->descriptor_addr == 0) |
| 399 | return; |
| 400 | } |
| 401 | |
| 402 | if (jit_debug) |
| 403 | fprintf_unfiltered (gdb_stdlog, |
| 404 | "jit_inferior_init, descriptor_addr = %s\n", |
| 405 | paddress (gdbarch, inf_data->descriptor_addr)); |
| 406 | |
| 407 | /* Read the descriptor so we can check the version number and load |
| 408 | any already JITed functions. */ |
| 409 | jit_read_descriptor (gdbarch, &descriptor, inf_data->descriptor_addr); |
| 410 | |
| 411 | /* Check that the version number agrees with that we support. */ |
| 412 | if (descriptor.version != 1) |
| 413 | error (_("Unsupported JIT protocol version in descriptor!")); |
| 414 | |
| 415 | /* If we've attached to a running program, we need to check the descriptor |
| 416 | to register any functions that were already generated. */ |
| 417 | for (cur_entry_addr = descriptor.first_entry; |
| 418 | cur_entry_addr != 0; |
| 419 | cur_entry_addr = cur_entry.next_entry) |
| 420 | { |
| 421 | jit_read_code_entry (gdbarch, cur_entry_addr, &cur_entry); |
| 422 | |
| 423 | /* This hook may be called many times during setup, so make sure we don't |
| 424 | add the same symbol file twice. */ |
| 425 | if (jit_find_objf_with_entry_addr (cur_entry_addr) != NULL) |
| 426 | continue; |
| 427 | |
| 428 | jit_register_code (gdbarch, cur_entry_addr, &cur_entry); |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | /* Exported routine to call when an inferior has been created. */ |
| 433 | |
| 434 | void |
| 435 | jit_inferior_created_hook (void) |
| 436 | { |
| 437 | jit_inferior_init (target_gdbarch); |
| 438 | } |
| 439 | |
| 440 | /* Exported routine to call to re-set the jit breakpoints, |
| 441 | e.g. when a program is rerun. */ |
| 442 | |
| 443 | void |
| 444 | jit_breakpoint_re_set (void) |
| 445 | { |
| 446 | jit_breakpoint_re_set_internal (target_gdbarch, |
| 447 | get_jit_inferior_data ()); |
| 448 | } |
| 449 | |
| 450 | /* Reset inferior_data, so sybols will be looked up again, and jit_breakpoint |
| 451 | will be reset. */ |
| 452 | |
| 453 | static void |
| 454 | jit_reset_inferior_data_and_breakpoints (void) |
| 455 | { |
| 456 | struct jit_inferior_data *inf_data; |
| 457 | |
| 458 | /* Force jit_inferior_init to re-lookup of jit symbol addresses. */ |
| 459 | inf_data = get_jit_inferior_data (); |
| 460 | inf_data->breakpoint_addr = 0; |
| 461 | inf_data->descriptor_addr = 0; |
| 462 | |
| 463 | /* Remove any existing JIT breakpoint(s). */ |
| 464 | remove_jit_event_breakpoints (); |
| 465 | |
| 466 | jit_inferior_init (target_gdbarch); |
| 467 | } |
| 468 | |
| 469 | /* Wrapper to match the observer function pointer prototype. */ |
| 470 | |
| 471 | static void |
| 472 | jit_inferior_created_observer (struct target_ops *objfile, int from_tty) |
| 473 | { |
| 474 | jit_reset_inferior_data_and_breakpoints (); |
| 475 | } |
| 476 | |
| 477 | /* This function cleans up any code entries left over when the |
| 478 | inferior exits. We get left over code when the inferior exits |
| 479 | without unregistering its code, for example when it crashes. */ |
| 480 | |
| 481 | static void |
| 482 | jit_inferior_exit_hook (struct inferior *inf) |
| 483 | { |
| 484 | struct objfile *objf; |
| 485 | struct objfile *temp; |
| 486 | |
| 487 | ALL_OBJFILES_SAFE (objf, temp) |
| 488 | if (objfile_data (objf, jit_objfile_data) != NULL) |
| 489 | jit_unregister_code (objf); |
| 490 | } |
| 491 | |
| 492 | static void |
| 493 | jit_executable_changed_observer (void) |
| 494 | { |
| 495 | jit_reset_inferior_data_and_breakpoints (); |
| 496 | } |
| 497 | |
| 498 | void |
| 499 | jit_event_handler (struct gdbarch *gdbarch) |
| 500 | { |
| 501 | struct jit_descriptor descriptor; |
| 502 | struct jit_code_entry code_entry; |
| 503 | CORE_ADDR entry_addr; |
| 504 | struct objfile *objf; |
| 505 | |
| 506 | /* Read the descriptor from remote memory. */ |
| 507 | jit_read_descriptor (gdbarch, &descriptor, |
| 508 | get_jit_inferior_data ()->descriptor_addr); |
| 509 | entry_addr = descriptor.relevant_entry; |
| 510 | |
| 511 | /* Do the corresponding action. */ |
| 512 | switch (descriptor.action_flag) |
| 513 | { |
| 514 | case JIT_NOACTION: |
| 515 | break; |
| 516 | case JIT_REGISTER: |
| 517 | jit_read_code_entry (gdbarch, entry_addr, &code_entry); |
| 518 | jit_register_code (gdbarch, entry_addr, &code_entry); |
| 519 | break; |
| 520 | case JIT_UNREGISTER: |
| 521 | objf = jit_find_objf_with_entry_addr (entry_addr); |
| 522 | if (objf == NULL) |
| 523 | printf_unfiltered (_("Unable to find JITed code " |
| 524 | "entry at address: %s\n"), |
| 525 | paddress (gdbarch, entry_addr)); |
| 526 | else |
| 527 | jit_unregister_code (objf); |
| 528 | |
| 529 | break; |
| 530 | default: |
| 531 | error (_("Unknown action_flag value in JIT descriptor!")); |
| 532 | break; |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | /* Provide a prototype to silence -Wmissing-prototypes. */ |
| 537 | |
| 538 | extern void _initialize_jit (void); |
| 539 | |
| 540 | void |
| 541 | _initialize_jit (void) |
| 542 | { |
| 543 | add_setshow_zinteger_cmd ("jit", class_maintenance, &jit_debug, |
| 544 | _("Set JIT debugging."), |
| 545 | _("Show JIT debugging."), |
| 546 | _("When non-zero, JIT debugging is enabled."), |
| 547 | NULL, |
| 548 | show_jit_debug, |
| 549 | &setdebuglist, &showdebuglist); |
| 550 | |
| 551 | observer_attach_inferior_created (jit_inferior_created_observer); |
| 552 | observer_attach_inferior_exit (jit_inferior_exit_hook); |
| 553 | observer_attach_executable_changed (jit_executable_changed_observer); |
| 554 | jit_objfile_data = register_objfile_data (); |
| 555 | jit_inferior_data = |
| 556 | register_inferior_data_with_cleanup (jit_inferior_data_cleanup); |
| 557 | } |