]> git.proxmox.com Git - mirror_edk2.git/blame - Nt32Pkg/Library/DxeNt32PeCoffExtraActionLib/DxeNt32PeCoffExtraActionLib.c
Update PeCoffExtraActionLib for NT32 to allow an app or driver to be loaded more...
[mirror_edk2.git] / Nt32Pkg / Library / DxeNt32PeCoffExtraActionLib / DxeNt32PeCoffExtraActionLib.c
CommitLineData
ffdd18bb 1/**@file\r
2\r
3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 PeiNt32PeCoffExtraActionLib.c\r
15\r
16Abstract:\r
17\r
18 Provides services to perform additional actions to relocate and unload\r
19 PE/Coff image for NT32 environment specific purpose such as souce level debug.\r
20 This version only works for DXE phase \r
21\r
22\r
23**/\r
24//\r
25// The package level header files this module uses\r
26//\r
27#include <FrameworkDxe.h>\r
ffdd18bb 28#include <WinNtDxe.h>\r
29\r
30//\r
31// The protocols, PPI and GUID defintions for this module\r
32//\r
33#include <Protocol/WinNtThunk.h>\r
34\r
35#include <Library/PeCoffLib.h>\r
ffdd18bb 36\r
37#include <Library/BaseLib.h>\r
38#include <Library/DebugLib.h>\r
39#include <Library/HobLib.h>\r
40#include <Library/BaseMemoryLib.h>\r
41#include <Library/PeCoffExtraActionLib.h>\r
42\r
43#define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100\r
44\r
45typedef struct {\r
46 CHAR8 *PdbPointer;\r
47 VOID *ModHandle;\r
48} PDB_NAME_TO_MOD_HANDLE;\r
49\r
50\r
51//\r
52// Cache of WinNtThunk protocol\r
53//\r
54EFI_WIN_NT_THUNK_PROTOCOL *mWinNt = NULL;\r
55\r
56//\r
57// An Array to hold the ModHandle\r
58//\r
59PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;\r
60UINTN mPdbNameModHandleArraySize = 0;\r
61\r
62\r
63/**\r
64 The constructor function gets the pointer of the WinNT thunk functions\r
65 It will ASSERT() if NT thunk protocol is not installed.\r
66\r
67 @retval EFI_SUCCESS WinNT thunk protocol is found and cached.\r
68\r
69**/\r
70EFI_STATUS\r
71EFIAPI\r
72DxeNt32PeCoffLibExtraActionConstructor (\r
73 IN EFI_HANDLE ImageHandle,\r
74 IN EFI_SYSTEM_TABLE *SystemTable\r
75 )\r
76{\r
77 EFI_HOB_GUID_TYPE *GuidHob;\r
78\r
79 //\r
80 // Retrieve WinNtThunkProtocol from GUID'ed HOB\r
81 //\r
82 GuidHob = GetFirstGuidHob (&gEfiWinNtThunkProtocolGuid);\r
83 ASSERT (GuidHob != NULL);\r
84 mWinNt = (EFI_WIN_NT_THUNK_PROTOCOL *)(*(UINTN *)(GET_GUID_HOB_DATA (GuidHob)));\r
85 ASSERT (mWinNt != NULL);\r
86\r
87\r
88 return EFI_SUCCESS;\r
89}\r
90\r
91/**\r
92 Convert the passed in Ascii string to Unicode.\r
93 \r
94 This function Convert the passed in Ascii string to Unicode.Optionally return\r
95 the length of the strings..\r
96\r
97 @param AsciiString Pointer to an AscII string\r
98 @param StrLen Length of string\r
99\r
100 @return Pointer to malloc'ed Unicode version of Ascii\r
101\r
102**/\r
103CHAR16 *\r
104AsciiToUnicode (\r
105 IN CHAR8 *Ascii,\r
106 IN UINTN *StrLen OPTIONAL\r
107 )\r
108{\r
109 UINTN Index;\r
110 CHAR16 *Unicode;\r
111\r
112 //\r
113 // Allocate a buffer for unicode string\r
114 //\r
115 for (Index = 0; Ascii[Index] != '\0'; Index++)\r
116 ;\r
117 Unicode = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
118 HEAP_ZERO_MEMORY,\r
119 ((Index + 1) * sizeof (CHAR16))\r
120 ); \r
121 if (Unicode == NULL) {\r
122 return NULL;\r
123 }\r
124\r
125 for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
126 Unicode[Index] = (CHAR16) Ascii[Index];\r
127 }\r
128\r
129 Unicode[Index] = '\0';\r
130\r
131 if (StrLen != NULL) {\r
132 *StrLen = Index;\r
133 }\r
134\r
135 return Unicode;\r
136}\r
137/**\r
138 Store the ModHandle in an array indexed by the Pdb File name.\r
139 The ModHandle is needed to unload the image. \r
140\r
141\r
142 @param ImageContext - Input data returned from PE Laoder Library. Used to find the \r
143 .PDB file name of the PE Image.\r
144 @param ModHandle - Returned from LoadLibraryEx() and stored for call to \r
145 FreeLibrary().\r
146\r
147 @return return EFI_SUCCESS when ModHandle was stored. \r
148\r
149--*/\r
150EFI_STATUS\r
151AddModHandle (\r
152 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
153 IN VOID *ModHandle\r
154 )\r
155\r
156{\r
157 UINTN Index;\r
158 PDB_NAME_TO_MOD_HANDLE *Array;\r
159 UINTN PreviousSize;\r
160 PDB_NAME_TO_MOD_HANDLE *TempArray;\r
a00ec39b 161 HANDLE Handle;\r
ffdd18bb 162\r
66352173 163 //\r
164 // Return EFI_ALREADY_STARTED if this DLL has already been loaded\r
165 //\r
166 Array = mPdbNameModHandleArray;\r
167 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
168 if (Array->PdbPointer != NULL && Array->ModHandle == ModHandle) {\r
169 return EFI_ALREADY_STARTED;\r
170 }\r
171 }\r
172 \r
ffdd18bb 173 Array = mPdbNameModHandleArray;\r
174 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
175 if (Array->PdbPointer == NULL) {\r
176 //\r
177 // Make a copy of the stirng and store the ModHandle\r
178 //\r
a00ec39b 179 Handle = mWinNt->GetProcessHeap ();\r
180 Array->PdbPointer = mWinNt->HeapAlloc ( Handle,\r
ffdd18bb 181 HEAP_ZERO_MEMORY,\r
182 AsciiStrLen (ImageContext->PdbPointer) + 1\r
183 ); \r
184 \r
185 ASSERT (Array->PdbPointer != NULL);\r
186\r
187 AsciiStrCpy (Array->PdbPointer, ImageContext->PdbPointer);\r
188 Array->ModHandle = ModHandle;\r
189 return EFI_SUCCESS;\r
190 }\r
191 }\r
192 \r
193 //\r
194 // No free space in mPdbNameModHandleArray so grow it by \r
195 // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires. \r
196 //\r
197 PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);\r
198 mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;\r
199 //\r
200 // re-allocate a new buffer and copy the old values to the new locaiton. \r
201 //\r
202 TempArray = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
203 HEAP_ZERO_MEMORY,\r
204 mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)\r
205 ); \r
206 \r
207 CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize);\r
208 \r
209 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, mPdbNameModHandleArray);\r
210 \r
211 mPdbNameModHandleArray = TempArray;\r
212 if (mPdbNameModHandleArray == NULL) {\r
213 ASSERT (FALSE);\r
214 return EFI_OUT_OF_RESOURCES;\r
215 }\r
216 \r
217 \r
218 return AddModHandle (ImageContext, ModHandle);\r
219}\r
220/**\r
221 Return the ModHandle and delete the entry in the array.\r
222\r
223\r
224 @param ImageContext - Input data returned from PE Laoder Library. Used to find the \r
225 .PDB file name of the PE Image.\r
226\r
227 @return \r
228 ModHandle - ModHandle assoicated with ImageContext is returned\r
229 NULL - No ModHandle associated with ImageContext\r
230\r
231**/\r
232VOID *\r
233RemoveModeHandle (\r
234 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
235 )\r
236{\r
237 UINTN Index;\r
238 PDB_NAME_TO_MOD_HANDLE *Array;\r
239\r
240 if (ImageContext->PdbPointer == NULL) {\r
241 //\r
242 // If no PDB pointer there is no ModHandle so return NULL\r
243 //\r
244 return NULL;\r
245 }\r
246\r
247 Array = mPdbNameModHandleArray;\r
248 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
249 if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {\r
250 //\r
251 // If you find a match return it and delete the entry\r
252 //\r
253 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, Array->PdbPointer);\r
254 Array->PdbPointer = NULL;\r
255 return Array->ModHandle;\r
256 }\r
257 }\r
258\r
259 return NULL;\r
260}\r
261\r
262/**\r
51f1a2b5 263 Performs additional actions after a PE/COFF image has been loaded and relocated.\r
ffdd18bb 264\r
51f1a2b5 265 For NT32, this function load symbols to support source level debugging.\r
266\r
267 If ImageContext is NULL, then ASSERT().\r
268\r
269 @param ImageContext Pointer to the image context structure that describes the\r
270 PE/COFF image that has already been loaded and relocated.\r
ffdd18bb 271\r
272**/\r
273VOID\r
274EFIAPI\r
275PeCoffLoaderRelocateImageExtraAction (\r
276 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
277 )\r
278{\r
66352173 279 EFI_STATUS Status;\r
ffdd18bb 280 VOID *DllEntryPoint;\r
281 CHAR16 *DllFileName;\r
282 HMODULE Library;\r
283 UINTN Index;\r
51f1a2b5 284\r
285 ASSERT (ImageContext != NULL);\r
286\r
ffdd18bb 287 //\r
288 // If we load our own PE COFF images the Windows debugger can not source\r
289 // level debug our code. If a valid PDB pointer exists usw it to load\r
290 // the *.dll file as a library using Windows* APIs. This allows \r
291 // source level debug. The image is still loaded and reloaced\r
292 // in the Framework memory space like on a real system (by the code above),\r
293 // but the entry point points into the DLL loaded by the code bellow. \r
294 //\r
295\r
296 DllEntryPoint = NULL;\r
297\r
298 //\r
299 // Load the DLL if it's not an EBC image.\r
300 //\r
301 if ((ImageContext->PdbPointer != NULL) &&\r
302 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
303 //\r
304 // Convert filename from ASCII to Unicode\r
305 //\r
306 DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);\r
307\r
308 //\r
309 // Check that we have a valid filename\r
310 //\r
311 if (Index < 5 || DllFileName[Index - 4] != '.') {\r
312 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);\r
313\r
314 //\r
315 // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
316 // The image will run, but we just can't source level debug. If we\r
317 // return an error the image will not run.\r
318 //\r
319 return;\r
320 }\r
321 //\r
322 // Replace .PDB with .DLL on the filename\r
323 //\r
324 DllFileName[Index - 3] = 'D';\r
325 DllFileName[Index - 2] = 'L';\r
326 DllFileName[Index - 1] = 'L';\r
327\r
328 //\r
329 // Load the .DLL file into the user process's address space for source \r
330 // level debug\r
331 //\r
332 Library = mWinNt->LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);\r
333 if (Library != NULL) {\r
334 //\r
335 // InitializeDriver is the entry point we put in all our EFI DLL's. The\r
336 // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the \r
337 // normal DLL entry point of DllMain, and prevents other modules that are\r
338 // referenced in side the DllFileName from being loaded. There is no error \r
339 // checking as the we can point to the PE32 image loaded by Tiano. This \r
340 // step is only needed for source level debuging\r
341 //\r
342 DllEntryPoint = (VOID *) (UINTN) mWinNt->GetProcAddress (Library, "InitializeDriver");\r
343\r
344 }\r
345\r
346 if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
66352173 347 Status = AddModHandle (ImageContext, Library);\r
348 if (Status == EFI_ALREADY_STARTED) {\r
349 //\r
350 // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.\r
351 //\r
352 ImageContext->PdbPointer = NULL;\r
353 DEBUG ((EFI_D_ERROR, "WARNING: DLL already loaded. No source level debug %s. \n", DllFileName));\r
354 } else {\r
355 //\r
356 // This DLL is not already loaded, so source level debugging is suported.\r
357 //\r
358 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
359 DEBUG ((EFI_D_INFO, "LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName));\r
360 }\r
ffdd18bb 361 } else {\r
66352173 362 //\r
363 // This DLL does not support source level debugging at all.\r
364 //\r
ffdd18bb 365 DEBUG ((EFI_D_ERROR, "WARNING: No source level debug %s. \n", DllFileName));\r
366 }\r
367\r
368 mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);\r
369 }\r
370\r
371 //\r
372 // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
373 // The image will run, but we just can't source level debug. If we\r
374 // return an error the image will not run.\r
375 //\r
376 return;\r
377} \r
378\r
379/**\r
51f1a2b5 380 Performs additional actions just before a PE/COFF image is unloaded. Any resources\r
381 that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.\r
ffdd18bb 382 \r
51f1a2b5 383 For NT32, this function unloads symbols for source level debugging.\r
384\r
ffdd18bb 385 If ImageContext is NULL, then ASSERT().\r
386 \r
51f1a2b5 387 @param ImageContext Pointer to the image context structure that describes the\r
388 PE/COFF image that is being unloaded.\r
ffdd18bb 389\r
390**/\r
391VOID\r
392EFIAPI\r
393PeCoffLoaderUnloadImageExtraAction (\r
394 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
395 )\r
396{\r
397 VOID *ModHandle;\r
398\r
51f1a2b5 399 ASSERT (ImageContext != NULL);\r
400\r
ffdd18bb 401 ModHandle = RemoveModeHandle (ImageContext);\r
402 if (ModHandle != NULL) {\r
403 mWinNt->FreeLibrary (ModHandle);\r
404 }\r
405 return;\r
ee31b443 406}\r