info.c 23.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
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21
 */

22
#include "config.h"
23

Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <string.h>
27 28
#include <stdarg.h>

29
#include "debugger.h"
30 31
#include "wingdi.h"
#include "winuser.h"
32
#include "tlhelp32.h"
33 34 35
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
Alexandre Julliard's avatar
Alexandre Julliard committed
36

Alexandre Julliard's avatar
Alexandre Julliard committed
37
/***********************************************************************
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
 *           print_help
 *
 * Implementation of the 'help' command.
 */
void print_help(void)
{
    int i = 0;
    static const char * const helptext[] =
        {
            "The commands accepted by the Wine debugger are a reasonable",
            "subset of the commands that gdb accepts.",
            "The commands currently are:",
            "  help                                   quit",
            "  break [*<addr>]                        watch *<addr>",
            "  delete break bpnum                     disable bpnum",
            "  enable bpnum                           condition <bpnum> [<expr>]",
            "  finish                                 cont [N]",
            "  step [N]                               next [N]",
            "  stepi [N]                              nexti [N]",
            "  x <addr>                               print <expr>",
            "  display <expr>                         undisplay <disnum>",
            "  local display <expr>                   delete display <disnum>",                  
            "  enable display <disnum>                disable display <disnum>",
61
            "  bt [<tid>|all]                         frame <n>",
62 63 64 65
            "  up                                     down",
            "  list <lines>                           disassemble [<addr>][,<addr>]",
            "  show dir                               dir <path>",
            "  set <reg> = <expr>                     set *<addr> = <expr>",
66 67
            "  pass                                   whatis",
            "  info (see 'help info' for options)",
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

            "The 'x' command accepts repeat counts and formats (including 'i') in the",
            "same way that gdb does.\n",

            "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.", */
            "",
            NULL
        };

    while (helptext[i]) dbg_printf("%s\n", helptext[i++]);
}


/***********************************************************************
 *           info_help
Alexandre Julliard's avatar
Alexandre Julliard committed
87
 *
88
 * Implementation of the 'help info' command.
Alexandre Julliard's avatar
Alexandre Julliard committed
89
 */
90
void info_help(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
91
{
92 93 94 95 96 97 98 99 100 101 102 103
    int i = 0;
    static const char * const infotext[] =
        {
            "The info commands allow you to get assorted bits of interesting stuff",
            "to be displayed.  The options are:",
            "  info break           Displays information about breakpoints",
            "  info class <name>    Displays information about window class <name>",
            "  info display         Shows auto-display expressions in use",
            "  info except <pid>    Shows exception handler chain (in a given process)",
            "  info locals          Displays values of all local vars for current frame",
            "  info maps <pid>      Shows virtual mappings (in a given process)",
            "  info process         Shows all running processes",
104 105
            "  info reg             Displays values of the general registers at top of stack",
            "  info all-reg         Displays the general and floating point registers",
106 107 108 109 110 111 112 113 114 115 116 117 118
            "  info segments <pid>  Displays information about all known segments",
            "  info share           Displays all loaded modules",
            "  info share <addr>    Displays internal module state",
            "  info stack           Dumps information about top of stack",
            "  info symbol <sym>    Displays information about a given symbol",
            "  info thread          Shows all running threads",
            "  info wnd <handle>    Displays internal window state",
            "",
            NULL
        };

    while (infotext[i]) dbg_printf("%s\n", infotext[i++]);
}
119

120
static const char* get_symtype_str(const IMAGEHLP_MODULE64* mi)
121
{
122
    switch (mi->SymType)
Alexandre Julliard's avatar
Alexandre Julliard committed
123
    {
124 125 126 127 128 129 130 131
    default:
    case SymNone:       return "--none--";
    case SymCoff:       return "COFF";
    case SymCv:         return "CodeView";
    case SymPdb:        return "PDB";
    case SymExport:     return "Export";
    case SymDeferred:   return "Deferred";
    case SymSym:        return "Sym";
132 133 134 135 136 137 138 139 140 141 142
    case SymDia:
        switch (mi->CVSig)
        {
        case 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24):
            return "Stabs";
        case 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24):
            return "Dwarf";
        default:
            return "DIA";

        }
Alexandre Julliard's avatar
Alexandre Julliard committed
143
    }
144
}
145

146 147
struct info_module
{
148
    IMAGEHLP_MODULE64*  mi;
Eric Pouech's avatar
Eric Pouech committed
149
    DWORD               base;
150 151 152
    unsigned            num_alloc;
    unsigned            num_used;
};
153

154
static void module_print_info(const IMAGEHLP_MODULE64* mi, BOOL is_embedded)
155
{
156
    dbg_printf("%8s-%8s\t%-16s%s\n",
157 158 159
               wine_dbgstr_longlong(mi->BaseOfImage),
               wine_dbgstr_longlong(mi->BaseOfImage + mi->ImageSize),
               is_embedded ? "\\" : get_symtype_str(mi), mi->ModuleName);
160 161 162 163
}

static int      module_compare(const void* p1, const void* p2)
{
164 165 166 167 168
    LONGLONG val = ((const IMAGEHLP_MODULE64*)p1)->BaseOfImage -
        ((const IMAGEHLP_MODULE64*)p2)->BaseOfImage;
    if (val < 0) return -1;
    else if (val > 0) return 1;
    else return 0;
169
}
170

171 172
static inline BOOL module_is_container(const IMAGEHLP_MODULE64* wmod_cntnr,
                                       const IMAGEHLP_MODULE64* wmod_child)
173 174
{
    return wmod_cntnr->BaseOfImage <= wmod_child->BaseOfImage &&
175 176
        wmod_cntnr->BaseOfImage + wmod_cntnr->ImageSize >=
        wmod_child->BaseOfImage + wmod_child->ImageSize;
177
}
178

179
static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx)
180 181
{
    struct info_module* im = (struct info_module*)ctx;
182

183
    if (im->num_used + 1 > im->num_alloc)
184
    {
185 186
        im->num_alloc += 16;
        im->mi = dbg_heap_realloc(im->mi, im->num_alloc * sizeof(*im->mi));
187
    }
188
    im->mi[im->num_used].SizeOfStruct = sizeof(im->mi[im->num_used]);
189
    if (SymGetModuleInfo64(dbg_curr_process->handle, base, &im->mi[im->num_used]))
190 191 192 193 194
    {
        im->num_used++;
    }   
    return TRUE;
}
195

196 197 198 199 200
/***********************************************************************
 *           info_win32_module
 *
 * Display information about a given module (DLL or EXE), or about all modules
 */
201
void info_win32_module(DWORD64 base)
202
{
Eric Pouech's avatar
Eric Pouech committed
203
    struct info_module  im;
Gerald Pfeifer's avatar
Gerald Pfeifer committed
204
    UINT                i, j, num_printed = 0;
Eric Pouech's avatar
Eric Pouech committed
205 206
    DWORD               opt;

207
    if (!dbg_curr_process)
208 209 210 211 212
    {
        dbg_printf("Cannot get info on module while no process is loaded\n");
        return;
    }

Eric Pouech's avatar
Eric Pouech committed
213 214
    im.mi = NULL;
    im.num_alloc = im.num_used = 0;
215

Eric Pouech's avatar
Eric Pouech committed
216 217 218 219 220 221
    /* this is a wine specific options to return also ELF modules in the
     * enumeration
     */
    SymSetOptions((opt = SymGetOptions()) | 0x40000000);
    SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, (void*)&im);
    SymSetOptions(opt);
222

Eric Pouech's avatar
Eric Pouech committed
223
    qsort(im.mi, im.num_used, sizeof(im.mi[0]), module_compare);
224

Eric Pouech's avatar
Eric Pouech committed
225
    dbg_printf("Module\tAddress\t\t\tDebug info\tName (%d modules)\n", im.num_used);
226

Eric Pouech's avatar
Eric Pouech committed
227 228 229 230 231 232
    for (i = 0; i < im.num_used; i++)
    {
        if (base && 
            (base < im.mi[i].BaseOfImage || base >= im.mi[i].BaseOfImage + im.mi[i].ImageSize))
            continue;
        if (strstr(im.mi[i].ModuleName, "<elf>"))
233
        {
Eric Pouech's avatar
Eric Pouech committed
234 235 236 237
            dbg_printf("ELF\t");
            module_print_info(&im.mi[i], FALSE);
            /* print all modules embedded in this one */
            for (j = 0; j < im.num_used; j++)
238
            {
Eric Pouech's avatar
Eric Pouech committed
239
                if (!strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[i], &im.mi[j]))
240
                {
Eric Pouech's avatar
Eric Pouech committed
241 242
                    dbg_printf("  \\-PE\t");
                    module_print_info(&im.mi[j], TRUE);
243
                }
244
            }
Eric Pouech's avatar
Eric Pouech committed
245 246 247 248 249
        }
        else
        {
            /* check module is not embedded in another module */
            for (j = 0; j < im.num_used; j++) 
250
            {
Eric Pouech's avatar
Eric Pouech committed
251 252
                if (strstr(im.mi[j].ModuleName, "<elf>") && module_is_container(&im.mi[j], &im.mi[i]))
                    break;
253
            }
Eric Pouech's avatar
Eric Pouech committed
254 255 256 257 258 259
            if (j < im.num_used) continue;
            if (strstr(im.mi[i].ModuleName, ".so") || strchr(im.mi[i].ModuleName, '<'))
                dbg_printf("ELF\t");
            else
                dbg_printf("PE\t");
            module_print_info(&im.mi[i], FALSE);
260
        }
Eric Pouech's avatar
Eric Pouech committed
261
        num_printed++;
Alexandre Julliard's avatar
Alexandre Julliard committed
262
    }
Eric Pouech's avatar
Eric Pouech committed
263 264 265
    HeapFree(GetProcessHeap(), 0, im.mi);

    if (base && !num_printed)
266
        dbg_printf("'0x%x%08x' is not a valid module address\n", (DWORD)(base >> 32), (DWORD)base);
Alexandre Julliard's avatar
Alexandre Julliard committed
267
}
Alexandre Julliard's avatar
Alexandre Julliard committed
268

269
struct class_walker
Alexandre Julliard's avatar
Alexandre Julliard committed
270
{
271 272 273 274
    ATOM*	table;
    int		used;
    int		alloc;
};
Alexandre Julliard's avatar
Alexandre Julliard committed
275

276
static void class_walker(HWND hWnd, struct class_walker* cw)
Alexandre Julliard's avatar
Alexandre Julliard committed
277
{
278 279 280 281
    char	clsName[128];
    int	        i;
    ATOM	atom;
    HWND	child;
Alexandre Julliard's avatar
Alexandre Julliard committed
282

283 284 285 286
    if (!GetClassName(hWnd, clsName, sizeof(clsName)))
        return;
    if ((atom = FindAtom(clsName)) == 0)
        return;
Alexandre Julliard's avatar
Alexandre Julliard committed
287

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
    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_heap_realloc(cw->table, cw->alloc * sizeof(ATOM));
        }
        cw->table[cw->used++] = atom;
        info_win32_class(hWnd, clsName);
    }
    do
    {
        if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
            class_walker(child, cw);
    } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
308 309
}

310
void info_win32_class(HWND hWnd, const char* name)
Alexandre Julliard's avatar
Alexandre Julliard committed
311
{
312
    WNDCLASSEXA	wca;
313
    HINSTANCE   hInst = hWnd ? (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE) : 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
314

315 316 317
    if (!name)
    {
        struct class_walker cw;
Alexandre Julliard's avatar
Alexandre Julliard committed
318

319 320 321 322 323 324
        cw.table = NULL;
        cw.used = cw.alloc = 0;
        class_walker(GetDesktopWindow(), &cw);
        HeapFree(GetProcessHeap(), 0, cw.table);
        return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
325

326 327 328 329 330
    if (!GetClassInfoEx(hInst, name, &wca))
    {
        dbg_printf("Cannot find class '%s'\n", name);
        return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
331

332
    dbg_printf("Class '%s':\n", name);
333
    dbg_printf("style=0x%08x  wndProc=%p\n"
334 335
               "inst=%p  icon=%p  cursor=%p  bkgnd=%p\n"
               "clsExtra=%d  winExtra=%d\n",
336
               wca.style, wca.lpfnWndProc, wca.hInstance,
337 338
               wca.hIcon, wca.hCursor, wca.hbrBackground,
               wca.cbClsExtra, wca.cbWndExtra);
339

340 341 342 343
    if (hWnd && wca.cbClsExtra)
    {
        int		i;
        WORD		w;
344

345 346 347 348 349 350 351 352
        dbg_printf("Extra bytes:");
        for (i = 0; i < wca.cbClsExtra / 2; i++)
        {
            w = GetClassWord(hWnd, i * 2);
            /* FIXME: depends on i386 endian-ity */
            dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
        }
        dbg_printf("\n");
353
    }
354 355 356 357 358
    dbg_printf("\n");
    /* FIXME:
     * + print #windows (or even list of windows...)
     * + print extra bytes => this requires a window handle on this very class...
     */
359 360
}

361
static void info_window(HWND hWnd, int indent)
362
{
363 364 365 366 367 368 369 370 371 372 373
    char	clsName[128];
    char	wndName[128];
    HWND	child;

    do
    {
        if (!GetClassName(hWnd, clsName, sizeof(clsName)))
            strcpy(clsName, "-- Unknown --");
        if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
            strcpy(wndName, "-- Empty --");

374 375
        dbg_printf("%*s%08lx%*s %-17.17s %08x %08x %08x %.14s\n",
                   indent, "", (DWORD_PTR)hWnd, 12 - indent, "",
376
                   clsName, GetWindowLong(hWnd, GWL_STYLE),
377
                   GetWindowLongPtr(hWnd, GWLP_WNDPROC),
378
                   GetWindowThreadProcessId(hWnd, NULL), wndName);
379 380 381 382

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

385
void info_win32_window(HWND hWnd, BOOL detailed)
386
{
387 388 389 390 391
    char	clsName[128];
    char	wndName[128];
    RECT	clientRect;
    RECT	windowRect;
    WORD	w;
392

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

395 396
    if (!detailed)
    {
397 398
        dbg_printf("%-20.20s %-17.17s %-8.8s %-8.8s %-8.8s %s\n",
                   "Window handle", "Class Name", "Style", "WndProc", "Thread", "Text");
399 400
        info_window(hWnd, 0);
        return;
401 402
    }

403 404 405 406 407 408 409 410 411 412 413 414
    if (!GetClassName(hWnd, clsName, sizeof(clsName)))
        strcpy(clsName, "-- Unknown --");
    if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
        strcpy(wndName, "-- Empty --");
    if (!GetClientRect(hWnd, &clientRect) || 
        !MapWindowPoints(hWnd, 0, (LPPOINT) &clientRect, 2))
        SetRectEmpty(&clientRect);
    if (!GetWindowRect(hWnd, &windowRect))
        SetRectEmpty(&windowRect);

    /* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
    dbg_printf("next=%p  child=%p  parent=%p  owner=%p  class='%s'\n"
415 416 417
               "inst=%p  active=%p  idmenu=%08x\n"
               "style=0x%08x  exstyle=0x%08x  wndproc=0x%08x  text='%s'\n"
               "client=%d,%d-%d,%d  window=%d,%d-%d,%d sysmenu=%p\n",
418 419 420 421 422
               GetWindow(hWnd, GW_HWNDNEXT),
               GetWindow(hWnd, GW_CHILD),
               GetParent(hWnd),
               GetWindow(hWnd, GW_OWNER),
               clsName,
423
               (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
424
               GetLastActivePopup(hWnd),
425
               GetWindowLongPtr(hWnd, GWLP_ID),
426 427
               GetWindowLong(hWnd, GWL_STYLE),
               GetWindowLong(hWnd, GWL_EXSTYLE),
428
               GetWindowLongPtr(hWnd, GWLP_WNDPROC),
429 430 431 432 433 434 435
               wndName,
               clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
               windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
               GetSystemMenu(hWnd, FALSE));

    if (GetClassLong(hWnd, GCL_CBWNDEXTRA))
    {
Gerald Pfeifer's avatar
Gerald Pfeifer committed
436 437
        UINT i;

438 439 440 441 442 443 444 445 446 447
        dbg_printf("Extra bytes:");
        for (i = 0; i < GetClassLong(hWnd, GCL_CBWNDEXTRA) / 2; i++)
        {
            w = GetWindowWord(hWnd, i * 2);
            /* FIXME: depends on i386 endian-ity */
            dbg_printf(" %02x %02x", HIBYTE(w), LOBYTE(w));
	}
        dbg_printf("\n");
    }
    dbg_printf("\n");
448 449
}

450
void info_win32_processes(void)
451
{
452
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
453 454
    if (snap != INVALID_HANDLE_VALUE)
    {
455 456 457
        PROCESSENTRY32  entry;
        DWORD           current = dbg_curr_process ? dbg_curr_process->pid : 0;
        BOOL            ok;
458

459
        entry.dwSize = sizeof(entry);
460
        ok = Process32First(snap, &entry);
461

462 463
        dbg_printf(" %-8.8s %-8.8s %-8.8s %s (all id:s are in hex)\n",
                   "pid", "threads", "parent", "executable");
464 465 466
        while (ok)
        {
            if (entry.th32ProcessID != GetCurrentProcessId())
467
                dbg_printf("%c%08x %-8d %08x '%s'\n",
468 469 470 471
                           (entry.th32ProcessID == current) ? '>' : ' ',
                           entry.th32ProcessID, entry.cntThreads,
                           entry.th32ParentProcessID, entry.szExeFile);
            ok = Process32Next(snap, &entry);
472
        }
473
        CloseHandle(snap);
474 475 476
    }
}

477
void info_win32_threads(void)
478
{
479
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
480 481
    if (snap != INVALID_HANDLE_VALUE)
    {
482 483 484
        THREADENTRY32	entry;
        BOOL 		ok;
	DWORD		lastProcessId = 0;
485

486
	entry.dwSize = sizeof(entry);
487
	ok = Thread32First(snap, &entry);
488

489 490
        dbg_printf("%-8.8s %-8.8s %s (all id:s are in hex)\n",
                   "process", "tid", "prio");
491 492 493
        while (ok)
        {
            if (entry.th32OwnerProcessID != GetCurrentProcessId())
494 495 496 497 498 499 500
	    {
		/* FIXME: this assumes that, in the snapshot, all threads of a same process are
		 * listed sequentially, which is not specified in the doc (Wine's implementation
		 * does it)
		 */
		if (entry.th32OwnerProcessID != lastProcessId)
		{
501
		    struct dbg_process*	p = dbg_get_process(entry.th32OwnerProcessID);
502

503
		    dbg_printf("%08x%s %s\n",
504
                               entry.th32OwnerProcessID, p ? " (D)" : "", p ? p->imageName : "");
505 506
		    lastProcessId = entry.th32OwnerProcessID;
		}
507
                dbg_printf("\t%08x %4d%s\n",
508 509
                           entry.th32ThreadID, entry.tpBasePri,
                           (entry.th32ThreadID == dbg_curr_tid) ? " <==" : "");
510 511

	    }
512
            ok = Thread32Next(snap, &entry);
513
        }
514

515
        CloseHandle(snap);
516
    }
517 518
}

519
/***********************************************************************
520
 *           info_win32_exceptions
521
 *
522
 * Get info on the exception frames of a given thread.
523
 */
524
void info_win32_exceptions(DWORD tid)
525
{
526 527
    struct dbg_thread*  thread;
    void*               next_frame;
528

529
    if (!dbg_curr_process || !dbg_curr_thread)
530
    {
531
        dbg_printf("Cannot get info on exceptions while no process is loaded\n");
532 533 534
        return;
    }

535
    dbg_printf("Exception frames:\n");
536

537
    if (tid == dbg_curr_tid) thread = dbg_curr_thread;
538 539
    else
    {
540 541 542 543
        thread = dbg_get_thread(dbg_curr_process, tid);

        if (!thread)
        {
544
            dbg_printf("Unknown thread id (%04x) in current process\n", tid);
545 546 547 548
            return;
        }
        if (SuspendThread(thread->handle) == -1)
        {
549
            dbg_printf("Can't suspend thread id (%04x)\n", tid);
550 551
            return;
        }
552 553
    }

554
    if (!dbg_read_memory(thread->teb, &next_frame, sizeof(next_frame)))
555
    {
556
        dbg_printf("Can't read TEB:except_frame\n");
557 558 559
        return;
    }

560
    while (next_frame != (void*)-1)
561
    {
562
        EXCEPTION_REGISTRATION_RECORD frame;
563

564 565
        dbg_printf("%p: ", next_frame);
        if (!dbg_read_memory(next_frame, &frame, sizeof(frame)))
566
        {
567
            dbg_printf("Invalid frame address\n");
568 569
            break;
        }
570
        dbg_printf("prev=%p handler=%p\n", frame.Prev, frame.Handler);
571 572 573
        next_frame = frame.Prev;
    }

574
    if (tid != dbg_curr_tid) ResumeThread(thread->handle);
575 576
}

577
void info_win32_segments(DWORD start, int length)
578 579 580 581 582 583 584 585 586
{
    char 	flags[3];
    DWORD 	i;
    LDT_ENTRY	le;

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

    for (i = start; i < start + length; i++)
    {
587
        if (!dbg_curr_process->process_io->get_selector(dbg_curr_thread->handle, (i << 3) | 7, &le))
588
            continue;
589

590
        if (le.HighWord.Bits.Type & 0x08)
591 592 593 594 595 596 597 598 599 600 601
        {
            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] = '-';
        }
602
        dbg_printf("%04x: sel=%04x base=%08x limit=%08x %d-bit %c%c%c\n",
603 604 605 606 607 608 609
                   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]);
610 611 612
    }
}

613
void info_win32_virtual(DWORD pid)
614
{
615 616
    MEMORY_BASIC_INFORMATION    mbi;
    char*                       addr = 0;
617 618
    const char*                 state;
    const char*                 type;
619
    char                        prot[3+1];
620
    HANDLE                      hProc;
621

622
    if (pid == dbg_curr_pid)
623
    {
624
        if (dbg_curr_process == NULL)
625
        {
626
            dbg_printf("Cannot look at mapping of current process, while no process is loaded\n");
627 628
            return;
        }
629
        hProc = dbg_curr_process->handle;
630 631 632 633 634 635
    }
    else
    {
        hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
        if (hProc == NULL)
        {
636
            dbg_printf("Cannot open process <%04x>\n", pid);
637 638 639
            return;
        }
    }
640

641
    dbg_printf("Address  Size     State   Type    RWX\n");
642

643
    while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
    {
        switch (mbi.State)
        {
        case MEM_COMMIT:        state = "commit "; break;
        case MEM_FREE:          state = "free   "; break;
        case MEM_RESERVE:       state = "reserve"; break;
        default:                state = "???    "; break;
        }
        if (mbi.State != MEM_FREE)
        {
            switch (mbi.Type)
            {
            case MEM_IMAGE:         type = "image  "; break;
            case MEM_MAPPED:        type = "mapped "; break;
            case MEM_PRIVATE:       type = "private"; break;
            case 0:                 type = "       "; break;
            default:                type = "???    "; break;
            }
662 663
            memset(prot, ' ' , sizeof(prot) - 1);
            prot[sizeof(prot) - 1] = '\0';
664 665 666 667 668 669 670 671 672 673 674 675 676 677
            if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
                prot[0] = 'R';
            if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
                prot[1] = 'W';
            if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
                prot[1] = 'C';
            if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
                prot[2] = 'X';
        }
        else
        {
            type = "";
            prot[0] = '\0';
        }
678
        dbg_printf("%08lx %08lx %s %s %s\n",
679
                   (DWORD_PTR)addr, (DWORD_PTR)addr + mbi.RegionSize - 1, state, type, prot);
680 681 682 683
        if (addr + mbi.RegionSize < addr) /* wrap around ? */
            break;
        addr += mbi.RegionSize;
    }
684
    if (pid != dbg_curr_pid) CloseHandle(hProc);
685
}
686

687
void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name)
688
{
689
    struct dbg_lvalue           lvalue;
690
    struct __wine_debug_channel channel;
691 692 693 694 695
    unsigned char               mask;
    int                         done = 0;
    BOOL                        bAll;
    void*                       addr;

696 697 698 699 700 701
    if (!dbg_curr_process || !dbg_curr_thread)
    {
        dbg_printf("Cannot set/get debug channels while no process is loaded\n");
        return;
    }

702
    if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found)
703 704 705
    {
        return;
    }
706
    addr = memory_to_linear_addr(&lvalue.addr);
707 708 709 710 711 712 713 714 715 716 717

    if (!cls)                          mask = ~0;
    else if (!strcmp(cls, "fixme"))    mask = (1 << __WINE_DBCL_FIXME);
    else if (!strcmp(cls, "err"))      mask = (1 << __WINE_DBCL_ERR);
    else if (!strcmp(cls, "warn"))     mask = (1 << __WINE_DBCL_WARN);
    else if (!strcmp(cls, "trace"))    mask = (1 << __WINE_DBCL_TRACE);
    else
    {
        dbg_printf("Unknown debug class %s\n", cls);
        return;
    }
718

719
    bAll = !strcmp("all", name);
720
    while (addr && dbg_read_memory(addr, &channel, sizeof(channel)))
721
    {
722 723
        if (!channel.name[0]) break;
        if (bAll || !strcmp( channel.name, name ))
724
        {
725 726 727
            if (turn_on) channel.flags |= mask;
            else channel.flags &= ~mask;
            if (dbg_write_memory(addr, &channel, sizeof(channel))) done++;
728
        }
729
        addr = (struct __wine_debug_channel *)addr + 1;
730
    }
731
    if (!done) dbg_printf("Unable to find debug channel %s\n", name);
732
    else WINE_TRACE("Changed %d channel instances\n", done);
733
}