3 Copyright (c) 2006 - 2010, Intel Corporation
4 All rights reserved. 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
);
287 // If we load our own PE COFF images the Windows debugger can not source
288 // level debug our code. If a valid PDB pointer exists usw it to load
289 // the *.dll file as a library using Windows* APIs. This allows
290 // source level debug. The image is still loaded and reloaced
291 // in the Framework memory space like on a real system (by the code above),
292 // but the entry point points into the DLL loaded by the code bellow.
295 DllEntryPoint
= NULL
;
298 // Load the DLL if it's not an EBC image.
300 if ((ImageContext
->PdbPointer
!= NULL
) &&
301 (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
)) {
303 // Convert filename from ASCII to Unicode
305 DllFileName
= AsciiToUnicode (ImageContext
->PdbPointer
, &Index
);
308 // Check that we have a valid filename
310 if (Index
< 5 || DllFileName
[Index
- 4] != '.') {
311 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, DllFileName
);
314 // Never return an error if PeCoffLoaderRelocateImage() succeeded.
315 // The image will run, but we just can't source level debug. If we
316 // return an error the image will not run.
321 // Replace .PDB with .DLL on the filename
323 DllFileName
[Index
- 3] = 'D';
324 DllFileName
[Index
- 2] = 'L';
325 DllFileName
[Index
- 1] = 'L';
328 // Load the .DLL file into the user process's address space for source
331 Library
= mWinNt
->LoadLibraryEx (DllFileName
, NULL
, DONT_RESOLVE_DLL_REFERENCES
);
332 if (Library
!= NULL
) {
334 // InitializeDriver is the entry point we put in all our EFI DLL's. The
335 // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the
336 // normal DLL entry point of DllMain, and prevents other modules that are
337 // referenced in side the DllFileName from being loaded. There is no error
338 // checking as the we can point to the PE32 image loaded by Tiano. This
339 // step is only needed for source level debuging
341 DllEntryPoint
= (VOID
*) (UINTN
) mWinNt
->GetProcAddress (Library
, "InitializeDriver");
345 if ((Library
!= NULL
) && (DllEntryPoint
!= NULL
)) {
346 Status
= AddModHandle (ImageContext
, Library
);
347 if (Status
== EFI_ALREADY_STARTED
) {
349 // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
351 ImageContext
->PdbPointer
= NULL
;
352 DEBUG ((EFI_D_ERROR
, "WARNING: DLL already loaded. No source level debug %s. \n", DllFileName
));
355 // This DLL is not already loaded, so source level debugging is suported.
357 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) DllEntryPoint
;
358 DEBUG ((EFI_D_INFO
, "LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName
));
362 // This DLL does not support source level debugging at all.
364 DEBUG ((EFI_D_ERROR
, "WARNING: No source level debug %s. \n", DllFileName
));
367 mWinNt
->HeapFree (mWinNt
->GetProcessHeap (), 0, DllFileName
);
371 // Never return an error if PeCoffLoaderRelocateImage() succeeded.
372 // The image will run, but we just can't source level debug. If we
373 // return an error the image will not run.
379 Performs additional actions just before a PE/COFF image is unloaded. Any resources
380 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
382 For NT32, this function unloads symbols for source level debugging.
384 If ImageContext is NULL, then ASSERT().
386 @param ImageContext Pointer to the image context structure that describes the
387 PE/COFF image that is being unloaded.
392 PeCoffLoaderUnloadImageExtraAction (
393 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
398 ASSERT (ImageContext
!= NULL
);
400 ModHandle
= RemoveModeHandle (ImageContext
);
401 if (ModHandle
!= NULL
) {
402 mWinNt
->FreeLibrary (ModHandle
);