1 /**@file
2 
3 Copyright (c) 2006 - 2013, 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   PeCoffGetEntryPoint.c
15 
16 Abstract:
17 
18   Tiano PE/COFF loader
19 
20 Revision History
21 
22 **/
23 
24 #include <PiPei.h>
25 #include <IndustryStandard/PeImage.h>
26 #include <WinNtPeim.h>
27 #include <Ppi/NtPeiLoadFile.h>
28 #include <Library/PeCoffGetEntryPointLib.h>
29 #include <Library/PeiServicesLib.h>
30 #include <Library/DebugLib.h>
31 
32 
33 RETURN_STATUS
34 EFIAPI
PeCoffLoaderGetEntryPoint(IN VOID * Pe32Data,IN OUT VOID ** EntryPoint)35 PeCoffLoaderGetEntryPoint (
36   IN     VOID  *Pe32Data,
37   IN OUT VOID  **EntryPoint
38   )
39 /*++
40 
41 Routine Description:
42 
43   Loads a PE/COFF image into memory, this is not follow the original purpose of
44   PeCoffGetEntryPoint library class.  But it's ok that Unix package not run on a real
45   platform and this is for source level debug.
46 
47 Arguments:
48 
49   Pe32Data   - Pointer to a PE/COFF Image
50 
51   EntryPoint - Pointer to the entry point of the PE/COFF image
52 
53 Returns:
54 
55   EFI_SUCCESS            if the EntryPoint was returned
56   EFI_INVALID_PARAMETER  if the EntryPoint could not be found from Pe32Data
57 
58 --*/
59 {
60   EFI_STATUS              Status;
61   EFI_PEI_PPI_DESCRIPTOR  *PpiDescriptor;
62   NT_PEI_LOAD_FILE_PPI    *PeiNtService;
63   EFI_PHYSICAL_ADDRESS    ImageAddress;
64   UINT64                  ImageSize;
65   EFI_PHYSICAL_ADDRESS    ImageEntryPoint;
66 
67   ASSERT (Pe32Data   != NULL);
68   ASSERT (EntryPoint != NULL);
69 
70   Status = PeiServicesLocatePpi (
71              &gNtPeiLoadFilePpiGuid,
72              0,
73              &PpiDescriptor,
74              (VOID**)&PeiNtService
75              );
76   ASSERT_EFI_ERROR (Status);
77 
78   Status = PeiNtService->PeiLoadFileService (
79                            Pe32Data,
80                            &ImageAddress,
81                            &ImageSize,
82                            &ImageEntryPoint
83                            );
84   if (EFI_ERROR (Status)) {
85     return Status;
86   }
87 
88   *EntryPoint = (VOID*)(UINTN)ImageEntryPoint;
89   return Status;
90 }
91 
92 /**
93   Returns the machine type of PE/COFF image.
94   This is copied from MDE BasePeCoffGetEntryPointLib, the code should be sync with it.
95   The reason is NT32 package needs to load the image to memory to support source
96   level debug.
97 
98 
99   @param  Pe32Data   Pointer to a PE/COFF header
100 
101   @return            Machine type or zero if not a valid iamge
102 
103 **/
104 UINT16
105 EFIAPI
PeCoffLoaderGetMachineType(IN VOID * Pe32Data)106 PeCoffLoaderGetMachineType (
107   IN  VOID  *Pe32Data
108   )
109 {
110   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
111   EFI_IMAGE_DOS_HEADER                 *DosHdr;
112 
113   ASSERT (Pe32Data   != NULL);
114 
115   DosHdr = (EFI_IMAGE_DOS_HEADER  *)Pe32Data;
116   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
117     //
118     // DOS image header is present, so read the PE header after the DOS image header.
119     //
120     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
121   } else {
122     //
123     // DOS image header is not present, so PE header is at the image base.
124     //
125     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
126   }
127 
128   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
129     return Hdr.Te->Machine;
130   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
131     return Hdr.Pe32->FileHeader.Machine;
132   }
133 
134   return 0x0000;
135 }
136 
137 /**
138   Returns a pointer to the PDB file name for a PE/COFF image that has been
139   loaded into system memory with the PE/COFF Loader Library functions.
140 
141   Returns the PDB file name for the PE/COFF image specified by Pe32Data.  If
142   the PE/COFF image specified by Pe32Data is not a valid, then NULL is
143   returned.  If the PE/COFF image specified by Pe32Data does not contain a
144   debug directory entry, then NULL is returned.  If the debug directory entry
145   in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
146   then NULL is returned.
147   If Pe32Data is NULL, then ASSERT().
148 
149   @param  Pe32Data   Pointer to the PE/COFF image that is loaded in system
150                      memory.
151 
152   @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
153           if it cannot be retrieved.
154 
155 **/
156 VOID *
157 EFIAPI
PeCoffLoaderGetPdbPointer(IN VOID * Pe32Data)158 PeCoffLoaderGetPdbPointer (
159   IN VOID  *Pe32Data
160   )
161 {
162   EFI_IMAGE_DOS_HEADER                  *DosHdr;
163   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
164   EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
165   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
166   UINTN                                 DirCount;
167   VOID                                  *CodeViewEntryPointer;
168   INTN                                  TEImageAdjust;
169   UINT32                                NumberOfRvaAndSizes;
170   UINT16                                Magic;
171 
172   ASSERT (Pe32Data   != NULL);
173 
174   TEImageAdjust       = 0;
175   DirectoryEntry      = NULL;
176   DebugEntry          = NULL;
177   NumberOfRvaAndSizes = 0;
178 
179   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
180   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
181     //
182     // DOS image header is present, so read the PE header after the DOS image header.
183     //
184     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
185   } else {
186     //
187     // DOS image header is not present, so PE header is at the image base.
188     //
189     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
190   }
191 
192   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
193     if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
194       DirectoryEntry  = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
195       TEImageAdjust   = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
196       DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
197                     Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +
198                     TEImageAdjust);
199     }
200   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
201     //
202     // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
203     //       It is due to backward-compatibility, for some system might
204     //       generate PE32+ image with PE32 Magic.
205     //
206     switch (Hdr.Pe32->FileHeader.Machine) {
207     case IMAGE_FILE_MACHINE_I386:
208       //
209       // Assume PE32 image with IA32 Machine field.
210       //
211       Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
212       break;
213     case IMAGE_FILE_MACHINE_X64:
214     case IMAGE_FILE_MACHINE_IA64:
215       //
216       // Assume PE32+ image with X64 or IA64 Machine field
217       //
218       Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
219       break;
220     default:
221       //
222       // For unknow Machine field, use Magic in optional Header
223       //
224       Magic = Hdr.Pe32->OptionalHeader.Magic;
225     }
226 
227     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
228       //
229       // Use PE32 offset get Debug Directory Entry
230       //
231       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
232       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
233       DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);
234     } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
235       //
236       // Use PE32+ offset get Debug Directory Entry
237       //
238       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
239       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
240       DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);
241     }
242 
243     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
244       DirectoryEntry = NULL;
245       DebugEntry = NULL;
246     }
247   } else {
248     return NULL;
249   }
250 
251   if (DebugEntry == NULL || DirectoryEntry == NULL) {
252     return NULL;
253   }
254 
255   for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
256     if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
257       if (DebugEntry->SizeOfData > 0) {
258         CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);
259         switch (* (UINT32 *) CodeViewEntryPointer) {
260         case CODEVIEW_SIGNATURE_NB10:
261           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
262         case CODEVIEW_SIGNATURE_RSDS:
263           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
264         case CODEVIEW_SIGNATURE_MTOC:
265           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
266           break;
267         default:
268           break;
269         }
270       }
271     }
272   }
273 
274   return NULL;
275 }
276 
277 /**
278   Returns the size of the PE/COFF headers
279 
280   Returns the size of the PE/COFF header specified by Pe32Data.
281   If Pe32Data is NULL, then ASSERT().
282 
283   @param  Pe32Data   Pointer to the PE/COFF image that is loaded in system
284                      memory.
285 
286   @return Size of PE/COFF header in bytes or zero if not a valid image.
287 
288 **/
289 UINT32
290 EFIAPI
PeCoffGetSizeOfHeaders(IN VOID * Pe32Data)291 PeCoffGetSizeOfHeaders (
292   IN VOID     *Pe32Data
293   )
294 {
295   EFI_IMAGE_DOS_HEADER                  *DosHdr;
296   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
297   UINTN                                 SizeOfHeaders;
298 
299   ASSERT (Pe32Data   != NULL);
300 
301   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
302   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
303     //
304     // DOS image header is present, so read the PE header after the DOS image header.
305     //
306     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
307   } else {
308     //
309     // DOS image header is not present, so PE header is at the image base.
310     //
311     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
312   }
313 
314   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
315     SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
316   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
317     SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
318   } else {
319     SizeOfHeaders = 0;
320   }
321 
322   return (UINT32) SizeOfHeaders;
323 }
324 
325