Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Wine debugger utility routines |
| 3 | * Eric Youngdale |
| 4 | * 9/93 |
| 5 | */ |
| 6 | |
| 7 | #include <stdio.h> |
Alexandre Julliard | ecc3712 | 1994-11-22 16:31:29 +0000 | [diff] [blame] | 8 | #include <stdlib.h> |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 9 | #include "ldt.h" |
Alexandre Julliard | 1850655 | 1995-01-24 16:21:01 +0000 | [diff] [blame] | 10 | #include "db_disasm.h" |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 11 | #include "regpos.h" |
| 12 | |
| 13 | extern int * regval; |
| 14 | extern unsigned int dbg_mask; |
| 15 | extern unsigned int dbg_mode; |
| 16 | |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 17 | void application_not_running() |
| 18 | { |
| 19 | fprintf(stderr,"Application not running\n"); |
| 20 | } |
| 21 | |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 22 | void print_address(unsigned int addr, FILE * outfile, int addrlen) |
| 23 | { |
| 24 | if (addrlen == 16) |
| 25 | { |
| 26 | fprintf( outfile, "%4.4x:%4.4x", addr >> 16, addr & 0xffff ); |
| 27 | } |
| 28 | else |
| 29 | { |
| 30 | extern char * find_nearest_symbol(unsigned int *); |
Alexandre Julliard | 73450d6 | 1994-05-18 18:29:32 +0000 | [diff] [blame] | 31 | |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 32 | char * name = find_nearest_symbol((unsigned int *) addr); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 33 | if(name) |
| 34 | fprintf(outfile,"0x%8.8x(%s)", addr, name); |
| 35 | else |
| 36 | fprintf(outfile,"0x%8.8x", addr); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 37 | } |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 38 | } |
| 39 | |
| 40 | |
| 41 | void info_reg(){ |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 42 | |
| 43 | if(!regval) { |
| 44 | application_not_running(); |
Alexandre Julliard | 73450d6 | 1994-05-18 18:29:32 +0000 | [diff] [blame] | 45 | return; |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 46 | } |
| 47 | |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 48 | fprintf(stderr,"Register dump:\n"); |
| 49 | /* First get the segment registers out of the way */ |
| 50 | fprintf(stderr," CS:%4.4x SS:%4.4x DS:%4.4x ES:%4.4x GS:%4.4x FS:%4.4x\n", |
| 51 | SC_CS, SC_SS, SC_DS, SC_ES, SC_GS, SC_FS); |
| 52 | |
| 53 | /* Now dump the main registers */ |
| 54 | fprintf(stderr," EIP:%8.8x ESP:%8.8x EBP:%8.8x EFLAGS:%8.8x\n", |
| 55 | SC_EIP(dbg_mask), SC_ESP(dbg_mask), SC_EBP(dbg_mask), SC_EFLAGS); |
| 56 | |
| 57 | /* And dump the regular registers */ |
| 58 | |
| 59 | fprintf(stderr," EAX:%8.8x EBX:%8.8x ECX:%8.8x EDX:%8.8x\n", |
| 60 | SC_EAX(dbg_mask), SC_EBX(dbg_mask), SC_ECX(dbg_mask), SC_EDX(dbg_mask)); |
| 61 | |
| 62 | /* Finally dump these main registers */ |
| 63 | fprintf(stderr," EDI:%8.8x ESI:%8.8x\n", |
| 64 | SC_EDI(dbg_mask), SC_ESI(dbg_mask)); |
| 65 | |
| 66 | } |
| 67 | |
| 68 | void info_stack(){ |
| 69 | unsigned int * dump; |
| 70 | int i; |
| 71 | |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 72 | if(!regval) { |
| 73 | application_not_running(); |
Alexandre Julliard | 73450d6 | 1994-05-18 18:29:32 +0000 | [diff] [blame] | 74 | return; |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 75 | } |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 76 | |
| 77 | fprintf(stderr,"Stack dump:\n"); |
| 78 | dump = (int*) SC_EIP(dbg_mask); |
| 79 | for(i=0; i<22; i++) |
| 80 | { |
| 81 | fprintf(stderr," %8.8x", *dump++); |
| 82 | if ((i % 8) == 7) |
| 83 | fprintf(stderr,"\n"); |
| 84 | } |
| 85 | fprintf(stderr,"\n"); |
| 86 | } |
| 87 | |
| 88 | |
| 89 | void examine_memory(int addr, int count, char format){ |
| 90 | char * pnt; |
| 91 | unsigned int * dump; |
| 92 | unsigned short int * wdump; |
| 93 | int i; |
| 94 | |
| 95 | if((addr & 0xffff0000) == 0 && dbg_mode == 16) |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 96 | addr |= (format == 'i' ? SC_CS : SC_DS) << 16; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 97 | |
| 98 | if(format != 'i' && count > 1) { |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 99 | print_address(addr, stderr, dbg_mode); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 100 | fprintf(stderr,": "); |
| 101 | }; |
| 102 | |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 103 | switch(format){ |
| 104 | case 's': |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 105 | pnt = dbg_mode == 16 ? (char *)PTR_SEG_TO_LIN(addr) |
| 106 | : (char *)addr; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 107 | if (count == 1) count = 256; |
| 108 | while(*pnt && count) { |
| 109 | fputc( *pnt++, stderr); |
| 110 | count--; |
| 111 | }; |
| 112 | fprintf(stderr,"\n"); |
| 113 | return; |
| 114 | |
| 115 | case 'i': |
| 116 | for(i=0; i<count; i++) { |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 117 | print_address(addr, stderr, dbg_mode); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 118 | fprintf(stderr,": "); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 119 | addr = db_disasm( addr, 0, (dbg_mode == 16) ); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 120 | fprintf(stderr,"\n"); |
| 121 | }; |
| 122 | return; |
| 123 | case 'x': |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 124 | dump = dbg_mode == 16 ? (unsigned int *)PTR_SEG_TO_LIN(addr) |
| 125 | : (unsigned int *)addr; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 126 | for(i=0; i<count; i++) |
| 127 | { |
| 128 | fprintf(stderr," %8.8x", *dump++); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 129 | addr += 4; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 130 | if ((i % 8) == 7) { |
| 131 | fprintf(stderr,"\n"); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 132 | print_address(addr, stderr, dbg_mode); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 133 | fprintf(stderr,": "); |
| 134 | }; |
| 135 | } |
| 136 | fprintf(stderr,"\n"); |
| 137 | return; |
| 138 | |
| 139 | case 'd': |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 140 | dump = dbg_mode == 16 ? (unsigned int *)PTR_SEG_TO_LIN(addr) |
| 141 | : (unsigned int *)addr; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 142 | for(i=0; i<count; i++) |
| 143 | { |
| 144 | fprintf(stderr," %d", *dump++); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 145 | addr += 4; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 146 | if ((i % 8) == 7) { |
| 147 | fprintf(stderr,"\n"); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 148 | print_address(addr, stderr, dbg_mode); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 149 | fprintf(stderr,": "); |
| 150 | }; |
| 151 | } |
| 152 | fprintf(stderr,"\n"); |
| 153 | return; |
| 154 | |
| 155 | case 'w': |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 156 | wdump = dbg_mode == 16 ? (unsigned short *)PTR_SEG_TO_LIN(addr) |
| 157 | : (unsigned short *)addr; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 158 | for(i=0; i<count; i++) |
| 159 | { |
Alexandre Julliard | 0e60778 | 1993-11-03 19:23:37 +0000 | [diff] [blame] | 160 | fprintf(stderr," %x", *wdump++); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 161 | addr += 2; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 162 | if ((i % 10) == 7) { |
| 163 | fprintf(stderr,"\n"); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 164 | print_address(addr, stderr, dbg_mode); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 165 | fprintf(stderr,": "); |
| 166 | }; |
| 167 | } |
| 168 | fprintf(stderr,"\n"); |
| 169 | return; |
| 170 | |
| 171 | case 'c': |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 172 | pnt = dbg_mode == 16 ? (char *)PTR_SEG_TO_LIN(addr) |
| 173 | : (char *)addr; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 174 | for(i=0; i<count; i++) |
| 175 | { |
| 176 | if(*pnt < 0x20) { |
| 177 | fprintf(stderr," "); |
| 178 | pnt++; |
| 179 | } else |
| 180 | fprintf(stderr," %c", *pnt++); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 181 | addr++; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 182 | if ((i % 32) == 7) { |
| 183 | fprintf(stderr,"\n"); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 184 | print_address(addr, stderr, dbg_mode); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 185 | fprintf(stderr,": "); |
| 186 | }; |
| 187 | } |
| 188 | fprintf(stderr,"\n"); |
| 189 | return; |
| 190 | |
| 191 | case 'b': |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 192 | pnt = dbg_mode == 16 ? (char *)PTR_SEG_TO_LIN(addr) |
| 193 | : (char *)addr; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 194 | for(i=0; i<count; i++) |
| 195 | { |
Alexandre Julliard | 234bc24 | 1994-12-10 13:02:28 +0000 | [diff] [blame] | 196 | fprintf(stderr," %02x", (*pnt++) & 0xff); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 197 | addr++; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 198 | if ((i % 32) == 7) { |
| 199 | fprintf(stderr,"\n"); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 200 | print_address(addr, stderr, dbg_mode); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 201 | fprintf(stderr,": "); |
| 202 | }; |
| 203 | } |
| 204 | fprintf(stderr,"\n"); |
| 205 | return; |
| 206 | }; |
| 207 | |
| 208 | /* The rest are fairly straightforward */ |
| 209 | |
| 210 | fprintf(stderr,"examine mem: %x %d %c\n", addr, count, format); |
| 211 | } |
| 212 | |
| 213 | char * helptext[] = { |
| 214 | "The commands accepted by the Wine debugger are a small subset", |
| 215 | "of the commands that gdb would accept. The commands currently", |
| 216 | "are:\n", |
Alexandre Julliard | 1850655 | 1995-01-24 16:21:01 +0000 | [diff] [blame] | 217 | " break *<addr> bt", |
| 218 | " disable bpnum enable bpnum", |
| 219 | " help quit", |
| 220 | " x <expr> cont", |
| 221 | " mode [16,32] print <expr>", |
| 222 | " set <reg> = <expr> set *<expr> = <expr>", |
| 223 | " info [reg,stack,break,segments] symbolfile <filename>", |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 224 | " define <identifier> <expr>", |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 225 | "", |
| 226 | "The 'x' command accepts repeat counts and formats (including 'i') in the", |
| 227 | "same way that gdb does.", |
| 228 | "", |
| 229 | " The following are examples of legal expressions:", |
| 230 | " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)", |
| 231 | " Also, a nm format symbol table can be read from a file using the", |
| 232 | " symbolfile command. Symbols can also be defined individually with", |
| 233 | " the define command.", |
| 234 | "", |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 235 | NULL}; |
| 236 | |
| 237 | void dbg_help(){ |
| 238 | int i; |
| 239 | i = 0; |
| 240 | while(helptext[i]) fprintf(stderr,"%s\n", helptext[i++]); |
| 241 | } |
| 242 | |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 243 | |
| 244 | struct frame{ |
| 245 | union{ |
| 246 | struct { |
| 247 | unsigned short saved_bp; |
| 248 | unsigned short saved_ip; |
| 249 | unsigned short saved_cs; |
| 250 | } win16; |
| 251 | struct { |
| 252 | unsigned long saved_bp; |
| 253 | unsigned long saved_ip; |
| 254 | unsigned short saved_cs; |
| 255 | } win32; |
| 256 | } u; |
| 257 | }; |
| 258 | |
| 259 | |
| 260 | void dbg_bt(){ |
| 261 | struct frame * frame; |
| 262 | unsigned short cs; |
| 263 | int frameno = 0; |
| 264 | |
| 265 | if(!regval) { |
| 266 | application_not_running(); |
Alexandre Julliard | 73450d6 | 1994-05-18 18:29:32 +0000 | [diff] [blame] | 267 | return; |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 268 | } |
| 269 | |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 270 | if (dbg_mode == 16) |
| 271 | frame = (struct frame *)PTR_SEG_OFF_TO_LIN( SC_SS, SC_BP & ~1 ); |
| 272 | else |
| 273 | frame = (struct frame *)SC_EBP(dbg_mask); |
Alexandre Julliard | 1850655 | 1995-01-24 16:21:01 +0000 | [diff] [blame] | 274 | |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 275 | fprintf(stderr,"Backtrace:\n"); |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 276 | cs = SC_CS; |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 277 | while((cs & 3) == 3) { |
| 278 | /* See if in 32 bit mode or not. Assume GDT means 32 bit. */ |
| 279 | if ((cs & 7) != 7) { |
Alexandre Julliard | aca0578 | 1994-10-17 18:12:41 +0000 | [diff] [blame] | 280 | void CallTo32(); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 281 | fprintf(stderr,"%d ",frameno++); |
| 282 | print_address(frame->u.win32.saved_ip,stderr,32); |
| 283 | fprintf( stderr, "\n" ); |
Alexandre Julliard | 1850655 | 1995-01-24 16:21:01 +0000 | [diff] [blame] | 284 | if(frame->u.win32.saved_ip<((unsigned long)CallTo32+1000))break; |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 285 | frame = (struct frame *) frame->u.win32.saved_bp; |
| 286 | } else { |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 287 | if (frame->u.win16.saved_bp & 1) cs = frame->u.win16.saved_cs; |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 288 | fprintf(stderr,"%d %4.4x:%4.4x\n", frameno++, cs, |
| 289 | frame->u.win16.saved_ip); |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame^] | 290 | frame = (struct frame *) PTR_SEG_OFF_TO_LIN( SC_SS, frame->u.win16.saved_bp & ~1); |
| 291 | if ((cs & 7) != 7) /* switching to 32-bit mode */ |
| 292 | { |
| 293 | extern int IF1632_Saved32_ebp; |
| 294 | frame = (struct frame *)IF1632_Saved32_ebp; |
| 295 | } |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 296 | } |
| 297 | } |
Alexandre Julliard | aca0578 | 1994-10-17 18:12:41 +0000 | [diff] [blame] | 298 | putchar('\n'); |
Alexandre Julliard | d18872d | 1994-05-11 12:18:19 +0000 | [diff] [blame] | 299 | } |
| 300 | |