break.c 31.8 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4 5
/*
 * Debugger break-points handling
 *
 * Copyright 1994 Martin von Loewis
 * Copyright 1995 Alexandre Julliard
6
 * Copyright 1999,2000 Eric Pouech
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
22

23
#include "config.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include "debugger.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#ifdef __i386__
#define DR7_CONTROL_SHIFT	16
#define DR7_CONTROL_SIZE 	4

#define DR7_RW_EXECUTE 		(0x0)
#define DR7_RW_WRITE		(0x1)
#define DR7_RW_READ		(0x3)

#define DR7_LEN_1		(0x0)
#define DR7_LEN_2		(0x4)
#define DR7_LEN_4		(0xC)

#define DR7_LOCAL_ENABLE_SHIFT	0
#define DR7_GLOBAL_ENABLE_SHIFT 1
#define DR7_ENABLE_SIZE 	2

#define DR7_LOCAL_ENABLE_MASK	(0x55)
#define DR7_GLOBAL_ENABLE_MASK	(0xAA)

#define DR7_CONTROL_RESERVED	(0xFC00)
#define DR7_LOCAL_SLOWDOWN	(0x100)
#define DR7_GLOBAL_SLOWDOWN	(0x200)

#define	DR7_ENABLE_MASK(dr)	(1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
#define	IS_DR7_SET(ctrl,dr) 	((ctrl)&DR7_ENABLE_MASK(dr))
Alexandre Julliard's avatar
Alexandre Julliard committed
51
#define INT3          0xcc   /* int 3 opcode */
52
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
53

Alexandre Julliard's avatar
Alexandre Julliard committed
54
#define MAX_BREAKPOINTS 100
Alexandre Julliard's avatar
Alexandre Julliard committed
55

56
static DBG_BREAKPOINT breakpoints[MAX_BREAKPOINTS];
Alexandre Julliard's avatar
Alexandre Julliard committed
57

Alexandre Julliard's avatar
Alexandre Julliard committed
58
static int next_bp = 1;  /* breakpoint 0 is reserved for step-over */
Alexandre Julliard's avatar
Alexandre Julliard committed
59

Alexandre Julliard's avatar
Alexandre Julliard committed
60 61 62 63 64 65
/***********************************************************************
 *           DEBUG_IsStepOverInstr
 *
 * Determine if the instruction at CS:EIP is an instruction that
 * we need to step over (like a call or a repetitive string move).
 */
66
static BOOL DEBUG_IsStepOverInstr(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
67
{
68
#ifdef __i386__
69 70 71 72 73 74 75
    BYTE*	instr;
    BYTE	ch;
    DBG_ADDR	addr;

    addr.seg = DEBUG_context.SegCs;
    addr.off = DEBUG_context.Eip;
    /* FIXME: old code was using V86BASE(DEBUG_context)
76
     * instead of passing through DOSMEM_MemoryBase
77 78
     */
    instr = (BYTE*)DEBUG_ToLinear(&addr);
Alexandre Julliard's avatar
Alexandre Julliard committed
79 80 81

    for (;;)
    {
82 83 84 85
        if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch)))
	    return FALSE;

        switch (ch)
Alexandre Julliard's avatar
Alexandre Julliard committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
        {
          /* Skip all prefixes */

        case 0x2e:  /* cs: */
        case 0x36:  /* ss: */
        case 0x3e:  /* ds: */
        case 0x26:  /* es: */
        case 0x64:  /* fs: */
        case 0x65:  /* gs: */
        case 0x66:  /* opcode size prefix */
        case 0x67:  /* addr size prefix */
        case 0xf0:  /* lock */
        case 0xf2:  /* repne */
        case 0xf3:  /* repe */
            instr++;
            continue;

          /* Handle call instructions */

105
        case 0xcd:  /* int <intno> */
Alexandre Julliard's avatar
Alexandre Julliard committed
106 107 108 109 110
        case 0xe8:  /* call <offset> */
        case 0x9a:  /* lcall <seg>:<off> */
            return TRUE;

        case 0xff:  /* call <regmodrm> */
111 112 113
	    if (!DEBUG_READ_MEM(instr + 1, &ch, sizeof(ch)))
	        return FALSE;
	    return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
Alexandre Julliard's avatar
Alexandre Julliard committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

          /* Handle string instructions */

        case 0x6c:  /* insb */
        case 0x6d:  /* insw */
        case 0x6e:  /* outsb */
        case 0x6f:  /* outsw */
        case 0xa4:  /* movsb */
        case 0xa5:  /* movsw */
        case 0xa6:  /* cmpsb */
        case 0xa7:  /* cmpsw */
        case 0xaa:  /* stosb */
        case 0xab:  /* stosw */
        case 0xac:  /* lodsb */
        case 0xad:  /* lodsw */
        case 0xae:  /* scasb */
        case 0xaf:  /* scasw */
            return TRUE;

        default:
            return FALSE;
        }
    }
137 138 139
#else
    return FALSE;
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
140 141 142
}


Alexandre Julliard's avatar
Alexandre Julliard committed
143 144 145 146 147 148
/***********************************************************************
 *           DEBUG_IsFctReturn
 *
 * Determine if the instruction at CS:EIP is an instruction that
 * is a function return.
 */
149
BOOL DEBUG_IsFctReturn(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
150
{
151
#ifdef __i386__
152 153 154 155 156 157 158
    BYTE*	instr;
    BYTE  	ch;
    DBG_ADDR	addr;

    addr.seg = DEBUG_context.SegCs;
    addr.off = DEBUG_context.Eip;
    /* FIXME: old code was using V86BASE(DEBUG_context)
159
     * instead of passing through DOSMEM_MemoryBase
160 161
     */
    instr = (BYTE*)DEBUG_ToLinear(&addr);
Alexandre Julliard's avatar
Alexandre Julliard committed
162

163
    if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch)))
164
        return FALSE;
165 166

    return (ch == 0xc2) || (ch == 0xc3);
167 168 169
#else
    return FALSE;
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
170 171 172
}


Alexandre Julliard's avatar
Alexandre Julliard committed
173 174 175 176 177
/***********************************************************************
 *           DEBUG_SetBreakpoints
 *
 * Set or remove all the breakpoints.
 */
178
void DEBUG_SetBreakpoints( BOOL set )
Alexandre Julliard's avatar
Alexandre Julliard committed
179
{
180
   int		i;
181

182 183 184
#ifdef __i386__
   DEBUG_context.Dr7 &= ~DR7_LOCAL_ENABLE_MASK;
#endif
185

186 187 188 189
   for (i = 0; i < next_bp; i++)
   {
      if (!(breakpoints[i].refcount && breakpoints[i].enabled))
	 continue;
190

191 192 193 194
      switch (breakpoints[i].type) {
      case DBG_BREAK:
	 {
#ifdef __i386__
195
	    char ch = set ? INT3 : breakpoints[i].u.b.opcode;
196 197

	    if (!DEBUG_WRITE_MEM( (void*)DEBUG_ToLinear(&breakpoints[i].addr),
198 199
				  &ch, sizeof(ch) ))
	    {
200
	       DEBUG_Printf(DBG_CHN_MESG, "Invalid address for breakpoint %d, disabling it\n", i);
201 202
	       breakpoints[i].enabled = FALSE;
	    }
203
#endif
204 205 206
	 }
	 break;
      case DBG_WATCH:
207
	 if (set)
208 209 210 211 212
	 {
#ifdef __i386__
	    DWORD	bits;
	    int		reg = breakpoints[i].u.w.reg;
	    LPDWORD	lpdr = NULL;
213

214
	    switch (reg)
215 216 217 218 219 220 221
	    {
	       case 0: lpdr = &DEBUG_context.Dr0; break;
	       case 1: lpdr = &DEBUG_context.Dr1; break;
	       case 2: lpdr = &DEBUG_context.Dr2; break;
	       case 3: lpdr = &DEBUG_context.Dr3; break;
	       default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
	    }
222

223 224 225 226 227 228 229 230 231
	    *lpdr = DEBUG_ToLinear(&breakpoints[i].addr);
	    bits = (breakpoints[i].u.w.rw) ? DR7_RW_WRITE : DR7_RW_READ;
	    switch (breakpoints[i].u.w.len + 1)
	    {
	       case 4: bits |= DR7_LEN_4;	break;
	       case 2: bits |= DR7_LEN_2;	break;
	       case 1: bits |= DR7_LEN_1;	break;
	       default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
	    }
232

233 234 235 236 237 238 239 240
	    DEBUG_context.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
	    DEBUG_context.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
	    DEBUG_context.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
#endif
	 }
	 break;
      }
   }
Alexandre Julliard's avatar
Alexandre Julliard committed
241 242
}

Alexandre Julliard's avatar
Alexandre Julliard committed
243 244 245 246 247
/***********************************************************************
 *           DEBUG_FindBreakpoint
 *
 * Find the breakpoint for a given address. Return the breakpoint
 * number or -1 if none.
248
 * If type is DBG_BREAKPOINT, addr is a complete addr
249
 * If type is DBG_WATCHPOINT, only addr.off is meaningful and contains
250
 * linear address
Alexandre Julliard's avatar
Alexandre Julliard committed
251
 */
252
static int DEBUG_FindBreakpoint( const DBG_ADDR *addr, int type )
Alexandre Julliard's avatar
Alexandre Julliard committed
253
{
254
   int i;
255

256 257 258 259 260
   for (i = 0; i < next_bp; i++)
   {
      if (breakpoints[i].refcount && breakpoints[i].enabled &&
	  breakpoints[i].type == type )
      {
261
	 if ((type == DBG_BREAK &&
262 263
	      breakpoints[i].addr.seg == addr->seg &&
	      breakpoints[i].addr.off == addr->off) ||
264
	     (type == DBG_WATCH &&
265 266 267 268 269 270
	      DEBUG_ToLinear(&breakpoints[i].addr) == addr->off))
	    return i;
      }
   }
   return -1;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
271

272 273 274 275 276
/***********************************************************************
 *           DEBUG_InitXPoint
 *
 * Find an empty slot in BP table to add a new break/watch point
 */
277
static	int	DEBUG_InitXPoint(int type, const DBG_ADDR* addr)
278 279
{
   int	num;
280 281 282

   for (num = (next_bp < MAX_BREAKPOINTS) ? next_bp++ : 1;
	num < MAX_BREAKPOINTS; num++)
283
   {
284
      if (breakpoints[num].refcount == 0)
285
      {
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
          breakpoints[num].refcount = 1;
          breakpoints[num].enabled = TRUE;
          breakpoints[num].type    = type;
          breakpoints[num].skipcount = 0;
          breakpoints[num].addr = *addr;
          switch (DEBUG_GetSelectorType( addr->seg ))
          {
          case MODE_32:
              breakpoints[num].is32 = 1;
              break;
          case MODE_VM86:
          case MODE_16:
              breakpoints[num].is32 = 0;
              break;
          default:
              RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
          }
          return num;
304 305
      }
   }
306

307
   DEBUG_Printf( DBG_CHN_MESG, "Too many breakpoints. Please delete some.\n" );
308
   return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
309 310
}

311 312 313 314 315 316 317 318
/***********************************************************************
 *           DEBUG_GetWatchedValue
 *
 * Returns the value watched by watch point 'num'.
 */
static	BOOL	DEBUG_GetWatchedValue( int num, LPDWORD val )
{
   BYTE		buf[4];
319 320

   if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&breakpoints[num].addr),
321 322
		       buf, breakpoints[num].u.w.len + 1))
      return FALSE;
323 324

   switch (breakpoints[num].u.w.len + 1)
325 326 327 328 329 330 331 332
   {
      case 4:	*val = *(DWORD*)buf;	break;
      case 2:	*val = *(WORD*)buf;	break;
      case 1:	*val = *(BYTE*)buf;	break;
      default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
   }
   return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
333 334 335 336 337 338

/***********************************************************************
 *           DEBUG_AddBreakpoint
 *
 * Add a breakpoint.
 */
339
BOOL DEBUG_AddBreakpoint( const DBG_VALUE *value, BOOL (*func)(void), BOOL verbose )
Alexandre Julliard's avatar
Alexandre Julliard committed
340
{
Alexandre Julliard's avatar
Alexandre Julliard committed
341
    int num;
342
    BYTE ch;
Alexandre Julliard's avatar
Alexandre Julliard committed
343

344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
    if ((num = DEBUG_FindBreakpoint(&value->addr, DBG_BREAK)) >= 1)
    {
        breakpoints[num].refcount++;
        return TRUE;
    }

    if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear( &value->addr ), &ch, sizeof(ch)))
    {
        if (verbose)
            DEBUG_Printf( DBG_CHN_MESG, "Invalid address, can't set breakpoint\n");
        return FALSE;
    }

    if ((num = DEBUG_InitXPoint(DBG_BREAK, &value->addr)) == -1)
        return FALSE;

    breakpoints[num].u.b.opcode = ch;
    breakpoints[num].u.b.func = func;

    DEBUG_Printf( DBG_CHN_MESG, "Breakpoint %d at ", num );
    DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16,
			TRUE );
    DEBUG_Printf( DBG_CHN_MESG, "\n" );

    return FALSE;
}

/***********************************************************************
 *           DEBUG_AddBreakpointFromValue
 *
 * Add a breakpoint.
 */
BOOL DEBUG_AddBreakpointFromValue( const DBG_VALUE *_value )
{
    DBG_VALUE value = *_value;

    if (value.type != NULL && value.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) && value.cookie == DV_HOST)
381 382 383 384 385 386 387 388 389 390
    {
        /*
         * We know that we have the actual offset stored somewhere
         * else in 32-bit space.  Grab it, and we
         * should be all set.
         */
        unsigned int seg2 = value.addr.seg;
        value.addr.seg = 0;
        value.addr.off = DEBUG_GetExprValue(&value, NULL);
        value.addr.seg = seg2;
391
        value.cookie = DV_TARGET;
392
    }
393

394
    if (!DEBUG_AddBreakpoint( &value, NULL, TRUE ))
395
    {
396 397 398 399 400 401 402 403 404
        if (!DBG_IVAR(CanDeferOnBPByAddr))
        {
            DEBUG_Printf( DBG_CHN_MESG, "Invalid address, can't set breakpoint\n"
                          "You can turn on deferring breakpoints by address by setting $CanDeferOnBPByAddr to 1\n");
            return FALSE;
        }
        DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint, will check again any time a new DLL is loaded\n");
        DEBUG_CurrProcess->delayed_bp = DBG_realloc(DEBUG_CurrProcess->delayed_bp,
                                                    sizeof(DBG_DELAYED_BP) * ++DEBUG_CurrProcess->num_delayed_bp);
405

406 407 408
        DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].is_symbol = FALSE;
        DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.value = value;
        return TRUE;
409
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
410

411
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
412 413
}

414 415 416 417 418 419 420
/***********************************************************************
 *           DEBUG_AddBreakpointFromId
 *
 * Add a breakpoint from a function name (and eventually a line #)
 */
void	DEBUG_AddBreakpointFromId(const char *name, int lineno)
{
421 422
    DBG_VALUE 	value;
    int		i;
423

424
    switch (DEBUG_GetSymbolValue(name, lineno, &value, TRUE))
425
    {
426
    case gsv_found:
427 428
        DEBUG_AddBreakpoint(&value, NULL, TRUE);
        return;
429 430 431 432
    case gsv_unknown:
        break;
    case gsv_aborted: /* user aborted symbol lookup */
        return;
433
    }
434

435 436 437 438 439 440 441 442 443 444
    DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint, will check again when a new DLL is loaded\n");
    for (i = 0; i < DEBUG_CurrProcess->num_delayed_bp; i++)
    {
        if (DEBUG_CurrProcess->delayed_bp[i].is_symbol &&
            !strcmp(name, DEBUG_CurrProcess->delayed_bp[i].u.symbol.name) &&
            lineno == DEBUG_CurrProcess->delayed_bp[i].u.symbol.lineno)
            return;
    }
    DEBUG_CurrProcess->delayed_bp = DBG_realloc(DEBUG_CurrProcess->delayed_bp,
                                                sizeof(DBG_DELAYED_BP) * ++DEBUG_CurrProcess->num_delayed_bp);
445

446 447 448
    DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].is_symbol = TRUE;
    DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.symbol.name = strcpy(DBG_alloc(strlen(name) + 1), name);
    DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.symbol.lineno = lineno;
449 450 451 452 453 454 455 456 457
}

/***********************************************************************
 *           DEBUG_AddBreakpointFromLineno
 *
 * Add a breakpoint from a line number in current file
 */
void	DEBUG_AddBreakpointFromLineno(int lineno)
{
458
    DBG_VALUE 			value;
459

460
    DEBUG_GetCurrentAddress(&value.addr);
461

462 463 464
    if (lineno != -1)
    {
        struct name_hash*	nh;
465

466 467 468 469 470 471 472 473
        DEBUG_FindNearestSymbol(&value.addr, TRUE, &nh, 0, NULL);
        if (nh == NULL)
        {
            DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint\n");
            return;
        }
        DEBUG_GetLineNumberAddr(nh, lineno, &value.addr, TRUE);
    }
474

475 476 477
    value.type = NULL;
    value.cookie = DV_TARGET;
    DEBUG_AddBreakpoint( &value,NULL, TRUE );
478
}
Alexandre Julliard's avatar
Alexandre Julliard committed
479

480 481 482 483 484 485 486
/***********************************************************************
 *           DEBUG_CheckDelayedBP
 *
 * Check is a registered delayed BP is now available.
 */
void		DEBUG_CheckDelayedBP(void)
{
487 488 489 490 491 492 493 494
    DBG_VALUE		value;
    int			i;
    DBG_DELAYED_BP*	dbp = DEBUG_CurrProcess->delayed_bp;

    for (i = 0; i < DEBUG_CurrProcess->num_delayed_bp; i++)
    {
        if (dbp[i].is_symbol)
        {
495
            if (DEBUG_GetSymbolValue(dbp[i].u.symbol.name, dbp[i].u.symbol.lineno, &value, TRUE) != gsv_found)
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
                continue;
        }
        else
            value = dbp[i].u.value;
        DEBUG_Printf(DBG_CHN_MESG, "trying to add delayed %s-bp\n", dbp[i].is_symbol ? "S" : "A");
        if (!dbp[i].is_symbol)
            DEBUG_Printf(DBG_CHN_MESG, "\t%04x %04lx:%08lx\n",
                         dbp[i].u.value.cookie,
                         dbp[i].u.value.addr.seg,
                         dbp[i].u.value.addr.off);
        else
            DEBUG_Printf(DBG_CHN_MESG, "\t'%s' @ %d\n",
                         dbp[i].u.symbol.name, dbp[i].u.symbol.lineno);

        if (DEBUG_AddBreakpoint(&value, NULL, FALSE))
            memmove(&dbp[i], &dbp[i+1], (--DEBUG_CurrProcess->num_delayed_bp - i) * sizeof(*dbp));
    }
513 514
}

515
/***********************************************************************
516 517 518 519 520 521 522
 *           DEBUG_AddWatchpoint
 *
 * Add a watchpoint.
 */
void DEBUG_AddWatchpoint( const DBG_VALUE *_value, BOOL is_write )
{
   DBG_VALUE	value = *_value;
523
   int		num, reg = -1;
524 525
   unsigned	seg2;
   DWORD	mask = 0;
526

527 528
   assert(_value->cookie == DV_TARGET || _value->cookie == DV_HOST);

529 530 531
#ifdef __i386__
   DEBUG_FixAddress( &value.addr, DEBUG_context.SegCs );
#endif
532

533
   if ( value.type != NULL && value.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) )
534 535 536 537 538 539 540 541 542 543 544
   {
      /*
       * We know that we have the actual offset stored somewhere
       * else in 32-bit space.  Grab it, and we
       * should be all set.
       */
      seg2 = value.addr.seg;
      value.addr.seg = 0;
      value.addr.off = DEBUG_GetExprValue(&value, NULL);
      value.addr.seg = seg2;
   }
545 546

   for (num = 1; num < next_bp; num++)
547
   {
548
      if (breakpoints[num].refcount && breakpoints[num].enabled &&
549 550 551 552 553 554 555 556
	  breakpoints[num].type == DBG_WATCH) {
	 mask |= (1 << breakpoints[num].u.w.reg);
      }
   }
#ifdef __i386__
   for (reg = 0; reg < 4 && (mask & (1 << reg)); reg++);
   if (reg == 4)
   {
557
      DEBUG_Printf(DBG_CHN_MESG, "All i386 hardware watchpoints have been set. Delete some\n");
558 559 560 561 562 563
      return;
   }
#endif

   if ((num = DEBUG_InitXPoint(DBG_WATCH, &value.addr)) == -1)
      return;
564

565 566 567
   breakpoints[num].u.w.len = 4 - 1;
   if (_value->type && DEBUG_GetObjectSize(_value->type) < 4)
      breakpoints[num].u.w.len = 2 - 1;
568 569

   if (!DEBUG_GetWatchedValue( num, &breakpoints[num].u.w.oldval))
570
   {
571
      DEBUG_Printf(DBG_CHN_MESG, "Bad address. Watchpoint not set\n");
572 573
      breakpoints[num].refcount = 0;
   }
Andreas Mohr's avatar
Andreas Mohr committed
574 575 576 577
   else
   {
      breakpoints[num].u.w.rw = (is_write) ? TRUE : FALSE;
      breakpoints[reg].u.w.reg = reg;
578

Andreas Mohr's avatar
Andreas Mohr committed
579
      DEBUG_Printf( DBG_CHN_MESG, "Watchpoint %d at ", num );
580
      DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16, TRUE );
Andreas Mohr's avatar
Andreas Mohr committed
581 582
      DEBUG_Printf( DBG_CHN_MESG, "\n" );
   }
583 584
}

585 586 587 588 589
/***********************************************************************
 *           DEBUG_AddWathpointFromId
 *
 * Add a watchpoint from a symbol name (and eventually a line #)
 */
590
void	DEBUG_AddWatchpointFromId(const char *name)
591 592
{
   DBG_VALUE value;
593

594 595 596
   switch (DEBUG_GetSymbolValue(name, -1, &value, TRUE))
   {
   case gsv_found:
597
      DEBUG_AddWatchpoint( &value, 1 );
598 599
      break;
   case gsv_unknown:
600
      DEBUG_Printf(DBG_CHN_MESG, "Unable to add watchpoint\n");
601 602 603 604
      break;
   case gsv_aborted: /* user aborted symbol lookup */
       break;
   }
605 606
}

Alexandre Julliard's avatar
Alexandre Julliard committed
607 608 609 610 611 612
/***********************************************************************
 *           DEBUG_DelBreakpoint
 *
 * Delete a breakpoint.
 */
void DEBUG_DelBreakpoint( int num )
Alexandre Julliard's avatar
Alexandre Julliard committed
613
{
614
    if ((num <= 0) || (num >= next_bp) || breakpoints[num].refcount == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
615
    {
616
        DEBUG_Printf( DBG_CHN_MESG, "Invalid breakpoint number %d\n", num );
Alexandre Julliard's avatar
Alexandre Julliard committed
617 618
        return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
619

620 621 622
    if (--breakpoints[num].refcount > 0)
       return;

Alexandre Julliard's avatar
Alexandre Julliard committed
623
    if( breakpoints[num].condition != NULL )
624 625 626 627
    {
       DEBUG_FreeExpr(breakpoints[num].condition);
       breakpoints[num].condition = NULL;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
628

Alexandre Julliard's avatar
Alexandre Julliard committed
629
    breakpoints[num].enabled = FALSE;
630
    breakpoints[num].refcount = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
631
    breakpoints[num].skipcount = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
632
}
Alexandre Julliard's avatar
Alexandre Julliard committed
633

Alexandre Julliard's avatar
Alexandre Julliard committed
634 635 636 637 638
/***********************************************************************
 *           DEBUG_EnableBreakpoint
 *
 * Enable or disable a break point.
 */
639
void DEBUG_EnableBreakpoint( int num, BOOL enable )
Alexandre Julliard's avatar
Alexandre Julliard committed
640
{
641
    if ((num <= 0) || (num >= next_bp) || breakpoints[num].refcount == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
642
    {
643
        DEBUG_Printf( DBG_CHN_MESG, "Invalid breakpoint number %d\n", num );
Alexandre Julliard's avatar
Alexandre Julliard committed
644 645
        return;
    }
646
    breakpoints[num].enabled = (enable) ? TRUE : FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
647
    breakpoints[num].skipcount = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
648
}
Alexandre Julliard's avatar
Alexandre Julliard committed
649 650


651 652 653 654 655 656 657 658
/***********************************************************************
 *           DEBUG_FindTriggeredWatchpoint
 *
 * Lookup the watchpoints to see if one has been triggered
 * Return >= (watch point index) if one is found and *oldval is set to
 * 	the value watched before the TRAP
 * Return -1 if none found (*oldval is undetermined)
 *
659
 * Unfortunately, Linux does *NOT* (A REAL PITA) report with ptrace
660 661 662 663 664 665 666
 * the DR6 register value, so we have to look with our own need the
 * cause of the TRAP.
 * -EP
 */
static int DEBUG_FindTriggeredWatchpoint(LPDWORD oldval)
{
   int				found = -1;
667 668
#ifdef __i386__
   int 				i;
669

670
   /* Method 1 => get triggered watchpoint from context (doesn't work on Linux
671
    * 2.2.x). This should be fixed in >= 2.2.16
672
    */
673
   for (i = 0; i < next_bp; i++)
674
   {
675 676
      DWORD val = 0;

677
      if (breakpoints[i].refcount && breakpoints[i].enabled &&
678 679 680 681
	  breakpoints[i].type == DBG_WATCH &&
	  (DEBUG_context.Dr6 & (1 << breakpoints[i].u.w.reg)))
      {
	 DEBUG_context.Dr6 &= ~(1 << breakpoints[i].u.w.reg);
682

683 684 685 686 687 688 689
	 *oldval = breakpoints[i].u.w.oldval;
	 if (DEBUG_GetWatchedValue(i, &val)) {
	    breakpoints[i].u.w.oldval = val;
	    return i;
	 }
      }
   }
690

691
   /* Method 1 failed, trying method 2 */
692

693 694 695 696
   /* Method 2 => check if value has changed among registered watchpoints
    * this really sucks, but this is how gdb 4.18 works on my linux box
    * -EP
    */
697
   for (i = 0; i < next_bp; i++)
698
   {
699 700
      DWORD val = 0;

701 702 703
      if (breakpoints[i].refcount && breakpoints[i].enabled &&
	  breakpoints[i].type == DBG_WATCH &&
	  DEBUG_GetWatchedValue(i, &val))
704 705
      {
	 *oldval = breakpoints[i].u.w.oldval;
706
	 if (val != *oldval)
707 708 709 710 711
	 {
	    DEBUG_context.Dr6 &= ~(1 << breakpoints[i].u.w.reg);
	    breakpoints[i].u.w.oldval = val;
	    found = i;
	    /* cannot break, because two watch points may have been triggered on
712
	     * the same access
713 714 715 716 717
	     * only one will be reported to the user (FIXME ?)
	     */
	 }
      }
   }
718
#endif
719 720 721
   return found;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
722 723 724 725 726 727 728 729 730
/***********************************************************************
 *           DEBUG_InfoBreakpoints
 *
 * Display break points information.
 */
void DEBUG_InfoBreakpoints(void)
{
    int i;

731
    DEBUG_Printf( DBG_CHN_MESG, "Breakpoints:\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
732 733
    for (i = 1; i < next_bp; i++)
    {
734
        if (breakpoints[i].refcount && breakpoints[i].type == DBG_BREAK)
Alexandre Julliard's avatar
Alexandre Julliard committed
735
        {
736
            DEBUG_Printf( DBG_CHN_MESG, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n');
737
            DEBUG_PrintAddress( &breakpoints[i].addr,
738
				breakpoints[i].is32 ? MODE_32 : MODE_16, TRUE);
739
            DEBUG_Printf( DBG_CHN_MESG, " (%u)\n", breakpoints[i].refcount );
Alexandre Julliard's avatar
Alexandre Julliard committed
740
	    if( breakpoints[i].condition != NULL )
741
	    {
742
	        DEBUG_Printf(DBG_CHN_MESG, "\t\tstop when  ");
Alexandre Julliard's avatar
Alexandre Julliard committed
743
 		DEBUG_DisplayExpr(breakpoints[i].condition);
744
		DEBUG_Printf(DBG_CHN_MESG, "\n");
745
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
746 747
        }
    }
748
    DEBUG_Printf( DBG_CHN_MESG, "Watchpoints:\n" );
749 750 751 752
    for (i = 1; i < next_bp; i++)
    {
        if (breakpoints[i].refcount && breakpoints[i].type == DBG_WATCH)
        {
753
            DEBUG_Printf( DBG_CHN_MESG, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n');
754
            DEBUG_PrintAddress( &breakpoints[i].addr,
755
				breakpoints[i].is32 ? MODE_32 : MODE_16, TRUE);
756 757
            DEBUG_Printf( DBG_CHN_MESG, " on %d byte%s (%c)\n",
		     breakpoints[i].u.w.len + 1,
758 759 760 761
		     breakpoints[i].u.w.len > 0 ? "s" : "",
		     breakpoints[i].u.w.rw ? 'W' : 'R');
	    if( breakpoints[i].condition != NULL )
	    {
762
	        DEBUG_Printf(DBG_CHN_MESG, "\t\tstop when  ");
763
 		DEBUG_DisplayExpr(breakpoints[i].condition);
764
		DEBUG_Printf(DBG_CHN_MESG, "\n");
765 766 767 768 769 770 771 772 773 774 775 776 777
	    }
        }
    }
}

/***********************************************************************
 *           DEBUG_ShallBreak
 *
 * Check whether or not the condition (bp / skipcount) of a break/watch
 * point are met.
 */
static	BOOL DEBUG_ShallBreak( int bpnum )
{
778 779 780
    if ( breakpoints[bpnum].condition != NULL )
    {
        DBG_VALUE value = DEBUG_EvalExpr(breakpoints[bpnum].condition);
781

782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
        if ( value.type == NULL )
        {
	    /*
	     * Something wrong - unable to evaluate this expression.
	     */
	    DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression ");
	    DEBUG_DisplayExpr(breakpoints[bpnum].condition);
	    DEBUG_Printf(DBG_CHN_MESG, "\nTurning off condition\n");
	    DEBUG_AddBPCondition(bpnum, NULL);
        }
        else if( !DEBUG_GetExprValue( &value, NULL) )
        {
	    return FALSE;
        }
    }
797

798 799
    if ( breakpoints[bpnum].skipcount > 0 && --breakpoints[bpnum].skipcount > 0 )
        return FALSE;
800

801 802 803
   if ((breakpoints[bpnum].type == DBG_BREAK) && breakpoints[bpnum].u.b.func)
       return breakpoints[bpnum].u.b.func();
   return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
804
}
Alexandre Julliard's avatar
Alexandre Julliard committed
805

Alexandre Julliard's avatar
Alexandre Julliard committed
806 807 808 809 810 811
/***********************************************************************
 *           DEBUG_ShouldContinue
 *
 * Determine if we should continue execution after a SIGTRAP signal when
 * executing in the given mode.
 */
812
BOOL DEBUG_ShouldContinue( DBG_ADDR *addr, DWORD code, int * count )
Alexandre Julliard's avatar
Alexandre Julliard committed
813
{
814 815 816 817 818 819
    int 	        bpnum;
    DWORD	        oldval;
    int 	        wpnum;
    enum dbg_mode       addr_mode;
    struct symbol_info  syminfo;
    enum exec_mode      mode = DEBUG_CurrThread->exec_mode;
Alexandre Julliard's avatar
Alexandre Julliard committed
820

821
#ifdef __i386__
822
    /* If not single-stepping, back up over the int3 instruction */
823 824
    if (code == EXCEPTION_BREAKPOINT)
    {
825
       DEBUG_context.Eip--;
826 827
       addr->off--;
    }
828
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
829

830
    bpnum = DEBUG_FindBreakpoint( addr, DBG_BREAK );
831
    breakpoints[0].enabled = FALSE;  /* disable the step-over breakpoint */
Alexandre Julliard's avatar
Alexandre Julliard committed
832 833 834

    if ((bpnum != 0) && (bpnum != -1))
    {
835
        if (!DEBUG_ShallBreak(bpnum)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
836

837
        DEBUG_Printf( DBG_CHN_MESG, "Stopped on breakpoint %d at ", bpnum );
838
        syminfo = DEBUG_PrintAddress( &breakpoints[bpnum].addr,
839
				      breakpoints[bpnum].is32 ? MODE_32 : MODE_16, TRUE );
840
        DEBUG_Printf( DBG_CHN_MESG, "\n" );
841

842 843
	if( syminfo.list.sourcefile != NULL )
	    DEBUG_List(&syminfo.list, NULL, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
844 845
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
846

847 848 849 850
    wpnum = DEBUG_FindTriggeredWatchpoint(&oldval);
    if ((wpnum != 0) && (wpnum != -1))
    {
       /* If not single-stepping, do not back up over the int3 instruction */
851
       if (code == EXCEPTION_BREAKPOINT)
852
       {
853 854
#ifdef __i386__
	   DEBUG_context.Eip++;
855
	   addr->off++;
856
#endif
857 858
       }
       if (!DEBUG_ShallBreak(wpnum)) return TRUE;
859

860
       addr_mode = DEBUG_GetSelectorType( addr->seg );
861
       DEBUG_Printf(DBG_CHN_MESG, "Stopped on watchpoint %d at ", wpnum);
862
       syminfo = DEBUG_PrintAddress( addr, addr_mode, TRUE );
863 864

       DEBUG_Printf(DBG_CHN_MESG, " values: old=%lu new=%lu\n",
865
                    oldval, breakpoints[wpnum].u.w.oldval);
866 867 868 869 870
       if (syminfo.list.sourcefile != NULL)
	  DEBUG_List(&syminfo.list, NULL, 0);
       return FALSE;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
871 872 873 874 875
    /*
     * If our mode indicates that we are stepping line numbers,
     * get the current function, and figure out if we are exactly
     * on a line number or not.
     */
876
    if( mode == EXEC_STEP_OVER || mode == EXEC_STEP_INSTR )
877
    {
878
	if( DEBUG_CheckLinenoStatus(addr) == AT_LINENUMBER )
879
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
880
	    (*count)--;
881 882 883 884
	}
    }
    else if( mode == EXEC_STEPI_OVER || mode == EXEC_STEPI_INSTR )
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
885
	(*count)--;
886
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
887 888

    if( *count > 0 || mode == EXEC_FINISH )
889
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
890 891 892 893
	/*
	 * We still need to execute more instructions.
	 */
	return TRUE;
894
    }
895

Alexandre Julliard's avatar
Alexandre Julliard committed
896 897 898 899
    /*
     * If we are about to stop, then print out the source line if we
     * have it.
     */
900
    if (mode != EXEC_CONT && mode != EXEC_FINISH)
901
    {
902 903
	DEBUG_FindNearestSymbol(addr, TRUE, NULL, 0, &syminfo.list);
	if (syminfo.list.sourcefile != NULL)
904 905 906 907
	{
	    DEBUG_List(&syminfo.list, NULL, 0);
	}
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
908

909
#ifdef __i386__
910 911 912
    /* If there's no breakpoint and we are not single-stepping, then
     * either we must have encountered an int3 in the Windows program
     * or someone is trying to stop us
913 914
     * If the later, (no int3 opcode at current address) then stop,
     * otherwise, let's skip it.
915
     */
916
    if ((bpnum == -1) && code == EXCEPTION_BREAKPOINT)
917
    {
918 919 920
        unsigned char   c;

        if (!DEBUG_READ_MEM(&addr, &c, 1)) c = 0xCC;
921
        DEBUG_context.Eip++;
922
	addr->off++;
923
        if (c != 0xCC) return FALSE;
924
    }
925
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
926

927
    /* no breakpoint, continue if in continuous mode */
928
    return (mode == EXEC_CONT || mode == EXEC_FINISH);
Alexandre Julliard's avatar
Alexandre Julliard committed
929 930
}

931
/***********************************************************************
932
 *           DEBUG_SuspendExecution
933 934 935 936 937 938 939 940
 *
 * Remove all breakpoints before entering the debug loop
 */
void	DEBUG_SuspendExecution( void )
{
   DEBUG_SetBreakpoints( FALSE );
   breakpoints[0] = DEBUG_CurrThread->stepOverBP;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
941 942 943 944 945 946 947

/***********************************************************************
 *           DEBUG_RestartExecution
 *
 * Set the breakpoints to the correct state to restart execution
 * in the given mode.
 */
948
void DEBUG_RestartExecution( int count )
Alexandre Julliard's avatar
Alexandre Julliard committed
949
{
Alexandre Julliard's avatar
Alexandre Julliard committed
950
    DBG_ADDR addr;
Alexandre Julliard's avatar
Alexandre Julliard committed
951 952 953 954
    DBG_ADDR addr2;
    int bp;
    int	delta;
    int status;
955
    enum exec_mode mode, ret_mode;
956 957
    DWORD instr;
    unsigned char ch;
Alexandre Julliard's avatar
Alexandre Julliard committed
958

959
    DEBUG_GetCurrentAddress( &addr );
Alexandre Julliard's avatar
Alexandre Julliard committed
960

Alexandre Julliard's avatar
Alexandre Julliard committed
961 962 963 964
    /*
     * This is the mode we will be running in after we finish.  We would like
     * to be able to modify this in certain cases.
     */
965
    ret_mode = mode = DEBUG_CurrThread->exec_mode;
Alexandre Julliard's avatar
Alexandre Julliard committed
966

967
    bp = DEBUG_FindBreakpoint( &addr, DBG_BREAK );
Alexandre Julliard's avatar
Alexandre Julliard committed
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
    if ( bp != -1 && bp != 0)
      {
	/*
	 * If we have set a new value, then save it in the BP number.
	 */
	if( count != 0 && mode == EXEC_CONT )
	  {
	    breakpoints[bp].skipcount = count;
	  }
        mode = EXEC_STEPI_INSTR;  /* If there's a breakpoint, skip it */
      }
    else
      {
	if( mode == EXEC_CONT && count > 1 )
	  {
983
	    DEBUG_Printf(DBG_CHN_MESG, "Not stopped at any breakpoint; argument ignored.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
984 985
	  }
      }
986

Alexandre Julliard's avatar
Alexandre Julliard committed
987 988 989 990 991
    if( mode == EXEC_FINISH && DEBUG_IsFctReturn() )
      {
	mode = ret_mode = EXEC_STEPI_INSTR;
      }

992 993
    instr = DEBUG_ToLinear( &addr );
    DEBUG_READ_MEM((void*)instr, &ch, sizeof(ch));
Alexandre Julliard's avatar
Alexandre Julliard committed
994 995 996 997 998 999
    /*
     * See if the function we are stepping into has debug info
     * and line numbers.  If not, then we step over it instead.
     * FIXME - we need to check for things like thunks or trampolines,
     * as the actual function may in fact have debug info.
     */
1000
    if ( ch == 0xe8 )
Alexandre Julliard's avatar
Alexandre Julliard committed
1001
      {
1002
	DEBUG_READ_MEM((void*)(instr + 1), &delta, sizeof(delta));
Alexandre Julliard's avatar
Alexandre Julliard committed
1003 1004 1005
	addr2 = addr;
	DEBUG_Disasm(&addr2, FALSE);
	addr2.off += delta;
1006

Alexandre Julliard's avatar
Alexandre Julliard committed
1007 1008 1009 1010 1011 1012 1013 1014
	status = DEBUG_CheckLinenoStatus(&addr2);
	/*
	 * Anytime we have a trampoline, step over it.
	 */
	if( ((mode == EXEC_STEP_OVER) || (mode == EXEC_STEPI_OVER))
	    && status == FUNC_IS_TRAMPOLINE )
	  {
#if 0
1015
	    DEBUG_Printf(DBG_CHN_MESG, "Not stepping into trampoline at %x (no lines)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1016 1017 1018 1019
		    addr2.off);
#endif
	    mode = EXEC_STEP_OVER_TRAMPOLINE;
	  }
1020

Alexandre Julliard's avatar
Alexandre Julliard committed
1021 1022 1023
	if( mode == EXEC_STEP_INSTR && status == FUNC_HAS_NO_LINES )
	  {
#if 0
1024
	    DEBUG_Printf(DBG_CHN_MESG, "Not stepping into function at %x (no lines)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
		    addr2.off);
#endif
	    mode = EXEC_STEP_OVER;
	  }
      }


    if( mode == EXEC_STEP_INSTR )
      {
	if( DEBUG_CheckLinenoStatus(&addr) == FUNC_HAS_NO_LINES )
	  {
1036 1037
	    DEBUG_Printf(DBG_CHN_MESG, "Single stepping until exit from function, \n");
	    DEBUG_Printf(DBG_CHN_MESG, "which has no line number information.\n");
1038

Alexandre Julliard's avatar
Alexandre Julliard committed
1039 1040 1041
	    ret_mode = mode = EXEC_FINISH;
	  }
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
1042 1043 1044 1045

    switch(mode)
    {
    case EXEC_CONT: /* Continuous execution */
1046
#ifdef __i386__
1047
        DEBUG_context.EFlags &= ~STEP_FLAG;
1048
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1049 1050 1051
        DEBUG_SetBreakpoints( TRUE );
        break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1052 1053 1054 1055 1056 1057 1058
    case EXEC_STEP_OVER_TRAMPOLINE:
      /*
       * This is the means by which we step over our conversion stubs
       * in callfrom*.s and callto*.s.  We dig the appropriate address
       * off the stack, and we set the breakpoint there instead of the
       * address just after the call.
       */
1059
#ifdef __i386__
1060 1061
      DEBUG_READ_MEM((void*)(DEBUG_context.Esp +
			     2 * sizeof(unsigned int)),
1062 1063
		     &addr.off, sizeof(addr.off));
      DEBUG_context.EFlags &= ~STEP_FLAG;
1064
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1065 1066
      breakpoints[0].addr    = addr;
      breakpoints[0].enabled = TRUE;
1067
      breakpoints[0].refcount = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1068
      breakpoints[0].skipcount = 0;
1069
      DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].u.b.opcode,
1070
		     sizeof(char));
Alexandre Julliard's avatar
Alexandre Julliard committed
1071 1072 1073 1074 1075
      DEBUG_SetBreakpoints( TRUE );
      break;

    case EXEC_FINISH:
    case EXEC_STEPI_OVER:  /* Stepping over a call */
Alexandre Julliard's avatar
Alexandre Julliard committed
1076
    case EXEC_STEP_OVER:  /* Stepping over a call */
Alexandre Julliard's avatar
Alexandre Julliard committed
1077
        if (DEBUG_IsStepOverInstr())
Alexandre Julliard's avatar
Alexandre Julliard committed
1078
        {
1079
#ifdef __i386__
1080
            DEBUG_context.EFlags &= ~STEP_FLAG;
1081
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1082
            DEBUG_Disasm(&addr, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1083 1084
            breakpoints[0].addr    = addr;
            breakpoints[0].enabled = TRUE;
1085
            breakpoints[0].refcount = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1086
	    breakpoints[0].skipcount = 0;
1087
	    DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].u.b.opcode,
1088
			   sizeof(char));
Alexandre Julliard's avatar
Alexandre Julliard committed
1089 1090 1091 1092
            DEBUG_SetBreakpoints( TRUE );
            break;
        }
        /* else fall through to single-stepping */
Alexandre Julliard's avatar
Alexandre Julliard committed
1093 1094

    case EXEC_STEP_INSTR: /* Single-stepping an instruction */
Alexandre Julliard's avatar
Alexandre Julliard committed
1095
    case EXEC_STEPI_INSTR: /* Single-stepping an instruction */
1096
#ifdef __i386__
1097
        DEBUG_context.EFlags |= STEP_FLAG;
1098
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1099
        break;
1100 1101
    default:
        RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1102
    }
1103
    DEBUG_CurrThread->stepOverBP = breakpoints[0];
1104
    DEBUG_CurrThread->exec_mode = ret_mode;
Alexandre Julliard's avatar
Alexandre Julliard committed
1105 1106 1107 1108 1109
}

int
DEBUG_AddBPCondition(int num, struct expr * exp)
{
1110
    if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount)
Alexandre Julliard's avatar
Alexandre Julliard committed
1111
    {
1112
        DEBUG_Printf( DBG_CHN_MESG, "Invalid breakpoint number %d\n", num );
Alexandre Julliard's avatar
Alexandre Julliard committed
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
        return FALSE;
    }

    if( breakpoints[num].condition != NULL )
      {
	DEBUG_FreeExpr(breakpoints[num].condition);
	breakpoints[num].condition = NULL;
      }

    if( exp != NULL )
      {
	breakpoints[num].condition = DEBUG_CloneExpr(exp);
      }

   return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1128
}