2 * Debugger break-points handling
4 * Copyright 1994 Martin von Loewis
5 * Copyright 1995 Alexandre Julliard
12 #include <sys/utsname.h>
17 #define INT3 0xcc /* int 3 opcode */
18 #define STEP_FLAG 0x100 /* single-step flag */
20 #define MAX_BREAKPOINTS 25
32 static BREAKPOINT breakpoints[MAX_BREAKPOINTS] = { { 0, }, };
34 static int next_bp = 1; /* breakpoint 0 is reserved for step-over */
37 /***********************************************************************
40 * Change the opcode at segment:addr.
42 static void DEBUG_SetOpcode( unsigned int segment, unsigned int addr, BYTE op )
46 *(BYTE *)PTR_SEG_OFF_TO_LIN( segment, addr ) = op;
48 else /* 32-bit code, so we have to change the protection first */
50 /* There are a couple of problems with this. On Linux prior to
51 1.1.62, this call fails (ENOACCESS) due to a bug in fs/exec.c.
52 This code is currently not tested at all on BSD.
53 How do I determine the page size in a more symbolic manner?
54 And why does mprotect need that start address of the page
56 Not that portability matters, this code is i386 only anyways...
57 How do I get the old protection in order to restore it later on?
59 if (mprotect((caddr_t)(addr & (~4095)), 4096,
60 PROT_READ|PROT_WRITE|PROT_EXEC) == -1)
62 perror( "Can't set break point" );
66 mprotect((caddr_t)(addr & ~4095), 4096, PROT_READ|PROT_EXEC);
71 /***********************************************************************
72 * DEBUG_SetBreakpoints
74 * Set or remove all the breakpoints.
76 void DEBUG_SetBreakpoints( BOOL set )
80 for (i = 0; i < MAX_BREAKPOINTS; i++)
82 if (breakpoints[i].in_use && breakpoints[i].enabled)
83 DEBUG_SetOpcode( breakpoints[i].segment, breakpoints[i].addr,
84 set ? INT3 : breakpoints[i].opcode );
89 /***********************************************************************
90 * DEBUG_FindBreakpoint
92 * Find the breakpoint for a given address. Return the breakpoint
93 * number or -1 if none.
95 int DEBUG_FindBreakpoint( unsigned int segment, unsigned int addr )
99 for (i = 0; i < MAX_BREAKPOINTS; i++)
101 if (breakpoints[i].in_use && breakpoints[i].enabled &&
102 breakpoints[i].segment == segment && breakpoints[i].addr == addr)
109 /***********************************************************************
110 * DEBUG_AddBreakpoint
114 void DEBUG_AddBreakpoint( unsigned int segment, unsigned int addr )
119 if (segment == 0xffffffff) segment = CS;
120 if (segment == WINE_CODE_SELECTOR) segment = 0;
122 if (next_bp < MAX_BREAKPOINTS)
124 else /* try to find an empty slot */
126 for (num = 1; num < MAX_BREAKPOINTS; num++)
127 if (!breakpoints[num].in_use) break;
128 if (num >= MAX_BREAKPOINTS)
130 fprintf( stderr, "Too many breakpoints. Please delete some.\n" );
134 p = segment ? (BYTE *)PTR_SEG_OFF_TO_LIN( segment, addr ) : (BYTE *)addr;
135 breakpoints[num].segment = segment;
136 breakpoints[num].addr = addr;
137 breakpoints[num].addrlen = !segment ? 32 :
138 (GET_SEL_FLAGS(segment) & LDT_FLAGS_32BIT) ? 32 : 16;
139 breakpoints[num].opcode = *p;
140 breakpoints[num].enabled = TRUE;
141 breakpoints[num].in_use = TRUE;
142 fprintf( stderr, "Breakpoint %d at ", num );
143 print_address( segment, addr, breakpoints[num].addrlen );
144 fprintf( stderr, "\n" );
148 /***********************************************************************
149 * DEBUG_DelBreakpoint
151 * Delete a breakpoint.
153 void DEBUG_DelBreakpoint( int num )
155 if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
157 fprintf( stderr, "Invalid breakpoint number %d\n", num );
160 breakpoints[num].enabled = FALSE;
161 breakpoints[num].in_use = FALSE;
165 /***********************************************************************
166 * DEBUG_EnableBreakpoint
168 * Enable or disable a break point.
170 void DEBUG_EnableBreakpoint( int num, BOOL enable )
172 if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
174 fprintf( stderr, "Invalid breakpoint number %d\n", num );
177 breakpoints[num].enabled = enable;
181 /***********************************************************************
182 * DEBUG_InfoBreakpoints
184 * Display break points information.
186 void DEBUG_InfoBreakpoints(void)
190 fprintf( stderr, "Breakpoints:\n" );
191 for (i = 1; i < next_bp; i++)
193 if (breakpoints[i].in_use)
195 fprintf( stderr, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n');
196 print_address( breakpoints[i].segment, breakpoints[i].addr,
197 breakpoints[i].addrlen );
198 fprintf( stderr, "\n" );
204 /***********************************************************************
205 * DEBUG_ShouldContinue
207 * Determine if we should continue execution after a SIGTRAP signal when
208 * executing in the given mode.
210 BOOL DEBUG_ShouldContinue( struct sigcontext_struct *context,
211 enum exec_mode mode )
213 unsigned int segment, addr;
216 /* If not single-stepping, back up over the int3 instruction */
217 if (!(EFL & STEP_FLAG)) EIP--;
219 segment = (CS == WINE_CODE_SELECTOR) ? 0 : CS;
221 bpnum = DEBUG_FindBreakpoint( segment, addr );
222 breakpoints[0].enabled = 0; /* disable the step-over breakpoint */
224 if ((bpnum != 0) && (bpnum != -1))
226 fprintf( stderr, "Stopped on breakpoint %d at ", bpnum );
227 print_address( breakpoints[bpnum].segment, breakpoints[bpnum].addr,
228 breakpoints[bpnum].addrlen );
229 fprintf( stderr, "\n" );
232 /* no breakpoint, continue if in continuous mode */
233 return (mode == EXEC_CONT);
237 /***********************************************************************
238 * DEBUG_RestartExecution
240 * Set the breakpoints to the correct state to restart execution
243 void DEBUG_RestartExecution( struct sigcontext_struct *context,
244 enum exec_mode mode, int instr_len )
246 unsigned int segment, addr;
248 segment = (CS == WINE_CODE_SELECTOR) ? 0 : CS;
251 if (DEBUG_FindBreakpoint( segment, addr ) != -1)
252 mode = EXEC_STEP_INSTR; /* If there's a breakpoint, skip it */
256 case EXEC_CONT: /* Continuous execution */
258 DEBUG_SetBreakpoints( TRUE );
261 case EXEC_STEP_OVER: /* Stepping over a call */
263 breakpoints[0].segment = segment;
264 breakpoints[0].addr = addr + instr_len;
265 breakpoints[0].enabled = TRUE;
266 breakpoints[0].in_use = TRUE;
267 breakpoints[0].opcode = segment ?
268 *(BYTE *)PTR_SEG_OFF_TO_LIN(segment,addr+instr_len) : *(BYTE *)addr;
269 DEBUG_SetBreakpoints( TRUE );
272 case EXEC_STEP_INSTR: /* Single-stepping an instruction */