No longer directly accessing debuggee memory.
[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 "config.h"
9 #include <stdio.h>
10 #include "debugger.h"
11
12 #define INT3          0xcc   /* int 3 opcode */
13
14 #define MAX_BREAKPOINTS 100
15
16 static BREAKPOINT breakpoints[MAX_BREAKPOINTS];
17
18 static int next_bp = 1;  /* breakpoint 0 is reserved for step-over */
19
20
21 /***********************************************************************
22  *           DEBUG_IsStepOverInstr
23  *
24  * Determine if the instruction at CS:EIP is an instruction that
25  * we need to step over (like a call or a repetitive string move).
26  */
27 static BOOL DEBUG_IsStepOverInstr(void)
28 {
29 #ifdef __i386__
30     BYTE*       instr;
31     BYTE        ch;
32     DBG_ADDR    addr;
33
34     addr.seg = DEBUG_context.SegCs;
35     addr.off = DEBUG_context.Eip;
36     /* FIXME: old code was using V86BASE(DEBUG_context)
37      * instead of passing thru DOSMEM_MemoryBase
38      */
39     instr = (BYTE*)DEBUG_ToLinear(&addr);
40
41     for (;;)
42     {
43         if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch)))
44             return FALSE;
45
46         switch (ch)
47         {
48           /* Skip all prefixes */
49
50         case 0x2e:  /* cs: */
51         case 0x36:  /* ss: */
52         case 0x3e:  /* ds: */
53         case 0x26:  /* es: */
54         case 0x64:  /* fs: */
55         case 0x65:  /* gs: */
56         case 0x66:  /* opcode size prefix */
57         case 0x67:  /* addr size prefix */
58         case 0xf0:  /* lock */
59         case 0xf2:  /* repne */
60         case 0xf3:  /* repe */
61             instr++;
62             continue;
63
64           /* Handle call instructions */
65
66         case 0xcd:  /* int <intno> */
67         case 0xe8:  /* call <offset> */
68         case 0x9a:  /* lcall <seg>:<off> */
69             return TRUE;
70
71         case 0xff:  /* call <regmodrm> */
72             if (!DEBUG_READ_MEM(instr + 1, &ch, sizeof(ch)))
73                 return FALSE;
74             return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
75
76           /* Handle string instructions */
77
78         case 0x6c:  /* insb */
79         case 0x6d:  /* insw */
80         case 0x6e:  /* outsb */
81         case 0x6f:  /* outsw */
82         case 0xa4:  /* movsb */
83         case 0xa5:  /* movsw */
84         case 0xa6:  /* cmpsb */
85         case 0xa7:  /* cmpsw */
86         case 0xaa:  /* stosb */
87         case 0xab:  /* stosw */
88         case 0xac:  /* lodsb */
89         case 0xad:  /* lodsw */
90         case 0xae:  /* scasb */
91         case 0xaf:  /* scasw */
92             return TRUE;
93
94         default:
95             return FALSE;
96         }
97     }
98 #else
99     return FALSE;
100 #endif
101 }
102
103
104 /***********************************************************************
105  *           DEBUG_IsFctReturn
106  *
107  * Determine if the instruction at CS:EIP is an instruction that
108  * is a function return.
109  */
110 BOOL DEBUG_IsFctReturn(void)
111 {
112 #ifdef __i386__
113     BYTE*       instr;
114     BYTE        ch;
115     DBG_ADDR    addr;
116
117     addr.seg = DEBUG_context.SegCs;
118     addr.off = DEBUG_context.Eip;
119     /* FIXME: old code was using V86BASE(DEBUG_context)
120      * instead of passing thru DOSMEM_MemoryBase
121      */
122     instr = (BYTE*)DEBUG_ToLinear(&addr);
123
124     if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch)))
125        return FALSE;
126
127     return (ch == 0xc2) || (ch == 0xc3);
128 #else
129     return FALSE;
130 #endif
131 }
132
133
134 /***********************************************************************
135  *           DEBUG_SetBreakpoints
136  *
137  * Set or remove all the breakpoints.
138  */
139 void DEBUG_SetBreakpoints( BOOL set )
140 {
141     int         i;
142     char        ch;
143
144     for (i = 0; i < MAX_BREAKPOINTS; i++)
145     {
146         if (breakpoints[i].refcount && breakpoints[i].enabled)
147         {
148             ch = set ? INT3 : breakpoints[i].opcode;
149
150             if (!DEBUG_WRITE_MEM( (void*)DEBUG_ToLinear(&breakpoints[i].addr), &ch, sizeof(ch) ))
151             {
152                 fprintf( stderr, "Invalid address for breakpoint %d, disabling it\n", i );
153                 breakpoints[i].enabled = FALSE;
154             }
155         }
156     }
157 }
158
159
160 /***********************************************************************
161  *           DEBUG_FindBreakpoint
162  *
163  * Find the breakpoint for a given address. Return the breakpoint
164  * number or -1 if none.
165  */
166 int DEBUG_FindBreakpoint( const DBG_ADDR *addr )
167 {
168     int i;
169
170     for (i = 0; i < MAX_BREAKPOINTS; i++)
171     {
172         if (breakpoints[i].refcount && breakpoints[i].enabled &&
173             breakpoints[i].addr.seg == addr->seg &&
174             breakpoints[i].addr.off == addr->off) return i;
175     }
176     return -1;
177 }
178
179
180 /***********************************************************************
181  *           DEBUG_AddBreakpoint
182  *
183  * Add a breakpoint.
184  */
185 void DEBUG_AddBreakpoint( const DBG_ADDR *address )
186 {
187     DBG_ADDR addr = *address;
188     int num;
189     unsigned int seg2;
190     BYTE ch;
191
192     DEBUG_FixAddress( &addr, DEBUG_context.SegCs );
193
194     if( addr.type != NULL && addr.type == DEBUG_TypeIntConst )
195       {
196         /*
197          * We know that we have the actual offset stored somewhere
198          * else in 32-bit space.  Grab it, and we
199          * should be all set.
200          */
201         seg2 = addr.seg;
202         addr.seg = 0;
203         addr.off = DEBUG_GetExprValue(&addr, NULL);
204         addr.seg = seg2;
205       }
206
207     if ((num = DEBUG_FindBreakpoint(&addr)) >= 1) 
208     {
209        breakpoints[num].refcount++;
210        return;
211     }
212
213     if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear( &addr ), &ch, sizeof(ch)))
214         return;
215
216     if (next_bp < MAX_BREAKPOINTS)
217         num = next_bp++;
218     else  /* try to find an empty slot */  
219     {
220         for (num = 1; num < MAX_BREAKPOINTS; num++)
221             if (!breakpoints[num].refcount) break;
222         if (num >= MAX_BREAKPOINTS)
223         {
224             fprintf( stderr, "Too many breakpoints. Please delete some.\n" );
225             return;
226         }
227     }
228     breakpoints[num].addr    = addr;
229     breakpoints[num].addrlen = 32;
230 #ifdef __i386__
231     if (addr.seg)
232        breakpoints[num].addrlen = DEBUG_GetSelectorType( addr.seg );
233     if (breakpoints[num].addrlen == 0) fprintf(stderr, "in bad shape\n");
234 #endif
235     breakpoints[num].opcode  = ch;
236     breakpoints[num].enabled = TRUE;
237     breakpoints[num].refcount = 1;
238     breakpoints[num].skipcount = 0;
239     fprintf( stderr, "Breakpoint %d at ", num );
240     DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].addrlen,
241                         TRUE );
242     fprintf( stderr, "\n" );
243 }
244
245
246 /***********************************************************************
247  *           DEBUG_DelBreakpoint
248  *
249  * Delete a breakpoint.
250  */
251 void DEBUG_DelBreakpoint( int num )
252 {
253     if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount)
254     {
255         fprintf( stderr, "Invalid breakpoint number %d\n", num );
256         return;
257     }
258
259     if (--breakpoints[num].refcount > 0)
260        return;
261
262     if( breakpoints[num].condition != NULL )
263       {
264         DEBUG_FreeExpr(breakpoints[num].condition);
265         breakpoints[num].condition = NULL;
266       }
267
268     breakpoints[num].enabled = FALSE;
269     breakpoints[num].refcount = 0;
270     breakpoints[num].skipcount = 0;
271 }
272
273
274 /***********************************************************************
275  *           DEBUG_EnableBreakpoint
276  *
277  * Enable or disable a break point.
278  */
279 void DEBUG_EnableBreakpoint( int num, BOOL enable )
280 {
281     if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount)
282     {
283         fprintf( stderr, "Invalid breakpoint number %d\n", num );
284         return;
285     }
286     breakpoints[num].enabled = (enable) ? TRUE : FALSE;
287     breakpoints[num].skipcount = 0;
288 }
289
290
291 /***********************************************************************
292  *           DEBUG_InfoBreakpoints
293  *
294  * Display break points information.
295  */
296 void DEBUG_InfoBreakpoints(void)
297 {
298     int i;
299
300     fprintf( stderr, "Breakpoints:\n" );
301     for (i = 1; i < next_bp; i++)
302     {
303         if (breakpoints[i].refcount)
304         {
305             fprintf( stderr, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n');
306             DEBUG_PrintAddress( &breakpoints[i].addr, breakpoints[i].addrlen, TRUE);
307             fprintf( stderr, " (%u)\n", breakpoints[i].refcount );
308             if( breakpoints[i].condition != NULL )
309             {
310                 fprintf(stderr, "\t\tstop when  ");
311                 DEBUG_DisplayExpr(breakpoints[i].condition);
312                 fprintf(stderr, "\n");
313             }
314         }
315     }
316 }
317
318 /***********************************************************************
319  *           DEBUG_ShouldContinue
320  *
321  * Determine if we should continue execution after a SIGTRAP signal when
322  * executing in the given mode.
323  */
324 BOOL DEBUG_ShouldContinue( enum exec_mode mode, int * count )
325 {
326     DBG_ADDR addr;
327     DBG_ADDR cond_addr;
328     int bpnum;
329     struct list_id list;
330
331 #ifdef __i386__
332     /* If not single-stepping, back up over the int3 instruction */
333     if (!(DEBUG_context.EFlags & STEP_FLAG)) 
334        DEBUG_context.Eip--;
335 #endif
336
337     DEBUG_GetCurrentAddress( &addr );
338     bpnum = DEBUG_FindBreakpoint( &addr );
339     breakpoints[0].enabled = FALSE;  /* disable the step-over breakpoint */
340
341     if ((bpnum != 0) && (bpnum != -1))
342     {
343         if( breakpoints[bpnum].condition != NULL )
344         {
345             cond_addr = DEBUG_EvalExpr(breakpoints[bpnum].condition);
346             if( cond_addr.type == NULL )
347             {
348                 /*
349                  * Something wrong - unable to evaluate this expression.
350                  */
351                 fprintf(stderr, "Unable to evaluate expression ");
352                 DEBUG_DisplayExpr(breakpoints[bpnum].condition);
353                 fprintf(stderr, "\nTurning off condition\n");
354                 DEBUG_AddBPCondition(bpnum, NULL);
355             }
356             else if( ! DEBUG_GetExprValue( &cond_addr, NULL) )
357             {
358                 return TRUE;
359             }
360         }
361
362         if( breakpoints[bpnum].skipcount > 0 )
363         {
364             breakpoints[bpnum].skipcount--;
365             if( breakpoints[bpnum].skipcount > 0 )
366             {
367                 return TRUE;
368             }
369         }
370         fprintf( stderr, "Stopped on breakpoint %d at ", bpnum );
371         DEBUG_PrintAddress( &breakpoints[bpnum].addr,
372                             breakpoints[bpnum].addrlen, TRUE );
373         fprintf( stderr, "\n" );
374         
375         /*
376          * See if there is a source file for this bp.  If so,
377          * then dig it out and display one line.
378          */
379         DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list);
380         if( list.sourcefile != NULL )
381         {
382             DEBUG_List(&list, NULL, 0);
383         }
384         return FALSE;
385     }
386
387     /*
388      * If our mode indicates that we are stepping line numbers,
389      * get the current function, and figure out if we are exactly
390      * on a line number or not.
391      */
392     if( mode == EXEC_STEP_OVER || mode == EXEC_STEP_INSTR )
393       {
394         if( DEBUG_CheckLinenoStatus(&addr) == AT_LINENUMBER )
395           {
396             (*count)--;
397           }
398       }
399     else if( mode == EXEC_STEPI_OVER 
400         || mode == EXEC_STEPI_INSTR )
401
402       {
403         (*count)--;
404       }
405
406     if( *count > 0 || mode == EXEC_FINISH )
407       {
408         /*
409          * We still need to execute more instructions.
410          */
411         return TRUE;
412       }
413     
414     /*
415      * If we are about to stop, then print out the source line if we
416      * have it.
417      */
418     if ((mode != EXEC_CONT && mode != EXEC_PASS && mode != EXEC_FINISH))
419       {
420         DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list);
421         if( list.sourcefile != NULL )
422           {
423             DEBUG_List(&list, NULL, 0);
424           }
425       }
426
427 #ifdef __i386__
428     /* If there's no breakpoint and we are not single-stepping, then we     */
429     /* must have encountered an int3 in the Windows program; let's skip it. */
430     if ((bpnum == -1) && !(DEBUG_context.EFlags & STEP_FLAG))
431         DEBUG_context.Eip++;
432 #endif
433
434     /* no breakpoint, continue if in continuous mode */
435     return (mode == EXEC_CONT || mode == EXEC_PASS || mode == EXEC_FINISH);
436 }
437
438 /***********************************************************************
439  *           DEBUG_RestartExecution
440  *
441  * Remove all breakpoints before entering the debug loop
442  */
443 void    DEBUG_SuspendExecution( void )
444 {
445    DEBUG_SetBreakpoints( FALSE );
446    breakpoints[0] = DEBUG_CurrThread->stepOverBP;
447 }
448
449 /***********************************************************************
450  *           DEBUG_RestartExecution
451  *
452  * Set the breakpoints to the correct state to restart execution
453  * in the given mode.
454  */
455 enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
456 {
457     DBG_ADDR addr;
458     DBG_ADDR addr2;
459     int bp;
460     int delta;
461     int status;
462     enum exec_mode ret_mode;
463     DWORD instr;
464     unsigned char ch;
465
466     DEBUG_GetCurrentAddress( &addr );
467
468     /*
469      * This is the mode we will be running in after we finish.  We would like
470      * to be able to modify this in certain cases.
471      */
472     ret_mode = mode;
473
474     bp = DEBUG_FindBreakpoint( &addr ); 
475     if ( bp != -1 && bp != 0)
476       {
477         /*
478          * If we have set a new value, then save it in the BP number.
479          */
480         if( count != 0 && mode == EXEC_CONT )
481           {
482             breakpoints[bp].skipcount = count;
483           }
484         mode = EXEC_STEPI_INSTR;  /* If there's a breakpoint, skip it */
485       }
486     else
487       {
488         if( mode == EXEC_CONT && count > 1 )
489           {
490             fprintf(stderr, "Not stopped at any breakpoint; argument ignored.\n");
491           }
492       }
493     
494     if( mode == EXEC_FINISH && DEBUG_IsFctReturn() )
495       {
496         mode = ret_mode = EXEC_STEPI_INSTR;
497       }
498
499     instr = DEBUG_ToLinear( &addr );
500     DEBUG_READ_MEM((void*)instr, &ch, sizeof(ch));
501     /*
502      * See if the function we are stepping into has debug info
503      * and line numbers.  If not, then we step over it instead.
504      * FIXME - we need to check for things like thunks or trampolines,
505      * as the actual function may in fact have debug info.
506      */
507     if( ch == 0xe8 )
508       {
509         DEBUG_READ_MEM((void*)(instr + 1), &delta, sizeof(delta));
510         addr2 = addr;
511         DEBUG_Disasm(&addr2, FALSE);
512         addr2.off += delta;
513         
514         status = DEBUG_CheckLinenoStatus(&addr2);
515         /*
516          * Anytime we have a trampoline, step over it.
517          */
518         if( ((mode == EXEC_STEP_OVER) || (mode == EXEC_STEPI_OVER))
519             && status == FUNC_IS_TRAMPOLINE )
520           {
521 #if 0
522             fprintf(stderr, "Not stepping into trampoline at %x (no lines)\n",
523                     addr2.off);
524 #endif
525             mode = EXEC_STEP_OVER_TRAMPOLINE;
526           }
527         
528         if( mode == EXEC_STEP_INSTR && status == FUNC_HAS_NO_LINES )
529           {
530 #if 0
531             fprintf(stderr, "Not stepping into function at %x (no lines)\n",
532                     addr2.off);
533 #endif
534             mode = EXEC_STEP_OVER;
535           }
536       }
537
538
539     if( mode == EXEC_STEP_INSTR )
540       {
541         if( DEBUG_CheckLinenoStatus(&addr) == FUNC_HAS_NO_LINES )
542           {
543             fprintf(stderr, "Single stepping until exit from function, \n");
544             fprintf(stderr, "which has no line number information.\n");
545             
546             ret_mode = mode = EXEC_FINISH;
547           }
548       }
549
550     switch(mode)
551     {
552     case EXEC_CONT: /* Continuous execution */
553     case EXEC_PASS: /* Continue, passing exception */
554 #ifdef __i386__
555         DEBUG_context.EFlags &= ~STEP_FLAG;
556 #endif
557         DEBUG_SetBreakpoints( TRUE );
558         break;
559
560     case EXEC_STEP_OVER_TRAMPOLINE:
561       /*
562        * This is the means by which we step over our conversion stubs
563        * in callfrom*.s and callto*.s.  We dig the appropriate address
564        * off the stack, and we set the breakpoint there instead of the
565        * address just after the call.
566        */
567 #ifdef __i386__
568       DEBUG_READ_MEM((void*)(DEBUG_context.Esp + 
569                              2 * sizeof(unsigned int)), 
570                      &addr.off, sizeof(addr.off));
571       DEBUG_context.EFlags &= ~STEP_FLAG;
572 #endif
573       breakpoints[0].addr    = addr;
574       breakpoints[0].enabled = TRUE;
575       breakpoints[0].refcount = 1;
576       breakpoints[0].skipcount = 0;
577       DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].opcode, sizeof(char));
578       DEBUG_SetBreakpoints( TRUE );
579       break;
580
581     case EXEC_FINISH:
582     case EXEC_STEPI_OVER:  /* Stepping over a call */
583     case EXEC_STEP_OVER:  /* Stepping over a call */
584         if (DEBUG_IsStepOverInstr())
585         {
586 #ifdef __i386__
587             DEBUG_context.EFlags &= ~STEP_FLAG;
588 #endif
589             DEBUG_Disasm(&addr, FALSE);
590             breakpoints[0].addr    = addr;
591             breakpoints[0].enabled = TRUE;
592             breakpoints[0].refcount = 1;
593             breakpoints[0].skipcount = 0;
594             DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].opcode, sizeof(char));
595             DEBUG_SetBreakpoints( TRUE );
596             break;
597         }
598         /* else fall through to single-stepping */
599
600     case EXEC_STEP_INSTR: /* Single-stepping an instruction */
601     case EXEC_STEPI_INSTR: /* Single-stepping an instruction */
602 #ifdef __i386__
603         DEBUG_context.EFlags |= STEP_FLAG;
604 #endif
605         break;
606     }
607     DEBUG_CurrThread->stepOverBP = breakpoints[0];
608     return ret_mode;
609 }
610
611 int
612 DEBUG_AddBPCondition(int num, struct expr * exp)
613 {
614     if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount)
615     {
616         fprintf( stderr, "Invalid breakpoint number %d\n", num );
617         return FALSE;
618     }
619
620     if( breakpoints[num].condition != NULL )
621       {
622         DEBUG_FreeExpr(breakpoints[num].condition);
623         breakpoints[num].condition = NULL;
624       }
625
626     if( exp != NULL )
627       {
628         breakpoints[num].condition = DEBUG_CloneExpr(exp);
629       }
630
631    return TRUE;
632 }