barcode source code 15-2: DeadlockDetection Reporting Options 540 in Visual C#

Encode Code39 in Visual C# 15-2: DeadlockDetection Reporting Options 540

Table 15-2: DeadlockDetection Reporting Options 540
Printing Code39 In Visual C#
Using Barcode generator for Visual Studio .NET Control to generate, create Code-39 image in .NET applications.
Decoding Code 3/9 In C#
Using Barcode recognizer for Visual Studio .NET Control to read, scan read, scan image in VS .NET applications.
Painting Bar Code In Visual C#.NET
Using Barcode generation for Visual Studio .NET Control to generate, create bar code image in .NET framework applications.
Barcode Scanner In Visual C#.NET
Using Barcode decoder for Visual Studio .NET Control to read, scan read, scan image in .NET applications.
Limits Logging to Wait-related functions Thread-related functions Critical-section functions Mutex functions Semaphore functions Event functions All hooked functions
Make Code 3 Of 9 In .NET
Using Barcode generator for ASP.NET Control to generate, create Code39 image in ASP.NET applications.
Generating Code39 In .NET Framework
Using Barcode printer for VS .NET Control to generate, create ANSI/AIM Code 39 image in Visual Studio .NET applications.
Along with the DeadlockDetection source code that comes with this book's sample files, I've included a DeadDetExt DLL that I wrote, TEXTFILEDDEXT.DLL. This relatively simple extension writes all the information to a text file. When you run DeadlockDetection with TEXTFILEDDEXT.DLL, the extension creates a text file in the same directory as the executable program. The text file will use the name of the executable with a .DD extension. For example, if you run DDSIMPTEST.EXE, the resulting file will be DDSIMPTEST.DD. Listing 15-1 shows some sample output from TEXTFILEDDEXT.DLL.
Code-39 Generation In VB.NET
Using Barcode drawer for .NET Control to generate, create Code 3 of 9 image in Visual Studio .NET applications.
GTIN - 13 Generation In C#.NET
Using Barcode drawer for .NET framework Control to generate, create EAN13 image in .NET framework applications.
Listing 15-1: DeadlockDetection output using TESTFILEDDEXT.DLL TID 0x00000DF8 0x00404150 Ret Addr [0x004011B2] C/R Ret Value (R) Function & Params InitializeCriticalSection
Draw UPC Symbol In Visual C#.NET
Using Barcode printer for VS .NET Control to generate, create UPC-A Supplement 5 image in .NET framework applications.
Making 2D Barcode In Visual C#.NET
Using Barcode encoder for Visual Studio .NET Control to generate, create Matrix Barcode image in .NET applications.
Data Matrix ECC200 Printer In Visual C#.NET
Using Barcode creation for Visual Studio .NET Control to generate, create Data Matrix 2d barcode image in .NET framework applications.
Generating USS Code 93, USS 93 In Visual C#.NET
Using Barcode printer for .NET Control to generate, create Code 9/3 image in .NET framework applications.
0x00000DF8 [0x004011CC] (R) 0x000007C0 CreateEventA 0x00000000, 1, 0, 0x004040F0 Event Name] 0x00000DF8 [0x004011EF] 0x00000000, 0x00000000, 0x00000000, 0x0012FF5C 0x00000DF8 [0x00401212] 0x00000000, 0x00000000, 0x00000000, 0x0012FF5C 0x00000DF8 [0x00401229] (C) 0x00404150 0x000000A8 [0x00401030] (C) 0x00404150 EnterCriticalSection EnterCriticalSection (R) 0x000007B8 CreateThread 0x00000000, (R) 0x000007BC CreateThread 0x00000000, [The
Create Bar Code In Objective-C
Using Barcode creation for iPhone Control to generate, create bar code image in iPhone applications.
EAN / UCC - 13 Drawer In Java
Using Barcode maker for Java Control to generate, create GS1 - 13 image in Java applications.
Scanning GTIN - 13 In None
Using Barcode recognizer for Software Control to read, scan read, scan image in Software applications.
Code128 Generator In VS .NET
Using Barcode maker for ASP.NET Control to generate, create Code 128 image in ASP.NET applications.
Print QR-Code In None
Using Barcode maker for Font Control to generate, create QR Code JIS X 0510 image in Font applications.
Encoding Data Matrix In VS .NET
Using Barcode creation for .NET framework Control to generate, create ECC200 image in .NET framework applications.
0x00000F04 [0x004010F3] (R) 0x000007B0 OpenEventA 0x001F0003, 0, 0x004040BC 541
Painting UPC - 13 In None
Using Barcode generator for Office Word Control to generate, create GS1 - 13 image in Word applications.
Encode Code128 In None
Using Barcode creator for Excel Control to generate, create Code 128C image in Microsoft Excel applications.
[The Event Name] 0x00000DF8 0x00404150 [0x00401229] (R) (C) 0x00000000 EnterCriticalSection WaitForSingleObject INFINITE 0x00000F04 [0x00401121] (C) 0x00404150 EnterCriticalSection
0x00000DF8 [0x0040123E] 0x000007C0,
Notice that the function and parameter information is wrapped in Listing 15-1 so that it displays on the page. The output shows the information in the following order: 1. The ID of the executing thread. 2. The return address to indicate which of your functions called the synchronization function. Using the CrashFinder utility from 12, you can look up the return addresses and discover how you got into the deadlock situations. 3. The call or return indicator to help identify actions that occur before and after specific functions. 4. The return value of the function if your program is reporting function returns. 5. The synchronization function name. 6. The parameter list for the synchronization function. Items in brackets are the humanreadable data. I concentrated on showing string values, but it would be trivial to add more data, such as individual flags. When you run your application and it deadlocks, kill the process and view the output file to see the last synchronization item called. TEXTFILEDDEXT.DLL keeps the file up to date by flushing the file buffers each time you call a WaitFor* function, EnterCriticalSection, or TryEnterCriticalSection. A word of caution: if you turn on full logging of all functions, you can generate some extremely large files in no time. Using the MTGDI Visual C++ sample application, I generated an 11-MB text file in a minute or two by creating a couple of threads. Implementing DeadlockDetection As you can see, using DeadlockDetection is fairly simple. Beneath the simplicity of use, however, is a fairly sophisticated implementation. The first part of DeadlockDetection's implementation I'll go over is how to hook functions. Hooking Imported Functions There are many ways to hook the function calls a program makes. The hard way is to hunt down all the CALL instructions and replace the address with one of your own. This approach is difficult and extremely error prone. Fortunately, with DeadlockDetection, the functions I need to hook are imported functions and are much easier to handle than CALL instructions. An imported function is a function that comes out of a DLL. For example, when your program calls OutputDebugString, it's calling a function that resides in KERNEL32.DLL. When I first started doing Win32-based programming, I thought that calling an imported function would be just like calling any other function a CALL or branch instruction would jump to an address and start executing the imported function. The only difference might be that with an imported function, the operating system program loader would have to run 542
through the executable and fix up the addresses to reflect where the DLL being called would be loaded into memory. When I looked at how a call to an imported function really is implemented, I was amazed at the simplicity and beauty of the design. The problem with the way I was thinking becomes apparent when you consider how many API functions there are and that you can easily call the same ones many times throughout your program. If the loader had to find and replace each occurrence of a call to OutputDebugString, for example, loading a program could take forever. Even if the linker generated a complete table that specified where each call to OutputDebugString took place in the code, the huge amount of looping and memory writing would make load times excruciatingly slow. So how does the loader tell your application where to find an imported function The solution is fiendishly clever. If you think about where the calls to OutputDebugString go, you'll soon realize that each call must go to the same address: the address where OutputDebugString is loaded into memory. Of course, your application can't know this address ahead of time, so instead, all your OutputDebugString calls get routed through a single, indirect address. When the program loader loads your executable and its dependent DLLs, the loader fixes up this one indirect address so that it corresponds to the final load address of OutputDebugString. The compiler makes this indirect addressing work by generating a jump to the indirect address any time your code calls the imported function. This indirect address is stored in the .idata (or import) section of the executable. If you import through __declspec(dllimport), instead of being an indirect jump, the code is an indirect call, thus saving a couple of instructions per function call. Hooking an imported function is a matter of finding the imports section of the executable, looking for the address of the particular function you want to hook, and then writing the hook function address in its place. Although hunting down and replacing function addresses might sound like a lot of work, it's not that bad because the Win32 Portable Executable (PE) file format is so nicely organized. In 10 of his excellent book Windows 95 System Programming Secrets (IDG Books, 1995), Matt Pietrek describes a method for hooking imported functions. Matt's code simply finds a module's imports section and, using the value returned from a call to GetProcAddress, loops through the imported functions. When Matt's code finds the function it's looking for, it overwrites the original imported function address with the hook function. Not surprisingly, given that 1995 is a past lifetime in software development circles, two small issues have changed since Matt's book came out. The first is that when Matt wrote his book, most developers didn't merge their imports section with other PE sections. Therefore, if the imports section is in read-only memory, you cause an access violation by writing the hook address. I fixed the read-only memory issue by setting the virtual memory protection to read-write before the hook function address is written to memory. The second issue, which is a little tougher to work around, is that under certain conditions you can't hook imported functions under Microsoft Windows Me. Since so many people ask me about how to hook functions, I decided to keep the Microsoft Windows Me support for hooking code, so it's relevant for me to discuss what happens under Windows Me. When you use DeadlockDetection, you want to be able to have the threading functions redirected any time you run your application, even when the application is running under the debugger. Although you wouldn't think that hooking functions while running under a debugger would be a problem, it is. In Windows XP, or when running a program in Windows Me outside a debugger, when you call GetProcAddress to find a function and then look through the imports section for that address, you'll always find it. But under Windows Me, 543
calling GetProcAddress in your program while it's running under a debugger returns a different address than when it runs outside a debugger. What GetProcAddress actually returns when running under the debugger is a debug thunk a special wrapper around the real call. The reason for the debug thunk is that Windows Me doesn't implement copy-on-write in the operating system for addresses above 2 GB. Copy-on-write means that when a page of shared memory is written to, the operating system makes a copy of that page and gives it to the process where the write is taking place. For the most part, Windows Me and Windows XP follow the same rules and everything is fine. However, for shared memory above 2 GB, where all the operating system DLLs load on Windows Me, Windows Me doesn't do the copy-on-write for those addresses. That means that when you change the memory inside an operating system DLL to set a breakpoint or to patch a function, it's patched for all processes in the system and will cause a complete system crash if another process executes at that changed location. Therefore, Windows Me goes to quite a bit of trouble to keep you from accidentally messing up that memory. The debug thunk returned by GetProcAddress when running under a debugger is a means by which Windows Me keeps debuggers from attempting to step into system functions above the 2-GB line. Overall, the lack of copy-on-write isn't much of an issue for most developers only those who write debuggers or who want to hook functions correctly whether or not they're running under a debugger. Fortunately, getting the real address for an imported function isn't too difficult it just takes a little more work, and you have to avoid GetProcAddress. The PE file IMAGE_IMPORT_DESCRIPTOR structure, which holds all the information about functions imported from a specific DLL, has pointers to two arrays in the executable. These arrays are called import address tables (IATs), or sometimes thunk data arrays. The first pointer references the real IAT, which the program loader fixes up when the executable is loaded. The second pointer references the original IAT, which is untouched by the loader and lists the imported functions. To find the real imported function address, simply work your way through the original IAT until you find the named function that you want to hook, and then write the hook address in the corresponding entry in the real IAT, which the program is using. By taking this extra step, the hooking code will always work no matter where it's called. HookImportedFunctionsByName is the function I wrote to take care of your hooking needs. Table 15-3 shows the parameters to HookImportedFunctionsByName and describes each one. Because I wanted to make the hooking as generic as possible, I went to the trouble of allowing you to hook multiple functions imported from the same DLL at the same time. As its name implies, the HookImportedFunctionsByName function will hook only those functions imported by name. Though I won't be discussing it in this book, I did include another function, HookOrdinalExport, that allows you to hook functions exported by ordinal.
Table 15-3: HookImportedFunctionsByName Parameter Descriptions Parameter hModule szImportMod UiCount Description The module in which the imports will be hooked. The name of the module whose functions are imported. The number of functions to hook. This parameter is the size of the paHookArray and paOrigFuncs arrays. 544
Table 15-3: HookImportedFunctionsByName Parameter Descriptions Parameter paHookArray Description The array of function descriptor structures that indicates which functions to hook. The array doesn't have to be in szFunc name order (though it's wise to keep the array sorted in function name order, because I might implement better searching in the future). Also, if a particular pProc is NULL, HookImportedFunctionsByName skips that item. The structure for each element in paHookArray is simply the name of the function to hook and a pointer to the new hook procedure. Because you might want to hook or unhook functions at will, HookImportedFunctionsByName returns all the original imported function addresses. The array of original addresses hooked by HookImportedFunctionsByName. If a function wasn't hooked, that item index will be NULL. Returns the number of functions hooked out of paHookArray.
Copyright © . All rights reserved.