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
);
209 fprintf( stderr
, "\n" );
213 /***********************************************************************
214 * DEBUG_DelBreakpoint
216 * Delete a breakpoint.
218 void DEBUG_DelBreakpoint( int num
)
220 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
222 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
225 breakpoints
[num
].enabled
= FALSE
;
226 breakpoints
[num
].in_use
= FALSE
;
230 /***********************************************************************
231 * DEBUG_EnableBreakpoint
233 * Enable or disable a break point.
235 void DEBUG_EnableBreakpoint( int num
, BOOL32 enable
)
237 if ((num
<= 0) || (num
>= next_bp
) || !breakpoints
[num
].in_use
)
239 fprintf( stderr
, "Invalid breakpoint number %d\n", num
);
242 breakpoints
[num
].enabled
= enable
;
246 /***********************************************************************
247 * DEBUG_InfoBreakpoints
249 * Display break points information.
251 void DEBUG_InfoBreakpoints(void)
255 fprintf( stderr
, "Breakpoints:\n" );
256 for (i
= 1; i
< next_bp
; i
++)
258 if (breakpoints
[i
].in_use
)
260 fprintf( stderr
, "%d: %c ", i
, breakpoints
[i
].enabled
? 'y' : 'n');
261 DEBUG_PrintAddress( &breakpoints
[i
].addr
, breakpoints
[i
].addrlen
);
262 fprintf( stderr
, "\n" );
268 /***********************************************************************
269 * DEBUG_ShouldContinue
271 * Determine if we should continue execution after a SIGTRAP signal when
272 * executing in the given mode.
274 BOOL32
DEBUG_ShouldContinue( SIGCONTEXT
*context
, enum exec_mode mode
)
279 /* If not single-stepping, back up over the int3 instruction */
280 if (!(EFL_reg(DEBUG_context
) & STEP_FLAG
)) EIP_reg(DEBUG_context
)--;
282 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
283 0 : CS_reg(DEBUG_context
);
284 addr
.off
= EIP_reg(DEBUG_context
);
286 bpnum
= DEBUG_FindBreakpoint( &addr
);
287 breakpoints
[0].enabled
= 0; /* disable the step-over breakpoint */
289 if ((bpnum
!= 0) && (bpnum
!= -1))
291 fprintf( stderr
, "Stopped on breakpoint %d at ", bpnum
);
292 DEBUG_PrintAddress( &breakpoints
[bpnum
].addr
,
293 breakpoints
[bpnum
].addrlen
);
294 fprintf( stderr
, "\n" );
298 /* If there's no breakpoint and we are not single-stepping, then we */
299 /* must have encountered an int3 in the Windows program; let's skip it. */
300 if ((bpnum
== -1) && !(EFL_reg(DEBUG_context
) & STEP_FLAG
))
301 EIP_reg(DEBUG_context
)++;
303 /* no breakpoint, continue if in continuous mode */
304 return (mode
== EXEC_CONT
);
308 /***********************************************************************
309 * DEBUG_RestartExecution
311 * Set the breakpoints to the correct state to restart execution
314 void DEBUG_RestartExecution( SIGCONTEXT
*context
, enum exec_mode mode
,
319 addr
.seg
= (CS_reg(DEBUG_context
) == WINE_CODE_SELECTOR
) ?
320 0 : CS_reg(DEBUG_context
);
321 addr
.off
= EIP_reg(DEBUG_context
);
323 if (DEBUG_FindBreakpoint( &addr
) != -1)
324 mode
= EXEC_STEP_INSTR
; /* If there's a breakpoint, skip it */
328 case EXEC_CONT
: /* Continuous execution */
329 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
330 DEBUG_SetBreakpoints( TRUE
);
333 case EXEC_STEP_OVER
: /* Stepping over a call */
334 if (DEBUG_IsStepOverInstr(DEBUG_context
))
336 EFL_reg(DEBUG_context
) &= ~STEP_FLAG
;
337 addr
.off
+= instr_len
;
338 breakpoints
[0].addr
= addr
;
339 breakpoints
[0].enabled
= TRUE
;
340 breakpoints
[0].in_use
= TRUE
;
341 breakpoints
[0].opcode
= *(BYTE
*)DBG_ADDR_TO_LIN( &addr
);
342 DEBUG_SetBreakpoints( TRUE
);
345 /* else fall through to single-stepping */
347 case EXEC_STEP_INSTR
: /* Single-stepping an instruction */
348 EFL_reg(DEBUG_context
) |= STEP_FLAG
;