Release 950706
[wine] / debugger / break.c
1 /*
2  * Debugger break-points handling
3  *
4  * Copyright 1994 Martin von Loewis
5  * Copyright 1995 Alexandre Julliard
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/mman.h>
11 #ifdef linux
12 #include <sys/utsname.h>
13 #endif
14 #include "windows.h"
15 #include "debugger.h"
16
17 #define INT3          0xcc   /* int 3 opcode */
18 #define STEP_FLAG     0x100  /* single-step flag */
19
20 #define MAX_BREAKPOINTS 25
21
22 typedef struct
23 {
24     unsigned int  segment;
25     unsigned int  addr;
26     BYTE          addrlen;
27     BYTE          opcode;
28     BOOL          enabled;
29     BOOL          in_use;
30 } BREAKPOINT;
31
32 static BREAKPOINT breakpoints[MAX_BREAKPOINTS] = { { 0, }, };
33
34 static int next_bp = 1;  /* breakpoint 0 is reserved for step-over */
35
36
37 /***********************************************************************
38  *           DEBUG_ChangeOpcode
39  *
40  * Change the opcode at segment:addr.
41  */
42 static void DEBUG_SetOpcode( unsigned int segment, unsigned int addr, BYTE op )
43 {
44     if (segment)
45     {
46         *(BYTE *)PTR_SEG_OFF_TO_LIN( segment, addr ) = op;
47     }
48     else  /* 32-bit code, so we have to change the protection first */
49     {
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
55            in the first place?
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?
58         */
59         if (mprotect((caddr_t)(addr & (~4095)), 4096,
60                      PROT_READ|PROT_WRITE|PROT_EXEC) == -1)
61         {
62             perror( "Can't set break point" );
63             return;
64         }
65         *(BYTE *)addr = op;
66         mprotect((caddr_t)(addr & ~4095), 4096, PROT_READ|PROT_EXEC);
67     }
68 }
69
70
71 /***********************************************************************
72  *           DEBUG_SetBreakpoints
73  *
74  * Set or remove all the breakpoints.
75  */
76 void DEBUG_SetBreakpoints( BOOL set )
77 {
78     int i;
79
80     for (i = 0; i < MAX_BREAKPOINTS; i++)
81     {
82         if (breakpoints[i].in_use && breakpoints[i].enabled)
83             DEBUG_SetOpcode( breakpoints[i].segment, breakpoints[i].addr,
84                              set ? INT3 : breakpoints[i].opcode );
85     }
86 }
87
88
89 /***********************************************************************
90  *           DEBUG_FindBreakpoint
91  *
92  * Find the breakpoint for a given address. Return the breakpoint
93  * number or -1 if none.
94  */
95 int DEBUG_FindBreakpoint( unsigned int segment, unsigned int addr )
96 {
97     int i;
98
99     for (i = 0; i < MAX_BREAKPOINTS; i++)
100     {
101         if (breakpoints[i].in_use && breakpoints[i].enabled &&
102             breakpoints[i].segment == segment && breakpoints[i].addr == addr)
103             return i;
104     }
105     return -1;
106 }
107
108
109 /***********************************************************************
110  *           DEBUG_AddBreakpoint
111  *
112  * Add a breakpoint.
113  */
114 void DEBUG_AddBreakpoint( unsigned int segment, unsigned int addr )
115 {
116     int num;
117     BYTE *p;
118
119     if (segment == 0xffffffff) segment = CS;
120     if (segment == WINE_CODE_SELECTOR) segment = 0;
121
122     if (next_bp < MAX_BREAKPOINTS)
123         num = next_bp++;
124     else  /* try to find an empty slot */  
125     {
126         for (num = 1; num < MAX_BREAKPOINTS; num++)
127             if (!breakpoints[num].in_use) break;
128         if (num >= MAX_BREAKPOINTS)
129         {
130             fprintf( stderr, "Too many breakpoints. Please delete some.\n" );
131             return;
132         }
133     }
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" );
145 }
146
147
148 /***********************************************************************
149  *           DEBUG_DelBreakpoint
150  *
151  * Delete a breakpoint.
152  */
153 void DEBUG_DelBreakpoint( int num )
154 {
155     if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
156     {
157         fprintf( stderr, "Invalid breakpoint number %d\n", num );
158         return;
159     }
160     breakpoints[num].enabled = FALSE;
161     breakpoints[num].in_use  = FALSE;
162 }
163
164
165 /***********************************************************************
166  *           DEBUG_EnableBreakpoint
167  *
168  * Enable or disable a break point.
169  */
170 void DEBUG_EnableBreakpoint( int num, BOOL enable )
171 {
172     if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
173     {
174         fprintf( stderr, "Invalid breakpoint number %d\n", num );
175         return;
176     }
177     breakpoints[num].enabled = enable;
178 }
179
180
181 /***********************************************************************
182  *           DEBUG_InfoBreakpoints
183  *
184  * Display break points information.
185  */
186 void DEBUG_InfoBreakpoints(void)
187 {
188     int i;
189
190     fprintf( stderr, "Breakpoints:\n" );
191     for (i = 1; i < next_bp; i++)
192     {
193         if (breakpoints[i].in_use)
194         {
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" );
199         }
200     }
201 }
202
203
204 /***********************************************************************
205  *           DEBUG_ShouldContinue
206  *
207  * Determine if we should continue execution after a SIGTRAP signal when
208  * executing in the given mode.
209  */
210 BOOL DEBUG_ShouldContinue( struct sigcontext_struct *context,
211                            enum exec_mode mode )
212 {
213     unsigned int segment, addr;
214     int bpnum;
215
216       /* If not single-stepping, back up over the int3 instruction */
217     if (!(EFL & STEP_FLAG)) EIP--;
218
219     segment = (CS == WINE_CODE_SELECTOR) ? 0 : CS;
220     addr    = EIP;
221     bpnum  = DEBUG_FindBreakpoint( segment, addr );
222     breakpoints[0].enabled = 0;  /* disable the step-over breakpoint */
223
224     if ((bpnum != 0) && (bpnum != -1))
225     {
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" );
230         return FALSE;
231     }
232       /* no breakpoint, continue if in continuous mode */
233     return (mode == EXEC_CONT);
234 }
235
236
237 /***********************************************************************
238  *           DEBUG_RestartExecution
239  *
240  * Set the breakpoints to the correct state to restart execution
241  * in the given mode.
242  */
243 void DEBUG_RestartExecution( struct sigcontext_struct *context,
244                              enum exec_mode mode, int instr_len )
245 {
246     unsigned int segment, addr;
247
248     segment = (CS == WINE_CODE_SELECTOR) ? 0 : CS;
249     addr    = EIP;
250
251     if (DEBUG_FindBreakpoint( segment, addr ) != -1)
252         mode = EXEC_STEP_INSTR;  /* If there's a breakpoint, skip it */
253
254     switch(mode)
255     {
256     case EXEC_CONT: /* Continuous execution */
257         EFL &= ~STEP_FLAG;
258         DEBUG_SetBreakpoints( TRUE );
259         break;
260
261     case EXEC_STEP_OVER:  /* Stepping over a call */
262         EFL &= ~STEP_FLAG;
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 );
270         break;
271
272     case EXEC_STEP_INSTR: /* Single-stepping an instruction */
273         EFL |= STEP_FLAG;
274         break;
275     }
276 }