]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/Library/DxeNt32PeCoffExtraActionLib/DxeNt32PeCoffExtraActionLib.c
Remove over-specified dependencies on IntelFrameworkPkg and IntelFrameworkModulePkg.
[mirror_edk2.git] / Nt32Pkg / Library / DxeNt32PeCoffExtraActionLib / DxeNt32PeCoffExtraActionLib.c
1 /**@file
2
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
8
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.
11
12 Module Name:
13
14 PeiNt32PeCoffExtraActionLib.c
15
16 Abstract:
17
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
21
22
23 **/
24 //
25 // The package level header files this module uses
26 //
27 #include <WinNtDxe.h>
28
29 //
30 // The protocols, PPI and GUID defintions for this module
31 //
32 #include <Protocol/WinNtThunk.h>
33
34 #include <Library/PeCoffLib.h>
35
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>
41
42 #define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100
43
44 typedef struct {
45 CHAR8 *PdbPointer;
46 VOID *ModHandle;
47 } PDB_NAME_TO_MOD_HANDLE;
48
49
50 //
51 // Cache of WinNtThunk protocol
52 //
53 EFI_WIN_NT_THUNK_PROTOCOL *mWinNt = NULL;
54
55 //
56 // An Array to hold the ModHandle
57 //
58 PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;
59 UINTN mPdbNameModHandleArraySize = 0;
60
61
62 /**
63 The constructor function gets the pointer of the WinNT thunk functions
64 It will ASSERT() if NT thunk protocol is not installed.
65
66 @retval EFI_SUCCESS WinNT thunk protocol is found and cached.
67
68 **/
69 EFI_STATUS
70 EFIAPI
71 DxeNt32PeCoffLibExtraActionConstructor (
72 IN EFI_HANDLE ImageHandle,
73 IN EFI_SYSTEM_TABLE *SystemTable
74 )
75 {
76 EFI_HOB_GUID_TYPE *GuidHob;
77
78 //
79 // Retrieve WinNtThunkProtocol from GUID'ed HOB
80 //
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);
85
86
87 return EFI_SUCCESS;
88 }
89
90 /**
91 Convert the passed in Ascii string to Unicode.
92
93 This function Convert the passed in Ascii string to Unicode.Optionally return
94 the length of the strings..
95
96 @param AsciiString Pointer to an AscII string
97 @param StrLen Length of string
98
99 @return Pointer to malloc'ed Unicode version of Ascii
100
101 **/
102 CHAR16 *
103 AsciiToUnicode (
104 IN CHAR8 *Ascii,
105 IN UINTN *StrLen OPTIONAL
106 )
107 {
108 UINTN Index;
109 CHAR16 *Unicode;
110
111 //
112 // Allocate a buffer for unicode string
113 //
114 for (Index = 0; Ascii[Index] != '\0'; Index++)
115 ;
116 Unicode = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),
117 HEAP_ZERO_MEMORY,
118 ((Index + 1) * sizeof (CHAR16))
119 );
120 if (Unicode == NULL) {
121 return NULL;
122 }
123
124 for (Index = 0; Ascii[Index] != '\0'; Index++) {
125 Unicode[Index] = (CHAR16) Ascii[Index];
126 }
127
128 Unicode[Index] = '\0';
129
130 if (StrLen != NULL) {
131 *StrLen = Index;
132 }
133
134 return Unicode;
135 }
136 /**
137 Store the ModHandle in an array indexed by the Pdb File name.
138 The ModHandle is needed to unload the image.
139
140
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
144 FreeLibrary().
145
146 @return return EFI_SUCCESS when ModHandle was stored.
147
148 --*/
149 EFI_STATUS
150 AddModHandle (
151 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
152 IN VOID *ModHandle
153 )
154
155 {
156 UINTN Index;
157 PDB_NAME_TO_MOD_HANDLE *Array;
158 UINTN PreviousSize;
159 PDB_NAME_TO_MOD_HANDLE *TempArray;
160 HANDLE Handle;
161
162 //
163 // Return EFI_ALREADY_STARTED if this DLL has already been loaded
164 //
165 Array = mPdbNameModHandleArray;
166 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
167 if (Array->PdbPointer != NULL && Array->ModHandle == ModHandle) {
168 return EFI_ALREADY_STARTED;
169 }
170 }
171
172 Array = mPdbNameModHandleArray;
173 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
174 if (Array->PdbPointer == NULL) {
175 //
176 // Make a copy of the stirng and store the ModHandle
177 //
178 Handle = mWinNt->GetProcessHeap ();
179 Array->PdbPointer = mWinNt->HeapAlloc ( Handle,
180 HEAP_ZERO_MEMORY,
181 AsciiStrLen (ImageContext->PdbPointer) + 1
182 );
183
184 ASSERT (Array->PdbPointer != NULL);
185
186 AsciiStrCpy (Array->PdbPointer, ImageContext->PdbPointer);
187 Array->ModHandle = ModHandle;
188 return EFI_SUCCESS;
189 }
190 }
191
192 //
193 // No free space in mPdbNameModHandleArray so grow it by
194 // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.
195 //
196 PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);
197 mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;
198 //
199 // re-allocate a new buffer and copy the old values to the new locaiton.
200 //
201 TempArray = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),
202 HEAP_ZERO_MEMORY,
203 mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)
204 );
205
206 CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize);
207
208 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, mPdbNameModHandleArray);
209
210 mPdbNameModHandleArray = TempArray;
211 if (mPdbNameModHandleArray == NULL) {
212 ASSERT (FALSE);
213 return EFI_OUT_OF_RESOURCES;
214 }
215
216
217 return AddModHandle (ImageContext, ModHandle);
218 }
219 /**
220 Return the ModHandle and delete the entry in the array.
221
222
223 @param ImageContext - Input data returned from PE Laoder Library. Used to find the
224 .PDB file name of the PE Image.
225
226 @return
227 ModHandle - ModHandle assoicated with ImageContext is returned
228 NULL - No ModHandle associated with ImageContext
229
230 **/
231 VOID *
232 RemoveModeHandle (
233 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
234 )
235 {
236 UINTN Index;
237 PDB_NAME_TO_MOD_HANDLE *Array;
238
239 if (ImageContext->PdbPointer == NULL) {
240 //
241 // If no PDB pointer there is no ModHandle so return NULL
242 //
243 return NULL;
244 }
245
246 Array = mPdbNameModHandleArray;
247 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
248 if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {
249 //
250 // If you find a match return it and delete the entry
251 //
252 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, Array->PdbPointer);
253 Array->PdbPointer = NULL;
254 return Array->ModHandle;
255 }
256 }
257
258 return NULL;
259 }
260
261 /**
262 Performs additional actions after a PE/COFF image has been loaded and relocated.
263
264 For NT32, this function load symbols to support source level debugging.
265
266 If ImageContext is NULL, then ASSERT().
267
268 @param ImageContext Pointer to the image context structure that describes the
269 PE/COFF image that has already been loaded and relocated.
270
271 **/
272 VOID
273 EFIAPI
274 PeCoffLoaderRelocateImageExtraAction (
275 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
276 )
277 {
278 EFI_STATUS Status;
279 VOID *DllEntryPoint;
280 CHAR16 *DllFileName;
281 HMODULE Library;
282 UINTN Index;
283
284 ASSERT (ImageContext != NULL);
285
286 //
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.
293 //
294
295 DllEntryPoint = NULL;
296
297 //
298 // Load the DLL if it's not an EBC image.
299 //
300 if ((ImageContext->PdbPointer != NULL) &&
301 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {
302 //
303 // Convert filename from ASCII to Unicode
304 //
305 DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
306
307 //
308 // Check that we have a valid filename
309 //
310 if (Index < 5 || DllFileName[Index - 4] != '.') {
311 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);
312
313 //
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.
317 //
318 return;
319 }
320 //
321 // Replace .PDB with .DLL on the filename
322 //
323 DllFileName[Index - 3] = 'D';
324 DllFileName[Index - 2] = 'L';
325 DllFileName[Index - 1] = 'L';
326
327 //
328 // Load the .DLL file into the user process's address space for source
329 // level debug
330 //
331 Library = mWinNt->LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
332 if (Library != NULL) {
333 //
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
340 //
341 DllEntryPoint = (VOID *) (UINTN) mWinNt->GetProcAddress (Library, "InitializeDriver");
342
343 }
344
345 if ((Library != NULL) && (DllEntryPoint != NULL)) {
346 Status = AddModHandle (ImageContext, Library);
347 if (Status == EFI_ALREADY_STARTED) {
348 //
349 // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
350 //
351 ImageContext->PdbPointer = NULL;
352 DEBUG ((EFI_D_ERROR, "WARNING: DLL already loaded. No source level debug %s. \n", DllFileName));
353 } else {
354 //
355 // This DLL is not already loaded, so source level debugging is suported.
356 //
357 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
358 DEBUG ((EFI_D_INFO, "LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName));
359 }
360 } else {
361 //
362 // This DLL does not support source level debugging at all.
363 //
364 DEBUG ((EFI_D_ERROR, "WARNING: No source level debug %s. \n", DllFileName));
365 }
366
367 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);
368 }
369
370 //
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.
374 //
375 return;
376 }
377
378 /**
379 Performs additional actions just before a PE/COFF image is unloaded. Any resources
380 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
381
382 For NT32, this function unloads symbols for source level debugging.
383
384 If ImageContext is NULL, then ASSERT().
385
386 @param ImageContext Pointer to the image context structure that describes the
387 PE/COFF image that is being unloaded.
388
389 **/
390 VOID
391 EFIAPI
392 PeCoffLoaderUnloadImageExtraAction (
393 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
394 )
395 {
396 VOID *ModHandle;
397
398 ASSERT (ImageContext != NULL);
399
400 ModHandle = RemoveModeHandle (ImageContext);
401 if (ModHandle != NULL) {
402 mWinNt->FreeLibrary (ModHandle);
403 }
404 return;
405 }