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