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