1 /* $Header$ */ 2 3 /* 4 * Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved. 5 * 6 * Please see the accompanying license file, LICENSE.TXT, for information 7 * on using and copying this software. 8 */ 9 /* 10 Name 11 vmdbg.h - T3 VM debugging API 12 Function 13 Provides an interface to debugging operations in the VM 14 Notes 15 16 Modified 17 11/23/99 MJRoberts - Creation 18 */ 19 20 #ifndef VMDBG_H 21 #define VMDBG_H 22 23 #include "vmglob.h" 24 #include "vmfunc.h" 25 #include "vmhash.h" 26 #include "vmobj.h" 27 #include "tcprstyp.h" 28 29 30 /* ------------------------------------------------------------------------ */ 31 /* 32 * Internal breakpoint tracking record 33 */ 34 struct CVmDebugBp 35 { 36 /* create */ 37 CVmDebugBp(); 38 39 /* delete */ 40 ~CVmDebugBp(); 41 42 /* notify of VM termination */ 43 void do_terminate(VMG0_); 44 45 /* get/set the in-use flag */ is_in_useCVmDebugBp46 int is_in_use() const { return in_use_; } set_in_useCVmDebugBp47 void set_in_use(int f) { in_use_ = f; } 48 49 /* get/set the disabled flag */ is_disabledCVmDebugBp50 int is_disabled() const { return disabled_; } set_disabledCVmDebugBp51 void set_disabled(int f) { disabled_ = f; } 52 53 /* 54 * set the breakpoint's information - returns zero on success, 55 * non-zero if an error occurs (such as compiling the condition 56 * expression) 57 */ 58 int set_info(VMG_ ulong code_addr, const char *cond, int change, 59 int disabled, char *errbuf, size_t errbuflen); 60 61 /* get my code address */ get_code_addrCVmDebugBp62 ulong get_code_addr() const { return code_addr_; } 63 64 /* 65 * Set the condition text - returns zero on success, non-zero if an 66 * error occurs compiling the expression. If 'change' is true, then we 67 * break when the condition changes; otherwise, we break when the 68 * condition becomes true. 69 */ 70 int set_condition(VMG_ const char *cond, int change, 71 char *errbuf, size_t errbuflen); 72 73 /* 74 * delete the breakpoint - remove the breakpoint from the code and 75 * mark it as unused 76 */ 77 void do_delete(VMG0_); 78 79 /* 80 * Set or remove the BP instruction at my code address. If 'always' 81 * is set, we'll update the instruction regardless of whether the 82 * debugger has control or not; normally, we'll only update the 83 * instruction when the debugger doesn't have control, since we 84 * don't leave breakpoint instructions in the code at other times. 85 */ 86 void set_bp_instr(VMG_ int set, int always); 87 88 /* check to see if I have a condition */ has_conditionCVmDebugBp89 int has_condition() const { return has_cond_ && compiled_cond_ != 0; } 90 91 /* 92 * Is our condition a stop-on-change condition? This returns true if 93 * so, false if this we instead have a stop-when-true condition. Note 94 * that this information is not meaningful unless has_condition() 95 * returns true. 96 */ stop_on_changeCVmDebugBp97 int stop_on_change() const { return stop_on_change_; } 98 99 /* 100 * evaluate the condition - return true if the condition evaluates 101 * to true (non-zero integer, true, or any object, string, or list 102 * value), false if not 103 */ 104 int eval_cond(VMG0_); 105 106 /* 107 * determine if this is a global breakpoint - a global breakpoint is 108 * one that is not associated with a code location (indicated by a 109 * code address of zero) 110 */ is_globalCVmDebugBp111 int is_global() const { return code_addr_ == 0; } 112 113 private: 114 /* code address of breakpoint */ 115 ulong code_addr_; 116 117 /* condition expression */ 118 char *cond_; 119 120 /* length of buffer allocated for cond, if any */ 121 size_t cond_buf_len_; 122 123 /* code object with compiled expression */ 124 class CVmPoolDynObj *compiled_cond_; 125 126 /* 127 * The previous value of the condition. If this is a stop-on-change 128 * condition, we'll stop as soon as the current value of the expression 129 * differs from this saved value. If we have a condition, but we 130 * haven't yet computed the "old" value, this will have the 'empty' 131 * type. 132 */ 133 vm_globalvar_t *prv_val; 134 135 /* 136 * original instruction byte at this breakpoint (we replace the 137 * instruction byte with the BP instruction, but we must remember 138 * the original for when we clear or disable the breakpoint) 139 */ 140 char orig_instr_; 141 142 /* flag: breakpoint is in use */ 143 uint in_use_ : 1; 144 145 /* flag: breakpoint has a conditional expression */ 146 uint has_cond_ : 1; 147 148 /* flag: our condition is stop-on-change, not stop-when-true */ 149 uint stop_on_change_ : 1; 150 151 /* flag: breakpoint is disabled */ 152 uint disabled_ : 1; 153 154 }; 155 156 /* maximum number of breakpoints */ 157 const size_t VMDBG_BP_MAX = 100; 158 159 /* ------------------------------------------------------------------------ */ 160 /* 161 * Structure for saving debugger step modes. This is used to save and 162 * restore the step modes before doing a recursive evaluation. 163 */ 164 struct vmdbg_step_save_t 165 { 166 int old_step; 167 int old_step_in; 168 int old_step_out; 169 }; 170 171 172 /* ------------------------------------------------------------------------ */ 173 /* 174 * Debugger API object 175 */ 176 class CVmDebug 177 { 178 friend class CVmRun; 179 friend struct CVmDebugBp; 180 181 public: 182 CVmDebug(VMG0_); 183 ~CVmDebug(); 184 185 /* 186 * Initialize. The VM will call this after setting up all of the VM 187 * globals, but before loading the image file. 188 */ 189 void init(VMG_ const char *image_filename); 190 191 /* 192 * Initialization phase 2 - this is called just after we finish 193 * loading the image file. The debugger can perform any final 194 * set-up that can't be handled until after the image is loaded. 195 */ 196 void init_after_load(VMG0_); 197 198 /* 199 * Terminate. The VM will call this when shutting down, before 200 * deleting any of the globals. 201 */ 202 void terminate(VMG0_); 203 204 /* 205 * Determine if the loaded program was compiled for debugging. 206 * We'll check to see if the image loader found a GSYM (global 207 * symbol table) block in the file. 208 */ 209 int image_has_debug_info(VMG0_) const; 210 211 /* determine if the debugger has control */ is_in_debugger()212 int is_in_debugger() const { return in_debugger_ != 0; } 213 214 215 /* -------------------------------------------------------------------- */ 216 /* 217 * Add an entry to a reverse-lookup hash table. The image file 218 * loader must call this function for each object, function, and 219 * property symbol it loads from the debug records in an image file. 220 */ 221 void add_rev_sym(const char *sym, size_t sym_len, 222 tc_symtype_t sym_type, ulong sym_val); 223 224 /* 225 * Look up a symbol given the type and identifier. Returns a 226 * pointer to a null-terminated string giving the name of the 227 * symbol, or null if the given identifier doesn't have an 228 * associated symbol. 229 */ objid_to_sym(vm_obj_id_t objid)230 const char *objid_to_sym(vm_obj_id_t objid) const 231 { return find_rev_sym(obj_rev_table_, (ulong)objid); } 232 propid_to_sym(vm_prop_id_t propid)233 const char *propid_to_sym(vm_prop_id_t propid) const 234 { return find_rev_sym(prop_rev_table_, (ulong)propid); } 235 funcaddr_to_sym(pool_ofs_t func_addr)236 const char *funcaddr_to_sym(pool_ofs_t func_addr) const 237 { return find_rev_sym(func_rev_table_, (ulong)func_addr); } 238 enum_to_sym(ulong enum_id)239 const char *enum_to_sym(ulong enum_id) const 240 { return find_rev_sym(enum_rev_table_, enum_id); } 241 242 /* 243 * Given a symbol name, get the final modifying object. If the symbol 244 * is a synthesized modified base object, we'll find the actual symbol 245 * that was used in the source code with 'modify.' 246 */ 247 const char *get_modifying_sym(const char *base_sym) const; 248 249 250 /* -------------------------------------------------------------------- */ 251 /* 252 * Method header list 253 */ 254 255 /* allocate the method header list */ 256 void alloc_method_header_list(ulong cnt); 257 258 /* 259 * Given a code pool address, find the method header containing the 260 * address. This searches the method header list for the nearest 261 * method header whose address is less than the given address. 262 */ 263 pool_ofs_t find_method_header(pool_ofs_t ofs); 264 265 /* get the number of method headers */ get_method_header_cnt()266 ulong get_method_header_cnt() const { return method_hdr_cnt_; } 267 268 /* set the given method header list entry */ set_method_header(ulong idx,ulong addr)269 void set_method_header(ulong idx, ulong addr) 270 { 271 /* store the given entry */ 272 method_hdr_[idx] = addr; 273 } 274 275 /* get the given method header entry */ get_method_header(ulong idx)276 ulong get_method_header(ulong idx) const { return method_hdr_[idx]; } 277 278 279 /* -------------------------------------------------------------------- */ 280 /* 281 * Get information on the source location at a given stack level. 282 * If successful, fills in the filename pointer and line number and 283 * returns zero. If no source information is available at the stack 284 * level, returns non-zero to indicate failure. 285 * 286 * Level 0 is the current stack level, 1 is the enclosing frame, and 287 * so on. 288 */ 289 int get_source_info(VMG_ const char **fname, unsigned long *linenum, 290 int level) const; 291 292 293 /* 294 * Enumerate local variables at the given stack level - 0 is the 295 * current stack level, 1 is the enclosing frame, and so on. 296 */ 297 void enum_locals(VMG_ void (*cbfunc)(void *, const char *, size_t), 298 void *cbctx, int level); 299 300 /* 301 * Build a stack trace listing, invoking the callback for each level 302 * of the stack trace. If 'source_info' is true, we'll include the 303 * source file name and line number for each point in the trace. 304 */ 305 void build_stack_listing(VMG_ 306 void (*cbfunc)(void *ctx, 307 const char *str, int strl), 308 void *cbctx, int source_info); 309 310 311 /* -------------------------------------------------------------------- */ 312 /* 313 * Breakpoints 314 */ 315 316 /* 317 * Toggle a breakpoint at the given code location. Returns zero on 318 * success, non-zero on failure. If successful, fills in *bpnum 319 * with the breakpoint ID, and fills in *did_set with true if we set 320 * a breakpoint, false if we deleted an existing breakpoint at the 321 * location. cond is null if the breakpoint is unconditional, or a 322 * pointer to a character string giving the source code for an 323 * expression that must evaluate to true when the breakpoint is 324 * encountered for the breakpoint to suspend execution. 325 */ 326 int toggle_breakpoint(VMG_ ulong code_addr, 327 const char *cond, int change, 328 int *bpnum, int *did_set, 329 char *errbuf, size_t errbuflen); 330 331 /* toggle the disabled status of a breakpoint */ 332 void toggle_breakpoint_disable(VMG_ int bpnum); 333 334 /* set a breakpoint's disabled status */ 335 void set_breakpoint_disable(VMG_ int bpnum, int disable); 336 337 /* determine if a breakpoint is disabled - returns true if so */ 338 int is_breakpoint_disabled(VMG_ int bpnum); 339 340 /* set a breakpoint's condition expression - returns 0 on success */ 341 int set_breakpoint_condition(VMG_ int bpnum, const char *cond, int change, 342 char *errbuf, size_t errbuflen); 343 344 /* delete a breakpoint given the breakpoint ID */ 345 void delete_breakpoint(VMG_ int bpnum); 346 347 /* -------------------------------------------------------------------- */ 348 /* 349 * Set execution mode. These calls do not immediately resume 350 * execution, but merely set the mode that will be in effect when 351 * execution resumes. These calls can only be made while the 352 * program is stopped. 353 */ 354 355 /* 356 * Set single-step mode to STEP IN. In this mode, we will stop as 357 * soon as we reach a new statement. 358 */ set_step_in()359 void set_step_in() 360 { 361 /* set single-step and step-in modes */ 362 single_step_ = TRUE; 363 step_in_ = TRUE; 364 step_out_ = FALSE; 365 } 366 367 /* 368 * Set single-step mode for a 'break' key (Ctrl-C, Ctrl+Break, etc., 369 * according to local conventions). This asynchronously interrupts the 370 * interpreter and breaks into the debugger while the program is 371 * running, which is useful to break out of infinite loops or very 372 * lengthy processing. 373 */ set_break_stop()374 void set_break_stop() 375 { 376 /* set single-step-in mode */ 377 set_step_in(); 378 379 /* 380 * Forget our last execution location, so that we'll stop again 381 * even if we haven't moved from our last break location. Since 382 * we're explicitly breaking execution, we want to stop whether 383 * we've gone anywhere or not. 384 */ 385 cur_stm_start_ = cur_stm_end_ = 0; 386 } 387 388 /* 389 * Set single-step mode to STEP OVER. In this mode, we will stop as 390 * soon as we reach a new statement at the same stack level as the 391 * current statement or at an enclosing stack level. 392 */ 393 void set_step_over(VMG0_); 394 395 /* 396 * Set single-step mode to STEP OUT. In this mode, we will stop as 397 * soon as we reach a new statement at a stack level enclosing the 398 * current statement's stack level. 399 */ 400 void set_step_out(VMG0_); 401 402 /* 403 * Set single-step mode to GO. In this mode, we won't stop until we 404 * reach a breakpoint. 405 */ set_go()406 void set_go() 407 { 408 /* clear single-step mode */ 409 single_step_ = FALSE; 410 step_in_ = FALSE; 411 step_out_ = FALSE; 412 } 413 414 /* 415 * Save the step mode in preparation for a recursive execution (of a 416 * debugger expression), and set the mode for the recursive 417 * execution. Turns off stepping modes. 418 */ prepare_for_eval(vmdbg_step_save_t * info)419 void prepare_for_eval(vmdbg_step_save_t *info) 420 { 421 /* save the original execution mode */ 422 info->old_step = single_step_; 423 info->old_step_in = step_in_; 424 info->old_step_out = step_out_; 425 426 /* set execution mode to RUN */ 427 single_step_ = FALSE; 428 step_in_ = FALSE; 429 step_out_ = FALSE; 430 } 431 432 /* restore original execution modes after recursive execution */ restore_from_eval(vmdbg_step_save_t * info)433 void restore_from_eval(vmdbg_step_save_t *info) 434 { 435 single_step_ = info->old_step; 436 step_in_ = info->old_step_in; 437 step_out_ = info->old_step_out; 438 } 439 440 441 /* -------------------------------------------------------------------- */ 442 /* 443 * Set the execution pointer to a new location. The new code 444 * address is given as an absolute code pool address. The new 445 * location must be within the current method. Updates 446 * *exec_ofs_ptr with the method offset of the new location. 447 */ set_exec_ofs(unsigned int * exec_ofs_ptr,unsigned long code_addr)448 int set_exec_ofs(unsigned int *exec_ofs_ptr, unsigned long code_addr) 449 { 450 /* set the method offset pointer */ 451 *exec_ofs_ptr = (unsigned int)(code_addr - entry_ofs_); 452 453 /* success */ 454 return 0; 455 } 456 457 /* 458 * Determine if a code location is within the current active method. 459 * Returns true if so, false if not. 460 */ 461 int is_in_current_method(VMG_ unsigned long code_addr); 462 463 /* -------------------------------------------------------------------- */ 464 /* 465 * Evaluate an expression. Returns zero on success, non-zero on 466 * failure. 'level' is the stack level at which to evaluate the 467 * expression - 0 is the currently active method, 1 is its caller, 468 * and so on. 469 */ 470 int eval_expr(VMG_ char *buf, size_t buflen, const char *expr, 471 int level, int *is_lval, int *is_openable, 472 void (*aggcb)(void *, const char *, int, const char *), 473 void *aggctx, int speculative); 474 475 /* 476 * Compile an expression. Fills in *code_obj with a handle to the 477 * code pool object containing the compiled byte-code. If dst_buf 478 * is non-null, we will format a message describing any error that 479 * occurs into the buffer. 480 * 481 * We'll compile the expression using the given local symbol table 482 * and the given active stack level. Note that the local symbol 483 * table specified need not be the local symbol table for the given 484 * active stack level, since we're only compiling, not evaluating, 485 * the expression; for example, when compiling a condition 486 * expression for a breakpoint, we'll normally compile the 487 * expression in the context of the breakpoint's source location, 488 * which might not even be in the active stack when the condition is 489 * compiled. 490 */ 491 int compile_expr(VMG_ const char *expr, 492 int level, class CVmDbgSymtab *local_symtab, 493 int self_valid, int speculative, int *is_lval, 494 class CVmPoolDynObj **code_obj, 495 char *dst_buf, size_t dst_buf_len); 496 497 /* -------------------------------------------------------------------- */ 498 /* 499 * Get/set the UI context. This information is for use by the UI 500 * code. We don't use the UI context for anything; we just maintain 501 * it so that the UI can keep track of what's going on between 502 * calls. 503 */ get_ui_ctx()504 void *get_ui_ctx() const { return ui_ctx_; } set_ui_ctx(void * ctx)505 void set_ui_ctx(void *ctx) { ui_ctx_ = ctx; } 506 507 protected: 508 /* -------------------------------------------------------------------- */ 509 /* 510 * CVmRun API - the byte-code execution loop uses these routines 511 */ 512 513 /* 514 * Step into the debugger - the byte-code execution loop calls this 515 * just before executing each instruction when the interpreter is in 516 * single-step mode, or when a breakpoint is encountered. We'll 517 * activate the debugger user interface if necessary. This returns 518 * in order to resume execution. bp is true if we encountered a 519 * breakpoint, false if we're single-stepping. 520 */ 521 void step(VMG_ const uchar **pc_ptr, pool_ofs_t, int bp, 522 int error_code); 523 524 /* 525 * synchronize the internal execution point - acts like a step() 526 * without actually stopping 527 */ 528 void sync_exec_pos(VMG_ const uchar *pc_ptr, 529 pool_ofs_t method_start_ofs); 530 531 /* 532 * Get single-step mode - returns true if we're stopping at each 533 * instruction, false if we're running until we hit a breakpoint. 534 * The byte-code execution loop should call step() on each 535 * instruction if this returns true. 536 * 537 * We must also single-step through code if there are any active 538 * global breakpoints, even when the user is not interactively 539 * single-stepping. 540 */ is_single_step()541 int is_single_step() const 542 { return single_step_ || global_bp_cnt_ != 0; } 543 544 545 /* -------------------------------------------------------------------- */ 546 /* 547 * Internal operations 548 */ 549 550 /* 551 * Get information on the execution location at the given stack 552 * level 553 */ 554 int get_stack_level_info(VMG_ int level, class CVmFuncPtr *func_ptr, 555 class CVmDbgLinePtr *line_ptr, 556 ulong *stm_start, ulong *stm_end) const; 557 558 /* 559 * look up a symbol in one of our reverse mapping tables 560 */ 561 const char *find_rev_sym(const class CVmHashTable *hashtab, 562 ulong val) const; 563 564 /* 565 * Format a value into a buffer 566 */ 567 void format_val(VMG_ char *buf, size_t buflen, 568 const struct vm_val_t *val); 569 570 /* find a breakpoint given a code address */ 571 CVmDebugBp *find_bp(ulong code_addr); 572 573 /* allocate a new breakpoint record */ 574 CVmDebugBp *alloc_bp(); 575 576 /* 577 * suspend/resume breakpoints - this doesn't affect the permanent 578 * status of any breakpoint, but simply allows for removal of BP 579 * instructions from the code while the debugger has control 580 */ 581 void suspend_all_bps(VMG0_); 582 void restore_all_bps(VMG0_); 583 584 private: 585 /* flag: debugger has control */ 586 int in_debugger_ : 1; 587 588 /* 589 * single-step mode - if this is true, we're stepping through code; 590 * otherwise, we're running until we hit a breakpoint 591 */ 592 int single_step_ : 1; 593 594 /* 595 * step-in mode - if this is true, and single_step_ is true, we'll 596 * break as soon as we reach a new statement anywhere; otherwise, 597 * we'll stop only if we reach a new statement at the same stack 598 * level as the current statement (in other words, we're stepping 599 * over subroutine calls made by the current statement) 600 */ 601 int step_in_ : 1 ; 602 603 /* 604 * Step-out mode - if this is true, and single_step_ is true, we'll 605 * break as soon as we reach a new statement outside the current 606 * call level. (This mode flag is actually only important for 607 * native code interaction, because we actually know to stop on a 608 * step-out using step-over with an enclosing stack level.) 609 */ 610 int step_out_ : 1; 611 612 /* 613 * step-over-breakpoint mode - if this is true, we're stepping over 614 * a breakpoint 615 */ 616 int step_over_bp_ : 1; 617 618 /* 619 * Original step flags - these store the step flags that will be in 620 * effect after we finish a step_over_bp operation 621 */ 622 int orig_single_step_ : 1; 623 int orig_step_in_ : 1; 624 int orig_step_out_ : 1; 625 626 /* 627 * flag: we've been initialized during program load; when this flag is 628 * set, we'll have to make corresponding uninitializations when the 629 * program terminates 630 */ 631 int program_inited_ : 1; 632 633 /* breakpoint being stepped over */ 634 CVmDebugBp *step_over_bp_bp_; 635 636 /* 637 * Step-resume stack frame level. When step_in_ is false, we won't 638 * resume stepping code until the frame pointer is at this level or 639 * an enclosing level. 640 */ 641 size_t step_frame_depth_; 642 643 /* 644 * Method header for the current function. We set this each time we 645 * enter the debugger via step(). 646 */ 647 CVmFuncPtr func_ptr_; 648 649 /* 650 * Debug records pointer for the current function. We set this each 651 * time we enter the debugger via step(). Note that we must keep 652 * track of whether the debug pointer is valid, because some 653 * functions might not have debug tables at all. 654 */ 655 CVmDbgTablePtr dbg_ptr_; 656 int dbg_ptr_valid_ : 1; 657 658 /* function header pointer for current function */ 659 pool_ofs_t entry_ofs_; 660 661 /* current program counter */ 662 pool_ofs_t pc_; 663 664 /* debugger line records for current statement */ 665 CVmDbgLinePtr cur_stm_line_; 666 667 /* 668 * Current statement boundaries. We set this each time we enter the 669 * debugger via step(). We usually step through code until we reach 670 * the beginning of a new statement; we use these boundaries to 671 * determine when we leave the current statement. As long as the 672 * current byte-code offset is within these boundaries, (inclusive), 673 * we know we're within the same statement. 674 */ 675 ulong cur_stm_start_; 676 ulong cur_stm_end_; 677 678 /* 679 * User interface context. We maintain this location for use by the 680 * UI code to store its context information. 681 */ 682 void *ui_ctx_; 683 684 /* 685 * Reverse-mapping hash tables for various symbol types. These hash 686 * tables allow us to find the symbol for a given object ID, 687 * property ID, or function address. 688 */ 689 class CVmHashTable *obj_rev_table_; 690 class CVmHashTable *prop_rev_table_; 691 class CVmHashTable *func_rev_table_; 692 class CVmHashTable *enum_rev_table_; 693 694 /* breakpoints */ 695 CVmDebugBp bp_[VMDBG_BP_MAX]; 696 697 /* 698 * Number of global breakpoints in effect (when this is non-zero, we 699 * must trace through code even in 'go' mode, so we can evaluate the 700 * global breakpoints repeatedly and thereby catch when the first 701 * one hits). This only counts enabled global breakpoints - if a 702 * global breakpoint is disabled it must be removed from this count, 703 * since we won't need to consider it when checking for hits. 704 */ 705 int global_bp_cnt_; 706 707 /* host interface (for the compiler's use) */ 708 class CTcHostIfcDebug *hostifc_; 709 710 /* 711 * method header list - this is a list of the method headers in the 712 * program, sorted by address 713 */ 714 ulong *method_hdr_; 715 ulong method_hdr_cnt_; 716 }; 717 718 /* ------------------------------------------------------------------------ */ 719 /* 720 * Debugger programmatic interface to the user interface. This is to be 721 * implemented by each UI subsystem. 722 */ 723 class CVmDebugUI 724 { 725 public: 726 /* 727 * Initialize. We'll call this once before entering any other 728 * functions, so that the UI code can set up its private 729 * information. The UI can create a private context and store a 730 * pointer via G_debugger->set_ui_ctx(). 731 */ 732 static void init(VMG_ const char *image_filename); 733 734 /* 735 * Initialization, phase 2 - this is called just after we've 736 * finished loading the image file. 737 */ 738 static void init_after_load(VMG0_); 739 740 /* 741 * Terminate. We'll call this before terminating, to allow the UI 742 * code to release any resources it allocated. 743 */ 744 static void terminate(VMG0_); 745 746 /* 747 * Invoke the UI main command loop entrypoint. The engine calls 748 * this whenever we hit a breakpoint or reach a single-step point. 749 * This routine should not return until it is ready to let the 750 * program continue execution. 751 */ 752 static void cmd_loop(VMG_ int bp_number, 753 int error_code, unsigned int *exec_ofs); 754 }; 755 756 757 /* ------------------------------------------------------------------------ */ 758 /* 759 * Hash table entry for reverse-mapping hash tables. These tables allow 760 * the debugger to look up a symbol name given the symbol's value: an 761 * object ID, a property ID, or a function address. We map each of 762 * these types of values to a ulong value, which we use as the hash key. 763 */ 764 class CVmHashEntryDbgRev: public CVmHashEntry 765 { 766 public: 767 /* 768 * Construct the entry. sym_val is the symbol's value (an object 769 * ID, a property ID, or a function address) coerced to a ulong. 770 */ 771 CVmHashEntryDbgRev(ulong sym_val, const char *sym, size_t len); 772 ~CVmHashEntryDbgRev(); 773 774 /* check for a match */ 775 virtual int matches(const char *str, size_t len) const; 776 777 /* get the symbol name for this entry */ get_sym()778 const char *get_sym() const { return sym_; } get_sym_len()779 size_t get_sym_len() const { return sym_len_; } 780 781 protected: 782 char *sym_; 783 size_t sym_len_; 784 }; 785 786 /* 787 * Hash function for reverse mapping tables. This hash function doesn't 788 * make any assumptions about the range of character values, since we're 789 * using sequences of raw binary bytes for hash keys. 790 */ 791 class CVmHashFuncDbgRev: public CVmHashFunc 792 { 793 public: 794 unsigned int compute_hash(const char *str, size_t len) const; 795 }; 796 797 798 /* ------------------------------------------------------------------------ */ 799 /* 800 * Condition compilation macros. Some files can be compiled for 801 * stand-alone use or use within a debugger application; when compiled 802 * stand-alone, certain debugger-related operations are removed, which 803 * can improve performance over the debugger-enabled version. 804 */ 805 #ifdef VM_DEBUGGER 806 /* 807 * DEBUGGER-ENABLED VERSION 808 */ 809 810 /* include debugger-only code */ 811 #define VM_IF_DEBUGGER(x) x 812 813 /* do NOT include non-debugger-only code */ 814 #define VM_IF_NOT_DEBUGGER(x) 815 816 #else /* VM_DEBUGGER */ 817 /* 818 * STAND-ALONE (NON-DEBUGGER) VERSION 819 */ 820 821 /* do NOT include debugger-only code in a stand-alone version */ 822 #define VM_IF_DEBUGGER(x) 823 824 /* include non-debugger-only code */ 825 #define VM_IF_NOT_DEBUGGER(x) x 826 827 #endif /* VM_DEBUGGER */ 828 829 #endif /* VMDBG_H */ 830 831