2 * Debugger break-points handling
4 * Copyright 1994 Martin von Loewis
5 * Copyright 1995 Alexandre Julliard
10 #include <sys/types.h>
15 #define INT3 0xcc /* int 3 opcode */
17 #define MAX_BREAKPOINTS 25
28 static BREAKPOINT breakpoints
[MAX_BREAKPOINTS
];
30 static int next_bp
= 1; /* breakpoint 0 is reserved for step-over */
33 /***********************************************************************
36 * Change the opcode at segment:addr.
38 static void DEBUG_SetOpcode( const DBG_ADDR
*addr
, BYTE op
)
42 *(BYTE
*)PTR_SEG_OFF_TO_LIN( addr
->seg
, addr
->off
) = op
;
44 else /* 32-bit code, so we have to change the protection first */
46 /* There are a couple of problems with this. On Linux prior to
47 1.1.62, this call fails (ENOACCESS) due to a bug in fs/exec.c.
48 This code is currently not tested at all on BSD.
49 How do I determine the page size in a more symbolic manner?
50 And why does mprotect need that start address of the page
52 Not that portability matters, this code is i386 only anyways...
53 How do I get the old protection in order to restore it later on?
55 if (mprotect((caddr_t
)(addr
->off
& (~4095)), 4096,
56 PROT_READ
| PROT_WRITE
| PROT_EXEC
) == -1)
58 perror( "Can't set break point" );
61 *(BYTE
*)addr
->off
= op
;
62 mprotect((caddr_t
)(addr
->off
& ~4095), 4096,
63 PROT_READ
| PROT_EXEC
);
68 /***********************************************************************
69 * DEBUG_IsStepOverInstr
71 * Determine if the instruction at CS:EIP is an instruction that
72 * we need to step over (like a call or a repetitive string move).
74 static BOOL
DEBUG_IsStepOverInstr( struct sigcontext_struct
*context
)
76 BYTE
*instr
= (BYTE
*)PTR_SEG_OFF_TO_LIN(CS_reg(context
),EIP_reg(context
));
82 /* Skip all prefixes */
90 case 0x66: /* opcode size prefix */
91 case 0x67: /* addr size prefix */
93 case 0xf2: /* repne */
98 /* Handle call instructions */
100 case 0xe8: /* call <offset> */
101 case 0x9a: /* lcall <seg>:<off> */
104 case 0xff: /* call <regmodrm> */
105 return (((instr
[1] & 0x38) == 0x10) ||
106 ((instr
[1] & 0x38) == 0x18));
108 /* Handle string instructions */
110 case 0x6c: /* insb */
111 case 0x6d: /* insw */
112 case 0x6e: /* outsb */
113 case 0x6f: /* outsw */
114 case 0xa4: /* movsb */
115 case 0xa5: /* movsw */
116 case 0xa6: /* cmpsb */
117 case 0xa7: /* cmpsw */
118 case 0xaa: /* stosb */
119 case 0xab: /* stosw */
120 case 0xac: /* lodsb */
121 case 0xad: /* lodsw */
122 case 0xae: /* scasb */
123 case 0xaf: /* scasw */
133 /***********************************************************************
134 * DEBUG_SetBreakpoints
136 * Set or remove all the breakpoints.
138 void DEBUG_SetBreakpoints( BOOL set
)
142 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
144 if (breakpoints
[i
].in_use
&& breakpoints
[i
].enabled
)
146 if (DEBUG_IsBadWritePtr( &breakpoints
[i
].addr
, 1 ))
148 fprintf( stderr
, "Invalid address for breakpoint %d, disabling it\n", i
);
149 breakpoints
[i
].enabled
= FALSE
;
151 else DEBUG_SetOpcode( &breakpoints
[i
].addr
,
152 set
? INT3
: breakpoints
[i
].opcode
);
158 /***********************************************************************
159 * DEBUG_FindBreakpoint
161 * Find the breakpoint for a given address. Return the breakpoint
162 * number or -1 if none.
164 int DEBUG_FindBreakpoint( const DBG_ADDR
*addr
)
168 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
170 if (breakpoints
[i
].in_use
&& breakpoints
[i
].enabled
&&
171 breakpoints
[i
].addr
.seg
== addr
->seg
&&
172 breakpoints
[i
].addr
.off
== addr
->off
) return i
;
178 /***********************************************************************
179 * DEBUG_AddBreakpoint
183 void DEBUG_AddBreakpoint( const DBG_ADDR
*address
)
185 DBG_ADDR addr
= *address
;
189 DBG_FIX_ADDR_SEG( &addr
, CS_reg(DEBUG_context
) );
191 if (next_bp
< MAX_BREAKPOINTS
)
193 else /* try to find an empty slot */
195 for (num
= 1; num
< MAX_BREAKPOINTS
; num
++)
196 if (!breakpoints
[num
].in_use
) break;
197 if (num
>= MAX_BREAKPOINTS
)
199 fprintf( stderr
, "Too many breakpoints. Please delete some.\n" );
203 if (!DBG_CHECK_READ_PTR( &addr
, 1 )) return;
204 p
= DBG_ADDR_TO_LIN( &addr
);
205 breakpoints
[num
].addr
= addr
;
206 breakpoints
[num
].addrlen
= !addr
.seg
? 32 :
207 (GET_SEL_FLAGS(addr
.seg
) & LDT_FLAGS_32BIT
) ? 32 : 16;
208 breakpoints
[num
].opcode
= *p
;
209 breakpoints
[num
].enabled
= TRUE
;
210 breakpoints
[num
].in_use
= TRUE
;
211 fprintf( stderr
, "Breakpoint %d at ", num
);
212 DEBUG_PrintAddress( &breakpoints
[num
].addr
, breakpoints
[num
].addrlen
);
213 fprintf( stderr
, "\n" );
217 /***********************************************************************
218 * DEBUG_DelBreakpoint
220 * Delete a breakpoint.
222 void DEBUG_DelBreakpoint( int num
)
224 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
226 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
229 breakpoints
[num
].enabled
= FALSE
;
230 breakpoints
[num
].in_use
= FALSE
;
234 /***********************************************************************
235 * DEBUG_EnableBreakpoint
237 * Enable or disable a break point.
239 void DEBUG_EnableBreakpoint( int num
, BOOL enable
)
241 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
243 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
246 breakpoints
[num
].enabled
= enable
;
250 /***********************************************************************
251 * DEBUG_InfoBreakpoints
253 * Display break points information.
255 void DEBUG_InfoBreakpoints(void)
259 fprintf( stderr
, "Breakpoints:\n" );
260 for (i
= 1; i
< next_bp
; i
++)
262 if (breakpoints
[i
].in_use
)
264 fprintf( stderr
, "%d: %c ", i
, breakpoints
[i
].enabled
? 'y' : 'n');
265 DEBUG_PrintAddress( &breakpoints
[i
].addr
, breakpoints
[i
].addrlen
);
266 fprintf( stderr
, "\n" );
272 /***********************************************************************
273 * DEBUG_ShouldContinue
275 * Determine if we should continue execution after a SIGTRAP signal when
276 * executing in the given mode.
278 BOOL
DEBUG_ShouldContinue( struct sigcontext_struct
*context
,
279 enum exec_mode mode
)
284 /* If not single-stepping, back up over the int3 instruction */
285 if (!(EFL_reg(DEBUG_context
) & STEP_FLAG
)) EIP_reg(DEBUG_context
)--;
287 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
288 0 : CS_reg(DEBUG_context
);
289 addr
.off
= EIP_reg(DEBUG_context
);
291 bpnum
= DEBUG_FindBreakpoint( &addr
);
292 breakpoints
[0].enabled
= 0; /* disable the step-over breakpoint */
294 if ((bpnum
!= 0) && (bpnum
!= -1))
296 fprintf( stderr
, "Stopped on breakpoint %d at ", bpnum
);
297 DEBUG_PrintAddress( &breakpoints
[bpnum
].addr
,
298 breakpoints
[bpnum
].addrlen
);
299 fprintf( stderr
, "\n" );
302 /* no breakpoint, continue if in continuous mode */
303 return (mode
== EXEC_CONT
);
307 /***********************************************************************
308 * DEBUG_RestartExecution
310 * Set the breakpoints to the correct state to restart execution
313 void DEBUG_RestartExecution( struct sigcontext_struct
*context
,
314 enum exec_mode mode
, int instr_len
)
318 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
319 0 : CS_reg(DEBUG_context
);
320 addr
.off
= EIP_reg(DEBUG_context
);
322 if (DEBUG_FindBreakpoint( &addr
) != -1)
323 mode
= EXEC_STEP_INSTR
; /* If there's a breakpoint, skip it */
327 case EXEC_CONT
: /* Continuous execution */
328 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
329 DEBUG_SetBreakpoints( TRUE
);
332 case EXEC_STEP_OVER
: /* Stepping over a call */
333 if (DEBUG_IsStepOverInstr(DEBUG_context
))
335 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
336 addr
.off
+= instr_len
;
337 breakpoints
[0].addr
= addr
;
338 breakpoints
[0].enabled
= TRUE
;
339 breakpoints
[0].in_use
= TRUE
;
340 breakpoints
[0].opcode
= *(BYTE
*)DBG_ADDR_TO_LIN( &addr
);
341 DEBUG_SetBreakpoints( TRUE
);
344 /* else fall through to single-stepping */
346 case EXEC_STEP_INSTR
: /* Single-stepping an instruction */
347 EFL_reg(DEBUG_context
) |= STEP_FLAG
;