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 |
| 6 | */ |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 7 | |
| 8 | #include <stdio.h> |
Alexandre Julliard | ecc3712 | 1994-11-22 16:31:29 +0000 | [diff] [blame] | 9 | #include <stdlib.h> |
Alexandre Julliard | 8664b89 | 1996-04-05 14:58:24 +0000 | [diff] [blame] | 10 | #include <sys/types.h> |
Alexandre Julliard | 234bc24 | 1994-12-10 13:02:28 +0000 | [diff] [blame] | 11 | #include <sys/mman.h> |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 12 | #include "module.h" |
| 13 | #include "process.h" |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 14 | #include "task.h" |
| 15 | #include "miscemu.h" |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 16 | #include "toolhelp.h" |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 17 | #include "windows.h" |
| 18 | #include "debugger.h" |
Ove Kaaven | 69df371 | 1998-10-11 12:27:04 +0000 | [diff] [blame] | 19 | #include "dosexe.h" |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 20 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 21 | #define INT3 0xcc /* int 3 opcode */ |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 22 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 23 | #define MAX_BREAKPOINTS 100 |
Alexandre Julliard | 234bc24 | 1994-12-10 13:02:28 +0000 | [diff] [blame] | 24 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 25 | typedef struct |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 26 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 27 | DBG_ADDR addr; |
| 28 | BYTE addrlen; |
| 29 | BYTE opcode; |
| 30 | BOOL16 enabled; |
| 31 | WORD skipcount; |
| 32 | BOOL16 in_use; |
| 33 | struct expr * condition; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 34 | } BREAKPOINT; |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 35 | |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 36 | static BREAKPOINT breakpoints[MAX_BREAKPOINTS]; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 37 | |
| 38 | static int next_bp = 1; /* breakpoint 0 is reserved for step-over */ |
| 39 | |
| 40 | |
| 41 | /*********************************************************************** |
| 42 | * DEBUG_ChangeOpcode |
| 43 | * |
| 44 | * Change the opcode at segment:addr. |
| 45 | */ |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 46 | static void DEBUG_SetOpcode( const DBG_ADDR *addr, BYTE op ) |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 47 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 48 | BYTE *ptr = DBG_ADDR_TO_LIN(addr); |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 49 | |
| 50 | /* There are a couple of problems with this. On Linux prior to |
| 51 | 1.1.62, this call fails (ENOACCESS) due to a bug in fs/exec.c. |
| 52 | This code is currently not tested at all on BSD. |
| 53 | How do I get the old protection in order to restore it later on? |
| 54 | */ |
| 55 | if (mprotect((caddr_t)((int)ptr & (~4095)), 4096, |
| 56 | PROT_READ | PROT_WRITE | PROT_EXEC) == -1) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 57 | { |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 58 | perror( "Can't set break point" ); |
| 59 | return; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 60 | } |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 61 | *ptr = op; |
| 62 | /* mprotect((caddr_t)(addr->off & ~4095), 4096, |
| 63 | PROT_READ | PROT_EXEC ); */ |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | |
| 67 | /*********************************************************************** |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 68 | * DEBUG_IsStepOverInstr |
| 69 | * |
| 70 | * Determine if the instruction at CS:EIP is an instruction that |
| 71 | * we need to step over (like a call or a repetitive string move). |
| 72 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 73 | static BOOL32 DEBUG_IsStepOverInstr() |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 74 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 75 | BYTE *instr = (BYTE *)CTX_SEG_OFF_TO_LIN( &DEBUG_context, |
| 76 | CS_reg(&DEBUG_context), |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 77 | EIP_reg(&DEBUG_context) ); |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 78 | |
| 79 | for (;;) |
| 80 | { |
| 81 | switch(*instr) |
| 82 | { |
| 83 | /* Skip all prefixes */ |
| 84 | |
| 85 | case 0x2e: /* cs: */ |
| 86 | case 0x36: /* ss: */ |
| 87 | case 0x3e: /* ds: */ |
| 88 | case 0x26: /* es: */ |
| 89 | case 0x64: /* fs: */ |
| 90 | case 0x65: /* gs: */ |
| 91 | case 0x66: /* opcode size prefix */ |
| 92 | case 0x67: /* addr size prefix */ |
| 93 | case 0xf0: /* lock */ |
| 94 | case 0xf2: /* repne */ |
| 95 | case 0xf3: /* repe */ |
| 96 | instr++; |
| 97 | continue; |
| 98 | |
| 99 | /* Handle call instructions */ |
| 100 | |
Ove Kaaven | 69df371 | 1998-10-11 12:27:04 +0000 | [diff] [blame] | 101 | case 0xcd: /* int <intno> */ |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 102 | case 0xe8: /* call <offset> */ |
| 103 | case 0x9a: /* lcall <seg>:<off> */ |
| 104 | return TRUE; |
| 105 | |
| 106 | case 0xff: /* call <regmodrm> */ |
| 107 | return (((instr[1] & 0x38) == 0x10) || |
| 108 | ((instr[1] & 0x38) == 0x18)); |
| 109 | |
| 110 | /* Handle string instructions */ |
| 111 | |
| 112 | case 0x6c: /* insb */ |
| 113 | case 0x6d: /* insw */ |
| 114 | case 0x6e: /* outsb */ |
| 115 | case 0x6f: /* outsw */ |
| 116 | case 0xa4: /* movsb */ |
| 117 | case 0xa5: /* movsw */ |
| 118 | case 0xa6: /* cmpsb */ |
| 119 | case 0xa7: /* cmpsw */ |
| 120 | case 0xaa: /* stosb */ |
| 121 | case 0xab: /* stosw */ |
| 122 | case 0xac: /* lodsb */ |
| 123 | case 0xad: /* lodsw */ |
| 124 | case 0xae: /* scasb */ |
| 125 | case 0xaf: /* scasw */ |
| 126 | return TRUE; |
| 127 | |
| 128 | default: |
| 129 | return FALSE; |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | |
| 135 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 136 | * DEBUG_IsFctReturn |
| 137 | * |
| 138 | * Determine if the instruction at CS:EIP is an instruction that |
| 139 | * is a function return. |
| 140 | */ |
| 141 | BOOL32 DEBUG_IsFctReturn(void) |
| 142 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 143 | BYTE *instr = (BYTE *)CTX_SEG_OFF_TO_LIN( &DEBUG_context, |
| 144 | CS_reg(&DEBUG_context), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 145 | EIP_reg(&DEBUG_context) ); |
| 146 | |
| 147 | for (;;) |
| 148 | { |
| 149 | switch(*instr) |
| 150 | { |
| 151 | case 0xc2: |
| 152 | case 0xc3: |
| 153 | return TRUE; |
| 154 | default: |
| 155 | return FALSE; |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | |
| 161 | /*********************************************************************** |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 162 | * DEBUG_SetBreakpoints |
| 163 | * |
| 164 | * Set or remove all the breakpoints. |
| 165 | */ |
Alexandre Julliard | 3051b64 | 1996-07-05 17:14:13 +0000 | [diff] [blame] | 166 | void DEBUG_SetBreakpoints( BOOL32 set ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 167 | { |
| 168 | int i; |
| 169 | |
| 170 | for (i = 0; i < MAX_BREAKPOINTS; i++) |
| 171 | { |
| 172 | if (breakpoints[i].in_use && breakpoints[i].enabled) |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 173 | { |
Alexandre Julliard | 7e6ae4b | 1996-12-08 19:25:27 +0000 | [diff] [blame] | 174 | /* Note: we check for read here, because if reading is allowed */ |
| 175 | /* writing permission will be forced in DEBUG_SetOpcode. */ |
| 176 | if (DEBUG_IsBadReadPtr( &breakpoints[i].addr, 1 )) |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 177 | { |
| 178 | fprintf( stderr, "Invalid address for breakpoint %d, disabling it\n", i ); |
| 179 | breakpoints[i].enabled = FALSE; |
| 180 | } |
| 181 | else DEBUG_SetOpcode( &breakpoints[i].addr, |
| 182 | set ? INT3 : breakpoints[i].opcode ); |
| 183 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 184 | } |
| 185 | } |
| 186 | |
| 187 | |
| 188 | /*********************************************************************** |
| 189 | * DEBUG_FindBreakpoint |
| 190 | * |
| 191 | * Find the breakpoint for a given address. Return the breakpoint |
| 192 | * number or -1 if none. |
| 193 | */ |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 194 | int DEBUG_FindBreakpoint( const DBG_ADDR *addr ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 195 | { |
| 196 | int i; |
| 197 | |
| 198 | for (i = 0; i < MAX_BREAKPOINTS; i++) |
| 199 | { |
| 200 | if (breakpoints[i].in_use && breakpoints[i].enabled && |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 201 | breakpoints[i].addr.seg == addr->seg && |
| 202 | breakpoints[i].addr.off == addr->off) return i; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 203 | } |
| 204 | return -1; |
| 205 | } |
| 206 | |
| 207 | |
| 208 | /*********************************************************************** |
| 209 | * DEBUG_AddBreakpoint |
| 210 | * |
| 211 | * Add a breakpoint. |
| 212 | */ |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 213 | void DEBUG_AddBreakpoint( const DBG_ADDR *address ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 214 | { |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 215 | DBG_ADDR addr = *address; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 216 | int num; |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 217 | unsigned int seg2; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 218 | BYTE *p; |
| 219 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 220 | DBG_FIX_ADDR_SEG( &addr, CS_reg(&DEBUG_context) ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 221 | |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 222 | if( addr.type != NULL && addr.type == DEBUG_TypeIntConst ) |
| 223 | { |
| 224 | /* |
| 225 | * We know that we have the actual offset stored somewhere |
| 226 | * else in 32-bit space. Grab it, and we |
| 227 | * should be all set. |
| 228 | */ |
| 229 | seg2 = addr.seg; |
| 230 | addr.seg = 0; |
| 231 | addr.off = DEBUG_GetExprValue(&addr, NULL); |
| 232 | addr.seg = seg2; |
| 233 | } |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 234 | if (!DBG_CHECK_READ_PTR( &addr, 1 )) return; |
Alexandre Julliard | 349a953 | 1997-02-02 19:01:52 +0000 | [diff] [blame] | 235 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 236 | if (next_bp < MAX_BREAKPOINTS) |
| 237 | num = next_bp++; |
| 238 | else /* try to find an empty slot */ |
| 239 | { |
| 240 | for (num = 1; num < MAX_BREAKPOINTS; num++) |
| 241 | if (!breakpoints[num].in_use) break; |
| 242 | if (num >= MAX_BREAKPOINTS) |
| 243 | { |
| 244 | fprintf( stderr, "Too many breakpoints. Please delete some.\n" ); |
| 245 | return; |
| 246 | } |
| 247 | } |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 248 | p = DBG_ADDR_TO_LIN( &addr ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 249 | breakpoints[num].addr = addr; |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 250 | breakpoints[num].addrlen = !addr.seg ? 32 : |
| 251 | (GET_SEL_FLAGS(addr.seg) & LDT_FLAGS_32BIT) ? 32 : 16; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 252 | breakpoints[num].opcode = *p; |
| 253 | breakpoints[num].enabled = TRUE; |
| 254 | breakpoints[num].in_use = TRUE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 255 | breakpoints[num].skipcount = 0; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 256 | fprintf( stderr, "Breakpoint %d at ", num ); |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 257 | DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].addrlen, |
| 258 | TRUE ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 259 | fprintf( stderr, "\n" ); |
| 260 | } |
| 261 | |
| 262 | |
| 263 | /*********************************************************************** |
| 264 | * DEBUG_DelBreakpoint |
| 265 | * |
| 266 | * Delete a breakpoint. |
| 267 | */ |
| 268 | void DEBUG_DelBreakpoint( int num ) |
| 269 | { |
| 270 | if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use) |
| 271 | { |
| 272 | fprintf( stderr, "Invalid breakpoint number %d\n", num ); |
| 273 | return; |
| 274 | } |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 275 | |
| 276 | if( breakpoints[num].condition != NULL ) |
| 277 | { |
| 278 | DEBUG_FreeExpr(breakpoints[num].condition); |
| 279 | breakpoints[num].condition = NULL; |
| 280 | } |
| 281 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 282 | breakpoints[num].enabled = FALSE; |
| 283 | breakpoints[num].in_use = FALSE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 284 | breakpoints[num].skipcount = 0; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 285 | } |
| 286 | |
| 287 | |
| 288 | /*********************************************************************** |
| 289 | * DEBUG_EnableBreakpoint |
| 290 | * |
| 291 | * Enable or disable a break point. |
| 292 | */ |
Alexandre Julliard | 3051b64 | 1996-07-05 17:14:13 +0000 | [diff] [blame] | 293 | void DEBUG_EnableBreakpoint( int num, BOOL32 enable ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 294 | { |
| 295 | if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use) |
| 296 | { |
| 297 | fprintf( stderr, "Invalid breakpoint number %d\n", num ); |
| 298 | return; |
| 299 | } |
| 300 | breakpoints[num].enabled = enable; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 301 | breakpoints[num].skipcount = 0; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 302 | } |
| 303 | |
| 304 | |
| 305 | /*********************************************************************** |
| 306 | * DEBUG_InfoBreakpoints |
| 307 | * |
| 308 | * Display break points information. |
| 309 | */ |
| 310 | void DEBUG_InfoBreakpoints(void) |
| 311 | { |
| 312 | int i; |
| 313 | |
| 314 | fprintf( stderr, "Breakpoints:\n" ); |
| 315 | for (i = 1; i < next_bp; i++) |
| 316 | { |
| 317 | if (breakpoints[i].in_use) |
| 318 | { |
| 319 | fprintf( stderr, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n'); |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 320 | DEBUG_PrintAddress( &breakpoints[i].addr, breakpoints[i].addrlen, |
| 321 | TRUE); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 322 | fprintf( stderr, "\n" ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 323 | if( breakpoints[i].condition != NULL ) |
| 324 | { |
| 325 | fprintf(stderr, "\t\tstop when "); |
| 326 | DEBUG_DisplayExpr(breakpoints[i].condition); |
| 327 | fprintf(stderr, "\n"); |
| 328 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 329 | } |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | |
| 334 | /*********************************************************************** |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 335 | * DEBUG_AddTaskEntryBreakpoint |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 336 | * |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 337 | * Add a breakpoint at the entry point of the given task |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 338 | */ |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 339 | void DEBUG_AddTaskEntryBreakpoint( HTASK16 hTask ) |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 340 | { |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 341 | TDB *pTask = (TDB *)GlobalLock16( hTask ); |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 342 | NE_MODULE *pModule; |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 343 | DBG_ADDR addr = { NULL, 0, 0 }; |
| 344 | |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 345 | if ( pTask ) |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 346 | { |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 347 | if (!(pModule = NE_GetPtr( pTask->hModule ))) return; |
| 348 | if (pModule->flags & NE_FFLAGS_LIBMODULE) return; /* Library */ |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 349 | |
Ove Kaaven | 69df371 | 1998-10-11 12:27:04 +0000 | [diff] [blame] | 350 | if (pModule->lpDosTask) { /* DOS module */ |
| 351 | addr.seg = pModule->lpDosTask->init_cs | ((DWORD)pModule->self << 16); |
| 352 | addr.off = pModule->lpDosTask->init_ip; |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 353 | fprintf( stderr, "DOS task '%s': ", NE_MODULE_NAME( pModule ) ); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 354 | DEBUG_AddBreakpoint( &addr ); |
| 355 | } else |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 356 | if (!(pModule->flags & NE_FFLAGS_WIN32)) /* NE module */ |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 357 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 358 | addr.seg = |
| 359 | GlobalHandleToSel(NE_SEG_TABLE(pModule)[pModule->cs-1].hSeg); |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 360 | addr.off = pModule->ip; |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 361 | fprintf( stderr, "Win16 task '%s': ", NE_MODULE_NAME( pModule ) ); |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 362 | DEBUG_AddBreakpoint( &addr ); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 363 | } |
| 364 | else /* PE module */ |
| 365 | { |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 366 | addr.seg = 0; |
| 367 | addr.off = (DWORD)RVA_PTR( pModule->module32, |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 368 | OptionalHeader.AddressOfEntryPoint); |
Ulrich Weigand | b9aa7c9 | 1998-11-14 18:43:00 +0000 | [diff] [blame] | 369 | fprintf( stderr, "Win32 task '%s': ", NE_MODULE_NAME( pModule ) ); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 370 | DEBUG_AddBreakpoint( &addr ); |
| 371 | } |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 372 | } |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 373 | |
| 374 | DEBUG_SetBreakpoints( TRUE ); /* Setup breakpoints */ |
| 375 | } |
| 376 | |
| 377 | |
| 378 | /*********************************************************************** |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 379 | * DEBUG_ShouldContinue |
| 380 | * |
| 381 | * Determine if we should continue execution after a SIGTRAP signal when |
| 382 | * executing in the given mode. |
| 383 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 384 | BOOL32 DEBUG_ShouldContinue( enum exec_mode mode, int * count ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 385 | { |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 386 | DBG_ADDR addr; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 387 | DBG_ADDR cond_addr; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 388 | int bpnum; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 389 | struct list_id list; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 390 | TDB *pTask = (TDB*)GlobalLock16( GetCurrentTask() ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 391 | |
| 392 | /* If not single-stepping, back up over the int3 instruction */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 393 | if (!(EFL_reg(&DEBUG_context) & STEP_FLAG)) EIP_reg(&DEBUG_context)--; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 394 | |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 395 | addr.seg = CS_reg(&DEBUG_context); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 396 | addr.off = EIP_reg(&DEBUG_context); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 397 | if (ISV86(&DEBUG_context)) addr.seg |= (DWORD)(pTask?(pTask->hModule):0)<<16; else |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 398 | if (IS_SELECTOR_SYSTEM(addr.seg)) addr.seg = 0; |
| 399 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 400 | GlobalUnlock16( GetCurrentTask() ); |
| 401 | |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 402 | bpnum = DEBUG_FindBreakpoint( &addr ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 403 | breakpoints[0].enabled = 0; /* disable the step-over breakpoint */ |
| 404 | |
| 405 | if ((bpnum != 0) && (bpnum != -1)) |
| 406 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 407 | if( breakpoints[bpnum].condition != NULL ) |
| 408 | { |
| 409 | cond_addr = DEBUG_EvalExpr(breakpoints[bpnum].condition); |
| 410 | if( cond_addr.type == NULL ) |
| 411 | { |
| 412 | /* |
| 413 | * Something wrong - unable to evaluate this expression. |
| 414 | */ |
| 415 | fprintf(stderr, "Unable to evaluate expression "); |
| 416 | DEBUG_DisplayExpr(breakpoints[bpnum].condition); |
| 417 | fprintf(stderr, "\nTurning off condition\n"); |
| 418 | DEBUG_AddBPCondition(bpnum, NULL); |
| 419 | } |
| 420 | else if( ! DEBUG_GetExprValue( &cond_addr, NULL) ) |
| 421 | { |
| 422 | return TRUE; |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | if( breakpoints[bpnum].skipcount > 0 ) |
| 427 | { |
| 428 | breakpoints[bpnum].skipcount--; |
| 429 | if( breakpoints[bpnum].skipcount > 0 ) |
| 430 | { |
| 431 | return TRUE; |
| 432 | } |
| 433 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 434 | fprintf( stderr, "Stopped on breakpoint %d at ", bpnum ); |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 435 | DEBUG_PrintAddress( &breakpoints[bpnum].addr, |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 436 | breakpoints[bpnum].addrlen, TRUE ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 437 | fprintf( stderr, "\n" ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 438 | |
| 439 | /* |
| 440 | * See if there is a source file for this bp. If so, |
| 441 | * then dig it out and display one line. |
| 442 | */ |
| 443 | DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list); |
| 444 | if( list.sourcefile != NULL ) |
| 445 | { |
| 446 | DEBUG_List(&list, NULL, 0); |
| 447 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 448 | return FALSE; |
| 449 | } |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 450 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 451 | /* |
| 452 | * If our mode indicates that we are stepping line numbers, |
| 453 | * get the current function, and figure out if we are exactly |
| 454 | * on a line number or not. |
| 455 | */ |
| 456 | if( mode == EXEC_STEP_OVER |
| 457 | || mode == EXEC_STEP_INSTR ) |
| 458 | { |
| 459 | if( DEBUG_CheckLinenoStatus(&addr) == AT_LINENUMBER ) |
| 460 | { |
| 461 | (*count)--; |
| 462 | } |
| 463 | } |
| 464 | else if( mode == EXEC_STEPI_OVER |
| 465 | || mode == EXEC_STEPI_INSTR ) |
| 466 | |
| 467 | { |
| 468 | (*count)--; |
| 469 | } |
| 470 | |
| 471 | if( *count > 0 || mode == EXEC_FINISH ) |
| 472 | { |
| 473 | /* |
| 474 | * We still need to execute more instructions. |
| 475 | */ |
| 476 | return TRUE; |
| 477 | } |
| 478 | |
| 479 | /* |
| 480 | * If we are about to stop, then print out the source line if we |
| 481 | * have it. |
| 482 | */ |
| 483 | if( (mode != EXEC_CONT && mode != EXEC_FINISH) ) |
| 484 | { |
| 485 | DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list); |
| 486 | if( list.sourcefile != NULL ) |
| 487 | { |
| 488 | DEBUG_List(&list, NULL, 0); |
| 489 | } |
| 490 | } |
| 491 | |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 492 | /* If there's no breakpoint and we are not single-stepping, then we */ |
| 493 | /* must have encountered an int3 in the Windows program; let's skip it. */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 494 | if ((bpnum == -1) && !(EFL_reg(&DEBUG_context) & STEP_FLAG)) |
| 495 | EIP_reg(&DEBUG_context)++; |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 496 | |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 497 | /* no breakpoint, continue if in continuous mode */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 498 | return (mode == EXEC_CONT || mode == EXEC_FINISH); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 499 | } |
| 500 | |
| 501 | |
| 502 | /*********************************************************************** |
| 503 | * DEBUG_RestartExecution |
| 504 | * |
| 505 | * Set the breakpoints to the correct state to restart execution |
| 506 | * in the given mode. |
| 507 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 508 | enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count ) |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 509 | { |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 510 | DBG_ADDR addr; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 511 | DBG_ADDR addr2; |
| 512 | int bp; |
| 513 | int delta; |
| 514 | int status; |
| 515 | unsigned int * value; |
| 516 | enum exec_mode ret_mode; |
| 517 | BYTE *instr; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 518 | TDB *pTask = (TDB*)GlobalLock16( GetCurrentTask() ); |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 519 | |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 520 | addr.seg = CS_reg(&DEBUG_context); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 521 | addr.off = EIP_reg(&DEBUG_context); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 522 | if (ISV86(&DEBUG_context)) addr.seg |= (DWORD)(pTask?(pTask->hModule):0)<<16; else |
Alexandre Julliard | 46ea8b3 | 1998-05-03 19:01:20 +0000 | [diff] [blame] | 523 | if (IS_SELECTOR_SYSTEM(addr.seg)) addr.seg = 0; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 524 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 525 | GlobalUnlock16( GetCurrentTask() ); |
| 526 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 527 | /* |
| 528 | * This is the mode we will be running in after we finish. We would like |
| 529 | * to be able to modify this in certain cases. |
| 530 | */ |
| 531 | ret_mode = mode; |
| 532 | |
| 533 | bp = DEBUG_FindBreakpoint( &addr ); |
| 534 | if ( bp != -1 && bp != 0) |
| 535 | { |
| 536 | /* |
| 537 | * If we have set a new value, then save it in the BP number. |
| 538 | */ |
| 539 | if( count != 0 && mode == EXEC_CONT ) |
| 540 | { |
| 541 | breakpoints[bp].skipcount = count; |
| 542 | } |
| 543 | mode = EXEC_STEPI_INSTR; /* If there's a breakpoint, skip it */ |
| 544 | } |
| 545 | else |
| 546 | { |
| 547 | if( mode == EXEC_CONT && count > 1 ) |
| 548 | { |
| 549 | fprintf(stderr,"Not stopped at any breakpoint; argument ignored.\n"); |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | if( mode == EXEC_FINISH && DEBUG_IsFctReturn() ) |
| 554 | { |
| 555 | mode = ret_mode = EXEC_STEPI_INSTR; |
| 556 | } |
| 557 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 558 | instr = (BYTE *)CTX_SEG_OFF_TO_LIN( &DEBUG_context, |
| 559 | CS_reg(&DEBUG_context), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 560 | EIP_reg(&DEBUG_context) ); |
| 561 | /* |
| 562 | * See if the function we are stepping into has debug info |
| 563 | * and line numbers. If not, then we step over it instead. |
| 564 | * FIXME - we need to check for things like thunks or trampolines, |
| 565 | * as the actual function may in fact have debug info. |
| 566 | */ |
| 567 | if( *instr == 0xe8 ) |
| 568 | { |
| 569 | delta = *(unsigned int*) (instr + 1); |
| 570 | addr2 = addr; |
| 571 | DEBUG_Disasm(&addr2, FALSE); |
| 572 | addr2.off += delta; |
| 573 | |
| 574 | status = DEBUG_CheckLinenoStatus(&addr2); |
| 575 | /* |
| 576 | * Anytime we have a trampoline, step over it. |
| 577 | */ |
| 578 | if( ((mode == EXEC_STEP_OVER) || (mode == EXEC_STEPI_OVER)) |
| 579 | && status == FUNC_IS_TRAMPOLINE ) |
| 580 | { |
| 581 | #if 0 |
| 582 | fprintf(stderr, "Not stepping into trampoline at %x (no lines)\n", |
| 583 | addr2.off); |
| 584 | #endif |
| 585 | mode = EXEC_STEP_OVER_TRAMPOLINE; |
| 586 | } |
| 587 | |
| 588 | if( mode == EXEC_STEP_INSTR && status == FUNC_HAS_NO_LINES ) |
| 589 | { |
| 590 | #if 0 |
| 591 | fprintf(stderr, "Not stepping into function at %x (no lines)\n", |
| 592 | addr2.off); |
| 593 | #endif |
| 594 | mode = EXEC_STEP_OVER; |
| 595 | } |
| 596 | } |
| 597 | |
| 598 | |
| 599 | if( mode == EXEC_STEP_INSTR ) |
| 600 | { |
| 601 | if( DEBUG_CheckLinenoStatus(&addr) == FUNC_HAS_NO_LINES ) |
| 602 | { |
| 603 | fprintf(stderr, "Single stepping until exit from function, \n"); |
| 604 | fprintf(stderr, "which has no line number information.\n"); |
| 605 | |
| 606 | ret_mode = mode = EXEC_FINISH; |
| 607 | } |
| 608 | } |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 609 | |
| 610 | switch(mode) |
| 611 | { |
| 612 | case EXEC_CONT: /* Continuous execution */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 613 | EFL_reg(&DEBUG_context) &= ~STEP_FLAG; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 614 | DEBUG_SetBreakpoints( TRUE ); |
| 615 | break; |
| 616 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 617 | case EXEC_STEP_OVER_TRAMPOLINE: |
| 618 | /* |
| 619 | * This is the means by which we step over our conversion stubs |
| 620 | * in callfrom*.s and callto*.s. We dig the appropriate address |
| 621 | * off the stack, and we set the breakpoint there instead of the |
| 622 | * address just after the call. |
| 623 | */ |
| 624 | value = (unsigned int *) ESP_reg(&DEBUG_context) + 2; |
| 625 | addr.off = *value; |
| 626 | EFL_reg(&DEBUG_context) &= ~STEP_FLAG; |
| 627 | breakpoints[0].addr = addr; |
| 628 | breakpoints[0].enabled = TRUE; |
| 629 | breakpoints[0].in_use = TRUE; |
| 630 | breakpoints[0].skipcount = 0; |
| 631 | breakpoints[0].opcode = *(BYTE *)DBG_ADDR_TO_LIN( &addr ); |
| 632 | DEBUG_SetBreakpoints( TRUE ); |
| 633 | break; |
| 634 | |
| 635 | case EXEC_FINISH: |
| 636 | case EXEC_STEPI_OVER: /* Stepping over a call */ |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 637 | case EXEC_STEP_OVER: /* Stepping over a call */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 638 | if (DEBUG_IsStepOverInstr()) |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 639 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 640 | EFL_reg(&DEBUG_context) &= ~STEP_FLAG; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 641 | DEBUG_Disasm(&addr, FALSE); |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 642 | breakpoints[0].addr = addr; |
| 643 | breakpoints[0].enabled = TRUE; |
| 644 | breakpoints[0].in_use = TRUE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 645 | breakpoints[0].skipcount = 0; |
Alexandre Julliard | b7258be | 1995-09-01 15:57:28 +0000 | [diff] [blame] | 646 | breakpoints[0].opcode = *(BYTE *)DBG_ADDR_TO_LIN( &addr ); |
| 647 | DEBUG_SetBreakpoints( TRUE ); |
| 648 | break; |
| 649 | } |
| 650 | /* else fall through to single-stepping */ |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 651 | |
| 652 | case EXEC_STEP_INSTR: /* Single-stepping an instruction */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 653 | case EXEC_STEPI_INSTR: /* Single-stepping an instruction */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 654 | EFL_reg(&DEBUG_context) |= STEP_FLAG; |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 655 | break; |
| 656 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 657 | return ret_mode; |
| 658 | } |
| 659 | |
| 660 | int |
| 661 | DEBUG_AddBPCondition(int num, struct expr * exp) |
| 662 | { |
| 663 | if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use) |
| 664 | { |
| 665 | fprintf( stderr, "Invalid breakpoint number %d\n", num ); |
| 666 | return FALSE; |
| 667 | } |
| 668 | |
| 669 | if( breakpoints[num].condition != NULL ) |
| 670 | { |
| 671 | DEBUG_FreeExpr(breakpoints[num].condition); |
| 672 | breakpoints[num].condition = NULL; |
| 673 | } |
| 674 | |
| 675 | if( exp != NULL ) |
| 676 | { |
| 677 | breakpoints[num].condition = DEBUG_CloneExpr(exp); |
| 678 | } |
| 679 | |
| 680 | return TRUE; |
Alexandre Julliard | 234bc24 | 1994-12-10 13:02:28 +0000 | [diff] [blame] | 681 | } |