2 * Debugger break-points handling
4 * Copyright 1994 Martin von Loewis
5 * Copyright 1995 Alexandre Julliard
14 #define INT3 0xcc /* int 3 opcode */
16 #define MAX_BREAKPOINTS 25
27 static BREAKPOINT breakpoints
[MAX_BREAKPOINTS
];
29 static int next_bp
= 1; /* breakpoint 0 is reserved for step-over */
32 /***********************************************************************
35 * Change the opcode at segment:addr.
37 static void DEBUG_SetOpcode( const DBG_ADDR
*addr
, BYTE op
)
41 *(BYTE
*)PTR_SEG_OFF_TO_LIN( addr
->seg
, addr
->off
) = op
;
43 else /* 32-bit code, so we have to change the protection first */
45 /* There are a couple of problems with this. On Linux prior to
46 1.1.62, this call fails (ENOACCESS) due to a bug in fs/exec.c.
47 This code is currently not tested at all on BSD.
48 How do I determine the page size in a more symbolic manner?
49 And why does mprotect need that start address of the page
51 Not that portability matters, this code is i386 only anyways...
52 How do I get the old protection in order to restore it later on?
54 if (mprotect((caddr_t
)(addr
->off
& (~4095)), 4096,
55 PROT_READ
| PROT_WRITE
| PROT_EXEC
) == -1)
57 perror( "Can't set break point" );
60 *(BYTE
*)addr
->off
= op
;
61 mprotect((caddr_t
)(addr
->off
& ~4095), 4096,
62 PROT_READ
| PROT_EXEC
);
67 /***********************************************************************
68 * DEBUG_IsStepOverInstr
70 * Determine if the instruction at CS:EIP is an instruction that
71 * we need to step over (like a call or a repetitive string move).
73 static BOOL
DEBUG_IsStepOverInstr( struct sigcontext_struct
*context
)
75 BYTE
*instr
= (BYTE
*)PTR_SEG_OFF_TO_LIN(CS_reg(context
),EIP_reg(context
));
81 /* Skip all prefixes */
89 case 0x66: /* opcode size prefix */
90 case 0x67: /* addr size prefix */
92 case 0xf2: /* repne */
97 /* Handle call instructions */
99 case 0xe8: /* call <offset> */
100 case 0x9a: /* lcall <seg>:<off> */
103 case 0xff: /* call <regmodrm> */
104 return (((instr
[1] & 0x38) == 0x10) ||
105 ((instr
[1] & 0x38) == 0x18));
107 /* Handle string instructions */
109 case 0x6c: /* insb */
110 case 0x6d: /* insw */
111 case 0x6e: /* outsb */
112 case 0x6f: /* outsw */
113 case 0xa4: /* movsb */
114 case 0xa5: /* movsw */
115 case 0xa6: /* cmpsb */
116 case 0xa7: /* cmpsw */
117 case 0xaa: /* stosb */
118 case 0xab: /* stosw */
119 case 0xac: /* lodsb */
120 case 0xad: /* lodsw */
121 case 0xae: /* scasb */
122 case 0xaf: /* scasw */
132 /***********************************************************************
133 * DEBUG_SetBreakpoints
135 * Set or remove all the breakpoints.
137 void DEBUG_SetBreakpoints( BOOL set
)
141 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
143 if (breakpoints
[i
].in_use
&& breakpoints
[i
].enabled
)
145 if (DEBUG_IsBadWritePtr( &breakpoints
[i
].addr
, 1 ))
147 fprintf( stderr
, "Invalid address for breakpoint %d, disabling it\n", i
);
148 breakpoints
[i
].enabled
= FALSE
;
150 else DEBUG_SetOpcode( &breakpoints
[i
].addr
,
151 set
? INT3
: breakpoints
[i
].opcode
);
157 /***********************************************************************
158 * DEBUG_FindBreakpoint
160 * Find the breakpoint for a given address. Return the breakpoint
161 * number or -1 if none.
163 int DEBUG_FindBreakpoint( const DBG_ADDR
*addr
)
167 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
169 if (breakpoints
[i
].in_use
&& breakpoints
[i
].enabled
&&
170 breakpoints
[i
].addr
.seg
== addr
->seg
&&
171 breakpoints
[i
].addr
.off
== addr
->off
) return i
;
177 /***********************************************************************
178 * DEBUG_AddBreakpoint
182 void DEBUG_AddBreakpoint( const DBG_ADDR
*address
)
184 DBG_ADDR addr
= *address
;
188 DBG_FIX_ADDR_SEG( &addr
, CS_reg(DEBUG_context
) );
190 if (next_bp
< MAX_BREAKPOINTS
)
192 else /* try to find an empty slot */
194 for (num
= 1; num
< MAX_BREAKPOINTS
; num
++)
195 if (!breakpoints
[num
].in_use
) break;
196 if (num
>= MAX_BREAKPOINTS
)
198 fprintf( stderr
, "Too many breakpoints. Please delete some.\n" );
202 if (!DBG_CHECK_READ_PTR( &addr
, 1 )) return;
203 p
= DBG_ADDR_TO_LIN( &addr
);
204 breakpoints
[num
].addr
= addr
;
205 breakpoints
[num
].addrlen
= !addr
.seg
? 32 :
206 (GET_SEL_FLAGS(addr
.seg
) & LDT_FLAGS_32BIT
) ? 32 : 16;
207 breakpoints
[num
].opcode
= *p
;
208 breakpoints
[num
].enabled
= TRUE
;
209 breakpoints
[num
].in_use
= TRUE
;
210 fprintf( stderr
, "Breakpoint %d at ", num
);
211 DEBUG_PrintAddress( &breakpoints
[num
].addr
, breakpoints
[num
].addrlen
);
212 fprintf( stderr
, "\n" );
216 /***********************************************************************
217 * DEBUG_DelBreakpoint
219 * Delete a breakpoint.
221 void DEBUG_DelBreakpoint( int num
)
223 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
225 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
228 breakpoints
[num
].enabled
= FALSE
;
229 breakpoints
[num
].in_use
= FALSE
;
233 /***********************************************************************
234 * DEBUG_EnableBreakpoint
236 * Enable or disable a break point.
238 void DEBUG_EnableBreakpoint( int num
, BOOL enable
)
240 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
242 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
245 breakpoints
[num
].enabled
= enable
;
249 /***********************************************************************
250 * DEBUG_InfoBreakpoints
252 * Display break points information.
254 void DEBUG_InfoBreakpoints(void)
258 fprintf( stderr
, "Breakpoints:\n" );
259 for (i
= 1; i
< next_bp
; i
++)
261 if (breakpoints
[i
].in_use
)
263 fprintf( stderr
, "%d: %c ", i
, breakpoints
[i
].enabled
? 'y' : 'n');
264 DEBUG_PrintAddress( &breakpoints
[i
].addr
, breakpoints
[i
].addrlen
);
265 fprintf( stderr
, "\n" );
271 /***********************************************************************
272 * DEBUG_ShouldContinue
274 * Determine if we should continue execution after a SIGTRAP signal when
275 * executing in the given mode.
277 BOOL
DEBUG_ShouldContinue( struct sigcontext_struct
*context
,
278 enum exec_mode mode
)
283 /* If not single-stepping, back up over the int3 instruction */
284 if (!(EFL_reg(DEBUG_context
) & STEP_FLAG
)) EIP_reg(DEBUG_context
)--;
286 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
287 0 : CS_reg(DEBUG_context
);
288 addr
.off
= EIP_reg(DEBUG_context
);
290 bpnum
= DEBUG_FindBreakpoint( &addr
);
291 breakpoints
[0].enabled
= 0; /* disable the step-over breakpoint */
293 if ((bpnum
!= 0) && (bpnum
!= -1))
295 fprintf( stderr
, "Stopped on breakpoint %d at ", bpnum
);
296 DEBUG_PrintAddress( &breakpoints
[bpnum
].addr
,
297 breakpoints
[bpnum
].addrlen
);
298 fprintf( stderr
, "\n" );
301 /* no breakpoint, continue if in continuous mode */
302 return (mode
== EXEC_CONT
);
306 /***********************************************************************
307 * DEBUG_RestartExecution
309 * Set the breakpoints to the correct state to restart execution
312 void DEBUG_RestartExecution( struct sigcontext_struct
*context
,
313 enum exec_mode mode
, int instr_len
)
317 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
318 0 : CS_reg(DEBUG_context
);
319 addr
.off
= EIP_reg(DEBUG_context
);
321 if (DEBUG_FindBreakpoint( &addr
) != -1)
322 mode
= EXEC_STEP_INSTR
; /* If there's a breakpoint, skip it */
326 case EXEC_CONT
: /* Continuous execution */
327 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
328 DEBUG_SetBreakpoints( TRUE
);
331 case EXEC_STEP_OVER
: /* Stepping over a call */
332 if (DEBUG_IsStepOverInstr(DEBUG_context
))
334 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
335 addr
.off
+= instr_len
;
336 breakpoints
[0].addr
= addr
;
337 breakpoints
[0].enabled
= TRUE
;
338 breakpoints
[0].in_use
= TRUE
;
339 breakpoints
[0].opcode
= *(BYTE
*)DBG_ADDR_TO_LIN( &addr
);
340 DEBUG_SetBreakpoints( TRUE
);
343 /* else fall through to single-stepping */
345 case EXEC_STEP_INSTR
: /* Single-stepping an instruction */
346 EFL_reg(DEBUG_context
) |= STEP_FLAG
;