Release 960225
[wine.git] / debugger / break.c
blob78e4cc67822587176522d81069b3fa4b96d1ae02
1 /*
2 * Debugger break-points handling
4 * Copyright 1994 Martin von Loewis
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/mman.h>
11 #include "windows.h"
12 #include "debugger.h"
14 #define INT3 0xcc /* int 3 opcode */
16 #define MAX_BREAKPOINTS 25
18 typedef struct
20 DBG_ADDR addr;
21 BYTE addrlen;
22 BYTE opcode;
23 BOOL enabled;
24 BOOL in_use;
25 } BREAKPOINT;
27 static BREAKPOINT breakpoints[MAX_BREAKPOINTS];
29 static int next_bp = 1; /* breakpoint 0 is reserved for step-over */
32 /***********************************************************************
33 * DEBUG_ChangeOpcode
35 * Change the opcode at segment:addr.
37 static void DEBUG_SetOpcode( const DBG_ADDR *addr, BYTE op )
39 if (addr->seg)
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
50 in the first place?
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" );
58 return;
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));
77 for (;;)
79 switch(*instr)
81 /* Skip all prefixes */
83 case 0x2e: /* cs: */
84 case 0x36: /* ss: */
85 case 0x3e: /* ds: */
86 case 0x26: /* es: */
87 case 0x64: /* fs: */
88 case 0x65: /* gs: */
89 case 0x66: /* opcode size prefix */
90 case 0x67: /* addr size prefix */
91 case 0xf0: /* lock */
92 case 0xf2: /* repne */
93 case 0xf3: /* repe */
94 instr++;
95 continue;
97 /* Handle call instructions */
99 case 0xe8: /* call <offset> */
100 case 0x9a: /* lcall <seg>:<off> */
101 return TRUE;
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 */
123 return TRUE;
125 default:
126 return FALSE;
132 /***********************************************************************
133 * DEBUG_SetBreakpoints
135 * Set or remove all the breakpoints.
137 void DEBUG_SetBreakpoints( BOOL set )
139 int i;
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 )
165 int i;
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;
173 return -1;
177 /***********************************************************************
178 * DEBUG_AddBreakpoint
180 * Add a breakpoint.
182 void DEBUG_AddBreakpoint( const DBG_ADDR *address )
184 DBG_ADDR addr = *address;
185 int num;
186 BYTE *p;
188 DBG_FIX_ADDR_SEG( &addr, CS_reg(DEBUG_context) );
190 if (next_bp < MAX_BREAKPOINTS)
191 num = next_bp++;
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" );
199 return;
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 );
226 return;
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 );
243 return;
245 breakpoints[num].enabled = enable;
249 /***********************************************************************
250 * DEBUG_InfoBreakpoints
252 * Display break points information.
254 void DEBUG_InfoBreakpoints(void)
256 int i;
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 )
280 DBG_ADDR addr;
281 int bpnum;
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" );
299 return FALSE;
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
310 * in the given mode.
312 void DEBUG_RestartExecution( struct sigcontext_struct *context,
313 enum exec_mode mode, int instr_len )
315 DBG_ADDR addr;
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 */
324 switch(mode)
326 case EXEC_CONT: /* Continuous execution */
327 EFL_reg(DEBUG_context) &= ~STEP_FLAG;
328 DEBUG_SetBreakpoints( TRUE );
329 break;
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 );
341 break;
343 /* else fall through to single-stepping */
345 case EXEC_STEP_INSTR: /* Single-stepping an instruction */
346 EFL_reg(DEBUG_context) |= STEP_FLAG;
347 break;