1 /**@file
2 
3 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
4 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 PEI phase
21 
22 
23 **/
24 //
25 // The package level header files this module uses
26 //
27 #include <PiPei.h>
28 #include <WinNtPeim.h>
29 
30 //
31 // The protocols, PPI and GUID defintions for this module
32 //
33 #include <Ppi/NtThunk.h>
34 
35 #include <PiPei.h>
36 #include <Library/PeCoffLib.h>
37 #include <Library/PeiServicesLib.h>
38 #include <Library/DebugLib.h>
39 #include <Library/BaseLib.h>
40 #include <Library/PeCoffExtraActionLib.h>
41 
42 //
43 // Cache of WinNtThunk protocol
44 //
45 EFI_WIN_NT_THUNK_PROTOCOL   *mWinNt = NULL;
46 
47 /**
48   The function caches the pointer of the WinNT thunk functions
49   It will ASSERT() if NT thunk ppi is not installed.
50 
51   @retval EFI_SUCCESS   WinNT thunk protocol is found and cached.
52 
53 **/
54 EFI_STATUS
55 EFIAPI
Nt32PeCoffGetWinNtThunkStucture()56 Nt32PeCoffGetWinNtThunkStucture (
57   )
58 {
59 	PEI_NT_THUNK_PPI  *NtThunkPpi;
60   EFI_STATUS        Status;
61 
62 
63   //
64   // Locate NtThunkPpi for retrieving standard output handle
65   //
66   Status = PeiServicesLocatePpi (
67               &gPeiNtThunkPpiGuid,
68               0,
69               NULL,
70               (VOID **) &NtThunkPpi
71               );
72 
73   ASSERT_EFI_ERROR (Status);
74 
75   mWinNt  = (EFI_WIN_NT_THUNK_PROTOCOL *) NtThunkPpi->NtThunk ();
76 
77   return EFI_SUCCESS;
78 }
79 
80 /**
81   Convert the passed in Ascii string to Unicode.
82 
83   This function  Convert the passed in Ascii string to Unicode.Optionally return
84    the length of the strings..
85 
86   @param  AsciiString    Pointer to an AscII string
87   @param  StrLen         Length of string
88 
89   @return  Pointer to malloc'ed Unicode version of Ascii
90 
91 **/
92 CHAR16 *
AsciiToUnicode(IN CHAR8 * Ascii,IN UINTN * StrLen OPTIONAL)93 AsciiToUnicode (
94   IN  CHAR8   *Ascii,
95   IN  UINTN   *StrLen OPTIONAL
96   )
97 {
98   UINTN   Index;
99   CHAR16  *Unicode;
100 
101   //
102   // Allocate a buffer for unicode string
103   //
104   for (Index = 0; Ascii[Index] != '\0'; Index++)
105     ;
106   Unicode = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),
107                                 HEAP_ZERO_MEMORY,
108                                 ((Index + 1) * sizeof (CHAR16))
109                                );
110   if (Unicode == NULL) {
111     return NULL;
112   }
113 
114   for (Index = 0; Ascii[Index] != '\0'; Index++) {
115     Unicode[Index] = (CHAR16) Ascii[Index];
116   }
117 
118   Unicode[Index] = '\0';
119 
120   if (StrLen != NULL) {
121     *StrLen = Index;
122   }
123 
124   return Unicode;
125 }
126 
127 /**
128   Performs additional actions after a PE/COFF image has been loaded and relocated.
129 
130   For NT32, this function load symbols to support source level debugging.
131 
132   If ImageContext is NULL, then ASSERT().
133 
134   @param  ImageContext  Pointer to the image context structure that describes the
135                         PE/COFF image that has already been loaded and relocated.
136 
137 **/
138 VOID
139 EFIAPI
PeCoffLoaderRelocateImageExtraAction(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)140 PeCoffLoaderRelocateImageExtraAction (
141   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
142   )
143 {
144   VOID              *DllEntryPoint;
145   CHAR16            *DllFileName;
146   HMODULE           Library;
147   UINTN             Index;
148 
149   ASSERT (ImageContext != NULL);
150 
151   if (mWinNt == NULL) {
152     Nt32PeCoffGetWinNtThunkStucture ();
153   }
154 	//
155   // If we load our own PE COFF images the Windows debugger can not source
156   //  level debug our code. If a valid PDB pointer exists usw it to load
157   //  the *.dll file as a library using Windows* APIs. This allows
158   //  source level debug. The image is still loaded and reloaced
159   //  in the Framework memory space like on a real system (by the code above),
160   //  but the entry point points into the DLL loaded by the code bellow.
161   //
162 
163   DllEntryPoint = NULL;
164 
165   //
166   // Load the DLL if it's not an EBC image.
167   //
168   if ((ImageContext->PdbPointer != NULL) &&
169       (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {
170     //
171     // Convert filename from ASCII to Unicode
172     //
173     DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
174 
175     //
176     // Check that we have a valid filename
177     //
178     if (Index < 5 || DllFileName[Index - 4] != '.') {
179       mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);
180 
181       //
182       // Never return an error if PeCoffLoaderRelocateImage() succeeded.
183       // The image will run, but we just can't source level debug. If we
184       // return an error the image will not run.
185       //
186       return;
187     }
188     //
189     // Replace .PDB with .DLL on the filename
190     //
191     DllFileName[Index - 3]  = 'D';
192     DllFileName[Index - 2]  = 'L';
193     DllFileName[Index - 1]  = 'L';
194 
195     //
196     // Load the .DLL file into the user process's address space for source
197     // level debug
198     //
199     Library = mWinNt->LoadLibraryEx  (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
200     if (Library != NULL) {
201       //
202       // InitializeDriver is the entry point we put in all our EFI DLL's. The
203       // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the
204       // normal DLL entry point of DllMain, and prevents other modules that are
205       // referenced in side the DllFileName from being loaded. There is no error
206       // checking as the we can point to the PE32 image loaded by Tiano. This
207       // step is only needed for source level debuging
208       //
209       DllEntryPoint = (VOID *) (UINTN) mWinNt->GetProcAddress (Library, "InitializeDriver");
210 
211     }
212 
213     if ((Library != NULL) && (DllEntryPoint != NULL)) {
214       ImageContext->EntryPoint  = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
215       DEBUG ((EFI_D_INFO, "LoadLibraryEx (%s,\n               NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName));
216      } else {
217       DEBUG ((EFI_D_ERROR, "WARNING: No source level debug %s. \n", DllFileName));
218     }
219 
220     mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);
221   }
222 
223   //
224   // Never return an error if PeCoffLoaderRelocateImage() succeeded.
225   // The image will run, but we just can't source level debug. If we
226   // return an error the image will not run.
227   //
228   return;
229 }
230 
231 /**
232   Performs additional actions just before a PE/COFF image is unloaded.  Any resources
233   that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
234 
235   For NT32, this function unloads symbols for source level debugging.
236 
237   If ImageContext is NULL, then ASSERT().
238 
239   @param  ImageContext  Pointer to the image context structure that describes the
240                         PE/COFF image that is being unloaded.
241 
242 **/
243 VOID
244 EFIAPI
PeCoffLoaderUnloadImageExtraAction(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)245 PeCoffLoaderUnloadImageExtraAction (
246   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
247   )
248 {
249   ASSERT (ImageContext != NULL);
250 }
251