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 Nt32PeCoffGetWinNtThunkStucture (
75 EFI_HOB_GUID_TYPE
*GuidHob
;
78 // Retrieve WinNtThunkProtocol from GUID'ed HOB
80 GuidHob
= GetFirstGuidHob (&gEfiWinNtThunkProtocolGuid
);
81 ASSERT (GuidHob
!= NULL
);
82 mWinNt
= (EFI_WIN_NT_THUNK_PROTOCOL
*)(*(UINTN
*)(GET_GUID_HOB_DATA (GuidHob
)));
83 ASSERT (mWinNt
!= NULL
);
90 Convert the passed in Ascii string to Unicode.
92 This function Convert the passed in Ascii string to Unicode.Optionally return
93 the length of the strings..
95 @param AsciiString Pointer to an AscII string
96 @param StrLen Length of string
98 @return Pointer to malloc'ed Unicode version of Ascii
104 IN UINTN
*StrLen OPTIONAL
111 // Allocate a buffer for unicode string
113 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++)
115 Unicode
= mWinNt
->HeapAlloc ( mWinNt
->GetProcessHeap (),
117 ((Index
+ 1) * sizeof (CHAR16
))
119 if (Unicode
== NULL
) {
123 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++) {
124 Unicode
[Index
] = (CHAR16
) Ascii
[Index
];
127 Unicode
[Index
] = '\0';
129 if (StrLen
!= NULL
) {
136 Store the ModHandle in an array indexed by the Pdb File name.
137 The ModHandle is needed to unload the image.
140 @param ImageContext - Input data returned from PE Laoder Library. Used to find the
141 .PDB file name of the PE Image.
142 @param ModHandle - Returned from LoadLibraryEx() and stored for call to
145 @return return EFI_SUCCESS when ModHandle was stored.
150 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
156 PDB_NAME_TO_MOD_HANDLE
*Array
;
158 PDB_NAME_TO_MOD_HANDLE
*TempArray
;
162 // Return EFI_ALREADY_STARTED if this DLL has already been loaded
164 Array
= mPdbNameModHandleArray
;
165 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
166 if (Array
->PdbPointer
!= NULL
&& Array
->ModHandle
== ModHandle
) {
167 return EFI_ALREADY_STARTED
;
171 Array
= mPdbNameModHandleArray
;
172 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
173 if (Array
->PdbPointer
== NULL
) {
175 // Make a copy of the stirng and store the ModHandle
177 Handle
= mWinNt
->GetProcessHeap ();
178 Array
->PdbPointer
= mWinNt
->HeapAlloc ( Handle
,
180 AsciiStrLen (ImageContext
->PdbPointer
) + 1
183 ASSERT (Array
->PdbPointer
!= NULL
);
185 AsciiStrCpy (Array
->PdbPointer
, ImageContext
->PdbPointer
);
186 Array
->ModHandle
= ModHandle
;
192 // No free space in mPdbNameModHandleArray so grow it by
193 // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.
195 PreviousSize
= mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
);
196 mPdbNameModHandleArraySize
+= MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE
;
198 // re-allocate a new buffer and copy the old values to the new locaiton.
200 TempArray
= mWinNt
->HeapAlloc ( mWinNt
->GetProcessHeap (),
202 mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
)
205 CopyMem ((VOID
*) (UINTN
) TempArray
, (VOID
*) (UINTN
)mPdbNameModHandleArray
, PreviousSize
);
207 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, mPdbNameModHandleArray
);
209 mPdbNameModHandleArray
= TempArray
;
210 if (mPdbNameModHandleArray
== NULL
) {
212 return EFI_OUT_OF_RESOURCES
;
216 return AddModHandle (ImageContext
, ModHandle
);
219 Return the ModHandle and delete the entry in the array.
222 @param ImageContext - Input data returned from PE Laoder Library. Used to find the
223 .PDB file name of the PE Image.
226 ModHandle - ModHandle assoicated with ImageContext is returned
227 NULL - No ModHandle associated with ImageContext
232 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
236 PDB_NAME_TO_MOD_HANDLE
*Array
;
238 if (ImageContext
->PdbPointer
== NULL
) {
240 // If no PDB pointer there is no ModHandle so return NULL
245 Array
= mPdbNameModHandleArray
;
246 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
247 if ((Array
->PdbPointer
!= NULL
) && (AsciiStrCmp(Array
->PdbPointer
, ImageContext
->PdbPointer
) == 0)) {
249 // If you find a match return it and delete the entry
251 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, Array
->PdbPointer
);
252 Array
->PdbPointer
= NULL
;
253 return Array
->ModHandle
;
261 Performs additional actions after a PE/COFF image has been loaded and relocated.
263 For NT32, this function load symbols to support source level debugging.
265 If ImageContext is NULL, then ASSERT().
267 @param ImageContext Pointer to the image context structure that describes the
268 PE/COFF image that has already been loaded and relocated.
273 PeCoffLoaderRelocateImageExtraAction (
274 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
283 ASSERT (ImageContext
!= NULL
);
285 if (mWinNt
== NULL
) {
286 Nt32PeCoffGetWinNtThunkStucture ();
290 // If we load our own PE COFF images the Windows debugger can not source
291 // level debug our code. If a valid PDB pointer exists usw it to load
292 // the *.dll file as a library using Windows* APIs. This allows
293 // source level debug. The image is still loaded and relocated
294 // in the Framework memory space like on a real system (by the code above),
295 // but the entry point points into the DLL loaded by the code bellow.
298 DllEntryPoint
= NULL
;
301 // Load the DLL if it's not an EBC image.
303 if ((ImageContext
->PdbPointer
!= NULL
) &&
304 (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
)) {
306 // Convert filename from ASCII to Unicode
308 DllFileName
= AsciiToUnicode (ImageContext
->PdbPointer
, &Index
);
311 // Check that we have a valid filename
313 if (Index
< 5 || DllFileName
[Index
- 4] != '.') {
314 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, DllFileName
);
317 // Never return an error if PeCoffLoaderRelocateImage() succeeded.
318 // The image will run, but we just can't source level debug. If we
319 // return an error the image will not run.
324 // Replace .PDB with .DLL on the filename
326 DllFileName
[Index
- 3] = 'D';
327 DllFileName
[Index
- 2] = 'L';
328 DllFileName
[Index
- 1] = 'L';
331 // Load the .DLL file into the user process's address space for source
334 Library
= mWinNt
->LoadLibraryEx (DllFileName
, NULL
, DONT_RESOLVE_DLL_REFERENCES
);
335 if (Library
!= NULL
) {
337 // InitializeDriver is the entry point we put in all our EFI DLL's. The
338 // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the
339 // normal DLL entry point of DllMain, and prevents other modules that are
340 // referenced in side the DllFileName from being loaded. There is no error
341 // checking as the we can point to the PE32 image loaded by Tiano. This
342 // step is only needed for source level debugging
344 DllEntryPoint
= (VOID
*) (UINTN
) mWinNt
->GetProcAddress (Library
, "InitializeDriver");
348 if ((Library
!= NULL
) && (DllEntryPoint
!= NULL
)) {
349 Status
= AddModHandle (ImageContext
, Library
);
350 if (Status
== EFI_ALREADY_STARTED
) {
352 // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
354 ImageContext
->PdbPointer
= NULL
;
355 DEBUG ((EFI_D_ERROR
, "WARNING: DLL already loaded. No source level debug %s. \n", DllFileName
));
358 // This DLL is not already loaded, so source level debugging is supported.
360 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) DllEntryPoint
;
361 DEBUG ((EFI_D_INFO
, "LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName
));
365 // This DLL does not support source level debugging at all.
367 DEBUG ((EFI_D_ERROR
, "WARNING: No source level debug %s. \n", DllFileName
));
370 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, DllFileName
);
374 // Never return an error if PeCoffLoaderRelocateImage() succeeded.
375 // The image will run, but we just can't source level debug. If we
376 // return an error the image will not run.
382 Performs additional actions just before a PE/COFF image is unloaded. Any resources
383 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
385 For NT32, this function unloads symbols for source level debugging.
387 If ImageContext is NULL, then ASSERT().
389 @param ImageContext Pointer to the image context structure that describes the
390 PE/COFF image that is being unloaded.
395 PeCoffLoaderUnloadImageExtraAction (
396 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
401 ASSERT (ImageContext
!= NULL
);
403 ModHandle
= RemoveModeHandle (ImageContext
);
404 if (ModHandle
!= NULL
) {
405 mWinNt
->FreeLibrary (ModHandle
);