Release 960405
[wine/multimedia.git] / debugger / break.c
blobedbddb8936ae97babcef1e7a18cb5060aeb93640
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/types.h>
11 #include <sys/mman.h>
12 #include "windows.h"
13 #include "debugger.h"
15 #define INT3 0xcc /* int 3 opcode */
17 #define MAX_BREAKPOINTS 25
19 typedef struct
21 DBG_ADDR addr;
22 BYTE addrlen;
23 BYTE opcode;
24 BOOL enabled;
25 BOOL in_use;
26 } BREAKPOINT;
28 static BREAKPOINT breakpoints[MAX_BREAKPOINTS];
30 static int next_bp = 1; /* breakpoint 0 is reserved for step-over */
33 /***********************************************************************
34 * DEBUG_ChangeOpcode
36 * Change the opcode at segment:addr.
38 static void DEBUG_SetOpcode( const DBG_ADDR *addr, BYTE op )
40 if (addr->seg)
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
51 in the first place?
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" );
59 return;
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));
78 for (;;)
80 switch(*instr)
82 /* Skip all prefixes */
84 case 0x2e: /* cs: */
85 case 0x36: /* ss: */
86 case 0x3e: /* ds: */
87 case 0x26: /* es: */
88 case 0x64: /* fs: */
89 case 0x65: /* gs: */
90 case 0x66: /* opcode size prefix */
91 case 0x67: /* addr size prefix */
92 case 0xf0: /* lock */
93 case 0xf2: /* repne */
94 case 0xf3: /* repe */
95 instr++;
96 continue;
98 /* Handle call instructions */
100 case 0xe8: /* call <offset> */
101 case 0x9a: /* lcall <seg>:<off> */
102 return TRUE;
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 */
124 return TRUE;
126 default:
127 return FALSE;
133 /***********************************************************************
134 * DEBUG_SetBreakpoints
136 * Set or remove all the breakpoints.
138 void DEBUG_SetBreakpoints( BOOL set )
140 int i;
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 )
166 int i;
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;
174 return -1;
178 /***********************************************************************
179 * DEBUG_AddBreakpoint
181 * Add a breakpoint.
183 void DEBUG_AddBreakpoint( const DBG_ADDR *address )
185 DBG_ADDR addr = *address;
186 int num;
187 BYTE *p;
189 DBG_FIX_ADDR_SEG( &addr, CS_reg(DEBUG_context) );
191 if (next_bp < MAX_BREAKPOINTS)
192 num = next_bp++;
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" );
200 return;
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 );
227 return;
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 );
244 return;
246 breakpoints[num].enabled = enable;
250 /***********************************************************************
251 * DEBUG_InfoBreakpoints
253 * Display break points information.
255 void DEBUG_InfoBreakpoints(void)
257 int i;
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 )
281 DBG_ADDR addr;
282 int bpnum;
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" );
300 return FALSE;
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
311 * in the given mode.
313 void DEBUG_RestartExecution( struct sigcontext_struct *context,
314 enum exec_mode mode, int instr_len )
316 DBG_ADDR addr;
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 */
325 switch(mode)
327 case EXEC_CONT: /* Continuous execution */
328 EFL_reg(DEBUG_context) &= ~STEP_FLAG;
329 DEBUG_SetBreakpoints( TRUE );
330 break;
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 );
342 break;
344 /* else fall through to single-stepping */
346 case EXEC_STEP_INSTR: /* Single-stepping an instruction */
347 EFL_reg(DEBUG_context) |= STEP_FLAG;
348 break;