1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     Tracing.cpp
8 
9 Abstract:
10 
11     This module implements tracing for the driver frameworks
12 
13 Author:
14 
15 
16 
17 
18 Revision History:
19 
20 
21 
22 
23 --*/
24 
25 #include "FxSupportPch.hpp"
26 #include "fxldrum.h"
27 
28 extern "C" {
29 #if defined(EVENT_TRACING)
30 #include "TracingUM.tmh"
31 #endif
32 }
33 
34 #include <strsafe.h>
35 #include <initguid.h>
36 #include "fxIFR.h"       // shared struct between IFR and debug ext.
37 #include "fxIFRKm.h"     // kernel mode only IFR definitions
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182 
183 
184 
185 
186 
187 
188 
189 
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 
206 
207 
208 
209 
210 
211 
212 
213 
214 
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 
225 
226 
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239 
240 
241 
242 
243 
244 
245 
246 
247 
248 
249 
250 
251 
252 
253 
254 _Must_inspect_result_
255 NTSTATUS
256 FxTraceInitialize(
257     VOID
258     )
259 
260 /*++
261 
262 Routine Description:
263 
264     This routine initializes the frameworks tracing.
265 
266     It must be called early on in the frameworks DriverEntry
267     initialization.
268 
269 Arguments:
270 
271     None
272 
273 Returns:
274 
275     NTSTATUS code
276 
277 --*/
278 {
279     //
280     // Initialize the tracing package.
281     //
282     WPP_INIT_TRACING(NULL, NULL);
283 
284     return STATUS_SUCCESS;
285 }
286 
287 VOID
288 TraceUninitialize(
289     VOID
290     )
291 /*++
292 
293 Routine Description:
294     This routine uninitializes the frameworks tracing.  It must be called just
295     before DriverUnload
296 
297 Arguments:
298     None
299 
300 Returns:
301     None
302 
303 --*/
304 {
305     WPP_CLEANUP(NULL);
306 }
307 
308 _Must_inspect_result_
309 NTSTATUS
310 FxWmiQueryTraceInformation(
311     __in TRACE_INFORMATION_CLASS /* TraceInformationClass */,
312     __out_bcount(TraceInformationLength) PVOID /* TraceInformation */,
313     __in ULONG /* TraceInformationLength */,
314     __out_opt PULONG /* RequiredLength */,
315     __in_opt PVOID /* Buffer */
316     )
317 {
318     return STATUS_UNSUCCESSFUL;
319 }
320 
321 _Must_inspect_result_
322 NTSTATUS
323 FxWmiTraceMessage(
324     __in TRACEHANDLE  LoggerHandle,
325     __in ULONG        MessageFlags,
326     __in LPGUID       MessageGuid,
327     __in USHORT       MessageNumber,
328          ...
329     )
330 {
331     NTSTATUS status = STATUS_SUCCESS;
332 
333     va_list va;
334     va_start(va, MessageNumber);
335     //
336     // UMDF is supported only on XP and newer OS so no need to support w2k
337     // tracing (which requires using a different tracing api, see kmdf impl)
338     //
339 #pragma prefast(suppress:__WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean");
340     status = TraceMessageVa(LoggerHandle,
341                             MessageFlags,
342                             MessageGuid,
343                             MessageNumber,
344                             va);
345 
346     va_end(va);
347 
348     return status;
349 }
350 
351 
352 //-----------------------------------------------------------------------------
353 // Subcomponents for the In-Flight Recorder follow.
354 //-----------------------------------------------------------------------------
355 
356 ULONG
357 FxIFRGetSize(
358     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
359     __in PCUNICODE_STRING RegistryPath
360     )
361 /*++
362 
363 Routine Description:
364     Checks to see if the service has overriden the default number of pages that
365     are in the IFR.
366 
367 Arguments:
368     RegistryPath - path to the service
369 
370 Return Value:
371     The size of the IFR to create in bytes (not pages!)
372 
373   --*/
374 {
375     FxAutoRegKey service, parameters;
376     NTSTATUS status;
377     ULONG numPages;
378 
379     //
380     // This is the value used in case of any error while retrieving 'LogPages'
381     // from the registry.
382     //
383     numPages  = FxIFRMinLogPages;
384 
385     //
386     // External representation of the IFR is the "log", so use tha term when
387     // overriding the size via the registry.
388     //
389     DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf");
390     DECLARE_CONST_UNICODE_STRING(valueName, L"LogPages");
391 
392     //
393     // UMDF may not provide this registry path
394     //
395     if (NULL == RegistryPath) {
396         goto defaultValues;
397     }
398 
399     status = FxRegKey::_OpenKey(NULL,
400                                 (PCUNICODE_STRING)RegistryPath,
401                                 &service.m_Key,
402                                 KEY_READ);
403     if (!NT_SUCCESS(status)) {
404         goto defaultValues;
405     }
406 
407     status = FxRegKey::_OpenKey(service.m_Key,
408                                 (PCUNICODE_STRING)&parametersPath,
409                                 &parameters.m_Key,
410                                 KEY_READ);
411     if (!NT_SUCCESS(status)) {
412         goto defaultValues;
413     }
414 
415     status = FxRegKey::_QueryULong(parameters.m_Key, &valueName, &numPages);
416     if (!NT_SUCCESS(status)) {
417         goto defaultValues;
418     }
419 
420     if (numPages == 0) {
421         numPages = FxIFRMinLogPages;
422     }
423 
424 defaultValues:
425     //
426     // This behavior is different from KMDF. KMDF would allocate Average page count (5)
427     // if Verifier is on otherwise 1 page if the request is large.
428     // Since for UMDF the memory is coming from WudfRd, which does not know about verifier
429     // we will give it max pages here.
430     //
431     if (numPages > FxIFRMaxLogPages) {
432         numPages = FxIFRMaxLogPages;
433     }
434 
435     return numPages * PAGE_SIZE;
436 }
437 
438 VOID
439 FxIFRStart(
440     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
441     __in PCUNICODE_STRING RegistryPath,
442     __in MdDriverObject DriverObject
443     )
444 /*++
445 
446 Routine Description:
447 
448     This routine initialize the In-Flight Recorder (IFR).
449 
450     The default log size is set by WDF_IFR_LOG_SIZE and currently
451     is 4096 (one x86 page).
452     This routine should be called very early in driver initialization
453     to allow the capture of all significant events.
454 
455 Arguments:
456 
457 Returns:
458 
459 --*/
460 {
461     PWDF_IFR_HEADER pHeader;
462     ULONG pageCount;
463     ULONG sizeCb;
464     HRESULT hr;
465     IWudfDeviceStack2 *pDeviceStack2;
466     PDRIVER_OBJECT_UM umDriverObject;
467     PWCHAR serviceName;
468     size_t bufferLengthCch;
469     ULONG allocatedBufferLengthCb;
470     LONG i;
471 
472     //
473     // Return early if IFR is disabled.
474     //
475     if (FxLibraryGlobals.IfrDisabled) {
476         ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
477         return;
478     }
479 
480     WDFCASSERT(FxIFRRecordSignature == WDF_IFR_RECORD_SIGNATURE);
481 
482     if (FxDriverGlobals == NULL || FxDriverGlobals->WdfLogHeader != NULL) {
483         return;
484     }
485 
486     //
487     // It is safe to use StringCchLength here as WudfHost makes sure that this
488     // RegistryPath is null terminated
489     //
490     hr = StringCchLength(RegistryPath->Buffer,
491                          RegistryPath->MaximumLength/sizeof(WCHAR),
492                          &bufferLengthCch);
493 
494     if (FAILED(hr)) {
495         return;
496     }
497 
498     //
499     // Lets find the last '\' that will mark the begining of the service name
500     //
501     for (i = (ULONG)bufferLengthCch - 1;
502         i >= 0 && RegistryPath->Buffer[i] != '\\';
503         i--);
504 
505     //
506     // We did not find the service name
507     //
508     if (i < 0) {
509         return;
510     }
511 
512     serviceName = &RegistryPath->Buffer[i+1];
513 
514     sizeCb = FxIFRGetSize(FxDriverGlobals, RegistryPath);
515     pageCount = sizeCb / PAGE_SIZE;
516 
517     //
518     // Get the IWudfDeviceStack interface
519     //
520     umDriverObject = (PDRIVER_OBJECT_UM)DriverObject;
521 
522     pDeviceStack2 = (IWudfDeviceStack2 *)umDriverObject->WudfDevStack;
523 
524     if(pDeviceStack2 == NULL) {
525         return;
526     }
527 
528     allocatedBufferLengthCb = 0;
529     hr = pDeviceStack2->AllocateIfrMemory(serviceName,
530                                           pageCount,
531                                           FALSE,
532                                           TRUE,
533                                           (PVOID *)&pHeader,
534                                           &allocatedBufferLengthCb);
535 
536     if (pHeader == NULL || allocatedBufferLengthCb <= sizeof(WDF_IFR_HEADER)) {
537         return;
538     }
539 
540     //
541     // Initialize the header.
542     // Base will be where the IFR records are placed.
543     // WPP_ThisDir_CTLGUID_FrameworksTraceGuid
544     //
545     RtlCopyMemory(&pHeader->Guid, (PVOID) &WdfTraceGuid, sizeof(GUID));
546 
547     pHeader->Base = (PUCHAR) &pHeader[1];
548     pHeader->Size = allocatedBufferLengthCb - sizeof(WDF_IFR_HEADER);
549 
550     pHeader->Offset.u.s.Current  = 0;
551     pHeader->Offset.u.s.Previous = 0;
552     pHeader->SequenceNumberPointer = &(DriverObject->IfrSequenceNumber);
553 
554     StringCchCopyA(pHeader->DriverName, WDF_IFR_HEADER_NAME_LEN, FxDriverGlobals->Public.DriverName);
555 
556     FxDriverGlobals->WdfLogHeader = pHeader;
557 
558     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
559                         "FxIFR logging started" );
560 
561     if (sizeCb > FxIFRMinLogSize) {
562         DoTraceLevelMessage(
563             FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER,
564             "FxIFR has been started with a size override:  size 0x%x bytes, "
565             "# Pages %d.  An extended IFR size may not be written to a minidump!",
566             sizeCb, sizeCb/PAGE_SIZE);
567     }
568 
569     if (sizeCb != allocatedBufferLengthCb) {
570         ASSERTMSG("FxIFR requested buffer size could not be allocated",FALSE);
571         DoTraceLevelMessage(
572             FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDRIVER,
573             "FxIFR requested an allocation of size 0x%x bytes, "
574             "Allocated memory was of size 0x%x bytes",
575             sizeCb, allocatedBufferLengthCb);
576     }
577 }
578 
579 VOID
580 FxIFRStop(
581     __in PFX_DRIVER_GLOBALS FxDriverGlobals
582     )
583 /*++
584 
585 Routine Description:
586 
587     This routine stops the In-Flight Recorder (IFR).
588 
589     For UMDF FxIFRStop is no longer required as WudfRd manages the buffer's lifetime
590     The buffer is kept alive till WudfRd unloads to aid in debugging in cases of
591     WudfHost crash or in dumps with WudfHost paged out or not captured
592 
593 Arguments:
594 
595 Returns:
596 
597 --*/
598 {
599     UNREFERENCED_PARAMETER(FxDriverGlobals);
600 
601     //
602     // Uncomment the code below if you add any logic to this function.
603     //
604     // if (FxLibraryGlobals.IfrDisabled) {
605     //     ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
606     //     return;
607     // }
608     //
609 }
610 
611 _Must_inspect_result_
612 NTSTATUS
613 FxIFR(
614     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
615     __in UCHAR              MessageLevel,
616     __in ULONG              MessageFlags,
617     __in LPGUID             MessageGuid,
618     __in USHORT             MessageNumber,
619          ...
620     )
621 /*++
622 
623 Routine Description:
624 
625     This routine is the main In-Flight Recorder (IFR) routine.
626 
627     It captures a WPP message to the IFR log.
628     The IFR is always running, e.g. not WPP logger is necessary
629     to start logging.
630 
631 Arguments:
632 
633     MessageLevel  - The WPP message level for this event
634     MessageFlags  - The WPP message flags for this event (see trace GUID)
635     MessageGuid   - The tracewpp generated guid for module emitting this event.
636     MessageNumber - The tracewpp generated message number within
637                     the emitting module.
638     ...           - Variable arguments associates with the emitted message.
639 
640 Returns:
641 
642     NTSTATUS
643 
644 --*/
645 {
646     size_t            size;
647     PWDF_IFR_RECORD   record;
648 
649     UNREFERENCED_PARAMETER( MessageLevel );
650 
651     //
652     // Return early if IFR is disabled.
653     //
654     if (FxLibraryGlobals.IfrDisabled) {
655         ASSERT(FxDriverGlobals->WdfLogHeader == NULL);
656         return STATUS_SUCCESS;
657     }
658 
659     if ( FxDriverGlobals->WdfLogHeader == NULL) {
660         return STATUS_UNSUCCESSFUL;
661     }
662 
663 
664 
665 
666 
667 
668 
669 
670 
671 
672 
673 
674 
675 
676 
677 
678 
679 
680 
681 
682 
683 
684 
685 
686 
687     UNREFERENCED_PARAMETER( MessageFlags );
688 
689 
690     //
691     // Determine the number bytes to follow header
692     //
693     size = 0;   // For Count of Bytes
694 
695     //
696     // Determine how much log space is needed for this
697     // trace record's data.
698     //
699     {
700         va_list   ap;
701         size_t    argLen;
702 
703         va_start(ap, MessageNumber);
704 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean");
705         while ((va_arg(ap, PVOID)) != NULL) {
706 
707             argLen = va_arg(ap, size_t);
708 
709             if (argLen > 0) {
710 
711                 if (argLen > FxIFRMaxMessageSize) {
712                     goto drop_message;
713                 }
714                 size += (USHORT) argLen;
715             }
716         }
717 
718         va_end(ap);
719 
720         //
721         // NOTE: The final size must be 32-bit (ULONG) aligned.
722         //       This is necessary for IA64 to prevent Alignment Faults.
723         //
724         size += (size % sizeof(ULONG)) ? sizeof(ULONG) - (size % sizeof(ULONG)) : 0;
725 
726         if (size > FxIFRMaxMessageSize) {
727             goto drop_message;
728         }
729     }
730 
731     size += sizeof(WDF_IFR_RECORD);
732 
733     //
734     // Allocate log space of the calculated size
735     //
736     {
737         PWDF_IFR_HEADER  header;
738         WDF_IFR_OFFSET   offsetRet;
739         WDF_IFR_OFFSET   offsetCur;
740         WDF_IFR_OFFSET   offsetNew;
741         USHORT           usSize = (USHORT) size;  // for a prefast artifact.
742 
743         header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader;
744         ASSERT(header->Size < FxIFRMaxLogSize); // size doesn't include header.
745         ASSERT(header->Size >= header->Offset.u.s.Current);
746         ASSERT(header->Size >= header->Offset.u.s.Previous);
747 
748         offsetRet.u.AsLONG = header->Offset.u.AsLONG;
749         offsetNew.u.AsLONG = offsetRet.u.s.Current;
750 
751         do {
752             offsetCur.u.AsLONG = offsetRet.u.AsLONG;
753 
754             if (&header->Base[header->Size] < &header->Base[offsetCur.u.s.Current+size]) {
755 
756                 offsetNew.u.s.Current  = 0;
757                 offsetNew.u.s.Previous = offsetRet.u.s.Previous;
758 
759                 offsetRet.u.AsLONG =
760                     InterlockedCompareExchange( &header->Offset.u.AsLONG,
761                                                 offsetNew.u.AsLONG,
762                                                 offsetCur.u.AsLONG );
763 
764                 if (offsetCur.u.AsLONG != offsetRet.u.AsLONG) {
765                     continue;
766                 } else {
767                     offsetNew.u.s.Current  = offsetCur.u.s.Current + usSize;
768                     offsetNew.u.s.Previous = offsetRet.u.s.Current;
769                 }
770             } else {
771 
772                 offsetNew.u.s.Current  = offsetCur.u.s.Current + usSize;
773                 offsetNew.u.s.Previous = offsetCur.u.s.Current;
774             }
775 
776             offsetRet.u.AsLONG =
777                 InterlockedCompareExchange( &header->Offset.u.AsLONG,
778                                             offsetNew.u.AsLONG,
779                                             offsetCur.u.AsLONG );
780 
781         } while (offsetCur.u.AsLONG != offsetRet.u.AsLONG);
782 
783         record = (PWDF_IFR_RECORD) &header->Base[offsetRet.u.s.Current];
784 
785         // RtlZeroMemory( record, sizeof(WDF_IFR_RECORD) );
786 
787         //
788         // Build record (fill all fields!)
789         //
790         record->Signature     = FxIFRRecordSignature;
791         record->Length        = (USHORT) size;
792         record->PrevOffset    = (USHORT) offsetRet.u.s.Previous;
793         record->MessageNumber = MessageNumber;
794         record->Sequence      = InterlockedIncrement(header->SequenceNumberPointer);
795         record->MessageGuid   = *MessageGuid;
796     }
797 
798     //
799     // Move variable part of data into log.
800     //
801     {
802         va_list  ap;
803         size_t   argLen;
804         PVOID    source;
805         PUCHAR   argsData;
806 
807         argsData = (UCHAR*) &record[1];
808 
809         va_start(ap, MessageNumber);
810 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean");
811         while ((source = va_arg(ap, PVOID)) != NULL) {
812 
813             argLen = va_arg(ap, size_t);
814 
815             if (argLen > 0) {
816 
817                 RtlCopyMemory( argsData, source, argLen );
818                 argsData += argLen;
819             }
820         }
821 
822         va_end(ap);
823     }
824 
825     return STATUS_SUCCESS;
826 
827     {
828         //
829         // Increment sequence number to indicate dropped message
830         //
831 drop_message:
832         PWDF_IFR_HEADER  header;
833         header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader;
834         InterlockedIncrement(header->SequenceNumberPointer);
835         return STATUS_UNSUCCESSFUL;
836     }
837 }
838 
839