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