Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Wine debugger utility routines |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright 1993 Eric Youngdale |
| 5 | * Copyright 1995 Alexandre Julliard |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Lesser General Public |
| 9 | * License as published by the Free Software Foundation; either |
| 10 | * version 2.1 of the License, or (at your option) any later version. |
| 11 | * |
| 12 | * This library is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * Lesser General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU Lesser General Public |
| 18 | * License along with this library; if not, write to the Free Software |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 20 | */ |
| 21 | |
Marcus Meissner | b0d52b0 | 1999-02-28 19:59:00 +0000 | [diff] [blame] | 22 | #include "config.h" |
Alexandre Julliard | ecc3712 | 1994-11-22 16:31:29 +0000 | [diff] [blame] | 23 | #include <stdlib.h> |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 24 | #include <string.h> |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 25 | #include "winbase.h" |
| 26 | #include "wingdi.h" |
| 27 | #include "winuser.h" |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 28 | #include "tlhelp32.h" |
Alexandre Julliard | ded3038 | 1995-07-06 17:18:27 +0000 | [diff] [blame] | 29 | #include "debugger.h" |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 30 | #include "expr.h" |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 31 | |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 32 | /*********************************************************************** |
Eric Pouech | b151865 | 1999-02-20 16:39:51 +0000 | [diff] [blame] | 33 | * DEBUG_PrintBasic |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 34 | * |
| 35 | * Implementation of the 'print' command. |
| 36 | */ |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 37 | void DEBUG_PrintBasic( const DBG_VALUE* value, int count, char format ) |
Alexandre Julliard | e2abbb1 | 1995-03-19 17:39:39 +0000 | [diff] [blame] | 38 | { |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 39 | char * default_format; |
| 40 | long long int res; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 41 | |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 42 | assert(value->cookie == DV_TARGET || value->cookie == DV_HOST); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 43 | if (value->type == NULL) |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 44 | { |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 45 | DEBUG_Printf(DBG_CHN_MESG, "Unable to evaluate expression\n"); |
| 46 | return; |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 47 | } |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 48 | |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 49 | default_format = NULL; |
| 50 | res = DEBUG_GetExprValue(value, &default_format); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 51 | |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 52 | switch (format) |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 53 | { |
| 54 | case 'x': |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 55 | if (value->addr.seg) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 56 | { |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 57 | DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%04lx", (long unsigned int)res); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 58 | } |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 59 | else |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 60 | { |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 61 | DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "0x%08lx", (long unsigned int)res); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 62 | } |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 63 | break; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 64 | |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 65 | case 'd': |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 66 | DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%ld\n", (long int)res); |
| 67 | break; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 68 | |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 69 | case 'c': |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 70 | DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '%c'", |
| 71 | (char)(res & 0xff), (char)(res & 0xff)); |
| 72 | break; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 73 | |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 74 | case 'u': |
| 75 | { |
| 76 | WCHAR wch = (WCHAR)(res & 0xFFFF); |
| 77 | DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%d = '", (unsigned)(res & 0xffff)); |
| 78 | DEBUG_OutputW(DBG_CHN_MESG, &wch, 1); |
| 79 | DEBUG_Printf(DBG_CHN_MESG, "'"); |
| 80 | } |
| 81 | break; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 82 | |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 83 | case 'i': |
| 84 | case 's': |
| 85 | case 'w': |
| 86 | case 'b': |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 87 | DEBUG_Printf(DBG_CHN_MESG, "Format specifier '%c' is meaningless in 'print' command\n", format); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 88 | case 0: |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 89 | if (default_format == NULL) break; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 90 | |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 91 | if (strstr(default_format, "%S") != NULL) |
| 92 | { |
| 93 | char* ptr; |
| 94 | int state = 0; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 95 | |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 96 | /* FIXME: simplistic implementation for default_format being |
| 97 | * foo%Sbar => will print foo, then string then bar |
| 98 | */ |
| 99 | for (ptr = default_format; *ptr; ptr++) |
Eric Pouech | 02ecb68 | 2001-12-21 20:29:58 +0000 | [diff] [blame] | 100 | { |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 101 | if (*ptr == '%') |
| 102 | { |
| 103 | state++; |
| 104 | } |
| 105 | else if (state == 1) |
| 106 | { |
| 107 | if (*ptr == 'S') |
| 108 | { |
| 109 | DBG_ADDR addr; |
| 110 | |
| 111 | addr.seg = 0; |
| 112 | addr.off = (long)res; |
| 113 | DEBUG_nchar += DEBUG_PrintStringA(DBG_CHN_MESG, &addr, -1); |
| 114 | } |
| 115 | else |
| 116 | { |
| 117 | /* shouldn't happen */ |
| 118 | DEBUG_Printf(DBG_CHN_MESG, "%%%c", *ptr); |
| 119 | DEBUG_nchar += 2; |
| 120 | } |
| 121 | state = 0; |
| 122 | } |
| 123 | else |
| 124 | { |
| 125 | DEBUG_OutputA(DBG_CHN_MESG, ptr, 1); |
| 126 | DEBUG_nchar++; |
| 127 | } |
Eric Pouech | 02ecb68 | 2001-12-21 20:29:58 +0000 | [diff] [blame] | 128 | } |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 129 | } |
| 130 | else if (strcmp(default_format, "%B") == 0) |
| 131 | { |
| 132 | DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, "%s", res ? "true" : "false"); |
| 133 | } |
| 134 | else if (strcmp(default_format, "%R") == 0) |
| 135 | { |
| 136 | if (value->cookie == DV_HOST) |
| 137 | DEBUG_InfoRegisters((CONTEXT*)value->addr.off); |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 138 | else |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 139 | DEBUG_Printf(DBG_CHN_MESG, "NIY: info on register struct in debuggee address space\n"); |
| 140 | DEBUG_nchar = 0; |
| 141 | } |
| 142 | else |
| 143 | { |
| 144 | DEBUG_nchar += DEBUG_Printf(DBG_CHN_MESG, default_format, res); |
| 145 | } |
Eric Pouech | 7bec5c1 | 2002-05-25 21:18:34 +0000 | [diff] [blame] | 146 | break; |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 147 | } |
| 148 | } |
| 149 | |
| 150 | |
| 151 | /*********************************************************************** |
| 152 | * DEBUG_PrintAddress |
| 153 | * |
| 154 | * Print an 16- or 32-bit address, with the nearest symbol if any. |
| 155 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 156 | struct symbol_info |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 157 | DEBUG_PrintAddress( const DBG_ADDR *addr, enum dbg_mode mode, int flag ) |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 158 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 159 | struct symbol_info rtn; |
| 160 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 161 | const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0, |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 162 | &rtn.list ); |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 163 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 164 | if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg&0xFFFF ); |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 165 | if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off ); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 166 | else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off ); |
| 167 | if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 168 | return rtn; |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 169 | } |
| 170 | /*********************************************************************** |
| 171 | * DEBUG_PrintAddressAndArgs |
| 172 | * |
| 173 | * Print an 16- or 32-bit address, with the nearest symbol if any. |
| 174 | * Similar to DEBUG_PrintAddress, but we print the arguments to |
| 175 | * each function (if known). This is useful in a backtrace. |
| 176 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 177 | struct symbol_info |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 178 | DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, enum dbg_mode mode, |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 179 | unsigned int ebp, int flag ) |
| 180 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 181 | struct symbol_info rtn; |
| 182 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 183 | const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp, |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 184 | &rtn.list ); |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 185 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 186 | if (addr->seg) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx:", addr->seg ); |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 187 | if (mode != MODE_32) DEBUG_Printf( DBG_CHN_MESG, "0x%04lx", addr->off ); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 188 | else DEBUG_Printf( DBG_CHN_MESG, "0x%08lx", addr->off ); |
| 189 | if (name) DEBUG_Printf( DBG_CHN_MESG, " (%s)", name ); |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 190 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 191 | return rtn; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 192 | } |
| 193 | |
| 194 | |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 195 | /*********************************************************************** |
| 196 | * DEBUG_Help |
| 197 | * |
| 198 | * Implementation of the 'help' command. |
| 199 | */ |
| 200 | void DEBUG_Help(void) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 201 | { |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 202 | int i = 0; |
Alexandre Julliard | d90840e | 1996-06-11 16:02:08 +0000 | [diff] [blame] | 203 | static const char * const helptext[] = |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 204 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 205 | "The commands accepted by the Wine debugger are a reasonable", |
Alexandre Julliard | 2197901 | 1997-03-05 08:22:35 +0000 | [diff] [blame] | 206 | "subset of the commands that gdb accepts.", |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 207 | "The commands currently are:", |
Alexandre Julliard | 410ae4f | 1999-06-18 18:23:11 +0000 | [diff] [blame] | 208 | " help quit", |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 209 | " break [*<addr>] delete break bpnum", |
| 210 | " disable bpnum enable bpnum", |
Alexandre Julliard | 410ae4f | 1999-06-18 18:23:11 +0000 | [diff] [blame] | 211 | " condition <bpnum> [<expr>] pass", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 212 | " bt cont [N]", |
| 213 | " step [N] next [N]", |
| 214 | " stepi [N] nexti [N]", |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 215 | " x <addr> print <expr>", |
| 216 | " set <reg> = <expr> set *<addr> = <expr>", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 217 | " up down", |
Alexandre Julliard | 2197901 | 1997-03-05 08:22:35 +0000 | [diff] [blame] | 218 | " list <lines> disassemble [<addr>][,<addr>]", |
| 219 | " frame <n> finish", |
| 220 | " show dir dir <path>", |
| 221 | " display <expr> undisplay <disnum>", |
Marcus Meissner | 40c11eb | 1999-01-24 09:37:33 +0000 | [diff] [blame] | 222 | " delete display <disnum> debugmsg <class>[-+]<type>\n", |
Alexandre Julliard | 954a413 | 2000-09-24 03:15:50 +0000 | [diff] [blame] | 223 | " mode [16,32,vm86] walk [wnd,class,queue,module,", |
Eric Pouech | d33bcb6 | 2000-03-15 19:57:20 +0000 | [diff] [blame] | 224 | " whatis process,modref <pid>]", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 225 | " info (see 'help info' for options)\n", |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 226 | |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 227 | "The 'x' command accepts repeat counts and formats (including 'i') in the", |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 228 | "same way that gdb does.\n", |
| 229 | |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 230 | " The following are examples of legal expressions:", |
| 231 | " $eax $eax+0x3 0x1000 ($eip + 256) *$eax *($esp + 3)", |
| 232 | " Also, a nm format symbol table can be read from a file using the", |
| 233 | " symbolfile command. Symbols can also be defined individually with", |
| 234 | " the define command.", |
| 235 | "", |
Alexandre Julliard | 808cb04 | 1995-08-17 17:11:36 +0000 | [diff] [blame] | 236 | NULL |
| 237 | }; |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 238 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 239 | while(helptext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", helptext[i++]); |
Alexandre Julliard | f0b2354 | 1993-09-29 12:21:49 +0000 | [diff] [blame] | 240 | } |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 241 | |
| 242 | |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 243 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 244 | * DEBUG_HelpInfo |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 245 | * |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 246 | * Implementation of the 'help info' command. |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 247 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 248 | void DEBUG_HelpInfo(void) |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 249 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 250 | int i = 0; |
| 251 | static const char * const infotext[] = |
| 252 | { |
| 253 | "The info commands allow you to get assorted bits of interesting stuff", |
| 254 | "to be displayed. The options are:", |
| 255 | " info break Dumps information about breakpoints", |
| 256 | " info display Shows auto-display expressions in use", |
| 257 | " info locals Displays values of all local vars for current frame", |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 258 | " info maps Dumps all virtual memory mappings", |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 259 | " info module <handle> Displays internal module state", |
| 260 | " info queue <handle> Displays internal queue state", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 261 | " info reg Displays values in all registers at top of stack", |
| 262 | " info segments Dumps information about all known segments", |
| 263 | " info share Dumps information about shared libraries", |
| 264 | " info stack Dumps information about top of stack", |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 265 | " info wnd <handle> Displays internal window state", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 266 | "", |
| 267 | NULL |
| 268 | }; |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 269 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 270 | while(infotext[i]) DEBUG_Printf(DBG_CHN_MESG,"%s\n", infotext[i++]); |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 271 | } |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 272 | |
| 273 | /* FIXME: merge InfoClass and InfoClass2 */ |
| 274 | void DEBUG_InfoClass(const char* name) |
| 275 | { |
| 276 | WNDCLASSEXA wca; |
| 277 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 278 | if (!GetClassInfoEx(0, name, &wca)) { |
| 279 | DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 280 | return; |
| 281 | } |
| 282 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 283 | DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 284 | DEBUG_Printf(DBG_CHN_MESG, |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 285 | "style=%08x wndProc=%08lx\n" |
François Gouget | d5042c4 | 2000-12-29 05:38:00 +0000 | [diff] [blame] | 286 | "inst=%p icon=%p cursor=%p bkgnd=%p\n" |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 287 | "clsExtra=%d winExtra=%d\n", |
| 288 | wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance, |
| 289 | wca.hIcon, wca.hCursor, wca.hbrBackground, |
| 290 | wca.cbClsExtra, wca.cbWndExtra); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 291 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 292 | /* FIXME: |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 293 | * + print #windows (or even list of windows...) |
| 294 | * + print extra bytes => this requires a window handle on this very class... |
| 295 | */ |
| 296 | } |
| 297 | |
| 298 | static void DEBUG_InfoClass2(HWND hWnd, const char* name) |
| 299 | { |
| 300 | WNDCLASSEXA wca; |
| 301 | |
François Gouget | d5042c4 | 2000-12-29 05:38:00 +0000 | [diff] [blame] | 302 | if (!GetClassInfoEx((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), name, &wca)) { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 303 | DEBUG_Printf(DBG_CHN_MESG, "Cannot find class '%s'\n", name); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 304 | return; |
| 305 | } |
| 306 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 307 | DEBUG_Printf(DBG_CHN_MESG, "Class '%s':\n", name); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 308 | DEBUG_Printf(DBG_CHN_MESG, |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 309 | "style=%08x wndProc=%08lx\n" |
François Gouget | d5042c4 | 2000-12-29 05:38:00 +0000 | [diff] [blame] | 310 | "inst=%p icon=%p cursor=%p bkgnd=%p\n" |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 311 | "clsExtra=%d winExtra=%d\n", |
| 312 | wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance, |
| 313 | wca.hIcon, wca.hCursor, wca.hbrBackground, |
| 314 | wca.cbClsExtra, wca.cbWndExtra); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 315 | |
| 316 | if (wca.cbClsExtra) { |
| 317 | int i; |
| 318 | WORD w; |
| 319 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 320 | DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" ); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 321 | for (i = 0; i < wca.cbClsExtra / 2; i++) { |
| 322 | w = GetClassWord(hWnd, i * 2); |
| 323 | /* FIXME: depends on i386 endian-ity */ |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 324 | DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w)); |
| 325 | DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w)); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 326 | } |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 327 | DEBUG_Printf(DBG_CHN_MESG, "\n" ); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 328 | } |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 329 | DEBUG_Printf(DBG_CHN_MESG, "\n" ); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 330 | } |
| 331 | |
| 332 | struct class_walker { |
| 333 | ATOM* table; |
| 334 | int used; |
| 335 | int alloc; |
| 336 | }; |
| 337 | |
| 338 | static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw) |
| 339 | { |
| 340 | char clsName[128]; |
| 341 | int i; |
| 342 | ATOM atom; |
| 343 | HWND child; |
| 344 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 345 | if (!GetClassName(hWnd, clsName, sizeof(clsName))) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 346 | return; |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 347 | if ((atom = FindAtom(clsName)) == 0) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 348 | return; |
| 349 | |
| 350 | for (i = 0; i < cw->used; i++) { |
| 351 | if (cw->table[i] == atom) |
| 352 | break; |
| 353 | } |
| 354 | if (i == cw->used) { |
| 355 | if (cw->used >= cw->alloc) { |
| 356 | cw->alloc += 16; |
| 357 | cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM)); |
| 358 | } |
| 359 | cw->table[cw->used++] = atom; |
| 360 | DEBUG_InfoClass2(hWnd, clsName); |
| 361 | } |
| 362 | do { |
| 363 | if ((child = GetWindow(hWnd, GW_CHILD)) != 0) |
| 364 | DEBUG_WalkClassesHelper(child, cw); |
| 365 | } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0); |
| 366 | } |
| 367 | |
| 368 | void DEBUG_WalkClasses(void) |
| 369 | { |
| 370 | struct class_walker cw; |
| 371 | |
| 372 | cw.table = NULL; |
| 373 | cw.used = cw.alloc = 0; |
| 374 | DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw); |
| 375 | DBG_free(cw.table); |
| 376 | } |
| 377 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 378 | void DEBUG_DumpQueue(DWORD q) |
| 379 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 380 | DEBUG_Printf(DBG_CHN_MESG, "No longer doing info queue '0x%08lx'\n", q); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 381 | } |
| 382 | |
| 383 | void DEBUG_WalkQueues(void) |
| 384 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 385 | DEBUG_Printf(DBG_CHN_MESG, "No longer walking queues list\n"); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 386 | } |
| 387 | |
| 388 | void DEBUG_InfoWindow(HWND hWnd) |
| 389 | { |
| 390 | char clsName[128]; |
| 391 | char wndName[128]; |
| 392 | RECT clientRect; |
| 393 | RECT windowRect; |
| 394 | int i; |
| 395 | WORD w; |
| 396 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 397 | if (!GetClassName(hWnd, clsName, sizeof(clsName))) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 398 | strcpy(clsName, "-- Unknown --"); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 399 | if (!GetWindowText(hWnd, wndName, sizeof(wndName))) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 400 | strcpy(wndName, "-- Empty --"); |
| 401 | if (!GetClientRect(hWnd, &clientRect)) |
| 402 | SetRectEmpty(&clientRect); |
| 403 | if (!GetWindowRect(hWnd, &windowRect)) |
| 404 | SetRectEmpty(&windowRect); |
| 405 | |
| 406 | /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */ |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 407 | DEBUG_Printf(DBG_CHN_MESG, |
François Gouget | d5042c4 | 2000-12-29 05:38:00 +0000 | [diff] [blame] | 408 | "next=%p child=%p parent=%p owner=%p class='%s'\n" |
| 409 | "inst=%p active=%p idmenu=%08lx\n" |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 410 | "style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n" |
François Gouget | d5042c4 | 2000-12-29 05:38:00 +0000 | [diff] [blame] | 411 | "client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%p\n", |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 412 | GetWindow(hWnd, GW_HWNDNEXT), |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 413 | GetWindow(hWnd, GW_CHILD), |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 414 | GetParent(hWnd), |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 415 | GetWindow(hWnd, GW_OWNER), |
| 416 | clsName, |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 417 | (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 418 | GetLastActivePopup(hWnd), |
| 419 | GetWindowLong(hWnd, GWL_ID), |
| 420 | GetWindowLong(hWnd, GWL_STYLE), |
| 421 | GetWindowLong(hWnd, GWL_EXSTYLE), |
| 422 | GetWindowLong(hWnd, GWL_WNDPROC), |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 423 | wndName, |
| 424 | clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, |
| 425 | windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 426 | GetSystemMenu(hWnd, FALSE)); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 427 | |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 428 | if (GetClassLong(hWnd, GCL_CBWNDEXTRA)) { |
| 429 | DEBUG_Printf(DBG_CHN_MESG, "Extra bytes:" ); |
| 430 | for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++) { |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 431 | w = GetWindowWord(hWnd, i * 2); |
| 432 | /* FIXME: depends on i386 endian-ity */ |
Eric Pouech | 66dbcaf | 2002-02-26 00:36:46 +0000 | [diff] [blame] | 433 | DEBUG_Printf(DBG_CHN_MESG, " %02x", HIBYTE(w)); |
| 434 | DEBUG_Printf(DBG_CHN_MESG, " %02x", LOBYTE(w)); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 435 | } |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 436 | DEBUG_Printf(DBG_CHN_MESG, "\n"); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 437 | } |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 438 | DEBUG_Printf(DBG_CHN_MESG, "\n"); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 439 | } |
| 440 | |
| 441 | void DEBUG_WalkWindows(HWND hWnd, int indent) |
| 442 | { |
| 443 | char clsName[128]; |
| 444 | char wndName[128]; |
| 445 | HWND child; |
| 446 | |
| 447 | if (!IsWindow(hWnd)) |
| 448 | hWnd = GetDesktopWindow(); |
| 449 | |
| 450 | if (!indent) /* first time around */ |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 451 | DEBUG_Printf(DBG_CHN_MESG, |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 452 | "%-16.16s %-17.17s %-8.8s %s\n", |
| 453 | "hwnd", "Class Name", " Style", " WndProc Text"); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 454 | |
| 455 | do { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 456 | if (!GetClassName(hWnd, clsName, sizeof(clsName))) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 457 | strcpy(clsName, "-- Unknown --"); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 458 | if (!GetWindowText(hWnd, wndName, sizeof(wndName))) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 459 | strcpy(wndName, "-- Empty --"); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 460 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 461 | /* FIXME: missing hmemTaskQ */ |
François Gouget | d5042c4 | 2000-12-29 05:38:00 +0000 | [diff] [blame] | 462 | DEBUG_Printf(DBG_CHN_MESG, "%*s%04x%*s", indent, "", (UINT)hWnd, 13-indent,""); |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 463 | DEBUG_Printf(DBG_CHN_MESG, "%-17.17s %08lx %08lx %.14s\n", |
| 464 | clsName, GetWindowLong(hWnd, GWL_STYLE), |
| 465 | GetWindowLong(hWnd, GWL_WNDPROC), wndName); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 466 | |
| 467 | if ((child = GetWindow(hWnd, GW_CHILD)) != 0) |
| 468 | DEBUG_WalkWindows(child, indent + 1 ); |
| 469 | } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0); |
| 470 | } |
| 471 | |
| 472 | void DEBUG_WalkProcess(void) |
| 473 | { |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 474 | HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); |
| 475 | if (snap != INVALID_HANDLE_VALUE) |
| 476 | { |
| 477 | PROCESSENTRY32 entry; |
| 478 | DWORD current = DEBUG_CurrProcess ? DEBUG_CurrProcess->pid : 0; |
Eric Pouech | f182235 | 2000-05-11 21:43:43 +0000 | [diff] [blame] | 479 | BOOL ok; |
| 480 | |
Eric Pouech | 66dbcaf | 2002-02-26 00:36:46 +0000 | [diff] [blame] | 481 | entry.dwSize = sizeof(entry); |
| 482 | ok = Process32First( snap, &entry ); |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 483 | |
Eric Pouech | 66dbcaf | 2002-02-26 00:36:46 +0000 | [diff] [blame] | 484 | DEBUG_Printf(DBG_CHN_MESG, " %-8.8s %-8.8s %-8.8s %s\n", |
| 485 | "pid", "threads", "parent", "executable" ); |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 486 | while (ok) |
| 487 | { |
| 488 | if (entry.th32ProcessID != GetCurrentProcessId()) |
Eric Pouech | 66dbcaf | 2002-02-26 00:36:46 +0000 | [diff] [blame] | 489 | DEBUG_Printf(DBG_CHN_MESG, "%c%08lx %-8ld %08lx '%s'\n", |
| 490 | (entry.th32ProcessID == current) ? '>' : ' ', |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 491 | entry.th32ProcessID, entry.cntThreads, |
Eric Pouech | 66dbcaf | 2002-02-26 00:36:46 +0000 | [diff] [blame] | 492 | entry.th32ParentProcessID, entry.szExeFile); |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 493 | ok = Process32Next( snap, &entry ); |
| 494 | } |
| 495 | CloseHandle( snap ); |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | void DEBUG_WalkThreads(void) |
| 500 | { |
| 501 | HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); |
| 502 | if (snap != INVALID_HANDLE_VALUE) |
| 503 | { |
Eric Pouech | 800773f | 2001-08-06 17:51:52 +0000 | [diff] [blame] | 504 | THREADENTRY32 entry; |
| 505 | DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0; |
| 506 | BOOL ok; |
| 507 | DWORD lastProcessId = 0; |
Eric Pouech | f182235 | 2000-05-11 21:43:43 +0000 | [diff] [blame] | 508 | |
Eric Pouech | 800773f | 2001-08-06 17:51:52 +0000 | [diff] [blame] | 509 | entry.dwSize = sizeof(entry); |
| 510 | ok = Thread32First( snap, &entry ); |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 511 | |
Eric Pouech | 800773f | 2001-08-06 17:51:52 +0000 | [diff] [blame] | 512 | DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" ); |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 513 | while (ok) |
| 514 | { |
| 515 | if (entry.th32OwnerProcessID != GetCurrentProcessId()) |
Eric Pouech | 800773f | 2001-08-06 17:51:52 +0000 | [diff] [blame] | 516 | { |
| 517 | /* FIXME: this assumes that, in the snapshot, all threads of a same process are |
| 518 | * listed sequentially, which is not specified in the doc (Wine's implementation |
| 519 | * does it) |
| 520 | */ |
| 521 | if (entry.th32OwnerProcessID != lastProcessId) |
| 522 | { |
| 523 | DBG_PROCESS* p = DEBUG_GetProcess(entry.th32OwnerProcessID); |
| 524 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 525 | DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n", |
Eric Pouech | 800773f | 2001-08-06 17:51:52 +0000 | [diff] [blame] | 526 | entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : ""); |
| 527 | lastProcessId = entry.th32OwnerProcessID; |
| 528 | } |
| 529 | DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n", |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 530 | entry.th32ThreadID, entry.tpBasePri, |
Eric Pouech | 800773f | 2001-08-06 17:51:52 +0000 | [diff] [blame] | 531 | (entry.th32ThreadID == current) ? " <==" : ""); |
| 532 | |
| 533 | } |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 534 | ok = Thread32Next( snap, &entry ); |
| 535 | } |
Eric Pouech | 800773f | 2001-08-06 17:51:52 +0000 | [diff] [blame] | 536 | |
Alexandre Julliard | a679541 | 2000-04-16 19:46:35 +0000 | [diff] [blame] | 537 | CloseHandle( snap ); |
| 538 | } |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 539 | } |
| 540 | |
| 541 | void DEBUG_WalkModref(DWORD p) |
| 542 | { |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 543 | DEBUG_Printf(DBG_CHN_MESG, "No longer walking module references list\n"); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 544 | } |
| 545 | |
Alexandre Julliard | 3972efa | 2002-08-13 18:04:01 +0000 | [diff] [blame] | 546 | /*********************************************************************** |
| 547 | * DEBUG_WalkExceptions |
| 548 | * |
| 549 | * Walk the exception frames of a given thread. |
| 550 | */ |
| 551 | void DEBUG_WalkExceptions(DWORD tid) |
| 552 | { |
| 553 | DBG_THREAD * thread; |
| 554 | void *next_frame; |
| 555 | |
| 556 | DEBUG_Printf( DBG_CHN_MESG, "Exception frames:\n" ); |
| 557 | |
| 558 | if (tid == DEBUG_CurrTid) thread = DEBUG_CurrThread; |
| 559 | else |
| 560 | { |
| 561 | thread = DEBUG_GetThread(DEBUG_CurrProcess, tid); |
| 562 | |
| 563 | if (!thread) |
| 564 | { |
| 565 | DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid); |
| 566 | return; |
| 567 | } |
| 568 | if (SuspendThread( thread->handle ) == -1) |
| 569 | { |
| 570 | DEBUG_Printf( DBG_CHN_MESG, "Can't suspend thread id (0x%08lx)\n", tid); |
| 571 | return; |
| 572 | } |
| 573 | } |
| 574 | |
| 575 | if (!DEBUG_READ_MEM(thread->teb, &next_frame, sizeof(next_frame))) |
| 576 | { |
| 577 | DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:except_frame\n"); |
| 578 | return; |
| 579 | } |
| 580 | |
| 581 | while (next_frame != (void *)-1) |
| 582 | { |
| 583 | EXCEPTION_FRAME frame; |
| 584 | |
| 585 | DEBUG_Printf( DBG_CHN_MESG, "%p: ", next_frame ); |
| 586 | if (!DEBUG_READ_MEM(next_frame, &frame, sizeof(frame))) |
| 587 | { |
| 588 | DEBUG_Printf( DBG_CHN_MESG, "Invalid frame address\n" ); |
| 589 | break; |
| 590 | } |
| 591 | DEBUG_Printf( DBG_CHN_MESG, "prev=%p handler=%p\n", frame.Prev, frame.Handler ); |
| 592 | next_frame = frame.Prev; |
| 593 | } |
| 594 | |
| 595 | if (tid != DEBUG_CurrTid) ResumeThread( thread->handle ); |
| 596 | } |
| 597 | |
| 598 | |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 599 | void DEBUG_InfoSegments(DWORD start, int length) |
| 600 | { |
| 601 | char flags[3]; |
| 602 | DWORD i; |
| 603 | LDT_ENTRY le; |
| 604 | |
| 605 | if (length == -1) length = (8192 - start); |
| 606 | |
| 607 | for (i = start; i < start + length; i++) |
| 608 | { |
| 609 | if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le)) |
| 610 | continue; |
| 611 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 612 | if (le.HighWord.Bits.Type & 0x08) |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 613 | { |
| 614 | flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-'; |
| 615 | flags[1] = '-'; |
| 616 | flags[2] = 'x'; |
| 617 | } |
| 618 | else |
| 619 | { |
| 620 | flags[0] = 'r'; |
| 621 | flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-'; |
| 622 | flags[2] = '-'; |
| 623 | } |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 624 | DEBUG_Printf(DBG_CHN_MESG, |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 625 | "%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n", |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 626 | i, (i<<3)|7, |
| 627 | (le.HighWord.Bits.BaseHi << 24) + |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 628 | (le.HighWord.Bits.BaseMid << 16) + le.BaseLow, |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 629 | ((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) << |
Eric Pouech | e5efa0c | 2000-04-13 19:31:58 +0000 | [diff] [blame] | 630 | (le.HighWord.Bits.Granularity ? 12 : 0), |
| 631 | le.HighWord.Bits.Default_Big ? 32 : 16, |
| 632 | flags[0], flags[1], flags[2] ); |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 633 | } |
| 634 | } |
| 635 | |
| 636 | void DEBUG_InfoVirtual(void) |
| 637 | { |
Eric Pouech | 26c1c42 | 2002-06-02 21:36:08 +0000 | [diff] [blame] | 638 | MEMORY_BASIC_INFORMATION mbi; |
| 639 | char* addr = 0; |
| 640 | char* state; |
| 641 | char* type; |
| 642 | char prot[3+1]; |
| 643 | |
| 644 | if (DEBUG_CurrProcess == NULL) |
| 645 | return; |
| 646 | |
| 647 | DEBUG_Printf(DBG_CHN_MESG, "Address Size State Type RWX\n"); |
| 648 | |
| 649 | while (VirtualQueryEx(DEBUG_CurrProcess->handle, addr, &mbi, sizeof(mbi)) >= sizeof(mbi)) |
| 650 | { |
| 651 | switch (mbi.State) |
| 652 | { |
| 653 | case MEM_COMMIT: state = "commit "; break; |
| 654 | case MEM_FREE: state = "free "; break; |
| 655 | case MEM_RESERVE: state = "reserve"; break; |
| 656 | default: state = "??? "; break; |
| 657 | } |
| 658 | if (mbi.State != MEM_FREE) |
| 659 | { |
| 660 | switch (mbi.Type) |
| 661 | { |
| 662 | case MEM_IMAGE: type = "image "; break; |
| 663 | case MEM_MAPPED: type = "mapped "; break; |
| 664 | case MEM_PRIVATE: type = "private"; break; |
| 665 | case 0: type = " "; break; |
| 666 | default: type = "??? "; break; |
| 667 | } |
| 668 | memset(prot, ' ' , sizeof(prot)-1); |
| 669 | prot[sizeof(prot)-1] = '\0'; |
| 670 | if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE)) |
| 671 | prot[0] = 'R'; |
| 672 | if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) |
| 673 | prot[1] = 'W'; |
| 674 | if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY)) |
| 675 | prot[1] = 'C'; |
| 676 | if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE)) |
| 677 | prot[2] = 'X'; |
| 678 | } |
| 679 | else |
| 680 | { |
| 681 | type = ""; |
| 682 | prot[0] = '\0'; |
| 683 | } |
| 684 | DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %s %s %s\n", |
| 685 | (DWORD)addr, mbi.RegionSize, state, type, prot); |
| 686 | if (addr + mbi.RegionSize < addr) /* wrap around ? */ |
| 687 | break; |
| 688 | addr += mbi.RegionSize; |
| 689 | } |
Eric Pouech | 527eea9 | 2000-03-08 16:44:54 +0000 | [diff] [blame] | 690 | } |
Eric Pouech | 26c1c42 | 2002-06-02 21:36:08 +0000 | [diff] [blame] | 691 | |
| 692 | struct dll_option_layout |
| 693 | { |
| 694 | void* next; |
| 695 | void* prev; |
| 696 | char* const* channels; |
| 697 | int nb_channels; |
| 698 | }; |
| 699 | |
| 700 | void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name) |
| 701 | { |
| 702 | DBG_VALUE val; |
| 703 | struct dll_option_layout dol; |
| 704 | int i; |
| 705 | char* str; |
| 706 | unsigned char buffer[32]; |
| 707 | unsigned char mask; |
| 708 | int done = 0; |
| 709 | BOOL bAll; |
| 710 | void* addr; |
| 711 | |
| 712 | if (!DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE)) |
| 713 | { |
| 714 | DEBUG_Printf(DBG_CHN_MESG, "Can't get first_option symbol"); |
| 715 | return; |
| 716 | } |
| 717 | addr = (void*)DEBUG_ToLinear(&val.addr); |
| 718 | if (!chnl) mask = 15; |
| 719 | else if (!strcmp(chnl, "fixme")) mask = 1; |
| 720 | else if (!strcmp(chnl, "err")) mask = 2; |
| 721 | else if (!strcmp(chnl, "warn")) mask = 4; |
| 722 | else if (!strcmp(chnl, "trace")) mask = 8; |
| 723 | else { DEBUG_Printf(DBG_CHN_MESG, "Unknown channel %s\n", chnl); return; } |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 724 | |
Eric Pouech | 26c1c42 | 2002-06-02 21:36:08 +0000 | [diff] [blame] | 725 | bAll = !strcmp("all", name); |
| 726 | while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol))) |
| 727 | { |
| 728 | for (i = 0; i < dol.nb_channels; i++) |
| 729 | { |
| 730 | if (DEBUG_READ_MEM((void*)(dol.channels + i), &str, sizeof(str)) && |
| 731 | DEBUG_READ_MEM(str, buffer, sizeof(buffer)) && |
| 732 | (!strcmp(buffer + 1, name) || bAll)) |
Eric Pouech | 10464c8 | 2002-08-02 19:00:53 +0000 | [diff] [blame] | 733 | { |
Eric Pouech | 26c1c42 | 2002-06-02 21:36:08 +0000 | [diff] [blame] | 734 | if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask; |
| 735 | if (DEBUG_WRITE_MEM(str, buffer, 1)) done++; |
| 736 | } |
| 737 | } |
| 738 | addr = dol.next; |
| 739 | } |
| 740 | if (!done) DEBUG_Printf(DBG_CHN_MESG, "Unable to find debug channel %s\n", name); |
| 741 | else DEBUG_Printf(DBG_CHN_TRACE, "Changed %d channel instances\n", done); |
| 742 | } |