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
DbgCaptureStackBackTace(_Out_writes_ (cFramesToCapture)PVOID * ppvFrames,_In_ ULONG cFramesToSkip,_In_ ULONG cFramesToCapture)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
CompareBacktraces(USHORT idx1,USHORT idx2)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
DbgDumpGdiHandleTableWithBT(void)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
DbgGdiHTIntegrityCheck(VOID)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
DbgLogEvent(PSLIST_HEADER pslh,LOG_EVENT_TYPE nEventType,LPARAM lParam)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
DbgPrintEvent(PLOGENTRY pLogEntry)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
DbgDumpEventList(PSLIST_HEADER pslh)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
DbgCleanupEventList(PSLIST_HEADER pslh)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
DbgDumpLockedGdiHandles(VOID)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
GdiDbgPreServiceHook(ULONG ulSyscallId,PULONG_PTR pulArguments)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
GdiDbgPostServiceHook(ULONG ulSyscallId,ULONG_PTR ulResult)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
QueryEnvironmentVariable(PUNICODE_STRING Name,PUNICODE_STRING Value)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
DbgCompareChannels(const void * a,const void * b)648 DbgCompareChannels(const void * a, const void * b)
649 {
650 return wcscmp((WCHAR*)a, ((DBG_CHANNEL*)b)->Name);
651 }
652
653 static BOOL
DbgAddDebugChannel(PPROCESSINFO ppi,WCHAR * channel,WCHAR * level,WCHAR op)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
DbgParseDebugChannels(PPROCESSINFO ppi,PUNICODE_STRING Value)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
DbgInitDebugChannels(VOID)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