Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Debugger break-points handling |
| 3 | * |
| 4 | * Copyright 1994 Martin von Loewis |
| 5 | * Copyright 1995 Alexandre Julliard |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 6 | * Copyright 1999,2000 Eric Pouech |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 7 | */ |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 8 | |
Marcus Meissner | b0d52b0 | 1999-02-28 19:59:00 +0000 | [diff] [blame] | 9 | #include "config.h" |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 10 | #include "debugger.h" |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 11 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 12 | #ifdef __i386__ |
| 13 | #define DR7_CONTROL_SHIFT 16 |
| 14 | #define DR7_CONTROL_SIZE 4 |
| 15 | |
| 16 | #define DR7_RW_EXECUTE (0x0) |
| 17 | #define DR7_RW_WRITE (0x1) |
| 18 | #define DR7_RW_READ (0x3) |
| 19 | |
| 20 | #define DR7_LEN_1 (0x0) |
| 21 | #define DR7_LEN_2 (0x4) |
| 22 | #define DR7_LEN_4 (0xC) |
| 23 | |
| 24 | #define DR7_LOCAL_ENABLE_SHIFT 0 |
| 25 | #define DR7_GLOBAL_ENABLE_SHIFT 1 |
| 26 | #define DR7_ENABLE_SIZE 2 |
| 27 | |
| 28 | #define DR7_LOCAL_ENABLE_MASK (0x55) |
| 29 | #define DR7_GLOBAL_ENABLE_MASK (0xAA) |
| 30 | |
| 31 | #define DR7_CONTROL_RESERVED (0xFC00) |
| 32 | #define DR7_LOCAL_SLOWDOWN (0x100) |
| 33 | #define DR7_GLOBAL_SLOWDOWN (0x200) |
| 34 | |
| 35 | #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr))) |
| 36 | #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr)) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 37 | #define INT3 0xcc /* int 3 opcode */ |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 38 | #endif |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 39 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 40 | #define MAX_BREAKPOINTS 100 |
Alexandre Julliard | 234bc24 | 1994-12-10 13:02:28 +0000 | [diff] [blame] | 41 | |
Eric Pouech | 04c16b8 | 2000-04-30 12:21:15 +0000 | [diff] [blame] | 42 | static DBG_BREAKPOINT breakpoints[MAX_BREAKPOINTS]; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 43 | |
| 44 | static int next_bp = 1; /* breakpoint 0 is reserved for step-over */ |
| 45 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 46 | /*********************************************************************** |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 47 | * DEBUG_IsStepOverInstr |
| 48 | * |
| 49 | * Determine if the instruction at CS:EIP is an instruction that |
| 50 | * we need to step over (like a call or a repetitive string move). |
| 51 | */ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 52 | static BOOL DEBUG_IsStepOverInstr(void) |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 53 | { |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 54 | #ifdef __i386__ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 55 | BYTE* instr; |
| 56 | BYTE ch; |
| 57 | DBG_ADDR addr; |
| 58 | |
| 59 | addr.seg = DEBUG_context.SegCs; |
| 60 | addr.off = DEBUG_context.Eip; |
| 61 | /* FIXME: old code was using V86BASE(DEBUG_context) |
| 62 | * instead of passing thru DOSMEM_MemoryBase |
| 63 | */ |
| 64 | instr = (BYTE*)DEBUG_ToLinear(&addr); |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 65 | |
| 66 | for (;;) |
| 67 | { |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 68 | if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch))) |
| 69 | return FALSE; |
| 70 | |
| 71 | switch (ch) |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 72 | { |
| 73 | /* Skip all prefixes */ |
| 74 | |
| 75 | case 0x2e: /* cs: */ |
| 76 | case 0x36: /* ss: */ |
| 77 | case 0x3e: /* ds: */ |
| 78 | case 0x26: /* es: */ |
| 79 | case 0x64: /* fs: */ |
| 80 | case 0x65: /* gs: */ |
| 81 | case 0x66: /* opcode size prefix */ |
| 82 | case 0x67: /* addr size prefix */ |
| 83 | case 0xf0: /* lock */ |
| 84 | case 0xf2: /* repne */ |
| 85 | case 0xf3: /* repe */ |
| 86 | instr++; |
| 87 | continue; |
| 88 | |
| 89 | /* Handle call instructions */ |
| 90 | |
Ove Kaaven | 69df371 | 1998-10-11 12:27:04 +0000 | [diff] [blame] | 91 | case 0xcd: /* int <intno> */ |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 92 | case 0xe8: /* call <offset> */ |
| 93 | case 0x9a: /* lcall <seg>:<off> */ |
| 94 | return TRUE; |
| 95 | |
| 96 | case 0xff: /* call <regmodrm> */ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 97 | if (!DEBUG_READ_MEM(instr + 1, &ch, sizeof(ch))) |
| 98 | return FALSE; |
| 99 | return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18)); |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 100 | |
| 101 | /* Handle string instructions */ |
| 102 | |
| 103 | case 0x6c: /* insb */ |
| 104 | case 0x6d: /* insw */ |
| 105 | case 0x6e: /* outsb */ |
| 106 | case 0x6f: /* outsw */ |
| 107 | case 0xa4: /* movsb */ |
| 108 | case 0xa5: /* movsw */ |
| 109 | case 0xa6: /* cmpsb */ |
| 110 | case 0xa7: /* cmpsw */ |
| 111 | case 0xaa: /* stosb */ |
| 112 | case 0xab: /* stosw */ |
| 113 | case 0xac: /* lodsb */ |
| 114 | case 0xad: /* lodsw */ |
| 115 | case 0xae: /* scasb */ |
| 116 | case 0xaf: /* scasw */ |
| 117 | return TRUE; |
| 118 | |
| 119 | default: |
| 120 | return FALSE; |
| 121 | } |
| 122 | } |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 123 | #else |
| 124 | return FALSE; |
| 125 | #endif |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | |
| 129 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 130 | * DEBUG_IsFctReturn |
| 131 | * |
| 132 | * Determine if the instruction at CS:EIP is an instruction that |
| 133 | * is a function return. |
| 134 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 135 | BOOL DEBUG_IsFctReturn(void) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 136 | { |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 137 | #ifdef __i386__ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 138 | BYTE* instr; |
| 139 | BYTE ch; |
| 140 | DBG_ADDR addr; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 141 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 142 | addr.seg = DEBUG_context.SegCs; |
| 143 | addr.off = DEBUG_context.Eip; |
| 144 | /* FIXME: old code was using V86BASE(DEBUG_context) |
| 145 | * instead of passing thru DOSMEM_MemoryBase |
| 146 | */ |
| 147 | instr = (BYTE*)DEBUG_ToLinear(&addr); |
| 148 | |
| 149 | if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch))) |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 150 | return FALSE; |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 151 | |
| 152 | return (ch == 0xc2) || (ch == 0xc3); |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 153 | #else |
| 154 | return FALSE; |
| 155 | #endif |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | |
| 159 | /*********************************************************************** |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 160 | * DEBUG_SetBreakpoints |
| 161 | * |
| 162 | * Set or remove all the breakpoints. |
| 163 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 164 | void DEBUG_SetBreakpoints( BOOL set ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 165 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 166 | int i; |
| 167 | |
| 168 | #ifdef __i386__ |
| 169 | DEBUG_context.Dr7 &= ~DR7_LOCAL_ENABLE_MASK; |
| 170 | #endif |
| 171 | |
| 172 | for (i = 0; i < next_bp; i++) |
| 173 | { |
| 174 | if (!(breakpoints[i].refcount && breakpoints[i].enabled)) |
| 175 | continue; |
| 176 | |
| 177 | switch (breakpoints[i].type) { |
| 178 | case DBG_BREAK: |
| 179 | { |
| 180 | #ifdef __i386__ |
Eric Pouech | b971745 | 2000-05-05 18:14:34 +0000 | [diff] [blame] | 181 | char ch = set ? INT3 : breakpoints[i].u.b.opcode; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 182 | |
| 183 | if (!DEBUG_WRITE_MEM( (void*)DEBUG_ToLinear(&breakpoints[i].addr), |
| 184 | &ch, sizeof(ch) )) |
| 185 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 186 | DEBUG_Printf(DBG_CHN_MESG, "Invalid address for breakpoint %d, disabling it\n", i); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 187 | breakpoints[i].enabled = FALSE; |
| 188 | } |
Ulrich Weigand | 1cbf27a | 2000-06-04 01:33:21 +0000 | [diff] [blame] | 189 | #endif |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 190 | } |
| 191 | break; |
| 192 | case DBG_WATCH: |
| 193 | if (set) |
| 194 | { |
| 195 | #ifdef __i386__ |
| 196 | DWORD bits; |
| 197 | int reg = breakpoints[i].u.w.reg; |
| 198 | LPDWORD lpdr = NULL; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 199 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 200 | switch (reg) |
| 201 | { |
| 202 | case 0: lpdr = &DEBUG_context.Dr0; break; |
| 203 | case 1: lpdr = &DEBUG_context.Dr1; break; |
| 204 | case 2: lpdr = &DEBUG_context.Dr2; break; |
| 205 | case 3: lpdr = &DEBUG_context.Dr3; break; |
| 206 | default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); |
| 207 | } |
| 208 | |
| 209 | *lpdr = DEBUG_ToLinear(&breakpoints[i].addr); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 210 | bits = (breakpoints[i].u.w.rw) ? DR7_RW_WRITE : DR7_RW_READ; |
| 211 | switch (breakpoints[i].u.w.len + 1) |
| 212 | { |
| 213 | case 4: bits |= DR7_LEN_4; break; |
| 214 | case 2: bits |= DR7_LEN_2; break; |
| 215 | case 1: bits |= DR7_LEN_1; break; |
| 216 | default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); |
| 217 | } |
| 218 | |
| 219 | DEBUG_context.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg)); |
| 220 | DEBUG_context.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg); |
| 221 | DEBUG_context.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN; |
| 222 | #endif |
| 223 | } |
| 224 | break; |
| 225 | } |
| 226 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 227 | } |
| 228 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 229 | /*********************************************************************** |
| 230 | * DEBUG_FindBreakpoint |
| 231 | * |
| 232 | * Find the breakpoint for a given address. Return the breakpoint |
| 233 | * number or -1 if none. |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 234 | * If type is DBG_BREAKPOINT, addr is a complete addr |
| 235 | * If type is DBG_WATCHPOINT, only addr.off is meaningful and contains |
| 236 | * linear address |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 237 | */ |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 238 | static int DEBUG_FindBreakpoint( const DBG_ADDR *addr, int type ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 239 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 240 | int i; |
| 241 | |
| 242 | for (i = 0; i < next_bp; i++) |
| 243 | { |
| 244 | if (breakpoints[i].refcount && breakpoints[i].enabled && |
| 245 | breakpoints[i].type == type ) |
| 246 | { |
| 247 | if ((type == DBG_BREAK && |
| 248 | breakpoints[i].addr.seg == addr->seg && |
| 249 | breakpoints[i].addr.off == addr->off) || |
| 250 | (type == DBG_WATCH && |
| 251 | DEBUG_ToLinear(&breakpoints[i].addr) == addr->off)) |
| 252 | return i; |
| 253 | } |
| 254 | } |
| 255 | return -1; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 256 | } |
| 257 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 258 | /*********************************************************************** |
| 259 | * DEBUG_InitXPoint |
| 260 | * |
| 261 | * Find an empty slot in BP table to add a new break/watch point |
| 262 | */ |
| 263 | static int DEBUG_InitXPoint(int type, DBG_ADDR* addr) |
| 264 | { |
| 265 | int num; |
| 266 | |
| 267 | for (num = (next_bp < MAX_BREAKPOINTS) ? next_bp++ : 1; |
| 268 | num < MAX_BREAKPOINTS; num++) |
| 269 | { |
| 270 | if (breakpoints[num].refcount == 0) |
| 271 | { |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 272 | breakpoints[num].refcount = 1; |
| 273 | breakpoints[num].enabled = TRUE; |
| 274 | breakpoints[num].type = type; |
| 275 | breakpoints[num].skipcount = 0; |
| 276 | breakpoints[num].addr = *addr; |
| 277 | switch (DEBUG_GetSelectorType( addr->seg )) |
| 278 | { |
| 279 | case MODE_32: |
| 280 | breakpoints[num].is32 = 1; |
| 281 | break; |
| 282 | case MODE_VM86: |
| 283 | case MODE_16: |
| 284 | breakpoints[num].is32 = 0; |
| 285 | break; |
| 286 | default: |
| 287 | RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); |
| 288 | } |
| 289 | return num; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 290 | } |
| 291 | } |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 292 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 293 | DEBUG_Printf( DBG_CHN_MESG, "Too many breakpoints. Please delete some.\n" ); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 294 | return -1; |
| 295 | } |
| 296 | |
| 297 | /*********************************************************************** |
| 298 | * DEBUG_GetWatchedValue |
| 299 | * |
| 300 | * Returns the value watched by watch point 'num'. |
| 301 | */ |
| 302 | static BOOL DEBUG_GetWatchedValue( int num, LPDWORD val ) |
| 303 | { |
| 304 | BYTE buf[4]; |
| 305 | |
| 306 | if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&breakpoints[num].addr), |
| 307 | buf, breakpoints[num].u.w.len + 1)) |
| 308 | return FALSE; |
| 309 | |
| 310 | switch (breakpoints[num].u.w.len + 1) |
| 311 | { |
| 312 | case 4: *val = *(DWORD*)buf; break; |
| 313 | case 2: *val = *(WORD*)buf; break; |
| 314 | case 1: *val = *(BYTE*)buf; break; |
| 315 | default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); |
| 316 | } |
| 317 | return TRUE; |
| 318 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 319 | |
| 320 | /*********************************************************************** |
| 321 | * DEBUG_AddBreakpoint |
| 322 | * |
| 323 | * Add a breakpoint. |
| 324 | */ |
Eric Pouech | b971745 | 2000-05-05 18:14:34 +0000 | [diff] [blame] | 325 | void DEBUG_AddBreakpoint( const DBG_VALUE *_value, BOOL (*func)(void) ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 326 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 327 | DBG_VALUE value = *_value; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 328 | int num; |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 329 | BYTE ch; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 330 | |
Eric Pouech | 7c7e3ba | 2000-08-15 12:00:33 +0000 | [diff] [blame] | 331 | if( value.type != NULL && value.type == DEBUG_TypeIntConst ) |
| 332 | { |
| 333 | /* |
| 334 | * We know that we have the actual offset stored somewhere |
| 335 | * else in 32-bit space. Grab it, and we |
| 336 | * should be all set. |
| 337 | */ |
| 338 | unsigned int seg2 = value.addr.seg; |
| 339 | value.addr.seg = 0; |
| 340 | value.addr.off = DEBUG_GetExprValue(&value, NULL); |
| 341 | value.addr.seg = seg2; |
| 342 | } |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 343 | |
| 344 | if ((num = DEBUG_FindBreakpoint(&value.addr, DBG_BREAK)) >= 1) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 345 | { |
| 346 | breakpoints[num].refcount++; |
| 347 | return; |
| 348 | } |
| 349 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 350 | if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear( &value.addr ), &ch, sizeof(ch))) |
Eric Pouech | 7c7e3ba | 2000-08-15 12:00:33 +0000 | [diff] [blame] | 351 | { |
| 352 | DEBUG_Printf( DBG_CHN_MESG, "Invalid address, can't set breakpoint\n"); |
| 353 | return; |
| 354 | } |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 355 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 356 | if ((num = DEBUG_InitXPoint(DBG_BREAK, &value.addr)) == -1) |
| 357 | return; |
| 358 | |
Eric Pouech | b971745 | 2000-05-05 18:14:34 +0000 | [diff] [blame] | 359 | breakpoints[num].u.b.opcode = ch; |
| 360 | breakpoints[num].u.b.func = func; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 361 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 362 | DEBUG_Printf( DBG_CHN_MESG, "Breakpoint %d at ", num ); |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 363 | DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16, |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 364 | TRUE ); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 365 | DEBUG_Printf( DBG_CHN_MESG, "\n" ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 366 | } |
| 367 | |
Eric Pouech | 911436b | 2000-06-18 19:30:24 +0000 | [diff] [blame] | 368 | /*********************************************************************** |
| 369 | * DEBUG_AddBreakpointFromId |
| 370 | * |
| 371 | * Add a breakpoint from a function name (and eventually a line #) |
| 372 | */ |
| 373 | void DEBUG_AddBreakpointFromId(const char *name, int lineno) |
| 374 | { |
| 375 | DBG_VALUE value; |
| 376 | |
| 377 | if (DEBUG_GetSymbolValue(name, lineno, &value, TRUE)) |
| 378 | DEBUG_AddBreakpoint(&value, NULL); |
| 379 | else |
| 380 | DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint\n"); |
| 381 | } |
| 382 | |
| 383 | /*********************************************************************** |
| 384 | * DEBUG_AddBreakpointFromLineno |
| 385 | * |
| 386 | * Add a breakpoint from a line number in current file |
| 387 | */ |
| 388 | void DEBUG_AddBreakpointFromLineno(int lineno) |
| 389 | { |
| 390 | DBG_VALUE value; |
| 391 | |
| 392 | DEBUG_GetCurrentAddress(&value.addr); |
| 393 | |
| 394 | if (lineno != -1) { |
| 395 | struct name_hash* nh; |
| 396 | |
| 397 | DEBUG_FindNearestSymbol(&value.addr, TRUE, &nh, 0, NULL); |
| 398 | if (nh == NULL) { |
| 399 | DEBUG_Printf(DBG_CHN_MESG,"Unable to add breakpoint\n"); |
| 400 | return; |
| 401 | } |
| 402 | DEBUG_GetLineNumberAddr(nh, lineno, &value.addr, TRUE); |
| 403 | } |
| 404 | |
| 405 | value.type = NULL; |
| 406 | value.cookie = DV_TARGET; |
| 407 | DEBUG_AddBreakpoint( &value, NULL ); |
| 408 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 409 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 410 | /*********************************************************************** |
| 411 | * DEBUG_AddWatchpoint |
| 412 | * |
| 413 | * Add a watchpoint. |
| 414 | */ |
| 415 | void DEBUG_AddWatchpoint( const DBG_VALUE *_value, BOOL is_write ) |
| 416 | { |
| 417 | DBG_VALUE value = *_value; |
Ulrich Weigand | 1cbf27a | 2000-06-04 01:33:21 +0000 | [diff] [blame] | 418 | int num, reg = -1; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 419 | unsigned seg2; |
| 420 | DWORD mask = 0; |
| 421 | |
| 422 | assert(_value->cookie == DV_TARGET || _value->cookie == DV_HOST); |
| 423 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 424 | #ifdef __i386__ |
| 425 | DEBUG_FixAddress( &value.addr, DEBUG_context.SegCs ); |
| 426 | #endif |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 427 | |
| 428 | if ( value.type != NULL && value.type == DEBUG_TypeIntConst ) |
| 429 | { |
| 430 | /* |
| 431 | * We know that we have the actual offset stored somewhere |
| 432 | * else in 32-bit space. Grab it, and we |
| 433 | * should be all set. |
| 434 | */ |
| 435 | seg2 = value.addr.seg; |
| 436 | value.addr.seg = 0; |
| 437 | value.addr.off = DEBUG_GetExprValue(&value, NULL); |
| 438 | value.addr.seg = seg2; |
| 439 | } |
| 440 | |
| 441 | for (num = 1; num < next_bp; num++) |
| 442 | { |
| 443 | if (breakpoints[num].refcount && breakpoints[num].enabled && |
| 444 | breakpoints[num].type == DBG_WATCH) { |
| 445 | mask |= (1 << breakpoints[num].u.w.reg); |
| 446 | } |
| 447 | } |
| 448 | #ifdef __i386__ |
| 449 | for (reg = 0; reg < 4 && (mask & (1 << reg)); reg++); |
| 450 | if (reg == 4) |
| 451 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 452 | DEBUG_Printf(DBG_CHN_MESG, "All i386 hardware watchpoints have been set. Delete some\n"); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 453 | return; |
| 454 | } |
| 455 | #endif |
| 456 | |
| 457 | if ((num = DEBUG_InitXPoint(DBG_WATCH, &value.addr)) == -1) |
| 458 | return; |
| 459 | |
| 460 | breakpoints[num].u.w.len = 4 - 1; |
| 461 | if (_value->type && DEBUG_GetObjectSize(_value->type) < 4) |
| 462 | breakpoints[num].u.w.len = 2 - 1; |
| 463 | |
| 464 | if (!DEBUG_GetWatchedValue( num, &breakpoints[num].u.w.oldval)) |
| 465 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 466 | DEBUG_Printf(DBG_CHN_MESG, "Bad address. Watchpoint not set\n"); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 467 | breakpoints[num].refcount = 0; |
| 468 | } |
Andreas Mohr | 20cd935 | 2000-09-12 23:40:40 +0000 | [diff] [blame] | 469 | else |
| 470 | { |
| 471 | breakpoints[num].u.w.rw = (is_write) ? TRUE : FALSE; |
| 472 | breakpoints[reg].u.w.reg = reg; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 473 | |
Andreas Mohr | 20cd935 | 2000-09-12 23:40:40 +0000 | [diff] [blame] | 474 | DEBUG_Printf( DBG_CHN_MESG, "Watchpoint %d at ", num ); |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 475 | DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16, TRUE ); |
Andreas Mohr | 20cd935 | 2000-09-12 23:40:40 +0000 | [diff] [blame] | 476 | DEBUG_Printf( DBG_CHN_MESG, "\n" ); |
| 477 | } |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 478 | } |
| 479 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 480 | /*********************************************************************** |
Eric Pouech | 911436b | 2000-06-18 19:30:24 +0000 | [diff] [blame] | 481 | * DEBUG_AddWathpointFromId |
| 482 | * |
| 483 | * Add a watchpoint from a symbol name (and eventually a line #) |
| 484 | */ |
| 485 | void DEBUG_AddWatchpointFromId(const char *name, int lineno) |
| 486 | { |
| 487 | DBG_VALUE value; |
| 488 | |
| 489 | if( DEBUG_GetSymbolValue(name, lineno, &value, TRUE) ) |
| 490 | DEBUG_AddWatchpoint( &value, 1 ); |
| 491 | else |
| 492 | DEBUG_Printf(DBG_CHN_MESG, "Unable to add watchpoint\n"); |
| 493 | } |
| 494 | |
| 495 | /*********************************************************************** |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 496 | * DEBUG_DelBreakpoint |
| 497 | * |
| 498 | * Delete a breakpoint. |
| 499 | */ |
| 500 | void DEBUG_DelBreakpoint( int num ) |
| 501 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 502 | if ((num <= 0) || (num >= next_bp) || breakpoints[num].refcount == 0) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 503 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 504 | DEBUG_Printf( DBG_CHN_MESG, "Invalid breakpoint number %d\n", num ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 505 | return; |
| 506 | } |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 507 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 508 | if (--breakpoints[num].refcount > 0) |
| 509 | return; |
| 510 | |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 511 | if( breakpoints[num].condition != NULL ) |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 512 | { |
| 513 | DEBUG_FreeExpr(breakpoints[num].condition); |
| 514 | breakpoints[num].condition = NULL; |
| 515 | } |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 516 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 517 | breakpoints[num].enabled = FALSE; |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 518 | breakpoints[num].refcount = 0; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 519 | breakpoints[num].skipcount = 0; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 520 | } |
| 521 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 522 | /*********************************************************************** |
| 523 | * DEBUG_EnableBreakpoint |
| 524 | * |
| 525 | * Enable or disable a break point. |
| 526 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 527 | void DEBUG_EnableBreakpoint( int num, BOOL enable ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 528 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 529 | if ((num <= 0) || (num >= next_bp) || breakpoints[num].refcount == 0) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 530 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 531 | DEBUG_Printf( DBG_CHN_MESG, "Invalid breakpoint number %d\n", num ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 532 | return; |
| 533 | } |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 534 | breakpoints[num].enabled = (enable) ? TRUE : FALSE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 535 | breakpoints[num].skipcount = 0; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 536 | } |
| 537 | |
| 538 | |
| 539 | /*********************************************************************** |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 540 | * DEBUG_FindTriggeredWatchpoint |
| 541 | * |
| 542 | * Lookup the watchpoints to see if one has been triggered |
| 543 | * Return >= (watch point index) if one is found and *oldval is set to |
| 544 | * the value watched before the TRAP |
| 545 | * Return -1 if none found (*oldval is undetermined) |
| 546 | * |
| 547 | * Unfortunately, Linux does *NOT* (A REAL PITA) report with ptrace |
| 548 | * the DR6 register value, so we have to look with our own need the |
| 549 | * cause of the TRAP. |
| 550 | * -EP |
| 551 | */ |
| 552 | static int DEBUG_FindTriggeredWatchpoint(LPDWORD oldval) |
| 553 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 554 | int found = -1; |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 555 | #ifdef __i386__ |
| 556 | int i; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 557 | |
| 558 | /* Method 1 => get triggered watchpoint from context (doesn't work on Linux |
Eric Pouech | 71189b5 | 2000-07-25 12:51:56 +0000 | [diff] [blame] | 559 | * 2.2.x). This should be fixed in >= 2.2.16 |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 560 | */ |
| 561 | for (i = 0; i < next_bp; i++) |
| 562 | { |
Ulrich Weigand | 1cbf27a | 2000-06-04 01:33:21 +0000 | [diff] [blame] | 563 | DWORD val = 0; |
| 564 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 565 | if (breakpoints[i].refcount && breakpoints[i].enabled && |
| 566 | breakpoints[i].type == DBG_WATCH && |
| 567 | (DEBUG_context.Dr6 & (1 << breakpoints[i].u.w.reg))) |
| 568 | { |
| 569 | DEBUG_context.Dr6 &= ~(1 << breakpoints[i].u.w.reg); |
| 570 | |
| 571 | *oldval = breakpoints[i].u.w.oldval; |
| 572 | if (DEBUG_GetWatchedValue(i, &val)) { |
| 573 | breakpoints[i].u.w.oldval = val; |
| 574 | return i; |
| 575 | } |
| 576 | } |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 577 | } |
| 578 | |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 579 | /* Method 1 failed, trying method 2 */ |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 580 | |
| 581 | /* Method 2 => check if value has changed among registered watchpoints |
| 582 | * this really sucks, but this is how gdb 4.18 works on my linux box |
| 583 | * -EP |
| 584 | */ |
| 585 | for (i = 0; i < next_bp; i++) |
| 586 | { |
Ulrich Weigand | 1cbf27a | 2000-06-04 01:33:21 +0000 | [diff] [blame] | 587 | DWORD val = 0; |
| 588 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 589 | if (breakpoints[i].refcount && breakpoints[i].enabled && |
| 590 | breakpoints[i].type == DBG_WATCH && |
| 591 | DEBUG_GetWatchedValue(i, &val)) |
| 592 | { |
| 593 | *oldval = breakpoints[i].u.w.oldval; |
| 594 | if (val != *oldval) |
| 595 | { |
| 596 | DEBUG_context.Dr6 &= ~(1 << breakpoints[i].u.w.reg); |
| 597 | breakpoints[i].u.w.oldval = val; |
| 598 | found = i; |
| 599 | /* cannot break, because two watch points may have been triggered on |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 600 | * the same access |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 601 | * only one will be reported to the user (FIXME ?) |
| 602 | */ |
| 603 | } |
| 604 | } |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 605 | } |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 606 | #endif |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 607 | return found; |
| 608 | } |
| 609 | |
| 610 | /*********************************************************************** |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 611 | * DEBUG_InfoBreakpoints |
| 612 | * |
| 613 | * Display break points information. |
| 614 | */ |
| 615 | void DEBUG_InfoBreakpoints(void) |
| 616 | { |
| 617 | int i; |
| 618 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 619 | DEBUG_Printf( DBG_CHN_MESG, "Breakpoints:\n" ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 620 | for (i = 1; i < next_bp; i++) |
| 621 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 622 | if (breakpoints[i].refcount && breakpoints[i].type == DBG_BREAK) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 623 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 624 | DEBUG_Printf( DBG_CHN_MESG, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n'); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 625 | DEBUG_PrintAddress( &breakpoints[i].addr, |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 626 | breakpoints[i].is32 ? MODE_32 : MODE_16, TRUE); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 627 | DEBUG_Printf( DBG_CHN_MESG, " (%u)\n", breakpoints[i].refcount ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 628 | if( breakpoints[i].condition != NULL ) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 629 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 630 | DEBUG_Printf(DBG_CHN_MESG, "\t\tstop when "); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 631 | DEBUG_DisplayExpr(breakpoints[i].condition); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 632 | DEBUG_Printf(DBG_CHN_MESG, "\n"); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 633 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 634 | } |
| 635 | } |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 636 | DEBUG_Printf( DBG_CHN_MESG, "Watchpoints:\n" ); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 637 | for (i = 1; i < next_bp; i++) |
| 638 | { |
| 639 | if (breakpoints[i].refcount && breakpoints[i].type == DBG_WATCH) |
| 640 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 641 | DEBUG_Printf( DBG_CHN_MESG, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n'); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 642 | DEBUG_PrintAddress( &breakpoints[i].addr, |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 643 | breakpoints[i].is32 ? MODE_32 : MODE_16, TRUE); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 644 | DEBUG_Printf( DBG_CHN_MESG, " on %d byte%s (%c)\n", |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 645 | breakpoints[i].u.w.len + 1, |
| 646 | breakpoints[i].u.w.len > 0 ? "s" : "", |
| 647 | breakpoints[i].u.w.rw ? 'W' : 'R'); |
| 648 | if( breakpoints[i].condition != NULL ) |
| 649 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 650 | DEBUG_Printf(DBG_CHN_MESG, "\t\tstop when "); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 651 | DEBUG_DisplayExpr(breakpoints[i].condition); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 652 | DEBUG_Printf(DBG_CHN_MESG, "\n"); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 653 | } |
| 654 | } |
| 655 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 656 | } |
| 657 | |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 658 | /*********************************************************************** |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 659 | * DEBUG_ShallBreak |
| 660 | * |
| 661 | * Check whether or not the condition (bp / skipcount) of a break/watch |
| 662 | * point are met. |
| 663 | */ |
| 664 | static BOOL DEBUG_ShallBreak( int bpnum ) |
| 665 | { |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 666 | if ( breakpoints[bpnum].condition != NULL ) |
| 667 | { |
| 668 | DBG_VALUE value = DEBUG_EvalExpr(breakpoints[bpnum].condition); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 669 | |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 670 | if ( value.type == NULL ) |
| 671 | { |
| 672 | /* |
| 673 | * Something wrong - unable to evaluate this expression. |
| 674 | */ |
| 675 | DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression "); |
| 676 | DEBUG_DisplayExpr(breakpoints[bpnum].condition); |
| 677 | DEBUG_Printf(DBG_CHN_MESG, "\nTurning off condition\n"); |
| 678 | DEBUG_AddBPCondition(bpnum, NULL); |
| 679 | } |
| 680 | else if( !DEBUG_GetExprValue( &value, NULL) ) |
| 681 | { |
| 682 | return FALSE; |
| 683 | } |
| 684 | } |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 685 | |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 686 | if ( breakpoints[bpnum].skipcount > 0 && --breakpoints[bpnum].skipcount > 0 ) |
| 687 | return FALSE; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 688 | |
Andreas Mohr | 522a9a9 | 2000-07-10 13:05:17 +0000 | [diff] [blame] | 689 | if ((breakpoints[bpnum].type == DBG_BREAK) && breakpoints[bpnum].u.b.func) |
| 690 | return breakpoints[bpnum].u.b.func(); |
| 691 | return TRUE; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 692 | } |
| 693 | |
| 694 | /*********************************************************************** |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 695 | * DEBUG_ShouldContinue |
| 696 | * |
| 697 | * Determine if we should continue execution after a SIGTRAP signal when |
| 698 | * executing in the given mode. |
| 699 | */ |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 700 | BOOL DEBUG_ShouldContinue( DBG_ADDR *addr, DWORD code, enum exec_mode mode, int * count ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 701 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 702 | int bpnum; |
| 703 | DWORD oldval; |
| 704 | int wpnum; |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 705 | enum dbg_mode addr_mode; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 706 | struct symbol_info syminfo; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 707 | |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 708 | #ifdef __i386__ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 709 | /* If not single-stepping, back up over the int3 instruction */ |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 710 | if (code == EXCEPTION_BREAKPOINT) |
| 711 | { |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 712 | DEBUG_context.Eip--; |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 713 | addr->off--; |
| 714 | } |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 715 | #endif |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 716 | |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 717 | bpnum = DEBUG_FindBreakpoint( addr, DBG_BREAK ); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 718 | breakpoints[0].enabled = FALSE; /* disable the step-over breakpoint */ |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 719 | |
| 720 | if ((bpnum != 0) && (bpnum != -1)) |
| 721 | { |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 722 | if (!DEBUG_ShallBreak(bpnum)) return TRUE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 723 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 724 | DEBUG_Printf( DBG_CHN_MESG, "Stopped on breakpoint %d at ", bpnum ); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 725 | syminfo = DEBUG_PrintAddress( &breakpoints[bpnum].addr, |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 726 | breakpoints[bpnum].is32 ? MODE_32 : MODE_16, TRUE ); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 727 | DEBUG_Printf( DBG_CHN_MESG, "\n" ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 728 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 729 | if( syminfo.list.sourcefile != NULL ) |
| 730 | DEBUG_List(&syminfo.list, NULL, 0); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 731 | return FALSE; |
| 732 | } |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 733 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 734 | wpnum = DEBUG_FindTriggeredWatchpoint(&oldval); |
| 735 | if ((wpnum != 0) && (wpnum != -1)) |
| 736 | { |
| 737 | /* If not single-stepping, do not back up over the int3 instruction */ |
| 738 | if (code == EXCEPTION_BREAKPOINT) |
| 739 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 740 | #ifdef __i386__ |
| 741 | DEBUG_context.Eip++; |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 742 | addr->off++; |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 743 | #endif |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 744 | } |
| 745 | if (!DEBUG_ShallBreak(wpnum)) return TRUE; |
| 746 | |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 747 | addr_mode = DEBUG_GetSelectorType( addr->seg ); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 748 | DEBUG_Printf(DBG_CHN_MESG, "Stopped on watchpoint %d at ", wpnum); |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 749 | syminfo = DEBUG_PrintAddress( addr, addr_mode, TRUE ); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 750 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 751 | DEBUG_Printf(DBG_CHN_MESG, " values: old=%lu new=%lu\n", |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 752 | oldval, breakpoints[wpnum].u.w.oldval); |
| 753 | if (syminfo.list.sourcefile != NULL) |
| 754 | DEBUG_List(&syminfo.list, NULL, 0); |
| 755 | return FALSE; |
| 756 | } |
| 757 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 758 | /* |
| 759 | * If our mode indicates that we are stepping line numbers, |
| 760 | * get the current function, and figure out if we are exactly |
| 761 | * on a line number or not. |
| 762 | */ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 763 | if( mode == EXEC_STEP_OVER || mode == EXEC_STEP_INSTR ) |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 764 | { |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 765 | if( DEBUG_CheckLinenoStatus(addr) == AT_LINENUMBER ) |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 766 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 767 | (*count)--; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 768 | } |
| 769 | } |
| 770 | else if( mode == EXEC_STEPI_OVER || mode == EXEC_STEPI_INSTR ) |
| 771 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 772 | (*count)--; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 773 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 774 | |
| 775 | if( *count > 0 || mode == EXEC_FINISH ) |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 776 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 777 | /* |
| 778 | * We still need to execute more instructions. |
| 779 | */ |
| 780 | return TRUE; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 781 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 782 | |
| 783 | /* |
| 784 | * If we are about to stop, then print out the source line if we |
| 785 | * have it. |
| 786 | */ |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 787 | if (mode != EXEC_CONT && mode != EXEC_PASS && mode != EXEC_FINISH) |
| 788 | { |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 789 | DEBUG_FindNearestSymbol( addr, TRUE, NULL, 0, &syminfo.list); |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 790 | if( syminfo.list.sourcefile != NULL ) |
| 791 | { |
| 792 | DEBUG_List(&syminfo.list, NULL, 0); |
| 793 | } |
| 794 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 795 | |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 796 | #ifdef __i386__ |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 797 | /* If there's no breakpoint and we are not single-stepping, then we */ |
| 798 | /* must have encountered an int3 in the Windows program; let's skip it. */ |
Eric Pouech | ebd01a9 | 2000-03-09 18:46:04 +0000 | [diff] [blame] | 799 | if ((bpnum == -1) && code == EXCEPTION_BREAKPOINT) |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 800 | { |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 801 | DEBUG_context.Eip++; |
James Abbatiello | ebef9a9 | 2000-09-01 01:22:05 +0000 | [diff] [blame] | 802 | addr->off++; |
| 803 | } |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 804 | #endif |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 805 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 806 | /* no breakpoint, continue if in continuous mode */ |
Alexandre Julliard | 410ae4f | 1999-06-18 18:23:11 +0000 | [diff] [blame] | 807 | return (mode == EXEC_CONT || mode == EXEC_PASS || mode == EXEC_FINISH); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 808 | } |
| 809 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 810 | /*********************************************************************** |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 811 | * DEBUG_SuspendExecution |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 812 | * |
| 813 | * Remove all breakpoints before entering the debug loop |
| 814 | */ |
| 815 | void DEBUG_SuspendExecution( void ) |
| 816 | { |
| 817 | DEBUG_SetBreakpoints( FALSE ); |
| 818 | breakpoints[0] = DEBUG_CurrThread->stepOverBP; |
| 819 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 820 | |
| 821 | /*********************************************************************** |
| 822 | * DEBUG_RestartExecution |
| 823 | * |
| 824 | * Set the breakpoints to the correct state to restart execution |
| 825 | * in the given mode. |
| 826 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 827 | enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 828 | { |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 829 | DBG_ADDR addr; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 830 | DBG_ADDR addr2; |
| 831 | int bp; |
| 832 | int delta; |
| 833 | int status; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 834 | enum exec_mode ret_mode; |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 835 | DWORD instr; |
| 836 | unsigned char ch; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 837 | |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 838 | DEBUG_GetCurrentAddress( &addr ); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 839 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 840 | /* |
| 841 | * This is the mode we will be running in after we finish. We would like |
| 842 | * to be able to modify this in certain cases. |
| 843 | */ |
| 844 | ret_mode = mode; |
| 845 | |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 846 | bp = DEBUG_FindBreakpoint( &addr, DBG_BREAK ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 847 | if ( bp != -1 && bp != 0) |
| 848 | { |
| 849 | /* |
| 850 | * If we have set a new value, then save it in the BP number. |
| 851 | */ |
| 852 | if( count != 0 && mode == EXEC_CONT ) |
| 853 | { |
| 854 | breakpoints[bp].skipcount = count; |
| 855 | } |
| 856 | mode = EXEC_STEPI_INSTR; /* If there's a breakpoint, skip it */ |
| 857 | } |
| 858 | else |
| 859 | { |
| 860 | if( mode == EXEC_CONT && count > 1 ) |
| 861 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 862 | DEBUG_Printf(DBG_CHN_MESG, "Not stopped at any breakpoint; argument ignored.\n"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 863 | } |
| 864 | } |
| 865 | |
| 866 | if( mode == EXEC_FINISH && DEBUG_IsFctReturn() ) |
| 867 | { |
| 868 | mode = ret_mode = EXEC_STEPI_INSTR; |
| 869 | } |
| 870 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 871 | instr = DEBUG_ToLinear( &addr ); |
| 872 | DEBUG_READ_MEM((void*)instr, &ch, sizeof(ch)); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 873 | /* |
| 874 | * See if the function we are stepping into has debug info |
| 875 | * and line numbers. If not, then we step over it instead. |
| 876 | * FIXME - we need to check for things like thunks or trampolines, |
| 877 | * as the actual function may in fact have debug info. |
| 878 | */ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 879 | if( ch == 0xe8 ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 880 | { |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 881 | DEBUG_READ_MEM((void*)(instr + 1), &delta, sizeof(delta)); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 882 | addr2 = addr; |
| 883 | DEBUG_Disasm(&addr2, FALSE); |
| 884 | addr2.off += delta; |
| 885 | |
| 886 | status = DEBUG_CheckLinenoStatus(&addr2); |
| 887 | /* |
| 888 | * Anytime we have a trampoline, step over it. |
| 889 | */ |
| 890 | if( ((mode == EXEC_STEP_OVER) || (mode == EXEC_STEPI_OVER)) |
| 891 | && status == FUNC_IS_TRAMPOLINE ) |
| 892 | { |
| 893 | #if 0 |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 894 | DEBUG_Printf(DBG_CHN_MESG, "Not stepping into trampoline at %x (no lines)\n", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 895 | addr2.off); |
| 896 | #endif |
| 897 | mode = EXEC_STEP_OVER_TRAMPOLINE; |
| 898 | } |
| 899 | |
| 900 | if( mode == EXEC_STEP_INSTR && status == FUNC_HAS_NO_LINES ) |
| 901 | { |
| 902 | #if 0 |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 903 | DEBUG_Printf(DBG_CHN_MESG, "Not stepping into function at %x (no lines)\n", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 904 | addr2.off); |
| 905 | #endif |
| 906 | mode = EXEC_STEP_OVER; |
| 907 | } |
| 908 | } |
| 909 | |
| 910 | |
| 911 | if( mode == EXEC_STEP_INSTR ) |
| 912 | { |
| 913 | if( DEBUG_CheckLinenoStatus(&addr) == FUNC_HAS_NO_LINES ) |
| 914 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 915 | DEBUG_Printf(DBG_CHN_MESG, "Single stepping until exit from function, \n"); |
| 916 | DEBUG_Printf(DBG_CHN_MESG, "which has no line number information.\n"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 917 | |
| 918 | ret_mode = mode = EXEC_FINISH; |
| 919 | } |
| 920 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 921 | |
| 922 | switch(mode) |
| 923 | { |
| 924 | case EXEC_CONT: /* Continuous execution */ |
Alexandre Julliard | 410ae4f | 1999-06-18 18:23:11 +0000 | [diff] [blame] | 925 | case EXEC_PASS: /* Continue, passing exception */ |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 926 | #ifdef __i386__ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 927 | DEBUG_context.EFlags &= ~STEP_FLAG; |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 928 | #endif |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 929 | DEBUG_SetBreakpoints( TRUE ); |
| 930 | break; |
| 931 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 932 | case EXEC_STEP_OVER_TRAMPOLINE: |
| 933 | /* |
| 934 | * This is the means by which we step over our conversion stubs |
| 935 | * in callfrom*.s and callto*.s. We dig the appropriate address |
| 936 | * off the stack, and we set the breakpoint there instead of the |
| 937 | * address just after the call. |
| 938 | */ |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 939 | #ifdef __i386__ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 940 | DEBUG_READ_MEM((void*)(DEBUG_context.Esp + |
| 941 | 2 * sizeof(unsigned int)), |
| 942 | &addr.off, sizeof(addr.off)); |
| 943 | DEBUG_context.EFlags &= ~STEP_FLAG; |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 944 | #endif |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 945 | breakpoints[0].addr = addr; |
| 946 | breakpoints[0].enabled = TRUE; |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 947 | breakpoints[0].refcount = 1; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 948 | breakpoints[0].skipcount = 0; |
Eric Pouech | b971745 | 2000-05-05 18:14:34 +0000 | [diff] [blame] | 949 | DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].u.b.opcode, |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 950 | sizeof(char)); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 951 | DEBUG_SetBreakpoints( TRUE ); |
| 952 | break; |
| 953 | |
| 954 | case EXEC_FINISH: |
| 955 | case EXEC_STEPI_OVER: /* Stepping over a call */ |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 956 | case EXEC_STEP_OVER: /* Stepping over a call */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 957 | if (DEBUG_IsStepOverInstr()) |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 958 | { |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 959 | #ifdef __i386__ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 960 | DEBUG_context.EFlags &= ~STEP_FLAG; |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 961 | #endif |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 962 | DEBUG_Disasm(&addr, FALSE); |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 963 | breakpoints[0].addr = addr; |
| 964 | breakpoints[0].enabled = TRUE; |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 965 | breakpoints[0].refcount = 1; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 966 | breakpoints[0].skipcount = 0; |
Eric Pouech | b971745 | 2000-05-05 18:14:34 +0000 | [diff] [blame] | 967 | DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].u.b.opcode, |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 968 | sizeof(char)); |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 969 | DEBUG_SetBreakpoints( TRUE ); |
| 970 | break; |
| 971 | } |
| 972 | /* else fall through to single-stepping */ |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 973 | |
| 974 | case EXEC_STEP_INSTR: /* Single-stepping an instruction */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 975 | case EXEC_STEPI_INSTR: /* Single-stepping an instruction */ |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 976 | #ifdef __i386__ |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 977 | DEBUG_context.EFlags |= STEP_FLAG; |
Ulrich Weigand | b3ec4b9 | 1999-11-13 20:58:45 +0000 | [diff] [blame] | 978 | #endif |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 979 | break; |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 980 | default: |
| 981 | RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 982 | } |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 983 | DEBUG_CurrThread->stepOverBP = breakpoints[0]; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 984 | return ret_mode; |
| 985 | } |
| 986 | |
| 987 | int |
| 988 | DEBUG_AddBPCondition(int num, struct expr * exp) |
| 989 | { |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 990 | if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 991 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 992 | DEBUG_Printf( DBG_CHN_MESG, "Invalid breakpoint number %d\n", num ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 993 | return FALSE; |
| 994 | } |
| 995 | |
| 996 | if( breakpoints[num].condition != NULL ) |
| 997 | { |
| 998 | DEBUG_FreeExpr(breakpoints[num].condition); |
| 999 | breakpoints[num].condition = NULL; |
| 1000 | } |
| 1001 | |
| 1002 | if( exp != NULL ) |
| 1003 | { |
| 1004 | breakpoints[num].condition = DEBUG_CloneExpr(exp); |
| 1005 | } |
| 1006 | |
| 1007 | return TRUE; |
Alexandre Julliard | 234bc24 | 1994-12-10 13:02:28 +0000 | [diff] [blame] | 1008 | } |