diff --git a/debugger/dbg.y b/debugger/dbg.y
index 80056574f32a30141b6d5a389473d882023c2e71..14f087a9d2c688ac383133cdd57d7a435821d1f7 100644
--- a/debugger/dbg.y
+++ b/debugger/dbg.y
@@ -173,7 +173,12 @@ command:
     | noprocess_state
     ;
 
-set_command: tSET lval_addr '=' expr_value tEOL { DEBUG_WriteMemory(&$2,$4); DEBUG_FreeExprMem(); }
+set_command: 
+      tSET lval_addr '=' expr_value tEOL { DEBUG_WriteMemory(&$2,$4); DEBUG_FreeExprMem(); }
+    | tSET '+' tIDENTIFIER tEOL {DEBUG_DbgChannel(TRUE, NULL, $3);}
+    | tSET '-' tIDENTIFIER tEOL {DEBUG_DbgChannel(FALSE, NULL, $3);}
+    | tSET tIDENTIFIER '+' tIDENTIFIER tEOL {DEBUG_DbgChannel(TRUE, $2, $4);}
+    | tSET tIDENTIFIER '-' tIDENTIFIER tEOL {DEBUG_DbgChannel(FALSE, $2, $4);}
     ;
 
 pathname:
diff --git a/debugger/debugger.h b/debugger/debugger.h
index 833c63c8cb7c513c293d1d737c6a410a438ae8d0..787b14900a4064274d3386049a504fd88a637188 100644
--- a/debugger/debugger.h
+++ b/debugger/debugger.h
@@ -404,6 +404,7 @@ extern void DEBUG_InfoSegments(DWORD s, int v);
 extern void DEBUG_InfoVirtual(void);
 extern void DEBUG_InfoWindow(HWND hWnd);
 extern void DEBUG_WalkWindows(HWND hWnd, int indent);
+extern void DEBUG_DbgChannel(BOOL add, const char* chnl, const char* name);
 
   /* debugger/memory.c */
 extern int  DEBUG_ReadMemory( const DBG_VALUE* value );
diff --git a/debugger/info.c b/debugger/info.c
index 0bc4e6d9a2e2b144d3bcb72cff832e6983c03670..8013d9950efe2dc17021a8cbed7e69184643ff4d 100644
--- a/debugger/info.c
+++ b/debugger/info.c
@@ -575,5 +575,109 @@ void DEBUG_InfoSegments(DWORD start, int length)
 
 void DEBUG_InfoVirtual(void)
 {
-   DEBUG_Printf(DBG_CHN_MESG, "No longer providing virtual mapping information\n");
+    MEMORY_BASIC_INFORMATION    mbi;
+    char*                       addr = 0;
+    char*                       state;
+    char*                       type;
+    char                        prot[3+1];
+
+    if (DEBUG_CurrProcess == NULL)
+        return;
+
+    DEBUG_Printf(DBG_CHN_MESG, "Address  Size     State   Type    RWX\n");
+
+    while (VirtualQueryEx(DEBUG_CurrProcess->handle, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
+    {
+        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;
+            }
+            memset(prot, ' ' , sizeof(prot)-1);
+            prot[sizeof(prot)-1] = '\0';
+            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';
+        }
+        DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %s %s %s\n",
+                     (DWORD)addr, mbi.RegionSize, state, type, prot);
+        if (addr + mbi.RegionSize < addr) /* wrap around ? */
+            break;
+        addr += mbi.RegionSize;
+    }
 }
+
+struct dll_option_layout
+{
+    void*               next;
+    void*               prev;
+    char* const*        channels;
+    int                 nb_channels;
+};
+
+void DEBUG_DbgChannel(BOOL turn_on, const char* chnl, const char* name)
+{
+    DBG_VALUE                   val;
+    struct dll_option_layout    dol;
+    int                         i;
+    char*                       str;
+    unsigned char               buffer[32];
+    unsigned char               mask;
+    int                         done = 0;
+    BOOL                        bAll;
+    void*                       addr;
+
+    if (!DEBUG_GetSymbolValue("first_dll", -1, &val, FALSE))
+    {
+        DEBUG_Printf(DBG_CHN_MESG, "Can't get first_option symbol");
+        return;
+    }
+    addr = (void*)DEBUG_ToLinear(&val.addr);
+    if (!chnl)                          mask = 15;
+    else if (!strcmp(chnl, "fixme"))    mask = 1;
+    else if (!strcmp(chnl, "err"))      mask = 2;
+    else if (!strcmp(chnl, "warn"))     mask = 4;
+    else if (!strcmp(chnl, "trace"))    mask = 8;
+    else { DEBUG_Printf(DBG_CHN_MESG, "Unknown channel %s\n", chnl); return; }
+    
+    bAll = !strcmp("all", name);
+    while (addr && DEBUG_READ_MEM(addr, &dol, sizeof(dol)))
+    {
+        for (i = 0; i < dol.nb_channels; i++)
+        {
+            if (DEBUG_READ_MEM((void*)(dol.channels + i), &str, sizeof(str)) &&
+                DEBUG_READ_MEM(str, buffer, sizeof(buffer)) &&
+                (!strcmp(buffer + 1, name) || bAll))
+            {   
+                if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask;
+                if (DEBUG_WRITE_MEM(str, buffer, 1)) done++;
+            }
+        }
+        addr = dol.next;
+    }
+    if (!done) DEBUG_Printf(DBG_CHN_MESG, "Unable to find debug channel %s\n", name);
+    else DEBUG_Printf(DBG_CHN_TRACE, "Changed %d channel instances\n", done);
+}
+