1 /* 2 * PROJECT: ReactOS win32 kernel mode subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/gdidbg.c 5 * PURPOSE: Special debugging functions for GDI 6 * PROGRAMMERS: Timo Kreuzer 7 */ 8 9 /** INCLUDES ******************************************************************/ 10 11 #if DBG 12 #include <win32k.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 extern ULONG gulFirstFree; 17 extern ULONG gulFirstUnused; 18 extern PENTRY gpentHmgr; 19 20 ULONG gulLogUnique = 0; 21 22 /* Note: the following values need to be sorted */ 23 DBG_CHANNEL DbgChannels[DbgChCount] = { 24 {L"EngBlt", DbgChEngBlt}, 25 {L"EngBrush", DbgChEngBrush}, 26 {L"EngClip", DbgChEngClip}, 27 {L"EngCursor", DbgChEngCursor}, 28 {L"EngDev", DbgChEngDev}, 29 {L"EngErr", DbgChEngErr}, 30 {L"EngEvent", DbgChEngEvent}, 31 {L"EngGrad", DbgChEngGrad}, 32 {L"EngLDev", DbgChEngLDev}, 33 {L"EngLine", DbgChEngLine}, 34 {L"EngMapping", DbgChEngMapping}, 35 {L"EngPDev", DbgChEngPDev}, 36 {L"EngSurface", DbgChEngSurface}, 37 {L"EngWnd", DbgChEngWnd}, 38 {L"EngXlate", DbgChEngXlate}, 39 {L"GdiBitmap", DbgChGdiBitmap}, 40 {L"GdiBlt", DbgChGdiBlt}, 41 {L"GdiBrush", DbgChGdiBrush}, 42 {L"GdiClipRgn", DbgChGdiClipRgn}, 43 {L"GdiCoord", DbgChGdiCoord}, 44 {L"GdiDC", DbgChGdiDC}, 45 {L"GdiDCAttr", DbgChGdiDCAttr}, 46 {L"GdiDCState", DbgChGdiDCState}, 47 {L"GdiDev", DbgChGdiDev}, 48 {L"GdiDib", DbgChGdiDib}, 49 {L"GdiFont", DbgChGdiFont}, 50 {L"GdiLine", DbgChGdiLine}, 51 {L"GdiObj", DbgChGdiObj}, 52 {L"GdiPalette", DbgChGdiPalette}, 53 {L"GdiPath", DbgChGdiPath}, 54 {L"GdiPen", DbgChGdiPen}, 55 {L"GdiPool", DbgChGdiPool}, 56 {L"GdiRgn", DbgChGdiRgn}, 57 {L"GdiText", DbgChGdiText}, 58 {L"GdiXFormObj", DbgChGdiXFormObj}, 59 {L"UserAccel", DbgChUserAccel}, 60 {L"UserCallback", DbgChUserCallback}, 61 {L"UserCallProc", DbgChUserCallProc}, 62 {L"UserCaret", DbgChUserCaret}, 63 {L"UserClass", DbgChUserClass}, 64 {L"UserClipbrd", DbgChUserClipbrd}, 65 {L"UserCsr", DbgChUserCsr}, 66 {L"UserDce", DbgChUserDce}, 67 {L"UserDefwnd", DbgChUserDefwnd}, 68 {L"UserDesktop", DbgChUserDesktop}, 69 {L"UserDisplay",DbgChUserDisplay}, 70 {L"UserEvent", DbgChUserEvent}, 71 {L"UserFocus", DbgChUserFocus}, 72 {L"UserHook", DbgChUserHook}, 73 {L"UserHotkey", DbgChUserHotkey}, 74 {L"UserIcon", DbgChUserIcon}, 75 {L"UserInput", DbgChUserInput}, 76 {L"UserKbd", DbgChUserKbd}, 77 {L"UserKbdLayout", DbgChUserKbdLayout}, 78 {L"UserMenu", DbgChUserMenu}, 79 {L"UserMetric", DbgChUserMetric}, 80 {L"UserMisc", DbgChUserMisc}, 81 {L"UserMonitor", DbgChUserMonitor}, 82 {L"UserMsg", DbgChUserMsg}, 83 {L"UserMsgQ", DbgChUserMsgQ}, 84 {L"UserObj", DbgChUserObj}, 85 {L"UserPainting", DbgChUserPainting}, 86 {L"UserProcess", DbgChUserProcess}, 87 {L"UserProp", DbgChUserProp}, 88 {L"UserScrollbar", DbgChUserScrollbar}, 89 {L"UserShutdown", DbgChUserShutdown}, 90 {L"UserSysparams", DbgChUserSysparams}, 91 {L"UserTimer", DbgChUserTimer}, 92 {L"UserThread", DbgChUserThread}, 93 {L"UserWinpos", DbgChUserWinpos}, 94 {L"UserWinsta", DbgChUserWinsta}, 95 {L"UserWnd", DbgChUserWnd} 96 }; 97 98 ULONG 99 NTAPI 100 DbgCaptureStackBackTace( 101 _Out_writes_(cFramesToCapture) PVOID* ppvFrames, 102 _In_ ULONG cFramesToSkip, 103 _In_ ULONG cFramesToCapture) 104 { 105 ULONG cFrameCount; 106 PVOID apvTemp[30]; 107 NT_ASSERT(cFramesToCapture <= _countof(apvTemp)); 108 109 /* Zero it out */ 110 RtlZeroMemory(ppvFrames, cFramesToCapture * sizeof(PVOID)); 111 112 /* Capture kernel stack */ 113 cFrameCount = RtlWalkFrameChain(apvTemp, _countof(apvTemp), 0); 114 115 /* If we should skip more than we have, we are done */ 116 if (cFramesToSkip > cFrameCount) 117 return 0; 118 119 /* Copy, but skip frames */ 120 cFrameCount -= cFramesToSkip; 121 cFrameCount = min(cFrameCount, cFramesToCapture); 122 RtlCopyMemory(ppvFrames, &apvTemp[cFramesToSkip], cFrameCount * sizeof(PVOID)); 123 124 /* Check if there is still space left */ 125 if (cFrameCount < cFramesToCapture) 126 { 127 /* Capture user stack */ 128 cFrameCount += RtlWalkFrameChain(&ppvFrames[cFrameCount], 129 cFramesToCapture - cFrameCount, 130 1); 131 } 132 133 return cFrameCount; 134 } 135 136 #if DBG_ENABLE_GDIOBJ_BACKTRACES 137 138 static 139 BOOL 140 CompareBacktraces( 141 USHORT idx1, 142 USHORT idx2) 143 { 144 POBJ pobj1, pobj2; 145 ULONG iLevel; 146 147 /* Get the objects */ 148 pobj1 = gpentHmgr[idx1].einfo.pobj; 149 pobj2 = gpentHmgr[idx2].einfo.pobj; 150 151 /* Loop all stack levels */ 152 for (iLevel = 0; iLevel < GDI_OBJECT_STACK_LEVELS; iLevel++) 153 { 154 /* If one level doesn't match we are done */ 155 if (pobj1->apvBackTrace[iLevel] != pobj2->apvBackTrace[iLevel]) 156 { 157 return FALSE; 158 } 159 } 160 161 return TRUE; 162 } 163 164 typedef struct 165 { 166 USHORT idx; 167 USHORT iCount; 168 } GDI_DBG_HANDLE_BT; 169 170 VOID 171 NTAPI 172 DbgDumpGdiHandleTableWithBT(void) 173 { 174 static BOOL bLeakReported = FALSE; 175 ULONG idx, j; 176 BOOL bAlreadyPresent; 177 GDI_DBG_HANDLE_BT aBacktraceTable[GDI_DBG_MAX_BTS]; 178 USHORT iCount; 179 KIRQL OldIrql; 180 POBJ pobj; 181 ULONG iLevel, ulObj; 182 183 /* Only report once */ 184 if (bLeakReported) 185 { 186 DPRINT1("GDI handle abusers already reported!\n"); 187 return; 188 } 189 190 bLeakReported = TRUE; 191 DPRINT1("Reporting GDI handle abusers:\n"); 192 193 /* Zero out the table */ 194 RtlZeroMemory(aBacktraceTable, sizeof(aBacktraceTable)); 195 196 /* We've got serious business to do */ 197 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 198 199 /* Step through GDI handle table and find out who our culprit is... */ 200 for (idx = RESERVE_ENTRIES_COUNT; idx < GDI_HANDLE_COUNT; idx++) 201 { 202 /* If the handle is free, continue */ 203 if (gpentHmgr[idx].einfo.pobj == 0) continue; 204 205 /* Check if this backtrace is already covered */ 206 bAlreadyPresent = FALSE; 207 for (j = RESERVE_ENTRIES_COUNT; j < idx; j++) 208 { 209 if (CompareBacktraces(idx, j)) 210 { 211 bAlreadyPresent = TRUE; 212 break; 213 } 214 } 215 216 if (bAlreadyPresent) continue; 217 218 /* We don't have this BT yet, count how often it is present */ 219 iCount = 1; 220 for (j = idx + 1; j < GDI_HANDLE_COUNT; j++) 221 { 222 if (CompareBacktraces(idx, j)) 223 { 224 iCount++; 225 } 226 } 227 228 /* Now add this backtrace */ 229 for (j = 0; j < GDI_DBG_MAX_BTS; j++) 230 { 231 /* Insert it below the next smaller count */ 232 if (aBacktraceTable[j].iCount < iCount) 233 { 234 /* Check if there are entries above */ 235 if (j < GDI_DBG_MAX_BTS - 1) 236 { 237 /* Move the following entries up by 1 */ 238 RtlMoveMemory(&aBacktraceTable[j], 239 &aBacktraceTable[j + 1], 240 GDI_DBG_MAX_BTS - j - 1); 241 } 242 243 /* Set this entry */ 244 aBacktraceTable[j].idx = idx; 245 aBacktraceTable[j].iCount = iCount; 246 247 /* We are done here */ 248 break; 249 } 250 } 251 } 252 253 /* Print the worst offenders... */ 254 DbgPrint("Count Handle Backtrace\n"); 255 DbgPrint("------------------------------------------------\n"); 256 for (j = 0; j < GDI_DBG_MAX_BTS; j++) 257 { 258 idx = aBacktraceTable[j].idx; 259 if (idx == 0) 260 break; 261 262 ulObj = ((ULONG)gpentHmgr[idx].FullUnique << 16) | idx; 263 pobj = gpentHmgr[idx].einfo.pobj; 264 265 DbgPrint("%5d %08lx ", aBacktraceTable[j].iCount, ulObj); 266 for (iLevel = 0; iLevel < GDI_OBJECT_STACK_LEVELS; iLevel++) 267 { 268 DbgPrint("%p,", pobj->apvBackTrace[iLevel]); 269 } 270 DbgPrint("\n"); 271 } 272 273 __debugbreak(); 274 275 KeLowerIrql(OldIrql); 276 } 277 278 #endif /* DBG_ENABLE_GDIOBJ_BACKTRACES */ 279 280 #if DBG 281 282 BOOL 283 NTAPI 284 DbgGdiHTIntegrityCheck(VOID) 285 { 286 ULONG i, nDeleted = 0, nFree = 0, nUsed = 0; 287 PGDI_TABLE_ENTRY pEntry; 288 BOOL r = 1; 289 290 KeEnterCriticalRegion(); 291 292 /* FIXME: Check reserved entries */ 293 294 /* Now go through the deleted objects */ 295 i = gulFirstFree & 0xffff; 296 while (i) 297 { 298 pEntry = &GdiHandleTable->Entries[i]; 299 if (i >= GDI_HANDLE_COUNT) 300 { 301 DPRINT1("nDeleted=%lu\n", nDeleted); 302 ASSERT(FALSE); 303 } 304 305 nDeleted++; 306 307 /* Check the entry */ 308 if ((pEntry->Type & GDI_ENTRY_BASETYPE_MASK) != 0) 309 { 310 r = 0; 311 DPRINT1("Deleted Entry has a type != 0\n"); 312 } 313 if ((ULONG_PTR)pEntry->KernelData >= GDI_HANDLE_COUNT) 314 { 315 r = 0; 316 DPRINT1("Deleted entries KernelPointer too big\n"); 317 } 318 if (pEntry->UserData != NULL) 319 { 320 r = 0; 321 DPRINT1("Deleted entry has UserData != 0\n"); 322 } 323 if (pEntry->ProcessId != 0) 324 { 325 r = 0; 326 DPRINT1("Deleted entry has ProcessId != 0\n"); 327 } 328 329 i = (ULONG_PTR)pEntry->KernelData & 0xffff; 330 }; 331 332 for (i = gulFirstUnused; 333 i < GDI_HANDLE_COUNT; 334 i++) 335 { 336 pEntry = &GdiHandleTable->Entries[i]; 337 338 if ((pEntry->Type) != 0) 339 { 340 r = 0; 341 DPRINT1("Free Entry has a type != 0\n"); 342 } 343 if ((ULONG_PTR)pEntry->KernelData != 0) 344 { 345 r = 0; 346 DPRINT1("Free entries KernelPointer != 0\n"); 347 } 348 if (pEntry->UserData != NULL) 349 { 350 r = 0; 351 DPRINT1("Free entry has UserData != 0\n"); 352 } 353 if (pEntry->ProcessId != 0) 354 { 355 r = 0; 356 DPRINT1("Free entry has ProcessId != 0\n"); 357 } 358 nFree++; 359 } 360 361 for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++) 362 { 363 HGDIOBJ Handle; 364 ULONG Type; 365 366 pEntry = &GdiHandleTable->Entries[i]; 367 Type = pEntry->Type; 368 Handle = (HGDIOBJ)(ULONG_PTR)((Type << GDI_ENTRY_UPPER_SHIFT) + i); 369 370 if (Type & GDI_ENTRY_BASETYPE_MASK) 371 { 372 if (pEntry->KernelData == NULL) 373 { 374 r = 0; 375 DPRINT1("Used entry has KernelData == 0\n"); 376 } 377 else if (pEntry->KernelData <= MmHighestUserAddress) 378 { 379 r = 0; 380 DPRINT1("Used entry invalid KernelData\n"); 381 } 382 else if (((POBJ)(pEntry->KernelData))->hHmgr != Handle) 383 { 384 r = 0; 385 DPRINT1("Used entry %lu, has invalid hHmg %p (expected: %p)\n", 386 i, ((POBJ)(pEntry->KernelData))->hHmgr, Handle); 387 } 388 nUsed++; 389 } 390 } 391 392 if (RESERVE_ENTRIES_COUNT + nDeleted + nFree + nUsed != GDI_HANDLE_COUNT) 393 { 394 r = 0; 395 DPRINT1("Number of all entries incorrect: RESERVE_ENTRIES_COUNT = %lu, nDeleted = %lu, nFree = %lu, nUsed = %lu\n", 396 RESERVE_ENTRIES_COUNT, nDeleted, nFree, nUsed); 397 } 398 399 KeLeaveCriticalRegion(); 400 401 return r; 402 } 403 404 #endif /* DBG */ 405 406 407 #if DBG_ENABLE_EVENT_LOGGING 408 409 VOID 410 NTAPI 411 DbgLogEvent(PSLIST_HEADER pslh, LOG_EVENT_TYPE nEventType, LPARAM lParam) 412 { 413 PLOGENTRY pLogEntry; 414 415 /* Log a maximum of 100 events */ 416 if (QueryDepthSList(pslh) >= 1000) return; 417 418 /* Allocate a logentry */ 419 pLogEntry = EngAllocMem(0, sizeof(LOGENTRY), 'golG'); 420 if (!pLogEntry) return; 421 422 /* Set type */ 423 pLogEntry->nEventType = nEventType; 424 pLogEntry->ulUnique = InterlockedIncrement((LONG*)&gulLogUnique); 425 pLogEntry->dwProcessId = HandleToUlong(PsGetCurrentProcessId()); 426 pLogEntry->dwThreadId = HandleToUlong(PsGetCurrentThreadId()); 427 pLogEntry->lParam = lParam; 428 429 /* Capture a backtrace */ 430 DbgCaptureStackBackTace(pLogEntry->apvBackTrace, 1, 20); 431 432 switch (nEventType) 433 { 434 case EVENT_ALLOCATE: 435 case EVENT_CREATE_HANDLE: 436 case EVENT_REFERENCE: 437 case EVENT_DEREFERENCE: 438 case EVENT_LOCK: 439 case EVENT_UNLOCK: 440 case EVENT_DELETE: 441 case EVENT_FREE: 442 case EVENT_SET_OWNER: 443 default: 444 break; 445 } 446 447 /* Push it on the list */ 448 InterlockedPushEntrySList(pslh, &pLogEntry->sleLink); 449 } 450 451 #define REL_ADDR(va) ((ULONG_PTR)va - (ULONG_PTR)&__ImageBase) 452 453 VOID 454 NTAPI 455 DbgPrintEvent(PLOGENTRY pLogEntry) 456 { 457 PSTR pstr; 458 459 switch (pLogEntry->nEventType) 460 { 461 case EVENT_ALLOCATE: pstr = "Allocate"; break; 462 case EVENT_CREATE_HANDLE: pstr = "CreatHdl"; break; 463 case EVENT_REFERENCE: pstr = "Ref"; break; 464 case EVENT_DEREFERENCE: pstr = "Deref"; break; 465 case EVENT_LOCK: pstr = "Lock"; break; 466 case EVENT_UNLOCK: pstr = "Unlock"; break; 467 case EVENT_DELETE: pstr = "Delete"; break; 468 case EVENT_FREE: pstr = "Free"; break; 469 case EVENT_SET_OWNER: pstr = "SetOwner"; break; 470 default: pstr = "Unknown"; break; 471 } 472 473 DbgPrint("[%lu] %03x:%03x %.8s val=%p <%lx,%lx,%lx,%lx>\n", 474 pLogEntry->ulUnique, 475 pLogEntry->dwProcessId, 476 pLogEntry->dwThreadId, 477 pstr, 478 (PVOID)pLogEntry->lParam, 479 REL_ADDR(pLogEntry->apvBackTrace[2]), 480 REL_ADDR(pLogEntry->apvBackTrace[3]), 481 REL_ADDR(pLogEntry->apvBackTrace[4]), 482 REL_ADDR(pLogEntry->apvBackTrace[5])); 483 } 484 485 VOID 486 NTAPI 487 DbgDumpEventList(PSLIST_HEADER pslh) 488 { 489 PSLIST_ENTRY psle; 490 PLOGENTRY pLogEntry; 491 492 while ((psle = InterlockedPopEntrySList(pslh))) 493 { 494 pLogEntry = CONTAINING_RECORD(psle, LOGENTRY, sleLink); 495 DbgPrintEvent(pLogEntry); 496 } 497 } 498 499 VOID 500 NTAPI 501 DbgCleanupEventList(PSLIST_HEADER pslh) 502 { 503 PSLIST_ENTRY psle; 504 PLOGENTRY pLogEntry; 505 506 while ((psle = InterlockedPopEntrySList(pslh))) 507 { 508 pLogEntry = CONTAINING_RECORD(psle, LOGENTRY, sleLink); 509 EngFreeMem(pLogEntry); 510 } 511 } 512 513 #endif /* DBG_ENABLE_EVENT_LOGGING */ 514 515 #if 1 || DBG_ENABLE_SERVICE_HOOKS 516 517 VOID 518 NTAPI 519 DbgDumpLockedGdiHandles(VOID) 520 { 521 ULONG i; 522 523 for (i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++) 524 { 525 PENTRY pentry = &gpentHmgr[i]; 526 527 if (pentry->Objt) 528 { 529 POBJ pobj = pentry->einfo.pobj; 530 if (pobj->cExclusiveLock > 0) 531 { 532 DPRINT1("Locked object: %lx, type = %lx. allocated from:\n", 533 i, pentry->Objt); 534 DBG_DUMP_EVENT_LIST(&pobj->slhLog); 535 } 536 } 537 } 538 } 539 540 void 541 NTAPI 542 GdiDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments) 543 { 544 PTHREADINFO pti = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); 545 if (pti && pti->cExclusiveLocks != 0) 546 { 547 DbgPrint("FATAL: Win32DbgPreServiceHook(0x%lx): There are %lu exclusive locks!\n", 548 ulSyscallId, pti->cExclusiveLocks); 549 DbgDumpLockedGdiHandles(); 550 ASSERT(FALSE); 551 } 552 553 } 554 555 ULONG_PTR 556 NTAPI 557 GdiDbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult) 558 { 559 PTHREADINFO pti = (PTHREADINFO)PsGetCurrentThreadWin32Thread(); 560 if (pti && pti->cExclusiveLocks != 0) 561 { 562 DbgPrint("FATAL: Win32DbgPostServiceHook(0x%lx): There are %lu exclusive locks!\n", 563 ulSyscallId, pti->cExclusiveLocks); 564 DbgDumpLockedGdiHandles(); 565 ASSERT(FALSE); 566 } 567 return ulResult; 568 } 569 570 #endif /* DBG_ENABLE_SERVICE_HOOKS */ 571 572 573 NTSTATUS NTAPI 574 QueryEnvironmentVariable(PUNICODE_STRING Name, 575 PUNICODE_STRING Value) 576 { 577 NTSTATUS Status; 578 PWSTR wcs; 579 UNICODE_STRING var; 580 PWSTR val; 581 PPEB Peb; 582 PWSTR Environment; 583 584 /* Ugly HACK for ReactOS system threads */ 585 if(!NtCurrentTeb()) 586 { 587 return(STATUS_VARIABLE_NOT_FOUND); 588 } 589 590 Peb = NtCurrentPeb(); 591 592 if (Peb == NULL) 593 { 594 return(STATUS_VARIABLE_NOT_FOUND); 595 } 596 597 Environment = Peb->ProcessParameters->Environment; 598 599 if (Environment == NULL) 600 { 601 return(STATUS_VARIABLE_NOT_FOUND); 602 } 603 604 Value->Length = 0; 605 606 wcs = Environment; 607 while (*wcs) 608 { 609 var.Buffer = wcs++; 610 wcs = wcschr(wcs, L'='); 611 if (wcs == NULL) 612 { 613 wcs = var.Buffer + wcslen(var.Buffer); 614 } 615 if (*wcs) 616 { 617 var.Length = var.MaximumLength = (wcs - var.Buffer) * sizeof(WCHAR); 618 val = ++wcs; 619 wcs += wcslen(wcs); 620 621 if (RtlEqualUnicodeString(&var, Name, TRUE)) 622 { 623 Value->Length = (wcs - val) * sizeof(WCHAR); 624 if (Value->Length <= Value->MaximumLength) 625 { 626 memcpy(Value->Buffer, val, 627 min(Value->Length + sizeof(WCHAR), Value->MaximumLength)); 628 Status = STATUS_SUCCESS; 629 } 630 else 631 { 632 Status = STATUS_BUFFER_TOO_SMALL; 633 } 634 635 return(Status); 636 } 637 } 638 wcs++; 639 } 640 641 return(STATUS_VARIABLE_NOT_FOUND); 642 } 643 644 static int __cdecl 645 DbgCompareChannels(const void * a, const void * b) 646 { 647 return wcscmp((WCHAR*)a, ((DBG_CHANNEL*)b)->Name); 648 } 649 650 static BOOL 651 DbgAddDebugChannel(PPROCESSINFO ppi, WCHAR* channel, WCHAR* level, WCHAR op) 652 { 653 DBG_CHANNEL *ChannelEntry; 654 UINT iLevel, iChannel; 655 656 /* Special treatment for the "all" channel */ 657 if (wcscmp(channel, L"all") == 0) 658 { 659 for (iChannel = 0; iChannel < DbgChCount; iChannel++) 660 { 661 DbgAddDebugChannel(ppi, DbgChannels[iChannel].Name, level, op); 662 } 663 return TRUE; 664 } 665 666 ChannelEntry = (DBG_CHANNEL*)bsearch(channel, 667 DbgChannels, 668 DbgChCount, 669 sizeof(DBG_CHANNEL), 670 DbgCompareChannels); 671 if(ChannelEntry == NULL) 672 { 673 return FALSE; 674 } 675 676 iChannel = ChannelEntry->Id; 677 ASSERT(iChannel < DbgChCount); 678 679 if(level == NULL || *level == L'\0' ||wcslen(level) == 0 ) 680 iLevel = MAX_LEVEL; 681 else if(wcsncmp(level, L"err", 3) == 0) 682 iLevel = ERR_LEVEL; 683 else if(wcsncmp(level, L"fixme", 5) == 0) 684 iLevel = FIXME_LEVEL; 685 else if(wcsncmp(level, L"warn", 4) == 0) 686 iLevel = WARN_LEVEL; 687 else if (wcsncmp(level, L"trace", 4) == 0) 688 iLevel = TRACE_LEVEL; 689 else 690 return FALSE; 691 692 if(op==L'+') 693 { 694 DBG_ENABLE_CHANNEL(ppi, iChannel, iLevel); 695 } 696 else 697 { 698 DBG_DISABLE_CHANNEL(ppi, iChannel, iLevel); 699 } 700 701 return TRUE; 702 } 703 704 static BOOL 705 DbgParseDebugChannels(PPROCESSINFO ppi, PUNICODE_STRING Value) 706 { 707 WCHAR *str, *separator, *c, op; 708 709 str = Value->Buffer; 710 711 do 712 { 713 separator = wcschr(str, L','); 714 if(separator != NULL) 715 *separator = L'\0'; 716 717 c = wcschr(str, L'+'); 718 if(c == NULL) 719 c = wcschr(str, L'-'); 720 721 if(c != NULL) 722 { 723 op = *c; 724 *c = L'\0'; 725 c++; 726 727 DbgAddDebugChannel(ppi, c, str, op); 728 } 729 730 str = separator + 1; 731 }while(separator != NULL); 732 733 return TRUE; 734 } 735 736 BOOL DbgInitDebugChannels(VOID) 737 { 738 WCHAR valBuffer[100]; 739 UNICODE_STRING Value; 740 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"DEBUGCHANNEL"); 741 NTSTATUS Status; 742 PPROCESSINFO ppi; 743 BOOL ret; 744 745 /* Initialize all channels to ERROR */ 746 ppi = PsGetCurrentProcessWin32Process(); 747 RtlFillMemory( ppi->DbgChannelLevel, 748 sizeof(ppi->DbgChannelLevel), 749 ERR_LEVEL); 750 751 /* Find DEBUGCHANNEL env var */ 752 Value.Buffer = valBuffer; 753 Value.Length = 0; 754 Value.MaximumLength = sizeof(valBuffer); 755 Status = QueryEnvironmentVariable(&Name, &Value); 756 757 /* It does not exist */ 758 if(Status == STATUS_VARIABLE_NOT_FOUND) 759 { 760 /* There is nothing more to do */ 761 return TRUE; 762 } 763 764 /* If the buffer in the stack is not enough allocate it */ 765 if(Status == STATUS_BUFFER_TOO_SMALL) 766 { 767 Value.Buffer = ExAllocatePool(PagedPool, Value.MaximumLength); 768 if(Value.Buffer == NULL) 769 { 770 return FALSE; 771 } 772 773 /* Get the env var again */ 774 Status = QueryEnvironmentVariable(&Name, &Value); 775 } 776 777 /* Check for error */ 778 if(!NT_SUCCESS(Status)) 779 { 780 if(Value.Buffer != valBuffer) 781 { 782 ExFreePool(Value.Buffer); 783 } 784 785 return FALSE; 786 } 787 788 /* Parse the variable */ 789 ret = DbgParseDebugChannels(ppi, &Value); 790 791 /* Clean up */ 792 if(Value.Buffer != valBuffer) 793 { 794 ExFreePool(Value.Buffer); 795 } 796 797 return ret; 798 } 799 800 801 #endif // DBG 802 803 /* EOF */ 804