2 * Debugger break-points handling
4 * Copyright 1994 Martin von Loewis
5 * Copyright 1995 Alexandre Julliard
12 #define INT3 0xcc /* int 3 opcode */
14 #define MAX_BREAKPOINTS 100
16 static BREAKPOINT breakpoints
[MAX_BREAKPOINTS
];
18 static int next_bp
= 1; /* breakpoint 0 is reserved for step-over */
21 /***********************************************************************
22 * DEBUG_IsStepOverInstr
24 * Determine if the instruction at CS:EIP is an instruction that
25 * we need to step over (like a call or a repetitive string move).
27 static BOOL
DEBUG_IsStepOverInstr(void)
34 addr
.seg
= DEBUG_context
.SegCs
;
35 addr
.off
= DEBUG_context
.Eip
;
36 /* FIXME: old code was using V86BASE(DEBUG_context)
37 * instead of passing thru DOSMEM_MemoryBase
39 instr
= (BYTE
*)DEBUG_ToLinear(&addr
);
43 if (!DEBUG_READ_MEM(instr
, &ch
, sizeof(ch
)))
48 /* Skip all prefixes */
56 case 0x66: /* opcode size prefix */
57 case 0x67: /* addr size prefix */
59 case 0xf2: /* repne */
64 /* Handle call instructions */
66 case 0xcd: /* int <intno> */
67 case 0xe8: /* call <offset> */
68 case 0x9a: /* lcall <seg>:<off> */
71 case 0xff: /* call <regmodrm> */
72 if (!DEBUG_READ_MEM(instr
+ 1, &ch
, sizeof(ch
)))
74 return (((ch
& 0x38) == 0x10) || ((ch
& 0x38) == 0x18));
76 /* Handle string instructions */
80 case 0x6e: /* outsb */
81 case 0x6f: /* outsw */
82 case 0xa4: /* movsb */
83 case 0xa5: /* movsw */
84 case 0xa6: /* cmpsb */
85 case 0xa7: /* cmpsw */
86 case 0xaa: /* stosb */
87 case 0xab: /* stosw */
88 case 0xac: /* lodsb */
89 case 0xad: /* lodsw */
90 case 0xae: /* scasb */
91 case 0xaf: /* scasw */
104 /***********************************************************************
107 * Determine if the instruction at CS:EIP is an instruction that
108 * is a function return.
110 BOOL
DEBUG_IsFctReturn(void)
117 addr
.seg
= DEBUG_context
.SegCs
;
118 addr
.off
= DEBUG_context
.Eip
;
119 /* FIXME: old code was using V86BASE(DEBUG_context)
120 * instead of passing thru DOSMEM_MemoryBase
122 instr
= (BYTE
*)DEBUG_ToLinear(&addr
);
124 if (!DEBUG_READ_MEM(instr
, &ch
, sizeof(ch
)))
127 return (ch
== 0xc2) || (ch
== 0xc3);
134 /***********************************************************************
135 * DEBUG_SetBreakpoints
137 * Set or remove all the breakpoints.
139 void DEBUG_SetBreakpoints( BOOL set
)
144 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
146 if (breakpoints
[i
].refcount
&& breakpoints
[i
].enabled
)
148 ch
= set
? INT3
: breakpoints
[i
].opcode
;
150 if (!DEBUG_WRITE_MEM( (void*)DEBUG_ToLinear(&breakpoints
[i
].addr
), &ch
, sizeof(ch
) ))
152 fprintf( stderr
, "Invalid address for breakpoint %d, disabling it\n", i
);
153 breakpoints
[i
].enabled
= FALSE
;
160 /***********************************************************************
161 * DEBUG_FindBreakpoint
163 * Find the breakpoint for a given address. Return the breakpoint
164 * number or -1 if none.
166 int DEBUG_FindBreakpoint( const DBG_ADDR
*addr
)
170 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
172 if (breakpoints
[i
].refcount
&& breakpoints
[i
].enabled
&&
173 breakpoints
[i
].addr
.seg
== addr
->seg
&&
174 breakpoints
[i
].addr
.off
== addr
->off
) return i
;
180 /***********************************************************************
181 * DEBUG_AddBreakpoint
185 void DEBUG_AddBreakpoint( const DBG_ADDR
*address
)
187 DBG_ADDR addr
= *address
;
192 DEBUG_FixAddress( &addr
, DEBUG_context
.SegCs
);
194 if( addr
.type
!= NULL
&& addr
.type
== DEBUG_TypeIntConst
)
197 * We know that we have the actual offset stored somewhere
198 * else in 32-bit space. Grab it, and we
203 addr
.off
= DEBUG_GetExprValue(&addr
, NULL
);
207 if ((num
= DEBUG_FindBreakpoint(&addr
)) >= 1)
209 breakpoints
[num
].refcount
++;
213 if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear( &addr
), &ch
, sizeof(ch
)))
216 if (next_bp
< MAX_BREAKPOINTS
)
218 else /* try to find an empty slot */
220 for (num
= 1; num
< MAX_BREAKPOINTS
; num
++)
221 if (!breakpoints
[num
].refcount
) break;
222 if (num
>= MAX_BREAKPOINTS
)
224 fprintf( stderr
, "Too many breakpoints. Please delete some.\n" );
228 breakpoints
[num
].addr
= addr
;
229 breakpoints
[num
].addrlen
= 32;
232 breakpoints
[num
].addrlen
= DEBUG_GetSelectorType( addr
.seg
);
233 if (breakpoints
[num
].addrlen
== 0) fprintf(stderr
, "in bad shape\n");
235 breakpoints
[num
].opcode
= ch
;
236 breakpoints
[num
].enabled
= TRUE
;
237 breakpoints
[num
].refcount
= 1;
238 breakpoints
[num
].skipcount
= 0;
239 fprintf( stderr
, "Breakpoint %d at ", num
);
240 DEBUG_PrintAddress( &breakpoints
[num
].addr
, breakpoints
[num
].addrlen
,
242 fprintf( stderr
, "\n" );
246 /***********************************************************************
247 * DEBUG_DelBreakpoint
249 * Delete a breakpoint.
251 void DEBUG_DelBreakpoint( int num
)
253 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].refcount
)
255 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
259 if (--breakpoints
[num
].refcount
> 0)
262 if( breakpoints
[num
].condition
!= NULL
)
264 DEBUG_FreeExpr(breakpoints
[num
].condition
);
265 breakpoints
[num
].condition
= NULL
;
268 breakpoints
[num
].enabled
= FALSE
;
269 breakpoints
[num
].refcount
= 0;
270 breakpoints
[num
].skipcount
= 0;
274 /***********************************************************************
275 * DEBUG_EnableBreakpoint
277 * Enable or disable a break point.
279 void DEBUG_EnableBreakpoint( int num
, BOOL enable
)
281 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].refcount
)
283 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
286 breakpoints
[num
].enabled
= (enable
) ? TRUE
: FALSE
;
287 breakpoints
[num
].skipcount
= 0;
291 /***********************************************************************
292 * DEBUG_InfoBreakpoints
294 * Display break points information.
296 void DEBUG_InfoBreakpoints(void)
300 fprintf( stderr
, "Breakpoints:\n" );
301 for (i
= 1; i
< next_bp
; i
++)
303 if (breakpoints
[i
].refcount
)
305 fprintf( stderr
, "%d: %c ", i
, breakpoints
[i
].enabled
? 'y' : 'n');
306 DEBUG_PrintAddress( &breakpoints
[i
].addr
, breakpoints
[i
].addrlen
, TRUE
);
307 fprintf( stderr
, " (%u)\n", breakpoints
[i
].refcount
);
308 if( breakpoints
[i
].condition
!= NULL
)
310 fprintf(stderr
, "\t\tstop when ");
311 DEBUG_DisplayExpr(breakpoints
[i
].condition
);
312 fprintf(stderr
, "\n");
318 /***********************************************************************
319 * DEBUG_ShouldContinue
321 * Determine if we should continue execution after a SIGTRAP signal when
322 * executing in the given mode.
324 BOOL
DEBUG_ShouldContinue( enum exec_mode mode
, int * count
)
332 /* If not single-stepping, back up over the int3 instruction */
333 if (!(DEBUG_context
.EFlags
& STEP_FLAG
))
337 DEBUG_GetCurrentAddress( &addr
);
338 bpnum
= DEBUG_FindBreakpoint( &addr
);
339 breakpoints
[0].enabled
= FALSE
; /* disable the step-over breakpoint */
341 if ((bpnum
!= 0) && (bpnum
!= -1))
343 if( breakpoints
[bpnum
].condition
!= NULL
)
345 cond_addr
= DEBUG_EvalExpr(breakpoints
[bpnum
].condition
);
346 if( cond_addr
.type
== NULL
)
349 * Something wrong - unable to evaluate this expression.
351 fprintf(stderr
, "Unable to evaluate expression ");
352 DEBUG_DisplayExpr(breakpoints
[bpnum
].condition
);
353 fprintf(stderr
, "\nTurning off condition\n");
354 DEBUG_AddBPCondition(bpnum
, NULL
);
356 else if( ! DEBUG_GetExprValue( &cond_addr
, NULL
) )
362 if( breakpoints
[bpnum
].skipcount
> 0 )
364 breakpoints
[bpnum
].skipcount
--;
365 if( breakpoints
[bpnum
].skipcount
> 0 )
370 fprintf( stderr
, "Stopped on breakpoint %d at ", bpnum
);
371 DEBUG_PrintAddress( &breakpoints
[bpnum
].addr
,
372 breakpoints
[bpnum
].addrlen
, TRUE
);
373 fprintf( stderr
, "\n" );
376 * See if there is a source file for this bp. If so,
377 * then dig it out and display one line.
379 DEBUG_FindNearestSymbol( &addr
, TRUE
, NULL
, 0, &list
);
380 if( list
.sourcefile
!= NULL
)
382 DEBUG_List(&list
, NULL
, 0);
388 * If our mode indicates that we are stepping line numbers,
389 * get the current function, and figure out if we are exactly
390 * on a line number or not.
392 if( mode
== EXEC_STEP_OVER
|| mode
== EXEC_STEP_INSTR
)
394 if( DEBUG_CheckLinenoStatus(&addr
) == AT_LINENUMBER
)
399 else if( mode
== EXEC_STEPI_OVER
400 || mode
== EXEC_STEPI_INSTR
)
406 if( *count
> 0 || mode
== EXEC_FINISH
)
409 * We still need to execute more instructions.
415 * If we are about to stop, then print out the source line if we
418 if ((mode
!= EXEC_CONT
&& mode
!= EXEC_PASS
&& mode
!= EXEC_FINISH
))
420 DEBUG_FindNearestSymbol( &addr
, TRUE
, NULL
, 0, &list
);
421 if( list
.sourcefile
!= NULL
)
423 DEBUG_List(&list
, NULL
, 0);
428 /* If there's no breakpoint and we are not single-stepping, then we */
429 /* must have encountered an int3 in the Windows program; let's skip it. */
430 if ((bpnum
== -1) && !(DEBUG_context
.EFlags
& STEP_FLAG
))
434 /* no breakpoint, continue if in continuous mode */
435 return (mode
== EXEC_CONT
|| mode
== EXEC_PASS
|| mode
== EXEC_FINISH
);
438 /***********************************************************************
439 * DEBUG_RestartExecution
441 * Remove all breakpoints before entering the debug loop
443 void DEBUG_SuspendExecution( void )
445 DEBUG_SetBreakpoints( FALSE
);
446 breakpoints
[0] = DEBUG_CurrThread
->stepOverBP
;
449 /***********************************************************************
450 * DEBUG_RestartExecution
452 * Set the breakpoints to the correct state to restart execution
455 enum exec_mode
DEBUG_RestartExecution( enum exec_mode mode
, int count
)
462 enum exec_mode ret_mode
;
466 DEBUG_GetCurrentAddress( &addr
);
469 * This is the mode we will be running in after we finish. We would like
470 * to be able to modify this in certain cases.
474 bp
= DEBUG_FindBreakpoint( &addr
);
475 if ( bp
!= -1 && bp
!= 0)
478 * If we have set a new value, then save it in the BP number.
480 if( count
!= 0 && mode
== EXEC_CONT
)
482 breakpoints
[bp
].skipcount
= count
;
484 mode
= EXEC_STEPI_INSTR
; /* If there's a breakpoint, skip it */
488 if( mode
== EXEC_CONT
&& count
> 1 )
490 fprintf(stderr
, "Not stopped at any breakpoint; argument ignored.\n");
494 if( mode
== EXEC_FINISH
&& DEBUG_IsFctReturn() )
496 mode
= ret_mode
= EXEC_STEPI_INSTR
;
499 instr
= DEBUG_ToLinear( &addr
);
500 DEBUG_READ_MEM((void*)instr
, &ch
, sizeof(ch
));
502 * See if the function we are stepping into has debug info
503 * and line numbers. If not, then we step over it instead.
504 * FIXME - we need to check for things like thunks or trampolines,
505 * as the actual function may in fact have debug info.
509 DEBUG_READ_MEM((void*)(instr
+ 1), &delta
, sizeof(delta
));
511 DEBUG_Disasm(&addr2
, FALSE
);
514 status
= DEBUG_CheckLinenoStatus(&addr2
);
516 * Anytime we have a trampoline, step over it.
518 if( ((mode
== EXEC_STEP_OVER
) || (mode
== EXEC_STEPI_OVER
))
519 && status
== FUNC_IS_TRAMPOLINE
)
522 fprintf(stderr
, "Not stepping into trampoline at %x (no lines)\n",
525 mode
= EXEC_STEP_OVER_TRAMPOLINE
;
528 if( mode
== EXEC_STEP_INSTR
&& status
== FUNC_HAS_NO_LINES
)
531 fprintf(stderr
, "Not stepping into function at %x (no lines)\n",
534 mode
= EXEC_STEP_OVER
;
539 if( mode
== EXEC_STEP_INSTR
)
541 if( DEBUG_CheckLinenoStatus(&addr
) == FUNC_HAS_NO_LINES
)
543 fprintf(stderr
, "Single stepping until exit from function, \n");
544 fprintf(stderr
, "which has no line number information.\n");
546 ret_mode
= mode
= EXEC_FINISH
;
552 case EXEC_CONT
: /* Continuous execution */
553 case EXEC_PASS
: /* Continue, passing exception */
555 DEBUG_context
.EFlags
&= ~STEP_FLAG
;
557 DEBUG_SetBreakpoints( TRUE
);
560 case EXEC_STEP_OVER_TRAMPOLINE
:
562 * This is the means by which we step over our conversion stubs
563 * in callfrom*.s and callto*.s. We dig the appropriate address
564 * off the stack, and we set the breakpoint there instead of the
565 * address just after the call.
568 DEBUG_READ_MEM((void*)(DEBUG_context
.Esp
+
569 2 * sizeof(unsigned int)),
570 &addr
.off
, sizeof(addr
.off
));
571 DEBUG_context
.EFlags
&= ~STEP_FLAG
;
573 breakpoints
[0].addr
= addr
;
574 breakpoints
[0].enabled
= TRUE
;
575 breakpoints
[0].refcount
= 1;
576 breakpoints
[0].skipcount
= 0;
577 DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr
), &breakpoints
[0].opcode
, sizeof(char));
578 DEBUG_SetBreakpoints( TRUE
);
582 case EXEC_STEPI_OVER
: /* Stepping over a call */
583 case EXEC_STEP_OVER
: /* Stepping over a call */
584 if (DEBUG_IsStepOverInstr())
587 DEBUG_context
.EFlags
&= ~STEP_FLAG
;
589 DEBUG_Disasm(&addr
, FALSE
);
590 breakpoints
[0].addr
= addr
;
591 breakpoints
[0].enabled
= TRUE
;
592 breakpoints
[0].refcount
= 1;
593 breakpoints
[0].skipcount
= 0;
594 DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr
), &breakpoints
[0].opcode
, sizeof(char));
595 DEBUG_SetBreakpoints( TRUE
);
598 /* else fall through to single-stepping */
600 case EXEC_STEP_INSTR
: /* Single-stepping an instruction */
601 case EXEC_STEPI_INSTR
: /* Single-stepping an instruction */
603 DEBUG_context
.EFlags
|= STEP_FLAG
;
607 DEBUG_CurrThread
->stepOverBP
= breakpoints
[0];
612 DEBUG_AddBPCondition(int num
, struct expr
* exp
)
614 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].refcount
)
616 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
620 if( breakpoints
[num
].condition
!= NULL
)
622 DEBUG_FreeExpr(breakpoints
[num
].condition
);
623 breakpoints
[num
].condition
= NULL
;
628 breakpoints
[num
].condition
= DEBUG_CloneExpr(exp
);