00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#include <ntos.h>
00027
#include <ntrtl.h>
00028
#include <nturtl.h>
00029
#include <zwapi.h>
00030
#include <stktrace.h>
00031
#include <heap.h>
00032
#include <heappriv.h>
00033
00034 BOOLEAN
00035
NtdllOkayToLockRoutine(
00036 IN PVOID Lock
00037 );
00038
00039
#if !defined(RtlGetCallersAddress) && defined(_X86_) && (!NTOS_KERNEL_RUNTIME)
00040
00041
VOID
00042
RtlGetCallersAddress(
00043 OUT PVOID *CallersAddress,
00044 OUT PVOID *CallersCaller
00045 )
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 {
00072 PVOID BackTrace[ 2 ];
00073 ULONG Hash;
00074
USHORT Count;
00075
00076
Count =
RtlCaptureStackBackTrace(
00077 2,
00078 2,
00079 BackTrace,
00080 &Hash
00081 );
00082
00083
if (ARGUMENT_PRESENT( CallersAddress )) {
00084
if (
Count >= 1) {
00085 *CallersAddress = BackTrace[ 0 ];
00086 }
00087
else {
00088 *CallersAddress =
NULL;
00089 }
00090 }
00091
00092
if (ARGUMENT_PRESENT( CallersCaller )) {
00093
if (
Count >= 2) {
00094 *CallersCaller = BackTrace[ 1 ];
00095 }
00096
else {
00097 *CallersCaller =
NULL;
00098 }
00099 }
00100
00101
return;
00102 }
00103
00104
#endif // !defined(RtlGetCallersAddress) && defined(_X86_) && (!NTOS_KERNEL_RUNTIME)
00105
00106
00107
00108
#if defined(_X86_) && (!NTOS_KERNEL_RUNTIME || !FPO)
00109
00110
00111
00112
00113
00114
PSTACK_TRACE_DATABASE RtlpStackTraceDataBase;
00115
00116
00117
PRTL_STACK_TRACE_ENTRY
00118 RtlpExtendStackTraceDataBase(
00119 IN
PRTL_STACK_TRACE_ENTRY InitialValue,
00120 IN ULONG Size
00121 );
00122
00123
00124
NTSTATUS
00125 RtlInitStackTraceDataBaseEx(
00126 IN PVOID CommitBase,
00127 IN ULONG CommitSize,
00128 IN ULONG ReserveSize,
00129 IN PRTL_INITIALIZE_LOCK_ROUTINE InitializeLockRoutine,
00130 IN PRTL_ACQUIRE_LOCK_ROUTINE AcquireLockRoutine,
00131 IN PRTL_RELEASE_LOCK_ROUTINE ReleaseLockRoutine,
00132 IN PRTL_OKAY_TO_LOCK_ROUTINE OkayToLockRoutine
00133 );
00134
00135
NTSTATUS
00136 RtlInitStackTraceDataBaseEx(
00137 IN PVOID CommitBase,
00138 IN ULONG CommitSize,
00139 IN ULONG ReserveSize,
00140 IN PRTL_INITIALIZE_LOCK_ROUTINE InitializeLockRoutine,
00141 IN PRTL_ACQUIRE_LOCK_ROUTINE AcquireLockRoutine,
00142 IN PRTL_RELEASE_LOCK_ROUTINE ReleaseLockRoutine,
00143 IN PRTL_OKAY_TO_LOCK_ROUTINE OkayToLockRoutine
00144 )
00145 {
00146
NTSTATUS Status;
00147
PSTACK_TRACE_DATABASE DataBase;
00148
00149 DataBase = (
PSTACK_TRACE_DATABASE)CommitBase;
00150
if (CommitSize == 0) {
00151 CommitSize =
PAGE_SIZE;
00152
Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
00153 (PVOID *)&CommitBase,
00154 0,
00155 &CommitSize,
00156 MEM_COMMIT,
00157 PAGE_READWRITE
00158 );
00159
if (!
NT_SUCCESS( Status )) {
00160 KdPrint((
"RTL: Unable to commit space to extend stack trace data base - Status = %lx\n",
00161 Status
00162 ));
00163
return Status;
00164 }
00165
00166 DataBase->
PreCommitted =
FALSE;
00167 }
00168
else
00169
if (CommitSize == ReserveSize) {
00170 RtlZeroMemory( DataBase,
sizeof( *DataBase ) );
00171 DataBase->
PreCommitted =
TRUE;
00172 }
00173
else {
00174
return STATUS_INVALID_PARAMETER;
00175 }
00176
00177 DataBase->
CommitBase = CommitBase;
00178 DataBase->
NumberOfBuckets = 37;
00179 DataBase->
NextFreeLowerMemory = (PCHAR)
00180 (&DataBase->
Buckets[ DataBase->
NumberOfBuckets ]);
00181 DataBase->
NextFreeUpperMemory = (PCHAR)CommitBase + ReserveSize;
00182
00183
if(!DataBase->
PreCommitted) {
00184 DataBase->
CurrentLowerCommitLimit = (PCHAR)CommitBase + CommitSize;
00185 DataBase->
CurrentUpperCommitLimit = (PCHAR)CommitBase + ReserveSize;
00186 }
00187
else {
00188 RtlZeroMemory( &DataBase->
Buckets[ 0 ],
00189 DataBase->
NumberOfBuckets *
sizeof( DataBase->
Buckets[ 0 ] )
00190 );
00191 }
00192
00193 DataBase->
EntryIndexArray = (
PRTL_STACK_TRACE_ENTRY *)DataBase->
NextFreeUpperMemory;
00194
00195 DataBase->
AcquireLockRoutine = AcquireLockRoutine;
00196 DataBase->
ReleaseLockRoutine = ReleaseLockRoutine;
00197 DataBase->
OkayToLockRoutine = OkayToLockRoutine;
00198
00199
Status = (InitializeLockRoutine)( &DataBase->
Lock.CriticalSection );
00200
if (!
NT_SUCCESS( Status )) {
00201 KdPrint((
"RTL: Unable to initialize stack trace data base CriticalSection, Status = %lx\n",
00202 Status
00203 ));
00204
return(
Status );
00205 }
00206
00207 RtlpStackTraceDataBase = DataBase;
00208
return( STATUS_SUCCESS );
00209 }
00210
00211
NTSTATUS
00212 RtlInitializeStackTraceDataBase(
00213 IN PVOID CommitBase,
00214 IN ULONG CommitSize,
00215 IN ULONG ReserveSize
00216 )
00217 {
00218
#ifdef NTOS_KERNEL_RUNTIME
00219
00220 BOOLEAN
00221
ExOkayToLockRoutine(
00222 IN PVOID Lock
00223 );
00224
00225
return RtlInitStackTraceDataBaseEx(
00226 CommitBase,
00227 CommitSize,
00228 ReserveSize,
00229 ExInitializeResource,
00230 (PRTL_RELEASE_LOCK_ROUTINE)ExAcquireResourceExclusive,
00231 (PRTL_RELEASE_LOCK_ROUTINE)ExReleaseResourceLite,
00232 ExOkayToLockRoutine
00233 );
00234
#else // #ifdef NTOS_KERNEL_RUNTIME
00235
00236
return RtlInitStackTraceDataBaseEx(
00237 CommitBase,
00238 CommitSize,
00239 ReserveSize,
00240 RtlInitializeCriticalSection,
00241 RtlEnterCriticalSection,
00242 RtlLeaveCriticalSection,
00243 NtdllOkayToLockRoutine
00244 );
00245
#endif // #ifdef NTOS_KERNEL_RUNTIME
00246
}
00247
00248
00249
PSTACK_TRACE_DATABASE
00250
RtlpAcquireStackTraceDataBase( VOID )
00251 {
00252
if (RtlpStackTraceDataBase !=
NULL) {
00253
if (RtlpStackTraceDataBase->
DumpInProgress ||
00254 !(RtlpStackTraceDataBase->
OkayToLockRoutine)( &RtlpStackTraceDataBase->
Lock.CriticalSection )
00255 ) {
00256
return(
NULL );
00257 }
00258
00259 (RtlpStackTraceDataBase->
AcquireLockRoutine)( &RtlpStackTraceDataBase->
Lock.CriticalSection );
00260 }
00261
00262
return( RtlpStackTraceDataBase );
00263 }
00264
00265
VOID
00266
RtlpReleaseStackTraceDataBase( VOID )
00267 {
00268 (RtlpStackTraceDataBase->
ReleaseLockRoutine)( &RtlpStackTraceDataBase->
Lock.CriticalSection );
00269
return;
00270 }
00271
00272
PRTL_STACK_TRACE_ENTRY
00273 RtlpExtendStackTraceDataBase(
00274 IN
PRTL_STACK_TRACE_ENTRY InitialValue,
00275 IN ULONG Size
00276 )
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 {
00306
NTSTATUS Status;
00307
PRTL_STACK_TRACE_ENTRY p, *pp;
00308 ULONG CommitSize;
00309
PSTACK_TRACE_DATABASE DataBase;
00310
00311 DataBase = RtlpStackTraceDataBase;
00312
00313
00314
00315
00316
00317
00318 pp = (
PRTL_STACK_TRACE_ENTRY *)DataBase->
NextFreeUpperMemory;
00319
00320
if ((! DataBase->
PreCommitted) &&
00321 ((PCHAR)(pp - 1) < (PCHAR)DataBase->
CurrentUpperCommitLimit)) {
00322
00323
00324
00325
00326
00327
00328 DataBase->
CurrentUpperCommitLimit =
00329 (PVOID)((PCHAR)DataBase->
CurrentUpperCommitLimit -
PAGE_SIZE);
00330
00331
if (DataBase->
CurrentUpperCommitLimit < DataBase->
CurrentLowerCommitLimit) {
00332
00333
00334
00335
00336
00337
00338 DataBase->
CurrentUpperCommitLimit =
00339 (PVOID)((PCHAR)DataBase->
CurrentUpperCommitLimit +
PAGE_SIZE);
00340
00341
return(
NULL );
00342 }
00343
00344 CommitSize =
PAGE_SIZE;
00345
Status = ZwAllocateVirtualMemory(
00346 NtCurrentProcess(),
00347 (PVOID *)&DataBase->
CurrentUpperCommitLimit,
00348 0,
00349 &CommitSize,
00350 MEM_COMMIT,
00351 PAGE_READWRITE
00352 );
00353
00354
if (!
NT_SUCCESS( Status )) {
00355
00356
00357
00358
00359
00360
00361 DataBase->
CurrentUpperCommitLimit =
00362 (PVOID)((PCHAR)DataBase->
CurrentUpperCommitLimit +
PAGE_SIZE);
00363
00364 KdPrint((
"RTL: Unable to commit space to extend stack trace data base - Status = %lx\n",
00365 Status
00366 ));
00367
return(
NULL );
00368 }
00369 }
00370
00371
00372
00373
00374
00375
00376 DataBase->
NextFreeUpperMemory -=
sizeof( *pp );
00377
00378
00379
00380
00381
00382
00383 p = (
PRTL_STACK_TRACE_ENTRY)DataBase->
NextFreeLowerMemory;
00384
00385
if ((! DataBase->
PreCommitted) &&
00386 (((PCHAR)p +
Size) > (PCHAR)DataBase->
CurrentLowerCommitLimit)) {
00387
00388
00389
00390
00391
00392
if (DataBase->
CurrentLowerCommitLimit >= DataBase->
CurrentUpperCommitLimit) {
00393
00394
00395
00396
00397
00398
return(
NULL );
00399 }
00400
00401
00402
00403
00404
00405 CommitSize =
Size;
00406
Status = ZwAllocateVirtualMemory(
00407 NtCurrentProcess(),
00408 (PVOID *)&DataBase->
CurrentLowerCommitLimit,
00409 0,
00410 &CommitSize,
00411 MEM_COMMIT,
00412 PAGE_READWRITE
00413 );
00414
00415
if (!
NT_SUCCESS( Status )) {
00416 KdPrint((
"RTL: Unable to commit space to extend stack trace data base - Status = %lx\n",
00417 Status
00418 ));
00419
return(
NULL );
00420 }
00421
00422 DataBase->
CurrentLowerCommitLimit =
00423 (PCHAR)DataBase->
CurrentLowerCommitLimit + CommitSize;
00424 }
00425
00426
00427
00428
00429
00430 DataBase->
NextFreeLowerMemory +=
Size;
00431
00432
00433
00434
00435
00436
00437
if (DataBase->
PreCommitted &&
00438 DataBase->
NextFreeLowerMemory >= DataBase->
NextFreeUpperMemory) {
00439
00440 DataBase->
NextFreeUpperMemory +=
sizeof( *pp );
00441 DataBase->
NextFreeLowerMemory -=
Size;
00442
return(
NULL );
00443 }
00444
00445
00446
00447
00448
00449 RtlMoveMemory( p, InitialValue, Size );
00450 p->
HashChain =
NULL;
00451 p->
TraceCount = 0;
00452 p->
Index = (
USHORT)(++DataBase->
NumberOfEntriesAdded);
00453
00454
00455
00456
00457
00458
00459 *--pp = p;
00460
00461
00462
00463
00464
00465
return( p );
00466 }
00467
00468
USHORT
00469 RtlLogStackBackTrace(
00470 VOID
00471 )
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 {
00502
PSTACK_TRACE_DATABASE DataBase;
00503
RTL_STACK_TRACE_ENTRY StackTrace;
00504
PRTL_STACK_TRACE_ENTRY p, *pp;
00505 ULONG Hash, RequestedSize, DepthSize;
00506
00507
if (RtlpStackTraceDataBase ==
NULL) {
00508
return 0;
00509 }
00510
00511 Hash = 0;
00512
00513
00514
00515
00516
00517
00518
00519
try {
00520 StackTrace.
Depth =
RtlCaptureStackBackTrace(
00521 1,
00522 MAX_STACK_DEPTH,
00523 StackTrace.
BackTrace,
00524 &Hash
00525 );
00526 }
00527 except(EXCEPTION_EXECUTE_HANDLER) {
00528 StackTrace.
Depth = 0;
00529 }
00530
00531
if (StackTrace.
Depth == 0) {
00532
return 0;
00533 }
00534
00535
00536
00537
00538
00539 DataBase =
RtlpAcquireStackTraceDataBase();
00540
00541
if (DataBase ==
NULL) {
00542
return( 0 );
00543 }
00544
00545 DataBase->
NumberOfEntriesLookedUp++;
00546
00547
try {
00548
00549
00550
00551
00552
00553
00554 DepthSize = StackTrace.
Depth *
sizeof( StackTrace.
BackTrace[ 0 ] );
00555 pp = &DataBase->
Buckets[ Hash % DataBase->
NumberOfBuckets ];
00556
00557
while (p = *pp) {
00558
if (p->
Depth == StackTrace.
Depth &&
00559 RtlCompareMemory( &p->
BackTrace[ 0 ],
00560 &StackTrace.
BackTrace[ 0 ],
00561 DepthSize
00562 ) == DepthSize
00563 ) {
00564
break;
00565 }
00566
else {
00567 pp = &p->
HashChain;
00568 }
00569 }
00570
00571
if (p ==
NULL) {
00572
00573
00574
00575
00576
00577
00578 RequestedSize = FIELD_OFFSET(
RTL_STACK_TRACE_ENTRY, BackTrace ) +
00579 DepthSize;
00580
00581 p = RtlpExtendStackTraceDataBase( &StackTrace, RequestedSize );
00582
00583
00584
00585
00586
00587
00588
if (p !=
NULL) {
00589 *pp = p;
00590 }
00591 }
00592 }
00593 except(EXCEPTION_EXECUTE_HANDLER) {
00594
00595
00596
00597
00598
00599 p =
NULL;
00600 }
00601
00602
00603
00604
00605
00606
RtlpReleaseStackTraceDataBase();
00607
00608
if (p !=
NULL) {
00609 p->
TraceCount++;
00610
return( p->
Index );
00611 }
00612
else {
00613
return( 0 );
00614 }
00615
00616
return 0;
00617 }
00618
#endif // defined(_X86_) && !NTOS_KERNEL_RUNTIME
00619
00620
00621
#if defined(_X86_)
00622
00623
USHORT
00624
RtlCaptureStackBackTrace(
00625 IN ULONG FramesToSkip,
00626 IN ULONG FramesToCapture,
00627 OUT PVOID *BackTrace,
00628 OUT PULONG BackTraceHash
00629 )
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 {
00659 PVOID Trace [2 * MAX_STACK_DEPTH];
00660 ULONG FramesFound;
00661 ULONG HashValue;
00662 ULONG
Index;
00663
00664
00665
00666
00667
00668 FramesToSkip++;
00669
00670
00671
00672
00673
00674
if (FramesToCapture + FramesToSkip >= 2 * MAX_STACK_DEPTH) {
00675
return 0;
00676 }
00677
00678 FramesFound =
RtlWalkFrameChain (
00679 Trace,
00680 FramesToCapture + FramesToSkip,
00681 0);
00682
00683
if (FramesFound <= FramesToSkip) {
00684
return 0;
00685 }
00686
00687
for (HashValue = 0,
Index = 0;
Index < FramesToCapture;
Index++) {
00688
00689
if (FramesToSkip +
Index >= FramesFound) {
00690
break;
00691 }
00692
00693 BackTrace[
Index] = Trace[FramesToSkip +
Index];
00694 HashValue += PtrToUlong(BackTrace[Index]);
00695 }
00696
00697 *BackTraceHash = HashValue;
00698
return (
USHORT)
Index;
00699 }
00700
#endif
00701
00702
00703
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
#ifdef NTOS_KERNEL_RUNTIME
00722
#define _KERNEL_MODE_STACK_TRACES_ 1
00723
#define _COLLECT_FRAME_WALK_STATISTICS_ 0
00724
#else
00725 #define _KERNEL_MODE_STACK_TRACES_ 0
00726 #define _COLLECT_FRAME_WALK_STATISTICS_ 0
00727
#endif
00728
00729 #define SIZE_1_KB ((ULONG_PTR) 0x400)
00730 #define SIZE_1_GB ((ULONG_PTR) 0x40000000)
00731
00732 #define PAGE_START(address) (((ULONG_PTR)address) & ~((ULONG_PTR)PAGE_SIZE - 1))
00733
00734
VOID CollectFrameWalkStatistics (ULONG Index);
00735
00736
#if (( i386 ) && ( FPO ))
00737
#pragma optimize( "y", off ) // disable FPO for consistent stack traces
00738
#endif
00739
00740 ULONG
00741 RtlWalkFrameChain (
00742
00743 OUT PVOID *Callers,
00744 IN ULONG Count,
00745 IN ULONG Flags)
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780 {
00781
#if defined(_X86_)
00782
00783 ULONG_PTR Fp, NewFp, ReturnAddress;
00784 ULONG
Index;
00785 ULONG_PTR StackEnd, StackStart;
00786 BOOLEAN Result;
00787
00788
00789
00790
00791
00792
00793 _asm mov Fp, EBP;
00794
00795 StackStart = Fp;
00796
00797
#if _KERNEL_MODE_STACK_TRACES_
00798
00799 StackEnd = (ULONG_PTR)(
KeGetCurrentThread()->StackBase);
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
if ((StackStart > StackEnd)
00817 || (
PAGE_START(StackEnd) -
PAGE_START(StackStart) >
PAGE_SIZE)) {
00818
00819 StackEnd = (StackStart +
PAGE_SIZE) & ~((ULONG_PTR)
PAGE_SIZE - 1);
00820
00821
00822
00823
00824
00825
00826
00827
if (
MmIsAddressValid ((PVOID)StackEnd)) {
00828 StackEnd +=
PAGE_SIZE;
00829 }
00830 }
00831
00832
#else
00833
00834 StackEnd = (ULONG_PTR)(NtCurrentTeb()->NtTib.StackBase);
00835
00836
#endif // #if _KERNEL_MODE_STACK_TRACES_
00837
00838
try {
00839
00840
for (
Index = 0;
Index <
Count;
Index++) {
00841
00842
if (Fp +
sizeof(ULONG_PTR) >= StackEnd) {
00843
break;
00844 }
00845
00846 NewFp = *((PULONG_PTR)(Fp + 0));
00847 ReturnAddress = *((PULONG_PTR)(Fp +
sizeof(ULONG_PTR)));
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
if (! (Fp < NewFp && NewFp < StackEnd)) {
00859
break;
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
if (StackStart < ReturnAddress && ReturnAddress < StackEnd) {
00869
break;
00870 }
00871
00872
if (ReturnAddress < 64 *
SIZE_1_KB) {
00873
break;
00874 }
00875
00876
00877
00878
00879
00880 Fp = NewFp;
00881 Callers[
Index] = (PVOID)ReturnAddress;
00882 }
00883 }
00884 except (
EXCEPTION_EXECUTE_HANDLER) {
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
DbgPrint (
"Unexpected exception in RtlWalkFrameChain ...\n");
00897 DbgBreakPoint ();
00898 }
00899
00900
00901
00902
00903
00904
#if _COLLECT_FRAME_WALK_STATISTICS_
00905
CollectFrameWalkStatistics (
Index);
00906
#endif // #if _COLLECT_FRAME_WALK_STATISTICS_
00907
00908
return Index;
00909
00910
#else
00911
00912
return 0;
00913
00914
#endif // #if defined(_X86_)
00915
}
00916
00917
00918
#if _COLLECT_FRAME_WALK_STATISTICS_
00919
00920 KSPIN_LOCK FrameWalkStatisticsLock;
00921 ULONG FrameWalkStatisticsCounters [32];
00922 ULONG FrameWalkCollectStatisticsCalls;
00923 BOOLEAN FrameWalkStatisticsInitialized;
00924
00925
VOID
00926
CollectFrameWalkStatistics (
00927
00928 ULONG Index)
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956 {
00957 KIRQL PreviousIrql;
00958 ULONG I;
00959 ULONG Percentage;
00960 ULONG TotalPercentage;
00961
00962
00963
00964
00965
00966
00967
00968
if (! FrameWalkStatisticsInitialized) {
00969
KeInitializeSpinLock (&FrameWalkStatisticsLock);
00970 FrameWalkStatisticsInitialized =
TRUE;
00971 }
00972
00973
KeAcquireSpinLock (
00974 &FrameWalkStatisticsLock,
00975 &PreviousIrql);
00976
00977 FrameWalkCollectStatisticsCalls++;
00978
00979
if (
Index < 32) {
00980 FrameWalkStatisticsCounters[
Index]++;
00981 }
00982
00983
if (FrameWalkCollectStatisticsCalls != 0
00984 && (FrameWalkCollectStatisticsCalls % 60000 == 0)) {
00985
00986
DbgPrint (
"FrameWalk: %u calls \n", FrameWalkCollectStatisticsCalls);
00987
00988 TotalPercentage = 0;
00989
00990
for (I = 0; I < 32; I++) {
00991
00992 Percentage = FrameWalkStatisticsCounters[I] * 100
00993 / FrameWalkCollectStatisticsCalls;
00994
00995
DbgPrint (
"FrameWalk: [%02u] %02u \n", I, Percentage);
00996
00997 TotalPercentage += Percentage;
00998 }
00999
01000
DbgPrint (
"FrameWalk: total %u \n", TotalPercentage);
01001 DbgBreakPoint ();
01002 }
01003
01004
KeReleaseSpinLock (
01005 &FrameWalkStatisticsLock,
01006 PreviousIrql);
01007 }
01008
01009
#endif // #if _COLLECT_FRAME_WALK_STATISTICS_
01010
01011