github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-debugger.c (about) 1 /* 2 * jit-debugger.c - Helper routines for single-step debugging of programs. 3 * 4 * Copyright (C) 2004 Southern Storm Software, Pty Ltd. 5 * 6 * This file is part of the libjit library. 7 * 8 * The libjit library is free software: you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public License 10 * as published by the Free Software Foundation, either version 2.1 of 11 * the License, or (at your option) any later version. 12 * 13 * The libjit library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with the libjit library. If not, see 20 * <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "jit-internal.h" 24 25 /*@ 26 27 @cindex jit-debugger.h 28 29 The @code{libjit} library provides support routines for breakpoint-based 30 single-step debugging. It isn't a full debugger, but provides the 31 infrastructure necessary to support one. 32 33 The front end virtual machine is responsible for inserting "potential 34 breakpoints" into the code when functions are built and compiled. This 35 is performed using @code{jit_insn_mark_breakpoint}: 36 37 @deftypefun int jit_insn_mark_breakpoint (jit_function_t @var{func}, jit_nint @var{data1}, jit_nint @var{data2}) 38 Mark the current position in @var{func} as corresponding to a breakpoint 39 location. When a break occurs, the debugging routines are passed 40 @var{func}, @var{data1}, and @var{data2} as arguments. By convention, 41 @var{data1} is the type of breakpoint (source line, function entry, 42 function exit, etc). 43 @end deftypefun 44 45 There are two ways for a front end to receive notification about breakpoints. 46 The bulk of this chapter describes the @code{jit_debugger_t} interface, 47 which handles most of the ugly details. In addition, a low-level "debug hook 48 mechanism" is provided for front ends that wish more control over the 49 process. The debug hook mechanism is described below, under the 50 @code{jit_debugger_set_hook} function. 51 52 This debugger implementation requires a threading system to work 53 successfully. At least two threads are required, in addition to those of 54 the program being debugged: 55 56 @enumerate 57 @item 58 Event thread which calls @code{jit_debugger_wait_event} to receive 59 notifications of breakpoints and other interesting events. 60 61 @item 62 User interface thread which calls functions like @code{jit_debugger_run}, 63 @code{jit_debugger_step}, etc, to control the debug process. 64 @end enumerate 65 66 These two threads should be set to "unbreakable" with a call to 67 @code{jit_debugger_set_breakable}. This prevents them from accidentally 68 stopping at a breakpoint, which would cause a system deadlock. 69 Other housekeeping threads, such as a finalization thread, should 70 also be set to "unbreakable" for the same reason. 71 72 @noindent 73 Events have the following members: 74 75 @table @code 76 @item type 77 The type of event (see the next table for details). 78 79 @item thread 80 The thread that the event occurred on. 81 82 @item function 83 The function that the breakpoint occurred within. 84 85 @item data1 86 @itemx data2 87 The data values at the breakpoint. These values are inserted into 88 the function's code with @code{jit_insn_mark_breakpoint}. 89 90 @item id 91 The identifier for the breakpoint. 92 93 @item trace 94 The stack trace corresponding to the location where the breakpoint 95 occurred. This value is automatically freed upon the next call 96 to @code{jit_debugger_wait_event}. If you wish to preserve the 97 value, then you must call @code{jit_stack_trace_copy}. 98 @end table 99 100 @noindent 101 The following event types are currently supported: 102 103 @table @code 104 @item JIT_DEBUGGER_TYPE_QUIT 105 A thread called @code{jit_debugger_quit}, indicating that it wanted the 106 event thread to terminate. 107 108 @item JIT_DEBUGGER_TYPE_HARD_BREAKPOINT 109 A thread stopped at a hard breakpoint. That is, a breakpoint defined 110 by a call to @code{jit_debugger_add_breakpoint}. 111 112 @item JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT 113 A thread stopped at a breakpoint that wasn't explicitly defined by 114 a call to @code{jit_debugger_add_breakpoint}. This typicaly results 115 from a call to a "step" function like @code{jit_debugger_step}, where 116 execution stopped at the next line but there isn't an explicit breakpoint 117 on that line. 118 119 @item JIT_DEBUGGER_TYPE_USER_BREAKPOINT 120 A thread stopped because of a call to @code{jit_debugger_break}. 121 122 @item JIT_DEBUGGER_TYPE_ATTACH_THREAD 123 A thread called @code{jit_debugger_attach_self}. The @code{data1} field 124 of the event is set to the value of @code{stop_immediately} for the call. 125 126 @item JIT_DEBUGGER_TYPE_DETACH_THREAD 127 A thread called @code{jit_debugger_detach_self}. 128 @end table 129 130 @deftypefun int jit_insn_mark_breakpoint_variable (jit_function_t @var{func}, jit_value_t @var{data1}, jit_value_t @var{data2}) 131 This function is similar to @code{jit_insn_mark_breakpoint} except that values 132 in @var{data1} and @var{data2} can be computed at runtime. You can use this 133 function for example to get address of local variable. 134 @end deftypefun 135 136 @*/ 137 138 /* 139 * Linked event, for the debugger event queue. 140 */ 141 typedef struct jit_debugger_linked_event 142 { 143 jit_debugger_event_t event; 144 struct jit_debugger_linked_event *next; 145 146 } jit_debugger_linked_event_t; 147 148 /* 149 * Run types. 150 */ 151 #define JIT_RUN_TYPE_STOPPED 0 152 #define JIT_RUN_TYPE_CONTINUE 1 153 #define JIT_RUN_TYPE_STEP 2 154 #define JIT_RUN_TYPE_NEXT 3 155 #define JIT_RUN_TYPE_FINISH 4 156 #define JIT_RUN_TYPE_DETACHED 5 157 158 /* 159 * Information about a thread that is under the control of the debugger. 160 */ 161 typedef struct jit_debugger_thread 162 { 163 struct jit_debugger_thread *next; 164 jit_debugger_thread_id_t id; 165 jit_thread_id_t native_id; 166 int volatile run_type; 167 jit_function_t find_func; 168 jit_nint last_data1; 169 jit_nint last_func_data1; 170 int breakable; 171 172 } *jit_debugger_thread_t; 173 174 /* 175 * Structure of a debugger instance. 176 */ 177 struct jit_debugger 178 { 179 jit_monitor_t queue_lock; 180 jit_monitor_t run_lock; 181 jit_context_t context; 182 jit_debugger_linked_event_t * volatile events; 183 jit_debugger_linked_event_t * volatile last_event; 184 }; 185 186 /* 187 * Lock the debugger object. 188 */ 189 #define lock_debugger(dbg) jit_monitor_lock(&((dbg)->run_lock)) 190 191 /* 192 * Unlock the debugger object. 193 */ 194 #define unlock_debugger(dbg) jit_monitor_unlock(&((dbg)->run_lock)) 195 196 /* 197 * Suspend the current thread until it is marked as running again. 198 * It is assumed that the debugger's monitor lock has been acquired. 199 */ 200 static void suspend_thread(jit_debugger_t dbg, jit_debugger_thread_t thread) 201 { 202 while(thread->run_type == JIT_RUN_TYPE_STOPPED) 203 { 204 jit_monitor_wait(&(dbg->run_lock), -1); 205 } 206 } 207 208 /* 209 * Wake all threads that are waiting on the debugger's monitor. 210 */ 211 #define wakeup_all(dbg) jit_monitor_signal_all(&((dbg)->run_lock)) 212 213 /* 214 * Get the information block for the current thread. 215 */ 216 static jit_debugger_thread_t get_current_thread(jit_debugger_t dbg) 217 { 218 /* TODO */ 219 return 0; 220 } 221 222 /* 223 * Get the information block for a specific thread. 224 */ 225 static jit_debugger_thread_t get_specific_thread 226 (jit_debugger_t dbg, jit_debugger_thread_id_t thread) 227 { 228 /* TODO */ 229 return 0; 230 } 231 232 /* 233 * Allocate space for a new event on the event queue. 234 */ 235 #define alloc_event() \ 236 ((jit_debugger_event_t *)jit_cnew(jit_debugger_linked_event_t)) 237 238 /* 239 * Add an event that was previously allocated with "alloc_event" 240 * to a debugger's event queue. 241 */ 242 static void add_event(jit_debugger_t dbg, jit_debugger_event_t *_event) 243 { 244 jit_debugger_linked_event_t *event = (jit_debugger_linked_event_t *)_event; 245 event->next = 0; 246 jit_monitor_lock(&(dbg->queue_lock)); 247 if(dbg->last_event) 248 { 249 dbg->last_event->next = event; 250 } 251 else 252 { 253 dbg->events = event; 254 } 255 dbg->last_event = event; 256 jit_monitor_signal(&(dbg->queue_lock)); 257 jit_monitor_unlock(&(dbg->queue_lock)); 258 } 259 260 /*@ 261 * @deftypefun int jit_debugging_possible (void) 262 * Determine if debugging is possible. i.e. that threading is available 263 * and compatible with the debugger's requirements. 264 * @end deftypefun 265 @*/ 266 int jit_debugging_possible(void) 267 { 268 return JIT_THREADS_SUPPORTED; 269 } 270 271 /*@ 272 * @deftypefun jit_debugger_t jit_debugger_create (jit_context_t @var{context}) 273 * Create a new debugger instance and attach it to a JIT @var{context}. 274 * If the context already has a debugger associated with it, then this 275 * function will return the previous debugger. 276 * @end deftypefun 277 @*/ 278 jit_debugger_t jit_debugger_create(jit_context_t context) 279 { 280 jit_debugger_t dbg; 281 if(context) 282 { 283 if(context->debugger) 284 { 285 return context->debugger; 286 } 287 dbg = jit_cnew(struct jit_debugger); 288 if(!dbg) 289 { 290 return 0; 291 } 292 dbg->context = context; 293 context->debugger = dbg; 294 jit_monitor_create(&(dbg->queue_lock)); 295 jit_monitor_create(&(dbg->run_lock)); 296 return dbg; 297 } 298 else 299 { 300 return 0; 301 } 302 } 303 304 /*@ 305 * @deftypefun void jit_debugger_destroy (jit_debugger_t @var{dbg}) 306 * Destroy a debugger instance. 307 * @end deftypefun 308 @*/ 309 void jit_debugger_destroy(jit_debugger_t dbg) 310 { 311 /* TODO */ 312 } 313 314 /*@ 315 * @deftypefun jit_context_t jit_debugger_get_context (jit_debugger_t @var{dbg}) 316 * Get the JIT context that is associated with a debugger instance. 317 * @end deftypefun 318 @*/ 319 jit_context_t jit_debugger_get_context(jit_debugger_t dbg) 320 { 321 if(dbg) 322 { 323 return dbg->context; 324 } 325 else 326 { 327 return 0; 328 } 329 } 330 331 /*@ 332 * @deftypefun jit_debugger_t jit_debugger_from_context (jit_context_t @var{context}) 333 * Get the debugger that is currently associated with a JIT @var{context}, 334 * or NULL if there is no debugger associated with the context. 335 * @end deftypefun 336 @*/ 337 jit_debugger_t jit_debugger_from_context(jit_context_t context) 338 { 339 if(context) 340 { 341 return context->debugger; 342 } 343 else 344 { 345 return 0; 346 } 347 } 348 349 /*@ 350 * @deftypefun jit_debugger_thread_id_t jit_debugger_get_self (jit_debugger_t @var{dbg}) 351 * Get the thread identifier associated with the current thread. 352 * The return values are normally values like 1, 2, 3, etc, allowing 353 * the user interface to report messages like "thread 3 has stopped 354 * at a breakpoint". 355 * @end deftypefun 356 @*/ 357 jit_debugger_thread_id_t jit_debugger_get_self(jit_debugger_t dbg) 358 { 359 jit_thread_id_t id = jit_thread_self(); 360 jit_debugger_thread_id_t thread; 361 thread = jit_debugger_get_thread(dbg, &id); 362 jit_thread_release_self(id); 363 return thread; 364 } 365 366 /*@ 367 * @deftypefun jit_debugger_thread_id_t jit_debugger_get_thread (jit_debugger_t @var{dbg}, const void *@var{native_thread}) 368 * Get the thread identifier for a specific native thread. The 369 * @var{native_thread} pointer is assumed to point at a block 370 * of memory containing a native thread handle. This would be a 371 * @code{pthread_t} on Pthreads platforms or a @code{HANDLE} 372 * on Win32 platforms. If the native thread has not been seen 373 * previously, then a new thread identifier is allocated. 374 * @end deftypefun 375 @*/ 376 jit_debugger_thread_id_t jit_debugger_get_thread 377 (jit_debugger_t dbg, const void *native_thread) 378 { 379 /* TODO */ 380 return 0; 381 } 382 383 /*@ 384 * @deftypefun int jit_debugger_get_native_thread (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}, void *@var{native_thread}) 385 * Get the native thread handle associated with a debugger thread identifier. 386 * Returns non-zero if OK, or zero if the debugger thread identifier is not 387 * yet associated with a native thread handle. 388 * @end deftypefun 389 @*/ 390 int jit_debugger_get_native_thread 391 (jit_debugger_t dbg, jit_debugger_thread_id_t thread, 392 void *native_thread) 393 { 394 jit_debugger_thread_t th; 395 lock_debugger(dbg); 396 th = get_specific_thread(dbg, thread); 397 if(th) 398 { 399 jit_memcpy(native_thread, &(th->native_id), sizeof(th->native_id)); 400 unlock_debugger(dbg); 401 return 1; 402 } 403 else 404 { 405 unlock_debugger(dbg); 406 return 0; 407 } 408 } 409 410 /*@ 411 * @deftypefun void jit_debugger_set_breakable (jit_debugger_t @var{dbg}, const void *@var{native_thread}, int @var{flag}) 412 * Set a flag that indicates if a native thread can stop at breakpoints. 413 * If set to 1 (the default), breakpoints will be active on the thread. 414 * If set to 0, breakpoints will be ignored on the thread. Typically 415 * this is used to mark threads associated with the debugger's user 416 * interface, or the virtual machine's finalization thread, so that they 417 * aren't accidentally suspended by the debugger (which might cause a 418 * deadlock). 419 * @end deftypefun 420 @*/ 421 void jit_debugger_set_breakable 422 (jit_debugger_t dbg, const void *native_thread, int flag) 423 { 424 jit_debugger_thread_t th; 425 jit_debugger_thread_id_t id; 426 id = jit_debugger_get_thread(dbg, native_thread); 427 lock_debugger(dbg); 428 th = get_specific_thread(dbg, id); 429 if(th) 430 { 431 th->breakable = flag; 432 } 433 unlock_debugger(dbg); 434 } 435 436 /*@ 437 * @deftypefun void jit_debugger_attach_self (jit_debugger_t @var{dbg}, int @var{stop_immediately}) 438 * Attach the current thread to a debugger. If @var{stop_immediately} 439 * is non-zero, then the current thread immediately suspends, waiting for 440 * the user to start it with @code{jit_debugger_run}. This function is 441 * typically called in a thread's startup code just before any "real work" 442 * is performed. 443 * @end deftypefun 444 @*/ 445 void jit_debugger_attach_self(jit_debugger_t dbg, int stop_immediately) 446 { 447 jit_debugger_event_t *event; 448 jit_debugger_thread_t th; 449 lock_debugger(dbg); 450 th = get_current_thread(dbg); 451 if(th) 452 { 453 event = alloc_event(); 454 if(event) 455 { 456 event->type = JIT_DEBUGGER_TYPE_ATTACH_THREAD; 457 event->thread = th->id; 458 event->data1 = (jit_nint)stop_immediately; 459 add_event(dbg, event); 460 th->find_func = 0; 461 th->last_data1 = 0; 462 th->last_func_data1 = 0; 463 if(stop_immediately) 464 { 465 th->run_type = JIT_RUN_TYPE_STOPPED; 466 suspend_thread(dbg, th); 467 } 468 else 469 { 470 th->run_type = JIT_RUN_TYPE_CONTINUE; 471 } 472 } 473 } 474 unlock_debugger(dbg); 475 } 476 477 /*@ 478 * @deftypefun void jit_debugger_detach_self (jit_debugger_t @var{dbg}) 479 * Detach the current thread from the debugger. This is typically 480 * called just before the thread exits. 481 * @end deftypefun 482 @*/ 483 void jit_debugger_detach_self(jit_debugger_t dbg) 484 { 485 jit_debugger_event_t *event; 486 jit_debugger_thread_t th; 487 lock_debugger(dbg); 488 th = get_current_thread(dbg); 489 if(th) 490 { 491 event = alloc_event(); 492 if(event) 493 { 494 event->type = JIT_DEBUGGER_TYPE_DETACH_THREAD; 495 event->thread = th->id; 496 add_event(dbg, event); 497 th->run_type = JIT_RUN_TYPE_DETACHED; 498 } 499 } 500 unlock_debugger(dbg); 501 } 502 503 /*@ 504 * @deftypefun int jit_debugger_wait_event (jit_debugger_t @var{dbg}, jit_debugger_event_t *@var{event}, jit_nint @var{timeout}) 505 * Wait for the next debugger event to arrive. Debugger events typically 506 * indicate breakpoints that have occurred. The @var{timeout} is in 507 * milliseconds, or -1 for an infinite timeout period. Returns non-zero 508 * if an event has arrived, or zero on timeout. 509 * @end deftypefun 510 @*/ 511 int jit_debugger_wait_event 512 (jit_debugger_t dbg, jit_debugger_event_t *event, jit_int timeout) 513 { 514 jit_debugger_linked_event_t *levent; 515 jit_monitor_lock(&(dbg->queue_lock)); 516 if((levent = dbg->events) == 0) 517 { 518 if(!jit_monitor_wait(&(dbg->queue_lock), timeout)) 519 { 520 jit_monitor_unlock(&(dbg->queue_lock)); 521 return 0; 522 } 523 levent = dbg->events; 524 } 525 *event = levent->event; 526 dbg->events = levent->next; 527 if(!(levent->next)) 528 { 529 dbg->last_event = 0; 530 } 531 jit_free(levent); 532 jit_monitor_unlock(&(dbg->queue_lock)); 533 return 1; 534 } 535 536 /*@ 537 * @deftypefun jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint (jit_debugger_t @var{dbg}, jit_debugger_breakpoint_info_t @var{info}) 538 * Add a hard breakpoint to a debugger instance. The @var{info} structure 539 * defines the conditions under which the breakpoint should fire. 540 * The fields of @var{info} are as follows: 541 * 542 * @table @code 543 * @item flags 544 * Flags that indicate which of the following fields should be matched. 545 * If a flag is not present, then all possible values of the field will match. 546 * Valid flags are @code{JIT_DEBUGGER_FLAG_THREAD}, 547 * @code{JIT_DEBUGGER_FLAG_FUNCTION}, @code{JIT_DEBUGGER_FLAG_DATA1}, 548 * and @code{JIT_DEBUGGER_FLAG_DATA2}. 549 * 550 * @item thread 551 * The thread to match against, if @code{JIT_DEBUGGER_FLAG_THREAD} is set. 552 * 553 * @item function 554 * The function to match against, if @code{JIT_DEBUGGER_FLAG_FUNCTION} is set. 555 * 556 * @item data1 557 * The @code{data1} value to match against, if @code{JIT_DEBUGGER_FLAG_DATA1} 558 * is set. 559 * 560 * @item data2 561 * The @code{data2} value to match against, if @code{JIT_DEBUGGER_FLAG_DATA2} 562 * is set. 563 * @end table 564 * 565 * The following special values for @code{data1} are recommended for marking 566 * breakpoint locations with @code{jit_insn_mark_breakpoint}: 567 * 568 * @table @code 569 * @item JIT_DEBUGGER_DATA1_LINE 570 * Breakpoint location that corresponds to a source line. This is used 571 * to determine where to continue to upon a "step". 572 * 573 * @item JIT_DEBUGGER_DATA1_ENTER 574 * Breakpoint location that corresponds to the start of a function. 575 * 576 * @item JIT_DEBUGGER_DATA1_LEAVE 577 * Breakpoint location that corresponds to the end of a function, just 578 * prior to a @code{return} statement. This is used to determine where 579 * to continue to upon a "finish". 580 * 581 * @item JIT_DEBUGGER_DATA1_THROW 582 * Breakpoint location that corresponds to an exception throw. 583 * @end table 584 * @end deftypefun 585 @*/ 586 jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint 587 (jit_debugger_t dbg, jit_debugger_breakpoint_info_t info) 588 { 589 /* TODO */ 590 return 0; 591 } 592 593 /*@ 594 * @deftypefun void jit_debugger_remove_breakpoint (jit_debugger_t @var{dbg}, jit_debugger_breakpoint_id_t @var{id}) 595 * Remove a previously defined breakpoint from a debugger instance. 596 * @end deftypefun 597 @*/ 598 void jit_debugger_remove_breakpoint 599 (jit_debugger_t dbg, jit_debugger_breakpoint_id_t id) 600 { 601 /* TODO */ 602 } 603 604 /*@ 605 * @deftypefun void jit_debugger_remove_all_breakpoints (jit_debugger_t @var{dbg}) 606 * Remove all breakpoints from a debugger instance. 607 * @end deftypefun 608 @*/ 609 void jit_debugger_remove_all_breakpoints(jit_debugger_t dbg) 610 { 611 /* TODO */ 612 } 613 614 /*@ 615 * @deftypefun int jit_debugger_is_alive (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}) 616 * Determine if a particular thread is still alive. 617 * @end deftypefun 618 @*/ 619 int jit_debugger_is_alive(jit_debugger_t dbg, jit_debugger_thread_id_t thread) 620 { 621 /* TODO */ 622 return 1; 623 } 624 625 /*@ 626 * @deftypefun int jit_debugger_is_running (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}) 627 * Determine if a particular thread is currently running (non-zero) or 628 * stopped (zero). 629 * @end deftypefun 630 @*/ 631 int jit_debugger_is_running(jit_debugger_t dbg, jit_debugger_thread_id_t thread) 632 { 633 jit_debugger_thread_t th; 634 int flag = 0; 635 lock_debugger(dbg); 636 th = get_specific_thread(dbg, thread); 637 if(th) 638 { 639 flag = (th->run_type != JIT_RUN_TYPE_STOPPED); 640 } 641 unlock_debugger(dbg); 642 return flag; 643 } 644 645 /*@ 646 * @deftypefun void jit_debugger_run (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}) 647 * Start the specified thread running, or continue from the last breakpoint. 648 * 649 * This function, and the others that follow, sends a request to the specified 650 * thread and then returns to the caller immediately. 651 * @end deftypefun 652 @*/ 653 void jit_debugger_run(jit_debugger_t dbg, jit_debugger_thread_id_t thread) 654 { 655 jit_debugger_thread_t th; 656 lock_debugger(dbg); 657 th = get_specific_thread(dbg, thread); 658 if(th && th->run_type == JIT_RUN_TYPE_STOPPED) 659 { 660 th->run_type = JIT_RUN_TYPE_CONTINUE; 661 wakeup_all(dbg); 662 } 663 unlock_debugger(dbg); 664 } 665 666 /*@ 667 * @deftypefun void jit_debugger_step (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}) 668 * Step over a single line of code. If the line performs a method call, 669 * then this will step into the call. The request will be ignored if 670 * the thread is currently running. 671 * @end deftypefun 672 @*/ 673 void jit_debugger_step(jit_debugger_t dbg, jit_debugger_thread_id_t thread) 674 { 675 jit_debugger_thread_t th; 676 lock_debugger(dbg); 677 th = get_specific_thread(dbg, thread); 678 if(th && th->run_type == JIT_RUN_TYPE_STOPPED) 679 { 680 th->run_type = JIT_RUN_TYPE_STEP; 681 wakeup_all(dbg); 682 } 683 unlock_debugger(dbg); 684 } 685 686 /*@ 687 * @deftypefun void jit_debugger_next (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}) 688 * Step over a single line of code but do not step into method calls. 689 * The request will be ignored if the thread is currently running. 690 * @end deftypefun 691 @*/ 692 void jit_debugger_next(jit_debugger_t dbg, jit_debugger_thread_id_t thread) 693 { 694 jit_debugger_thread_t th; 695 lock_debugger(dbg); 696 th = get_specific_thread(dbg, thread); 697 if(th && th->run_type == JIT_RUN_TYPE_STOPPED) 698 { 699 th->run_type = JIT_RUN_TYPE_NEXT; 700 wakeup_all(dbg); 701 } 702 unlock_debugger(dbg); 703 } 704 705 /*@ 706 * @deftypefun void jit_debugger_finish (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}) 707 * Keep running until the end of the current function. The request will 708 * be ignored if the thread is currently running. 709 * @end deftypefun 710 @*/ 711 void jit_debugger_finish(jit_debugger_t dbg, jit_debugger_thread_id_t thread) 712 { 713 jit_debugger_thread_t th; 714 lock_debugger(dbg); 715 th = get_specific_thread(dbg, thread); 716 if(th && th->run_type == JIT_RUN_TYPE_STOPPED) 717 { 718 th->run_type = JIT_RUN_TYPE_FINISH; 719 wakeup_all(dbg); 720 } 721 unlock_debugger(dbg); 722 } 723 724 /*@ 725 * @deftypefun void jit_debugger_break (jit_debugger_t @var{dbg}) 726 * Force an explicit user breakpoint at the current location within the 727 * current thread. Control returns to the caller when the debugger 728 * calls one of the above "run" or "step" functions in another thread. 729 * @end deftypefun 730 @*/ 731 void jit_debugger_break(jit_debugger_t dbg) 732 { 733 jit_debugger_event_t *event; 734 jit_debugger_thread_t th; 735 lock_debugger(dbg); 736 th = get_current_thread(dbg); 737 if(th && th->breakable) 738 { 739 event = alloc_event(); 740 if(event) 741 { 742 th->run_type = JIT_RUN_TYPE_STOPPED; 743 th->find_func = 0; 744 th->last_data1 = 0; 745 th->last_func_data1 = 0; 746 event->type = JIT_DEBUGGER_TYPE_USER_BREAKPOINT; 747 event->thread = th->id; 748 event->trace = jit_exception_get_stack_trace(); 749 add_event(dbg, event); 750 suspend_thread(dbg, th); 751 } 752 } 753 unlock_debugger(dbg); 754 } 755 756 /*@ 757 * @deftypefun void jit_debugger_quit (jit_debugger_t @var{dbg}) 758 * Sends a request to the thread that called @code{jit_debugger_wait_event} 759 * indicating that the debugger should quit. 760 * @end deftypefun 761 @*/ 762 void jit_debugger_quit(jit_debugger_t dbg) 763 { 764 jit_debugger_event_t *event; 765 lock_debugger(dbg); 766 event = alloc_event(); 767 if(event) 768 { 769 event->type = JIT_DEBUGGER_TYPE_QUIT; 770 add_event(dbg, event); 771 } 772 unlock_debugger(dbg); 773 } 774 775 /*@ 776 * @deftypefun jit_debugger_hook_func jit_debugger_set_hook (jit_context_t @var{context}, jit_debugger_hook_func @var{hook}) 777 * Set a debugger hook on a JIT context. Returns the previous hook. 778 * 779 * Debug hooks are a very low-level breakpoint mechanism. Upon reaching each 780 * breakpoint in a function, a user-supplied hook function is called. 781 * It is up to the hook function to decide whether to stop execution 782 * or to ignore the breakpoint. The hook function has the following 783 * prototype: 784 * 785 * @example 786 * void hook(jit_function_t func, jit_nint data1, jit_nint data2); 787 * @end example 788 * 789 * The @code{func} argument indicates the function that the breakpoint 790 * occurred within. The @code{data1} and @code{data2} arguments are 791 * those supplied to @code{jit_insn_mark_breakpoint}. The debugger can use 792 * these values to indicate information about the breakpoint's type 793 * and location. 794 * 795 * Hook functions can be used for other purposes besides breakpoint 796 * debugging. For example, a program could be instrumented with hooks 797 * that tally up the number of times that each function is called, 798 * or which profile the amount of time spent in each function. 799 * 800 * By convention, @code{data1} values less than 10000 are intended for 801 * use by user-defined hook functions. Values of 10000 and greater are 802 * reserved for the full-blown debugger system described earlier. 803 * @end deftypefun 804 @*/ 805 jit_debugger_hook_func jit_debugger_set_hook 806 (jit_context_t context, jit_debugger_hook_func hook) 807 { 808 jit_debugger_hook_func prev; 809 if(context) 810 { 811 prev = context->debug_hook; 812 context->debug_hook = hook; 813 return prev; 814 } 815 else 816 { 817 return 0; 818 } 819 } 820 821 void _jit_debugger_hook(jit_function_t func, jit_nint data1, jit_nint data2) 822 { 823 jit_context_t context; 824 jit_debugger_t dbg; 825 jit_debugger_thread_t th; 826 jit_debugger_event_t *event; 827 int stop; 828 829 /* Find the context and look for a user-supplied debug hook */ 830 context = func->context; 831 if(context->debug_hook) 832 { 833 (*(context->debug_hook))(func, data1, data2); 834 } 835 836 /* Ignore breakpoints with data1 values less than 10000. These are 837 presumed to be handled by a user-supplied debug hook instead */ 838 if(data1 < JIT_DEBUGGER_DATA1_FIRST) 839 { 840 return; 841 } 842 843 /* Determine if there is a debugger attached to the context */ 844 dbg = context->debugger; 845 if(!dbg) 846 { 847 return; 848 } 849 850 /* Lock down the debugger while we do this */ 851 lock_debugger(dbg); 852 853 /* Get the current thread's information block */ 854 th = get_current_thread(dbg); 855 if(!th || !(th->breakable)) 856 { 857 unlock_debugger(dbg); 858 return; 859 } 860 861 /* Determine if there is a hard breakpoint at this location */ 862 /* TODO */ 863 864 /* Determine if we are looking for a soft breakpoint */ 865 stop = 0; 866 switch(th->run_type) 867 { 868 case JIT_RUN_TYPE_STEP: 869 { 870 /* Stop at all breakpoints */ 871 stop = 1; 872 } 873 break; 874 875 case JIT_RUN_TYPE_NEXT: 876 { 877 /* Stop only if we are in the same function as the last stopping 878 point, or if we might have already left the function */ 879 if(func == th->find_func || th->find_func == 0 || 880 th->last_func_data1 == JIT_DEBUGGER_DATA1_LEAVE || 881 th->last_data1 == JIT_DEBUGGER_DATA1_THROW) 882 { 883 stop = 1; 884 } 885 if(func == th->find_func) 886 { 887 th->last_func_data1 = data1; 888 } 889 } 890 break; 891 892 case JIT_RUN_TYPE_FINISH: 893 { 894 /* Stop if we are at a leave point, or we saw an exception */ 895 if((func == th->find_func && data1 == JIT_DEBUGGER_DATA1_LEAVE) || 896 th->last_data1 == JIT_DEBUGGER_DATA1_THROW || 897 th->find_func == 0) 898 { 899 stop = 1; 900 } 901 } 902 break; 903 } 904 th->last_data1 = data1; 905 906 /* Do we need to stop the thread at this breakpoint? */ 907 if(stop) 908 { 909 event = alloc_event(); 910 if(event) 911 { 912 th->run_type = JIT_RUN_TYPE_STOPPED; 913 th->find_func = func; 914 th->last_func_data1 = data1; 915 event->type = JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT; 916 event->thread = th->id; 917 event->function = func; 918 event->data1 = data1; 919 event->data2 = data2; 920 event->trace = jit_exception_get_stack_trace(); 921 add_event(dbg, event); 922 suspend_thread(dbg, th); 923 } 924 } 925 926 /* Unlock and exit */ 927 unlock_debugger(dbg); 928 }