3 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 PeiNt32PeCoffExtraActionLib.c
18 Provides services to perform additional actions to relocate and unload
19 PE/Coff image for NT32 environment specific purpose such as souce level debug.
20 This version only works for DXE phase
25 // The package level header files this module uses
30 // The protocols, PPI and GUID defintions for this module
32 #include <Protocol/WinNtThunk.h>
34 #include <Library/PeCoffLib.h>
36 #include <Library/BaseLib.h>
37 #include <Library/DebugLib.h>
38 #include <Library/HobLib.h>
39 #include <Library/BaseMemoryLib.h>
40 #include <Library/PeCoffExtraActionLib.h>
42 #define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100
47 } PDB_NAME_TO_MOD_HANDLE
;
51 // Cache of WinNtThunk protocol
53 EFI_WIN_NT_THUNK_PROTOCOL
*mWinNt
= NULL
;
56 // An Array to hold the ModHandle
58 PDB_NAME_TO_MOD_HANDLE
*mPdbNameModHandleArray
= NULL
;
59 UINTN mPdbNameModHandleArraySize
= 0;
63 The constructor function gets the pointer of the WinNT thunk functions
64 It will ASSERT() if NT thunk protocol is not installed.
66 @retval EFI_SUCCESS WinNT thunk protocol is found and cached.
71 DxeNt32PeCoffLibExtraActionConstructor (
72 IN EFI_HANDLE ImageHandle
,
73 IN EFI_SYSTEM_TABLE
*SystemTable
76 EFI_HOB_GUID_TYPE
*GuidHob
;
79 // Retrieve WinNtThunkProtocol from GUID'ed HOB
81 GuidHob
= GetFirstGuidHob (&gEfiWinNtThunkProtocolGuid
);
82 ASSERT (GuidHob
!= NULL
);
83 mWinNt
= (EFI_WIN_NT_THUNK_PROTOCOL
*)(*(UINTN
*)(GET_GUID_HOB_DATA (GuidHob
)));
84 ASSERT (mWinNt
!= NULL
);
91 Convert the passed in Ascii string to Unicode.
93 This function Convert the passed in Ascii string to Unicode.Optionally return
94 the length of the strings..
96 @param AsciiString Pointer to an AscII string
97 @param StrLen Length of string
99 @return Pointer to malloc'ed Unicode version of Ascii
105 IN UINTN
*StrLen OPTIONAL
112 // Allocate a buffer for unicode string
114 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++)
116 Unicode
= mWinNt
->HeapAlloc ( mWinNt
->GetProcessHeap (),
118 ((Index
+ 1) * sizeof (CHAR16
))
120 if (Unicode
== NULL
) {
124 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++) {
125 Unicode
[Index
] = (CHAR16
) Ascii
[Index
];
128 Unicode
[Index
] = '\0';
130 if (StrLen
!= NULL
) {
137 Store the ModHandle in an array indexed by the Pdb File name.
138 The ModHandle is needed to unload the image.
141 @param ImageContext - Input data returned from PE Laoder Library. Used to find the
142 .PDB file name of the PE Image.
143 @param ModHandle - Returned from LoadLibraryEx() and stored for call to
146 @return return EFI_SUCCESS when ModHandle was stored.
151 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
157 PDB_NAME_TO_MOD_HANDLE
*Array
;
159 PDB_NAME_TO_MOD_HANDLE
*TempArray
;
163 // Return EFI_ALREADY_STARTED if this DLL has already been loaded
165 Array
= mPdbNameModHandleArray
;
166 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
167 if (Array
->PdbPointer
!= NULL
&& Array
->ModHandle
== ModHandle
) {
168 return EFI_ALREADY_STARTED
;
172 Array
= mPdbNameModHandleArray
;
173 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
174 if (Array
->PdbPointer
== NULL
) {
176 // Make a copy of the stirng and store the ModHandle
178 Handle
= mWinNt
->GetProcessHeap ();
179 Array
->PdbPointer
= mWinNt
->HeapAlloc ( Handle
,
181 AsciiStrLen (ImageContext
->PdbPointer
) + 1
184 ASSERT (Array
->PdbPointer
!= NULL
);
186 AsciiStrCpy (Array
->PdbPointer
, ImageContext
->PdbPointer
);
187 Array
->ModHandle
= ModHandle
;
193 // No free space in mPdbNameModHandleArray so grow it by
194 // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.
196 PreviousSize
= mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
);
197 mPdbNameModHandleArraySize
+= MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE
;
199 // re-allocate a new buffer and copy the old values to the new locaiton.
201 TempArray
= mWinNt
->HeapAlloc ( mWinNt
->GetProcessHeap (),
203 mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
)
206 CopyMem ((VOID
*) (UINTN
) TempArray
, (VOID
*) (UINTN
)mPdbNameModHandleArray
, PreviousSize
);
208 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, mPdbNameModHandleArray
);
210 mPdbNameModHandleArray
= TempArray
;
211 if (mPdbNameModHandleArray
== NULL
) {
213 return EFI_OUT_OF_RESOURCES
;
217 return AddModHandle (ImageContext
, ModHandle
);
220 Return the ModHandle and delete the entry in the array.
223 @param ImageContext - Input data returned from PE Laoder Library. Used to find the
224 .PDB file name of the PE Image.
227 ModHandle - ModHandle assoicated with ImageContext is returned
228 NULL - No ModHandle associated with ImageContext
233 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
237 PDB_NAME_TO_MOD_HANDLE
*Array
;
239 if (ImageContext
->PdbPointer
== NULL
) {
241 // If no PDB pointer there is no ModHandle so return NULL
246 Array
= mPdbNameModHandleArray
;
247 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
248 if ((Array
->PdbPointer
!= NULL
) && (AsciiStrCmp(Array
->PdbPointer
, ImageContext
->PdbPointer
) == 0)) {
250 // If you find a match return it and delete the entry
252 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, Array
->PdbPointer
);
253 Array
->PdbPointer
= NULL
;
254 return Array
->ModHandle
;
262 Performs additional actions after a PE/COFF image has been loaded and relocated.
264 For NT32, this function load symbols to support source level debugging.
266 If ImageContext is NULL, then ASSERT().
268 @param ImageContext Pointer to the image context structure that describes the
269 PE/COFF image that has already been loaded and relocated.
274 PeCoffLoaderRelocateImageExtraAction (
275 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
284 ASSERT (ImageContext
!= NULL
);
286 if (mWinNt
== NULL
) {
291 // If we load our own PE COFF images the Windows debugger can not source
292 // level debug our code. If a valid PDB pointer exists usw it to load
293 // the *.dll file as a library using Windows* APIs. This allows
294 // source level debug. The image is still loaded and reloaced
295 // in the Framework memory space like on a real system (by the code above),
296 // but the entry point points into the DLL loaded by the code bellow.
299 DllEntryPoint
= NULL
;
302 // Load the DLL if it's not an EBC image.
304 if ((ImageContext
->PdbPointer
!= NULL
) &&
305 (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
)) {
307 // Convert filename from ASCII to Unicode
309 DllFileName
= AsciiToUnicode (ImageContext
->PdbPointer
, &Index
);
312 // Check that we have a valid filename
314 if (Index
< 5 || DllFileName
[Index
- 4] != '.') {
315 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, DllFileName
);
318 // Never return an error if PeCoffLoaderRelocateImage() succeeded.
319 // The image will run, but we just can't source level debug. If we
320 // return an error the image will not run.
325 // Replace .PDB with .DLL on the filename
327 DllFileName
[Index
- 3] = 'D';
328 DllFileName
[Index
- 2] = 'L';
329 DllFileName
[Index
- 1] = 'L';
332 // Load the .DLL file into the user process's address space for source
335 Library
= mWinNt
->LoadLibraryEx (DllFileName
, NULL
, DONT_RESOLVE_DLL_REFERENCES
);
336 if (Library
!= NULL
) {
338 // InitializeDriver is the entry point we put in all our EFI DLL's. The
339 // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the
340 // normal DLL entry point of DllMain, and prevents other modules that are
341 // referenced in side the DllFileName from being loaded. There is no error
342 // checking as the we can point to the PE32 image loaded by Tiano. This
343 // step is only needed for source level debuging
345 DllEntryPoint
= (VOID
*) (UINTN
) mWinNt
->GetProcAddress (Library
, "InitializeDriver");
349 if ((Library
!= NULL
) && (DllEntryPoint
!= NULL
)) {
350 Status
= AddModHandle (ImageContext
, Library
);
351 if (Status
== EFI_ALREADY_STARTED
) {
353 // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
355 ImageContext
->PdbPointer
= NULL
;
356 DEBUG ((EFI_D_ERROR
, "WARNING: DLL already loaded. No source level debug %s. \n", DllFileName
));
359 // This DLL is not already loaded, so source level debugging is suported.
361 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) DllEntryPoint
;
362 DEBUG ((EFI_D_INFO
, "LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName
));
366 // This DLL does not support source level debugging at all.
368 DEBUG ((EFI_D_ERROR
, "WARNING: No source level debug %s. \n", DllFileName
));
371 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, DllFileName
);
375 // Never return an error if PeCoffLoaderRelocateImage() succeeded.
376 // The image will run, but we just can't source level debug. If we
377 // return an error the image will not run.
383 Performs additional actions just before a PE/COFF image is unloaded. Any resources
384 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
386 For NT32, this function unloads symbols for source level debugging.
388 If ImageContext is NULL, then ASSERT().
390 @param ImageContext Pointer to the image context structure that describes the
391 PE/COFF image that is being unloaded.
396 PeCoffLoaderUnloadImageExtraAction (
397 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
402 ASSERT (ImageContext
!= NULL
);
403 if (mWinNt
== NULL
) {
407 ModHandle
= RemoveModeHandle (ImageContext
);
408 if (ModHandle
!= NULL
) {
409 mWinNt
->FreeLibrary (ModHandle
);