info.c 12.8 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2
/*
 * Wine debugger utility routines
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4 5
 *
 * Copyright 1993 Eric Youngdale
 * Copyright 1995 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
6 7
 */

8
#include "config.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
9
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
10
#include <stdlib.h>
11 12 13 14
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "toolhelp.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
15
#include "debugger.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
16
#include "expr.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
17

Alexandre Julliard's avatar
Alexandre Julliard committed
18
/***********************************************************************
19
 *           DEBUG_PrintBasic
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21 22
 *
 * Implementation of the 'print' command.
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
23
void DEBUG_PrintBasic( const DBG_ADDR *addr, int count, char format )
Alexandre Julliard's avatar
Alexandre Julliard committed
24
{
Alexandre Julliard's avatar
Alexandre Julliard committed
25
  char        * default_format;
Alexandre Julliard's avatar
Alexandre Julliard committed
26
  long long int value;
Alexandre Julliard's avatar
Alexandre Julliard committed
27

Alexandre Julliard's avatar
Alexandre Julliard committed
28
  if( addr->type == NULL )
Alexandre Julliard's avatar
Alexandre Julliard committed
29
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
30 31
      fprintf(stderr, "Unable to evaluate expression\n");
      return;
Alexandre Julliard's avatar
Alexandre Julliard committed
32
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
33 34
  
  default_format = NULL;
35
  value = DEBUG_GetExprValue(addr, &default_format);
Alexandre Julliard's avatar
Alexandre Julliard committed
36

Alexandre Julliard's avatar
Alexandre Julliard committed
37
  switch(format)
Alexandre Julliard's avatar
Alexandre Julliard committed
38
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
39
    case 'x':
Alexandre Julliard's avatar
Alexandre Julliard committed
40 41 42 43 44 45 46 47
      if (addr->seg) 
	{
	  DEBUG_nchar += fprintf( stderr, "0x%04lx", (long unsigned int) value );
	}
      else 
	{
	  DEBUG_nchar += fprintf( stderr, "0x%08lx", (long unsigned int) value );
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
48 49
      break;
      
Alexandre Julliard's avatar
Alexandre Julliard committed
50
    case 'd':
Alexandre Julliard's avatar
Alexandre Julliard committed
51
      DEBUG_nchar += fprintf( stderr, "%ld\n", (long int) value );
Alexandre Julliard's avatar
Alexandre Julliard committed
52 53
      break;
      
Alexandre Julliard's avatar
Alexandre Julliard committed
54
    case 'c':
Alexandre Julliard's avatar
Alexandre Julliard committed
55
      DEBUG_nchar += fprintf( stderr, "%d = '%c'",
Alexandre Julliard's avatar
Alexandre Julliard committed
56 57 58
	       (char)(value & 0xff), (char)(value & 0xff) );
      break;
      
Alexandre Julliard's avatar
Alexandre Julliard committed
59 60 61 62
    case 'i':
    case 's':
    case 'w':
    case 'b':
Alexandre Julliard's avatar
Alexandre Julliard committed
63 64 65 66
      fprintf( stderr, "Format specifier '%c' is meaningless in 'print' command\n", format );
    case 0:
      if( default_format != NULL )
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
67
	  DEBUG_nchar += fprintf( stderr, default_format, value );
Alexandre Julliard's avatar
Alexandre Julliard committed
68 69
	}
      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
70
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
71
}
Alexandre Julliard's avatar
Alexandre Julliard committed
72 73


Alexandre Julliard's avatar
Alexandre Julliard committed
74 75 76 77 78
/***********************************************************************
 *           DEBUG_PrintAddress
 *
 * Print an 16- or 32-bit address, with the nearest symbol if any.
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
79
struct symbol_info
Alexandre Julliard's avatar
Alexandre Julliard committed
80
DEBUG_PrintAddress( const DBG_ADDR *addr, int addrlen, int flag )
Alexandre Julliard's avatar
Alexandre Julliard committed
81
{
Alexandre Julliard's avatar
Alexandre Julliard committed
82 83 84 85
    struct symbol_info rtn;

    const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, 0, 
						&rtn.list );
Alexandre Julliard's avatar
Alexandre Julliard committed
86

Alexandre Julliard's avatar
Alexandre Julliard committed
87
    if (addr->seg) fprintf( stderr, "0x%04lx:", addr->seg&0xFFFF );
Alexandre Julliard's avatar
Alexandre Julliard committed
88 89 90
    if (addrlen == 16) fprintf( stderr, "0x%04lx", addr->off );
    else fprintf( stderr, "0x%08lx", addr->off );
    if (name) fprintf( stderr, " (%s)", name );
Alexandre Julliard's avatar
Alexandre Julliard committed
91
    return rtn;
Alexandre Julliard's avatar
Alexandre Julliard committed
92 93 94 95 96 97 98 99
}
/***********************************************************************
 *           DEBUG_PrintAddressAndArgs
 *
 * Print an 16- or 32-bit address, with the nearest symbol if any.
 * Similar to DEBUG_PrintAddress, but we print the arguments to
 * each function (if known).  This is useful in a backtrace.
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
100
struct symbol_info
Alexandre Julliard's avatar
Alexandre Julliard committed
101 102 103
DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr, int addrlen, 
			   unsigned int ebp, int flag )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
104 105 106 107
    struct symbol_info rtn;

    const char *name = DEBUG_FindNearestSymbol( addr, flag, &rtn.sym, ebp, 
						&rtn.list );
Alexandre Julliard's avatar
Alexandre Julliard committed
108 109 110 111 112 113

    if (addr->seg) fprintf( stderr, "0x%04lx:", addr->seg );
    if (addrlen == 16) fprintf( stderr, "0x%04lx", addr->off );
    else fprintf( stderr, "0x%08lx", addr->off );
    if (name) fprintf( stderr, " (%s)", name );

Alexandre Julliard's avatar
Alexandre Julliard committed
114
    return rtn;
Alexandre Julliard's avatar
Alexandre Julliard committed
115 116
}

Alexandre Julliard's avatar
Alexandre Julliard committed
117 118 119 120 121 122 123 124 125

/***********************************************************************
 *           DEBUG_Help
 *
 * Implementation of the 'help' command.
 */
void DEBUG_Help(void)
{
    int i = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
126
    static const char * const helptext[] =
Alexandre Julliard's avatar
Alexandre Julliard committed
127
{
Alexandre Julliard's avatar
Alexandre Julliard committed
128
"The commands accepted by the Wine debugger are a reasonable",
Alexandre Julliard's avatar
Alexandre Julliard committed
129
"subset of the commands that gdb accepts.",
Alexandre Julliard's avatar
Alexandre Julliard committed
130
"The commands currently are:",
131
"  help                                   quit",
Alexandre Julliard's avatar
Alexandre Julliard committed
132 133
"  break [*<addr>]                        delete break bpnum",
"  disable bpnum                          enable bpnum",
134
"  condition <bpnum> [<expr>]             pass",
Alexandre Julliard's avatar
Alexandre Julliard committed
135 136 137
"  bt                                     cont [N]",
"  step [N]                               next [N]",
"  stepi [N]                              nexti [N]",
Alexandre Julliard's avatar
Alexandre Julliard committed
138 139
"  x <addr>                               print <expr>",
"  set <reg> = <expr>                     set *<addr> = <expr>",
Alexandre Julliard's avatar
Alexandre Julliard committed
140
"  up                                     down",
Alexandre Julliard's avatar
Alexandre Julliard committed
141 142 143 144
"  list <lines>                           disassemble [<addr>][,<addr>]",
"  frame <n>                              finish",
"  show dir                               dir <path>",
"  display <expr>                         undisplay <disnum>",
145
"  delete display <disnum>                debugmsg <class>[-+]<type>\n",
146 147
"  mode [16,32]                           walk [wnd,class,queue,module,",
"                                               process,modref <pid>]",
Alexandre Julliard's avatar
Alexandre Julliard committed
148
"  info (see 'help info' for options)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
149

Alexandre Julliard's avatar
Alexandre Julliard committed
150
"The 'x' command accepts repeat counts and formats (including 'i') in the",
Alexandre Julliard's avatar
Alexandre Julliard committed
151 152
"same way that gdb does.\n",

Alexandre Julliard's avatar
Alexandre Julliard committed
153 154 155 156 157 158
" The following are examples of legal expressions:",
" $eax     $eax+0x3   0x1000   ($eip + 256)  *$eax   *($esp + 3)",
" Also, a nm format symbol table can be read from a file using the",
" symbolfile command.  Symbols can also be defined individually with",
" the define command.",
"",
Alexandre Julliard's avatar
Alexandre Julliard committed
159 160
NULL
};
Alexandre Julliard's avatar
Alexandre Julliard committed
161

Alexandre Julliard's avatar
Alexandre Julliard committed
162
    while(helptext[i]) fprintf(stderr,"%s\n", helptext[i++]);
Alexandre Julliard's avatar
Alexandre Julliard committed
163
}
Alexandre Julliard's avatar
Alexandre Julliard committed
164 165 166


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
167
 *           DEBUG_HelpInfo
Alexandre Julliard's avatar
Alexandre Julliard committed
168
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
169
 * Implementation of the 'help info' command.
Alexandre Julliard's avatar
Alexandre Julliard committed
170
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
171 172 173 174
void DEBUG_HelpInfo(void)
{
    int i = 0;
    static const char * const infotext[] =
Alexandre Julliard's avatar
Alexandre Julliard committed
175
{
Alexandre Julliard's avatar
Alexandre Julliard committed
176 177 178 179 180
"The info commands allow you to get assorted bits of interesting stuff",
"to be displayed.  The options are:",
"  info break           Dumps information about breakpoints",
"  info display         Shows auto-display expressions in use",
"  info locals          Displays values of all local vars for current frame",
Alexandre Julliard's avatar
Alexandre Julliard committed
181
"  info maps            Dumps all virtual memory mappings",
Alexandre Julliard's avatar
Alexandre Julliard committed
182 183
"  info module <handle> Displays internal module state",
"  info queue <handle>  Displays internal queue state",
Alexandre Julliard's avatar
Alexandre Julliard committed
184 185 186 187
"  info reg             Displays values in all registers at top of stack",
"  info segments        Dumps information about all known segments",
"  info share           Dumps information about shared libraries",
"  info stack           Dumps information about top of stack",
Alexandre Julliard's avatar
Alexandre Julliard committed
188
"  info wnd <handle>    Displays internal window state",
Alexandre Julliard's avatar
Alexandre Julliard committed
189 190 191
"",
NULL
};
Alexandre Julliard's avatar
Alexandre Julliard committed
192

Alexandre Julliard's avatar
Alexandre Julliard committed
193
    while(infotext[i]) fprintf(stderr,"%s\n", infotext[i++]);
Alexandre Julliard's avatar
Alexandre Julliard committed
194
}
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455

/* FIXME: merge InfoClass and InfoClass2 */
void DEBUG_InfoClass(const char* name)
{
   WNDCLASSEXA	wca;

   if (!GetClassInfoExA(0, name, &wca)) {
      fprintf(stderr, "Cannot find class '%s'\n", name);
      return;
   }

   fprintf(stderr,  "Class '%s':\n", name);
   fprintf(stderr,  
	   "style=%08x  wndProc=%08lx\n"
	   "inst=%04x  icon=%04x  cursor=%04x  bkgnd=%04x\n"
	   "clsExtra=%d  winExtra=%d\n",
	   wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
	   wca.hIcon, wca.hCursor, wca.hbrBackground,
	   wca.cbClsExtra, wca.cbWndExtra);

   /* FIXME: 
    * + print #windows (or even list of windows...)
    * + print extra bytes => this requires a window handle on this very class...
    */
}

static	void DEBUG_InfoClass2(HWND hWnd, const char* name)
{
   WNDCLASSEXA	wca;

   if (!GetClassInfoExA(GetWindowLongA(hWnd, GWL_HINSTANCE), name, &wca)) {
      fprintf(stderr, "Cannot find class '%s'\n", name);
      return;
   }

   fprintf(stderr,  "Class '%s':\n", name);
   fprintf(stderr,  
	   "style=%08x  wndProc=%08lx\n"
	   "inst=%04x  icon=%04x  cursor=%04x  bkgnd=%04x\n"
	   "clsExtra=%d  winExtra=%d\n",
	   wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
	   wca.hIcon, wca.hCursor, wca.hbrBackground,
	   wca.cbClsExtra, wca.cbWndExtra);

   if (wca.cbClsExtra) {
      int		i;
      WORD		w;

      fprintf(stderr,  "Extra bytes:" );
      for (i = 0; i < wca.cbClsExtra / 2; i++) {
	 w = GetClassWord(hWnd, i * 2);
	 /* FIXME: depends on i386 endian-ity */
	 fprintf(stderr,  " %02x", HIBYTE(w));
	 fprintf(stderr,  " %02x", LOBYTE(w));
      }
      fprintf(stderr,  "\n" );
    }
    fprintf(stderr,  "\n" );
}

struct class_walker {
   ATOM*	table;
   int		used;
   int		alloc;
};

static	void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
{
   char	clsName[128];
   int	i;
   ATOM	atom;
   HWND	child;

   if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
      return;
   if ((atom = FindAtomA(clsName)) == 0)
      return;

   for (i = 0; i < cw->used; i++) {
      if (cw->table[i] == atom)
	 break;
   }
   if (i == cw->used) {
      if (cw->used >= cw->alloc) {
	 cw->alloc += 16;
	 cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
      }
      cw->table[cw->used++] = atom;
      DEBUG_InfoClass2(hWnd, clsName);
   }
   do {
      if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
	 DEBUG_WalkClassesHelper(child, cw);
   } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
}

void DEBUG_WalkClasses(void)
{
   struct class_walker cw;

   cw.table = NULL;
   cw.used = cw.alloc = 0;
   DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
   DBG_free(cw.table);
}

void DEBUG_DumpModule(DWORD mod)
{
   fprintf(stderr, "No longer doing info module '0x%08lx'\n", mod);
}

void DEBUG_WalkModules(void)
{
   fprintf(stderr, "No longer walking modules list\n");
}

void DEBUG_DumpQueue(DWORD q)
{
   fprintf(stderr, "No longer doing info queue '0x%08lx'\n", q);
}

void DEBUG_WalkQueues(void)
{
   fprintf(stderr, "No longer walking queues list\n");
}

void DEBUG_InfoWindow(HWND hWnd)
{
   char	clsName[128];
   char	wndName[128];
   RECT	clientRect;
   RECT	windowRect;
   int	i;
   WORD	w;

   if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
       strcpy(clsName, "-- Unknown --");
   if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
      strcpy(wndName, "-- Empty --");
   if (!GetClientRect(hWnd, &clientRect))
      SetRectEmpty(&clientRect);
   if (!GetWindowRect(hWnd, &windowRect))
      SetRectEmpty(&windowRect);

   /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
   fprintf(stderr,
	   "next=0x%04x  child=0x%04x  parent=0x%04x  owner=0x%04x  class='%s'\n"
	   "inst=%08lx  active=%04x  idmenu=%08lx\n"
	   "style=%08lx  exstyle=%08lx  wndproc=%08lx  text='%s'\n"
	   "client=%d,%d-%d,%d  window=%d,%d-%d,%d sysmenu=%04x\n",
	   GetWindow(hWnd, GW_HWNDNEXT), 
	   GetWindow(hWnd, GW_CHILD),
	   GetParent(hWnd), 
	   GetWindow(hWnd, GW_OWNER),
	   clsName,
	   GetWindowLongA(hWnd, GWL_HINSTANCE), 
	   GetLastActivePopup(hWnd),
	   GetWindowLongA(hWnd, GWL_ID),
	   GetWindowLongA(hWnd, GWL_STYLE),
	   GetWindowLongA(hWnd, GWL_EXSTYLE),
	   GetWindowLongA(hWnd, GWL_WNDPROC),
	   wndName, 
	   clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, 
	   windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, 
	   GetSystemMenu(hWnd, FALSE));

    if (GetClassLongA(hWnd, GCL_CBWNDEXTRA)) {
        fprintf(stderr,  "Extra bytes:" );
        for (i = 0; i < GetClassLongA(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
	   w = GetWindowWord(hWnd, i * 2);
	   /* FIXME: depends on i386 endian-ity */
	   fprintf(stderr,  " %02x", HIBYTE(w));
	   fprintf(stderr,  " %02x", LOBYTE(w));
	}
        fprintf(stderr, "\n");
    }
    fprintf(stderr, "\n");
}

void DEBUG_WalkWindows(HWND hWnd, int indent)
{
   char	clsName[128];
   char	wndName[128];
   HWND	child;

   if (!IsWindow(hWnd))
      hWnd = GetDesktopWindow();

    if (!indent)  /* first time around */
       fprintf(stderr,  
	       "%-16.16s %-17.17s %-8.8s %s\n",
	       "hwnd", "Class Name", " Style", " WndProc Text");

    do {
       if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
	  strcpy(clsName, "-- Unknown --");
       if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
	  strcpy(wndName, "-- Empty --");
       
       /* FIXME: missing hmemTaskQ */
       fprintf(stderr, "%*s%04x%*s", indent, "", hWnd, 13-indent,"");
       fprintf(stderr, "%-17.17s %08lx %08lx %.14s\n",
	       clsName, GetWindowLongA(hWnd, GWL_STYLE),
	       GetWindowLongA(hWnd, GWL_WNDPROC), wndName);

       if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
	  DEBUG_WalkWindows(child, indent + 1 );
    } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
}

void DEBUG_WalkProcess(void)
{
   fprintf(stderr, "No longer walking processes list\n");
}

void DEBUG_WalkModref(DWORD p)
{
   fprintf(stderr, "No longer walking module references list\n");
}

void DEBUG_InfoSegments(DWORD start, int length)
{
    char 	flags[3];
    DWORD 	i;
    LDT_ENTRY	le;

    if (length == -1) length = (8192 - start);

    for (i = start; i < start + length; i++)
    {
       if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
	  continue;

        if (le.HighWord.Bits.Type & 0x08) 
        {
            flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
            flags[1] = '-';
            flags[2] = 'x';
        }
        else
        {
            flags[0] = 'r';
            flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
            flags[2] = '-';
        }
        fprintf(stderr, 
		"%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
		i, (i<<3)|7, 
		(le.HighWord.Bits.BaseHi << 24) + 
		    (le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
		((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) << 
		    (le.HighWord.Bits.Granularity ? 12 : 0),
		le.HighWord.Bits.Default_Big ? 32 : 16,
		flags[0], flags[1], flags[2] );
    }
}

void DEBUG_InfoVirtual(void)
{
   fprintf(stderr, "No longer providing virtual mapping information\n");
}