db_run.c revision 308418
11541Srgrimes/*- 21541Srgrimes * Mach Operating System 31541Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University 41541Srgrimes * All Rights Reserved. 51541Srgrimes * 61541Srgrimes * Permission to use, copy, modify and distribute this software and its 71541Srgrimes * documentation is hereby granted, provided that both the copyright 81541Srgrimes * notice and this permission notice appear in all copies of the 91541Srgrimes * software, derivative works or modified versions, and any portions 101541Srgrimes * thereof, and that both notices appear in supporting documentation. 111541Srgrimes * 121541Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 131541Srgrimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 141541Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 151541Srgrimes * 161541Srgrimes * Carnegie Mellon requests users of this software to return to 171541Srgrimes * 181541Srgrimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 191541Srgrimes * School of Computer Science 201541Srgrimes * Carnegie Mellon University 211541Srgrimes * Pittsburgh PA 15213-3890 221541Srgrimes * 231541Srgrimes * any improvements or extensions that they make and grant Carnegie the 241541Srgrimes * rights to redistribute these changes. 251541Srgrimes */ 261541Srgrimes/* 271541Srgrimes * Author: David B. Golub, Carnegie Mellon University 281541Srgrimes * Date: 7/90 291541Srgrimes */ 301541Srgrimes 311541Srgrimes/* 321541Srgrimes * Commands to run process. 331541Srgrimes */ 341541Srgrimes 351541Srgrimes#include <sys/cdefs.h> 361541Srgrimes__FBSDID("$FreeBSD: stable/11/sys/ddb/db_run.c 308418 2016-11-07 12:10:17Z kib $"); 371541Srgrimes 381541Srgrimes#include <sys/param.h> 3912577Sbde#include <sys/kdb.h> 401541Srgrimes#include <sys/proc.h> 411541Srgrimes 421541Srgrimes#include <machine/kdb.h> 431541Srgrimes#include <machine/pcb.h> 442112Swollman 452946Swollman#include <vm/vm.h> 461541Srgrimes 471541Srgrimes#include <ddb/ddb.h> 481541Srgrimes#include <ddb/db_break.h> 491541Srgrimes#include <ddb/db_access.h> 501541Srgrimes 511541Srgrimes#define STEP_ONCE 1 521541Srgrimes#define STEP_RETURN 2 531541Srgrimes#define STEP_CALLT 3 541541Srgrimes#define STEP_CONTINUE 4 552946Swollman#define STEP_INVISIBLE 5 562946Swollman#define STEP_COUNT 6 572946Swollmanstatic int db_run_mode = STEP_CONTINUE; 581541Srgrimes 5912577Sbdestatic bool db_sstep_multiple; 6012577Sbdestatic bool db_sstep_print; 6110653Sdgstatic int db_loop_count; 6210358Sjulianstatic int db_call_depth; 6310358Sjulian 6412569Sbdeint db_inst_count; 6512569Sbdeint db_load_count; 6610358Sjulianint db_store_count; 671541Srgrimes 681541Srgrimes#ifdef SOFTWARE_SSTEP 691541Srgrimesdb_breakpoint_t db_not_taken_bkpt = 0; 701541Srgrimesdb_breakpoint_t db_taken_bkpt = 0; 711541Srgrimes#endif 721541Srgrimes 731541Srgrimes#ifndef db_set_single_step 741541Srgrimesvoid db_set_single_step(void); 752946Swollman#endif 762946Swollman#ifndef db_clear_single_step 772946Swollmanvoid db_clear_single_step(void); 782946Swollman#endif 792946Swollman#ifndef db_pc_is_singlestep 802946Swollmanstatic bool 812946Swollmandb_pc_is_singlestep(db_addr_t pc) 822946Swollman{ 832946Swollman#ifdef SOFTWARE_SSTEP 841541Srgrimes if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address) 851541Srgrimes || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address)) 861541Srgrimes return (true); 871541Srgrimes#endif 881541Srgrimes return (false); 891541Srgrimes} 901541Srgrimes#endif 911541Srgrimes 921541Srgrimesbool 931541Srgrimesdb_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint) 941541Srgrimes{ 951541Srgrimes db_addr_t pc; 961541Srgrimes db_breakpoint_t bkpt; 971541Srgrimes 981541Srgrimes *is_breakpoint = IS_BREAKPOINT_TRAP(type, code); 991541Srgrimes *is_watchpoint = IS_WATCHPOINT_TRAP(type, code); 1001541Srgrimes pc = PC_REGS(); 1011541Srgrimes if (db_pc_is_singlestep(pc)) 1021541Srgrimes *is_breakpoint = false; 1031541Srgrimes 1041541Srgrimes db_clear_single_step(); 1051541Srgrimes db_clear_breakpoints(); 1061541Srgrimes db_clear_watchpoints(); 1071541Srgrimes 1081541Srgrimes#ifdef FIXUP_PC_AFTER_BREAK 1091541Srgrimes if (*is_breakpoint) { 1101541Srgrimes /* 1111541Srgrimes * Breakpoint trap. Fix up the PC if the 1121541Srgrimes * machine requires it. 1131541Srgrimes */ 1141541Srgrimes FIXUP_PC_AFTER_BREAK 1151541Srgrimes pc = PC_REGS(); 1161541Srgrimes } 1171541Srgrimes#endif 1181541Srgrimes 1191541Srgrimes /* 1201541Srgrimes * Now check for a breakpoint at this address. 1211541Srgrimes */ 1222946Swollman bkpt = db_find_breakpoint_here(pc); 1231541Srgrimes if (bkpt) { 1241541Srgrimes if (--bkpt->count == 0) { 12512158Sbde bkpt->count = bkpt->init_count; 12612158Sbde *is_breakpoint = true; 1271541Srgrimes return (true); /* stop here */ 1281541Srgrimes } 1291541Srgrimes return (false); /* continue the countdown */ 1301541Srgrimes } else if (*is_breakpoint) { 1311541Srgrimes#ifdef BKPT_SKIP 1322946Swollman BKPT_SKIP; 1332946Swollman#endif 1341541Srgrimes } 1351541Srgrimes 1361541Srgrimes *is_breakpoint = false; /* might be a breakpoint, but not ours */ 1371541Srgrimes 1381541Srgrimes /* 1391541Srgrimes * If not stepping, then silently ignore single-step traps 14012158Sbde * (except for clearing the single-step-flag above). 14112158Sbde * 14212158Sbde * If stepping, then abort if the trap type is unexpected. 14312158Sbde * Breakpoints owned by us are expected and were handled above. 14412158Sbde * Single-steps are expected and are handled below. All others 1451541Srgrimes * are unexpected. 1461541Srgrimes * 1471541Srgrimes * Only do either of these if the MD layer claims to classify 1481541Srgrimes * single-step traps unambiguously (by defining IS_SSTEP_TRAP). 1492946Swollman * Otherwise, fall through to the bad historical behaviour 1502946Swollman * given by turning unexpected traps into expected traps: if not 1511541Srgrimes * stepping, then expect only breakpoints and stop, and if 1521541Srgrimes * stepping, then expect only single-steps and step. 1531541Srgrimes */ 1541541Srgrimes#ifdef IS_SSTEP_TRAP 1551541Srgrimes if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code)) 1561541Srgrimes return (false); 1571541Srgrimes if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) { 1581541Srgrimes printf("Stepping aborted\n"); 1591541Srgrimes return (true); 1601541Srgrimes } 1611541Srgrimes#endif 1621541Srgrimes 1631541Srgrimes if (db_run_mode == STEP_INVISIBLE) { 1641541Srgrimes db_run_mode = STEP_CONTINUE; 1651541Srgrimes return (false); /* continue */ 1661541Srgrimes } 1671541Srgrimes if (db_run_mode == STEP_COUNT) { 1681541Srgrimes return (false); /* continue */ 1691541Srgrimes } 1701541Srgrimes if (db_run_mode == STEP_ONCE) { 1711541Srgrimes if (--db_loop_count > 0) { 1721541Srgrimes if (db_sstep_print) { 1731541Srgrimes db_printf("\t\t"); 1741541Srgrimes db_print_loc_and_inst(pc); 1751541Srgrimes db_printf("\n"); 1761541Srgrimes } 1771541Srgrimes return (false); /* continue */ 1781541Srgrimes } 1791541Srgrimes } 1801541Srgrimes if (db_run_mode == STEP_RETURN) { 1811541Srgrimes /* continue until matching return */ 1821541Srgrimes db_expr_t ins; 1831541Srgrimes 1841541Srgrimes ins = db_get_value(pc, sizeof(int), false); 1851541Srgrimes if (!inst_trap_return(ins) && 1861541Srgrimes (!inst_return(ins) || --db_call_depth != 0)) { 1871541Srgrimes if (db_sstep_print) { 1881541Srgrimes if (inst_call(ins) || inst_return(ins)) { 1892946Swollman int i; 1902946Swollman 1911541Srgrimes db_printf("[after %6d] ", db_inst_count); 1921541Srgrimes for (i = db_call_depth; --i > 0; ) 1931541Srgrimes db_printf(" "); 1941541Srgrimes db_print_loc_and_inst(pc); 1951541Srgrimes db_printf("\n"); 1961541Srgrimes } 1971541Srgrimes } 1981541Srgrimes if (inst_call(ins)) 1998876Srgrimes db_call_depth++; 2001541Srgrimes return (false); /* continue */ 2011541Srgrimes } 2021541Srgrimes } 2031541Srgrimes if (db_run_mode == STEP_CALLT) { 2041541Srgrimes /* continue until call or return */ 2051541Srgrimes db_expr_t ins; 2061541Srgrimes 2071541Srgrimes ins = db_get_value(pc, sizeof(int), false); 2081541Srgrimes if (!inst_call(ins) && 2091541Srgrimes !inst_return(ins) && 2101541Srgrimes !inst_trap_return(ins)) { 2111541Srgrimes return (false); /* continue */ 2121541Srgrimes } 2131541Srgrimes } 2141541Srgrimes return (true); 2151541Srgrimes} 2161541Srgrimes 2171541Srgrimesvoid 2181541Srgrimesdb_restart_at_pc(bool watchpt) 2191541Srgrimes{ 2201541Srgrimes db_addr_t pc = PC_REGS(); 2211541Srgrimes 2221541Srgrimes if ((db_run_mode == STEP_COUNT) || 2231541Srgrimes ((db_run_mode == STEP_ONCE) && db_sstep_multiple) || 2241541Srgrimes (db_run_mode == STEP_RETURN) || 2251541Srgrimes (db_run_mode == STEP_CALLT)) { 2261541Srgrimes /* 2271541Srgrimes * We are about to execute this instruction, 2281541Srgrimes * so count it now. 2291541Srgrimes */ 2301541Srgrimes#ifdef SOFTWARE_SSTEP 2311541Srgrimes db_expr_t ins = 2321541Srgrimes#endif 2331541Srgrimes db_get_value(pc, sizeof(int), false); 2341541Srgrimes db_inst_count++; 2351541Srgrimes db_load_count += inst_load(ins); 2361541Srgrimes db_store_count += inst_store(ins); 2371541Srgrimes#ifdef SOFTWARE_SSTEP 2381541Srgrimes /* XXX works on mips, but... */ 23910358Sjulian if (inst_branch(ins) || inst_call(ins)) { 24010358Sjulian ins = db_get_value(next_instr_address(pc,1), 24112569Sbde sizeof(int), false); 24212569Sbde db_inst_count++; 2431541Srgrimes db_load_count += inst_load(ins); 2441541Srgrimes db_store_count += inst_store(ins); 2452946Swollman } 2462946Swollman#endif /* SOFTWARE_SSTEP */ 2471541Srgrimes } 2481541Srgrimes 2492946Swollman if (db_run_mode == STEP_CONTINUE) { 2502946Swollman if (watchpt || db_find_breakpoint_here(pc)) { 2512946Swollman /* 2522946Swollman * Step over breakpoint/watchpoint. 2532946Swollman */ 2542946Swollman db_run_mode = STEP_INVISIBLE; 2552946Swollman db_set_single_step(); 2562946Swollman } else { 2572946Swollman db_set_breakpoints(); 2582946Swollman db_set_watchpoints(); 2592946Swollman } 2602946Swollman } else { 2618876Srgrimes db_set_single_step(); 2622946Swollman } 2631541Srgrimes} 2641541Srgrimes 2651541Srgrimes#ifdef SOFTWARE_SSTEP 2661541Srgrimes/* 2671541Srgrimes * Software implementation of single-stepping. 2681541Srgrimes * If your machine does not have a trace mode 2691541Srgrimes * similar to the vax or sun ones you can use 2701541Srgrimes * this implementation, done for the mips. 2711541Srgrimes * Just define the above conditional and provide 2721541Srgrimes * the functions/macros defined below. 2731541Srgrimes * 2742946Swollman * extern bool 2751541Srgrimes * inst_branch(), returns true if the instruction might branch 2761541Srgrimes * extern unsigned 2771541Srgrimes * branch_taken(), return the address the instruction might 2781541Srgrimes * branch to 2791541Srgrimes * db_getreg_val(); return the value of a user register, 2801541Srgrimes * as indicated in the hardware instruction 2811541Srgrimes * encoding, e.g. 8 for r8 2821541Srgrimes * 2831541Srgrimes * next_instr_address(pc,bd) returns the address of the first 2841541Srgrimes * instruction following the one at "pc", 2852946Swollman * which is either in the taken path of 2862946Swollman * the branch (bd==1) or not. This is 2872946Swollman * for machines (mips) with branch delays. 2882946Swollman * 28912429Sphk * A single-step may involve at most 2 breakpoints - 29012429Sphk * one for branch-not-taken and one for branch taken. 29112429Sphk * If one of these addresses does not already have a breakpoint, 2922946Swollman * we allocate a breakpoint and save it here. 29312429Sphk * These breakpoints are deleted on return. 2942946Swollman */ 29512429Sphk 29612429Sphkvoid 29712429Sphkdb_set_single_step(void) 29812429Sphk{ 29912429Sphk db_addr_t pc = PC_REGS(), brpc; 30012429Sphk unsigned inst; 30112429Sphk 30212429Sphk /* 3032946Swollman * User was stopped at pc, e.g. the instruction 30412429Sphk * at pc was not executed. 3052946Swollman */ 30612429Sphk inst = db_get_value(pc, sizeof(int), false); 30712429Sphk if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { 3082946Swollman brpc = branch_taken(inst, pc); 3092997Swollman if (brpc != pc) { /* self-branches are hopeless */ 3102997Swollman db_taken_bkpt = db_set_temp_breakpoint(brpc); 3112997Swollman } 3122997Swollman pc = next_instr_address(pc, 1); 3132997Swollman } 3142997Swollman pc = next_instr_address(pc, 0); 3152997Swollman db_not_taken_bkpt = db_set_temp_breakpoint(pc); 3162997Swollman} 317 318void 319db_clear_single_step(void) 320{ 321 322 if (db_not_taken_bkpt != 0) { 323 db_delete_temp_breakpoint(db_not_taken_bkpt); 324 db_not_taken_bkpt = 0; 325 } 326 if (db_taken_bkpt != 0) { 327 db_delete_temp_breakpoint(db_taken_bkpt); 328 db_taken_bkpt = 0; 329 } 330} 331 332#endif /* SOFTWARE_SSTEP */ 333 334extern int db_cmd_loop_done; 335 336/* single-step */ 337/*ARGSUSED*/ 338void 339db_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 340{ 341 bool print = false; 342 343 if (count == -1) 344 count = 1; 345 346 if (modif[0] == 'p') 347 print = true; 348 349 db_run_mode = STEP_ONCE; 350 db_loop_count = count; 351 db_sstep_multiple = (count != 1); 352 db_sstep_print = print; 353 db_inst_count = 0; 354 db_load_count = 0; 355 db_store_count = 0; 356 357 db_cmd_loop_done = 1; 358} 359 360/* trace and print until call/return */ 361/*ARGSUSED*/ 362void 363db_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 364 char *modif) 365{ 366 bool print = false; 367 368 if (modif[0] == 'p') 369 print = true; 370 371 db_run_mode = STEP_CALLT; 372 db_sstep_print = print; 373 db_inst_count = 0; 374 db_load_count = 0; 375 db_store_count = 0; 376 377 db_cmd_loop_done = 1; 378} 379 380/*ARGSUSED*/ 381void 382db_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 383 char *modif) 384{ 385 bool print = false; 386 387 if (modif[0] == 'p') 388 print = true; 389 390 db_run_mode = STEP_RETURN; 391 db_call_depth = 1; 392 db_sstep_print = print; 393 db_inst_count = 0; 394 db_load_count = 0; 395 db_store_count = 0; 396 397 db_cmd_loop_done = 1; 398} 399 400/* continue */ 401/*ARGSUSED*/ 402void 403db_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 404{ 405 if (modif[0] == 'c') 406 db_run_mode = STEP_COUNT; 407 else 408 db_run_mode = STEP_CONTINUE; 409 db_inst_count = 0; 410 db_load_count = 0; 411 db_store_count = 0; 412 413 db_cmd_loop_done = 1; 414} 415