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