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 if (addr
->seg
) ptr
= (BYTE
*)PTR_SEG_OFF_TO_LIN( addr
->seg
, addr
->off
);
43 else ptr
= (BYTE
*)addr
->off
;
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 get the old protection in order to restore it later on?
50 if (mprotect((caddr_t
)((int)ptr
& (~4095)), 4096,
51 PROT_READ
| PROT_WRITE
| PROT_EXEC
) == -1)
53 perror( "Can't set break point" );
57 /* mprotect((caddr_t)(addr->off & ~4095), 4096,
58 PROT_READ | PROT_EXEC ); */
62 /***********************************************************************
63 * DEBUG_IsStepOverInstr
65 * Determine if the instruction at CS:EIP is an instruction that
66 * we need to step over (like a call or a repetitive string move).
68 static BOOL32
DEBUG_IsStepOverInstr( SIGCONTEXT
*context
)
70 BYTE
*instr
= (BYTE
*)PTR_SEG_OFF_TO_LIN(CS_reg(context
),EIP_reg(context
));
76 /* Skip all prefixes */
84 case 0x66: /* opcode size prefix */
85 case 0x67: /* addr size prefix */
87 case 0xf2: /* repne */
92 /* Handle call instructions */
94 case 0xe8: /* call <offset> */
95 case 0x9a: /* lcall <seg>:<off> */
98 case 0xff: /* call <regmodrm> */
99 return (((instr
[1] & 0x38) == 0x10) ||
100 ((instr
[1] & 0x38) == 0x18));
102 /* Handle string instructions */
104 case 0x6c: /* insb */
105 case 0x6d: /* insw */
106 case 0x6e: /* outsb */
107 case 0x6f: /* outsw */
108 case 0xa4: /* movsb */
109 case 0xa5: /* movsw */
110 case 0xa6: /* cmpsb */
111 case 0xa7: /* cmpsw */
112 case 0xaa: /* stosb */
113 case 0xab: /* stosw */
114 case 0xac: /* lodsb */
115 case 0xad: /* lodsw */
116 case 0xae: /* scasb */
117 case 0xaf: /* scasw */
127 /***********************************************************************
128 * DEBUG_SetBreakpoints
130 * Set or remove all the breakpoints.
132 void DEBUG_SetBreakpoints( BOOL32 set
)
136 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
138 if (breakpoints
[i
].in_use
&& breakpoints
[i
].enabled
)
140 /* Note: we check for read here, because if reading is allowed */
141 /* writing permission will be forced in DEBUG_SetOpcode. */
142 if (DEBUG_IsBadReadPtr( &breakpoints
[i
].addr
, 1 ))
144 fprintf( stderr
, "Invalid address for breakpoint %d, disabling it\n", i
);
145 breakpoints
[i
].enabled
= FALSE
;
147 else DEBUG_SetOpcode( &breakpoints
[i
].addr
,
148 set
? INT3
: breakpoints
[i
].opcode
);
154 /***********************************************************************
155 * DEBUG_FindBreakpoint
157 * Find the breakpoint for a given address. Return the breakpoint
158 * number or -1 if none.
160 int DEBUG_FindBreakpoint( const DBG_ADDR
*addr
)
164 for (i
= 0; i
< MAX_BREAKPOINTS
; i
++)
166 if (breakpoints
[i
].in_use
&& breakpoints
[i
].enabled
&&
167 breakpoints
[i
].addr
.seg
== addr
->seg
&&
168 breakpoints
[i
].addr
.off
== addr
->off
) return i
;
174 /***********************************************************************
175 * DEBUG_AddBreakpoint
179 void DEBUG_AddBreakpoint( const DBG_ADDR
*address
)
181 DBG_ADDR addr
= *address
;
185 DBG_FIX_ADDR_SEG( &addr
, CS_reg(DEBUG_context
) );
187 if (next_bp
< MAX_BREAKPOINTS
)
189 else /* try to find an empty slot */
191 for (num
= 1; num
< MAX_BREAKPOINTS
; num
++)
192 if (!breakpoints
[num
].in_use
) break;
193 if (num
>= MAX_BREAKPOINTS
)
195 fprintf( stderr
, "Too many breakpoints. Please delete some.\n" );
199 if (!DBG_CHECK_READ_PTR( &addr
, 1 )) return;
200 p
= DBG_ADDR_TO_LIN( &addr
);
201 breakpoints
[num
].addr
= addr
;
202 breakpoints
[num
].addrlen
= !addr
.seg
? 32 :
203 (GET_SEL_FLAGS(addr
.seg
) & LDT_FLAGS_32BIT
) ? 32 : 16;
204 breakpoints
[num
].opcode
= *p
;
205 breakpoints
[num
].enabled
= TRUE
;
206 breakpoints
[num
].in_use
= TRUE
;
207 fprintf( stderr
, "Breakpoint %d at ", num
);
208 DEBUG_PrintAddress( &breakpoints
[num
].addr
, breakpoints
[num
].addrlen
,
210 fprintf( stderr
, "\n" );
214 /***********************************************************************
215 * DEBUG_DelBreakpoint
217 * Delete a breakpoint.
219 void DEBUG_DelBreakpoint( int num
)
221 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
223 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
226 breakpoints
[num
].enabled
= FALSE
;
227 breakpoints
[num
].in_use
= FALSE
;
231 /***********************************************************************
232 * DEBUG_EnableBreakpoint
234 * Enable or disable a break point.
236 void DEBUG_EnableBreakpoint( int num
, BOOL32 enable
)
238 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
240 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
243 breakpoints
[num
].enabled
= enable
;
247 /***********************************************************************
248 * DEBUG_InfoBreakpoints
250 * Display break points information.
252 void DEBUG_InfoBreakpoints(void)
256 fprintf( stderr
, "Breakpoints:\n" );
257 for (i
= 1; i
< next_bp
; i
++)
259 if (breakpoints
[i
].in_use
)
261 fprintf( stderr
, "%d: %c ", i
, breakpoints
[i
].enabled
? 'y' : 'n');
262 DEBUG_PrintAddress( &breakpoints
[i
].addr
, breakpoints
[i
].addrlen
,
264 fprintf( stderr
, "\n" );
270 /***********************************************************************
271 * DEBUG_ShouldContinue
273 * Determine if we should continue execution after a SIGTRAP signal when
274 * executing in the given mode.
276 BOOL32
DEBUG_ShouldContinue( SIGCONTEXT
*context
, enum exec_mode mode
)
281 /* If not single-stepping, back up over the int3 instruction */
282 if (!(EFL_reg(DEBUG_context
) & STEP_FLAG
)) EIP_reg(DEBUG_context
)--;
284 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
285 0 : CS_reg(DEBUG_context
);
286 addr
.off
= EIP_reg(DEBUG_context
);
288 bpnum
= DEBUG_FindBreakpoint( &addr
);
289 breakpoints
[0].enabled
= 0; /* disable the step-over breakpoint */
291 if ((bpnum
!= 0) && (bpnum
!= -1))
293 fprintf( stderr
, "Stopped on breakpoint %d at ", bpnum
);
294 DEBUG_PrintAddress( &breakpoints
[bpnum
].addr
,
295 breakpoints
[bpnum
].addrlen
, TRUE
);
296 fprintf( stderr
, "\n" );
300 /* If there's no breakpoint and we are not single-stepping, then we */
301 /* must have encountered an int3 in the Windows program; let's skip it. */
302 if ((bpnum
== -1) && !(EFL_reg(DEBUG_context
) & STEP_FLAG
))
303 EIP_reg(DEBUG_context
)++;
305 /* no breakpoint, continue if in continuous mode */
306 return (mode
== EXEC_CONT
);
310 /***********************************************************************
311 * DEBUG_RestartExecution
313 * Set the breakpoints to the correct state to restart execution
316 void DEBUG_RestartExecution( SIGCONTEXT
*context
, enum exec_mode mode
,
321 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
322 0 : CS_reg(DEBUG_context
);
323 addr
.off
= EIP_reg(DEBUG_context
);
325 if (DEBUG_FindBreakpoint( &addr
) != -1)
326 mode
= EXEC_STEP_INSTR
; /* If there's a breakpoint, skip it */
330 case EXEC_CONT
: /* Continuous execution */
331 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
332 DEBUG_SetBreakpoints( TRUE
);
335 case EXEC_STEP_OVER
: /* Stepping over a call */
336 if (DEBUG_IsStepOverInstr(DEBUG_context
))
338 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
339 addr
.off
+= instr_len
;
340 breakpoints
[0].addr
= addr
;
341 breakpoints
[0].enabled
= TRUE
;
342 breakpoints
[0].in_use
= TRUE
;
343 breakpoints
[0].opcode
= *(BYTE
*)DBG_ADDR_TO_LIN( &addr
);
344 DEBUG_SetBreakpoints( TRUE
);
347 /* else fall through to single-stepping */
349 case EXEC_STEP_INSTR
: /* Single-stepping an instruction */
350 EFL_reg(DEBUG_context
) |= STEP_FLAG
;