1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 #include "udffs.h"
7 #if defined(UDF_DBG) || defined(PRINT_ALWAYS)
8 
9 //#define TRACK_RESOURCES
10 //#define TRACK_REF_COUNTERS
11 
12 ULONG ResCounter = 0;
13 ULONG AcqCounter = 0;
14 ULONG UdfTimeStamp = -1;
15 
16 BOOLEAN
17 UDFDebugAcquireResourceSharedLite(
18       IN PERESOURCE Resource,
19       IN BOOLEAN    Wait,
20       ULONG         BugCheckId,
21       ULONG         Line
22 ) {
23     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
24 #ifdef TRACK_RESOURCES
25     UDFPrint(("Res:Sha:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
26         BugCheckId,Line,PsGetCurrentThread()));
27 #endif
28 
29     BOOLEAN     Success;
30 
31 #ifdef USE_DLD
32 
33     if (Wait) {
34         DLDAcquireShared(Resource, BugCheckId, Line,FALSE);
35         Success = TRUE;
36     } else {
37         Success = ExAcquireResourceSharedLite(Resource,Wait);
38     }
39 
40 #else
41 
42     Success = ExAcquireResourceSharedLite(Resource,Wait);
43 
44 #endif // USE_DLD
45 
46     if(Success) {
47 #ifdef TRACK_RESOURCES
48         UDFPrint(("Res:Sha:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
49             BugCheckId,Line,PsGetCurrentThread()));
50 #endif
51         AcqCounter++;
52         return Success;
53     }
54 #ifdef TRACK_RESOURCES
55     UDFPrint(("Res:Sha:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
56         BugCheckId,Line,PsGetCurrentThread()));
57 #endif
58     return FALSE;
59 }
60 
61 BOOLEAN
62 UDFDebugAcquireSharedStarveExclusive(
63       IN PERESOURCE Resource,
64       IN BOOLEAN    Wait,
65       ULONG         BugCheckId,
66       ULONG         Line
67 ) {
68     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
69 #ifdef TRACK_RESOURCES
70     UDFPrint(("Res:Sha*:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
71         BugCheckId,Line,PsGetCurrentThread()));
72 #endif
73 
74     BOOLEAN     Success;
75 
76 #ifdef USE_DLD
77 
78     if (Wait) {
79         DLDAcquireShared(Resource, BugCheckId, Line,FALSE);
80         Success = TRUE;
81     } else {
82         Success = ExAcquireResourceSharedLite(Resource,Wait);
83     }
84 
85 #else
86 
87     Success = ExAcquireResourceSharedLite(Resource,Wait);
88 
89 #endif // USE_DLD
90 
91     if(Success) {
92 #ifdef TRACK_RESOURCES
93         UDFPrint(("Res:Sha*:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
94             BugCheckId,Line,PsGetCurrentThread()));
95 #endif
96         AcqCounter++;
97         return Success;
98     }
99 #ifdef TRACK_RESOURCES
100     UDFPrint(("Res:Sha*:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
101         BugCheckId,Line,PsGetCurrentThread()));
102 #endif
103     return FALSE;
104 }
105 
106 BOOLEAN
107 UDFDebugAcquireResourceExclusiveLite(
108       IN PERESOURCE Resource,
109       IN BOOLEAN    Wait,
110       ULONG         BugCheckId,
111       ULONG         Line
112 ) {
113     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
114 #ifdef TRACK_RESOURCES
115     UDFPrint(("Res:Exc:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
116         BugCheckId,Line,PsGetCurrentThread()));
117 #endif
118 
119 
120     BOOLEAN     Success;
121 
122 #ifdef USE_DLD
123 
124     if (Wait) {
125         DLDAcquireExclusive(Resource, BugCheckId, Line);
126         Success = TRUE;
127     } else {
128         Success = ExAcquireResourceExclusiveLite(Resource,Wait);
129     }
130 
131 #else
132 
133     Success = ExAcquireResourceExclusiveLite(Resource,Wait);
134 
135 #endif // USE_DLD
136 
137 
138 
139     if(Success) {
140 #ifdef TRACK_RESOURCES
141         UDFPrint(("Res:Exc:OK:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
142             BugCheckId,Line,PsGetCurrentThread()));
143 #endif
144         AcqCounter++;
145         return Success;
146     }
147 #ifdef TRACK_RESOURCES
148     UDFPrint(("Res:Exc:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
149         BugCheckId,Line,PsGetCurrentThread()));
150 #endif
151 //    BrutePoint();
152     return FALSE;
153 
154 }
155 
156 VOID
157 UDFDebugReleaseResourceForThreadLite(
158     IN PERESOURCE  Resource,
159     IN ERESOURCE_THREAD  ResourceThreadId,
160     ULONG         BugCheckId,
161     ULONG         Line
162     )
163 {
164     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
165 #ifdef TRACK_RESOURCES
166     UDFPrint(("Res:Free:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
167         BugCheckId,Line,PsGetCurrentThread()));
168 #endif
169     ExReleaseResourceForThreadLite(Resource, ResourceThreadId);
170 #ifdef TRACK_RESOURCES
171     UDFPrint(("Res:Free:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
172         BugCheckId,Line,ResourceThreadId));
173 #endif
174     AcqCounter--;
175 }
176 
177 VOID
178 UDFDebugDeleteResource(
179     IN PERESOURCE  Resource,
180     IN ERESOURCE_THREAD  ResourceThreadId,
181     ULONG         BugCheckId,
182     ULONG         Line
183     )
184 {
185     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
186 #ifdef TRACK_RESOURCES
187     UDFPrint(("Res:Del:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
188         BugCheckId,Line,ResourceThreadId));
189 #endif
190     _SEH2_TRY {
191         ASSERT((*((PULONG)Resource)));
192         ASSERT((*(((PULONG)Resource)+1)));
193         ExDeleteResourceLite(Resource);
194         RtlZeroMemory(Resource, sizeof(ERESOURCE));
195     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
196         BrutePoint();
197     } _SEH2_END;
198 #ifdef TRACK_RESOURCES
199     UDFPrint(("Res:Del:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
200         BugCheckId,Line,ResourceThreadId));
201 #endif
202     ResCounter--;
203 }
204 
205 NTSTATUS
206 UDFDebugInitializeResourceLite(
207     IN PERESOURCE  Resource,
208     IN ERESOURCE_THREAD  ResourceThreadId,
209     ULONG         BugCheckId,
210     ULONG         Line
211     )
212 {
213     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
214     NTSTATUS RC;
215 #ifdef TRACK_RESOURCES
216     UDFPrint(("Res:Ini:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
217         BugCheckId,Line,ResourceThreadId));
218 #endif
219     ASSERT(!(*((PULONG)Resource)));
220     ASSERT(!(*(((PULONG)Resource)+1)));
221     RC = ExInitializeResourceLite(Resource);
222 #ifdef TRACK_RESOURCES
223     UDFPrint(("Res:Ini:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
224         BugCheckId,Line,ResourceThreadId));
225 #endif
226     if(NT_SUCCESS(RC)) {
227         ResCounter++;
228     }
229     return RC;
230 }
231 
232 VOID
233 UDFDebugConvertExclusiveToSharedLite(
234     IN PERESOURCE  Resource,
235     IN ERESOURCE_THREAD  ResourceThreadId,
236     ULONG         BugCheckId,
237     ULONG         Line
238     )
239 {
240     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
241 #ifdef TRACK_RESOURCES
242     UDFPrint(("Res:2Sha:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
243         BugCheckId,Line,ResourceThreadId));
244 #endif
245     ExConvertExclusiveToSharedLite(Resource);
246 #ifdef TRACK_RESOURCES
247     UDFPrint(("Res:2Sha:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
248         BugCheckId,Line,ResourceThreadId));
249 #endif
250 }
251 
252 BOOLEAN
253 UDFDebugAcquireSharedWaitForExclusive(
254       IN PERESOURCE Resource,
255       IN BOOLEAN    Wait,
256       ULONG         BugCheckId,
257       ULONG         Line
258 ) {
259     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
260 #ifdef TRACK_RESOURCES
261     UDFPrint(("Res:Sha*:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
262         BugCheckId,Line,PsGetCurrentThread()));
263 #endif
264 
265     BOOLEAN     Success;
266 
267 #ifdef USE_DLD
268 
269     if (Wait) {
270         DLDAcquireShared(Resource, BugCheckId, Line,TRUE);
271         Success = TRUE;
272     } else {
273         Success = ExAcquireSharedWaitForExclusive(Resource,Wait);
274     }
275 
276 #else
277 
278     Success = ExAcquireSharedWaitForExclusive(Resource,Wait);
279 
280 #endif // USE_DLD
281 
282 
283     if(Success) {
284 #ifdef TRACK_RESOURCES
285         UDFPrint(("Res:Sha*:OK:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
286             BugCheckId,Line,PsGetCurrentThread()));
287 #endif
288         return Success;
289     }
290 #ifdef TRACK_RESOURCES
291     UDFPrint(("Res:Sha*:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
292         BugCheckId,Line,PsGetCurrentThread()));
293 #endif
294 //    BrutePoint();
295     return FALSE;
296 
297 }
298 
299 
300 LONG
301 UDFDebugInterlockedIncrement(
302     IN PLONG      addr,
303     ULONG         BugCheckId,
304     ULONG         Line)
305 {
306 #ifdef TRACK_REF_COUNTERS
307     LONG a;
308     a = InterlockedIncrement(addr);
309     UDFPrint(("ThId:%x:Ilck:Inc:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n",
310         PsGetCurrentThread(),BugCheckId,Line,addr,a-1,a));
311     return a;
312 #else
313     return InterlockedIncrement(addr);
314 #endif
315 }
316 
317 LONG
318 UDFDebugInterlockedDecrement(
319     IN PLONG      addr,
320     ULONG         BugCheckId,
321     ULONG         Line)
322 {
323 #ifdef TRACK_REF_COUNTERS
324     LONG a;
325     a = InterlockedDecrement(addr);
326     UDFPrint(("ThId:%x:Ilck:Dec:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n",
327         PsGetCurrentThread(),BugCheckId,Line,addr,a+1,a));
328     return a;
329 #else
330     return InterlockedDecrement(addr);
331 #endif
332 }
333 
334 LONG
335 UDFDebugInterlockedExchangeAdd(
336     IN PLONG      addr,
337     IN LONG       i,
338     ULONG         BugCheckId,
339     ULONG         Line)
340 {
341 #ifdef TRACK_REF_COUNTERS
342     LONG a;
343     a = InterlockedExchangeAdd(addr,i);
344     UDFPrint(("ThId:%x:Ilck:Add:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n",
345         PsGetCurrentThread(),BugCheckId,Line,addr,a,a+i));
346     return a;
347 #else
348     return InterlockedExchangeAdd(addr,i);
349 #endif
350 }
351 
352 #define MAX_MEM_DEBUG_DESCRIPTORS 8192
353 
354 typedef struct _MEM_DESC {
355     ULONG   Length;
356     PCHAR   Addr;
357 #ifdef TRACK_SYS_ALLOC_CALLERS
358     ULONG   SrcId;
359     ULONG   SrcLine;
360 #endif //TRACK_SYS_ALLOC_CALLERS
361     POOL_TYPE Type;
362 } MEM_DESC, *PMEM_DESC;
363 
364 
365 MEM_DESC    MemDesc[MAX_MEM_DEBUG_DESCRIPTORS];
366 ULONG       cur_max = 0;
367 ULONG       AllocCountPaged = 0;
368 ULONG       AllocCountNPaged = 0;
369 ULONG       MemDescInited = 0;
370 
371 PVOID
372 DebugAllocatePool(
373    POOL_TYPE Type,
374    ULONG size
375 #ifdef TRACK_SYS_ALLOC_CALLERS
376  , ULONG SrcId,
377    ULONG SrcLine
378 #endif //TRACK_SYS_ALLOC_CALLERS
379 ) {
380     ULONG i;
381 //    UDFPrint(("SysAllocated: %x\n",AllocCount));
382     if(!MemDescInited) {
383         RtlZeroMemory(&MemDesc, sizeof(MemDesc));
384         MemDescInited = 1;
385     }
386     for (i=0;i<cur_max;i++) {
387         if (MemDesc[i].Addr==NULL) {
388             MemDesc[i].Addr = (PCHAR)ExAllocatePoolWithTag(Type, (size), 'Fnwd'); // dwnF
389 
390             ASSERT(MemDesc[i].Addr);
391 
392             if(MemDesc[i].Addr) {
393                 if(Type == PagedPool) {
394                     AllocCountPaged += (size+7) & ~7;
395                 } else {
396                     AllocCountNPaged += (size+7) & ~7;
397                 }
398             }
399 
400             MemDesc[i].Length = size;
401             MemDesc[i].Type = Type;
402 #ifdef TRACK_SYS_ALLOC_CALLERS
403             MemDesc[i].SrcId   = SrcId;
404             MemDesc[i].SrcLine = SrcLine;
405 #endif //TRACK_SYS_ALLOC_CALLERS
406             return MemDesc[i].Addr;
407         }
408     }
409     if(cur_max == MAX_MEM_DEBUG_DESCRIPTORS) {
410         UDFPrint(("Debug memory descriptor list full\n"));
411         return ExAllocatePoolWithTag(Type, (size) , 'Fnwd');
412     }
413 
414     MemDesc[i].Addr = (PCHAR)ExAllocatePoolWithTag(Type, (size) , 'Fnwd');
415 
416     if(MemDesc[i].Addr) {
417         if(Type == PagedPool) {
418             AllocCountPaged += (size+7) & ~7;
419         } else {
420             AllocCountNPaged += (size+7) & ~7;
421         }
422     }
423 
424     MemDesc[i].Length = (size);
425 #ifdef TRACK_SYS_ALLOC_CALLERS
426     MemDesc[i].SrcId   = SrcId;
427     MemDesc[i].SrcLine = SrcLine;
428 #endif //TRACK_SYS_ALLOC_CALLERS
429     MemDesc[i].Type = Type;
430     cur_max++;
431     return MemDesc[cur_max-1].Addr;
432 
433 }
434 
435 VOID DebugFreePool(PVOID addr) {
436     ULONG i;
437 
438     ASSERT(addr);
439 
440     for (i=0;i<cur_max;i++) {
441         if (MemDesc[i].Addr == addr)  {
442 
443             if(MemDesc[i].Type == PagedPool) {
444                 AllocCountPaged -= (MemDesc[i].Length+7) & ~7;
445             } else {
446                 AllocCountNPaged -= (MemDesc[i].Length+7) & ~7;
447             }
448 
449             MemDesc[i].Addr = NULL;
450             MemDesc[i].Length = 0;
451 #ifdef TRACK_SYS_ALLOC_CALLERS
452             MemDesc[i].SrcId   = 0;
453             MemDesc[i].SrcLine = 0;
454 #endif //TRACK_SYS_ALLOC_CALLERS
455             goto not_bug;
456         }
457     }
458     if (i==cur_max && cur_max != MAX_MEM_DEBUG_DESCRIPTORS) {
459         UDFPrint(("Buug! - Deallocating nonallocated block\n"));
460         return;
461     }
462 not_bug:
463 //    UDFPrint(("SysAllocated: %x\n",AllocCount));
464     ExFreePool(addr);
465 }
466 
467 NTSTATUS
468 UDFWaitForSingleObject(
469     IN PLONG Object,
470     IN PLARGE_INTEGER Timeout OPTIONAL
471     )
472 {
473     UDFPrint(("UDFWaitForSingleObject\n"));
474     LARGE_INTEGER LocalTimeout;
475     LARGE_INTEGER delay;
476     delay.QuadPart = -(WAIT_FOR_XXX_EMU_DELAY);
477 
478     if(Timeout && (Timeout->QuadPart)) LocalTimeout = *Timeout;
479     else LocalTimeout.QuadPart = 0x7FFFFFFFFFFFFFFFLL;
480 
481     UDFPrint(("SignalState %x\n", *Object));
482     if(!Object) return STATUS_INVALID_PARAMETER;
483     if((*Object)) return STATUS_SUCCESS;
484     while(LocalTimeout.QuadPart>0 && !(*Object) ) {
485         UDFPrint(("SignalState %x\n", *Object));
486         // Stall for a while.
487         KeDelayExecutionThread(KernelMode, FALSE, &delay);
488         LocalTimeout.QuadPart -= WAIT_FOR_XXX_EMU_DELAY;
489     }
490     return STATUS_SUCCESS;
491 } // end UDFWaitForSingleObject()
492 
493 NTSTATUS
494 DbgWaitForSingleObject_(
495     IN PVOID Object,
496     IN PLARGE_INTEGER Timeout OPTIONAL
497     )
498 {
499     PLARGE_INTEGER to;
500     LARGE_INTEGER dto;
501 //    LARGE_INTEGER cto;
502     NTSTATUS RC;
503     ULONG c = 20;
504 
505     dto.QuadPart = -5LL*1000000LL*10LL; // 5 sec
506 //    cto.QuadPart = Timeout->QuadPart;
507     if(Timeout) {
508         if(dto.QuadPart > Timeout->QuadPart) {
509             to = Timeout;
510         } else {
511             to = &dto;
512         }
513     } else {
514         to = &dto;
515     }
516 
517     for(; c--; c) {
518         RC = KeWaitForSingleObject(Object, Executive, KernelMode, FALSE, to);
519         if(RC == STATUS_SUCCESS)
520             break;
521         UDFPrint(("No response ?\n"));
522         if(c<2)
523             BrutePoint();
524     }
525     return RC;
526 }
527 #endif // UDF_DBG
528