]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BasePeCoffGetEntryPointLib/PeCoffGetEntryPoint.c
UefiCpuPkg/MpLib.c: Set AP state after X2APIC mode enabled
[mirror_edk2.git] / MdePkg / Library / BasePeCoffGetEntryPointLib / PeCoffGetEntryPoint.c
CommitLineData
e1f414b6 1/** @file\r
afa22326 2 Provides the services to get the entry point to a PE/COFF image that has either been \r
22e6fe86 3 loaded into memory or is executing at it's linked address.\r
4\r
412e9dea 5 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
19388d29
HT
6 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
7 This program and the accompanying materials\r
e1f414b6 8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
2fc59a00 10 http://opensource.org/licenses/bsd-license.php.\r
e1f414b6 11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
e1f414b6 15**/\r
16\r
c892d846 17\r
c7d265a9 18#include <Base.h>\r
c892d846 19\r
c7d265a9 20#include <Library/PeCoffGetEntryPointLib.h>\r
21#include <Library/DebugLib.h>\r
22\r
23#include <IndustryStandard/PeImage.h>\r
e1f414b6 24\r
412e9dea
JF
25#define PE_COFF_IMAGE_ALIGN_SIZE 4\r
26\r
e1f414b6 27/**\r
28 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
29 into system memory with the PE/COFF Loader Library functions.\r
30\r
31 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry\r
32 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then\r
33 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.\r
34 If Pe32Data is NULL, then ASSERT().\r
35 If EntryPoint is NULL, then ASSERT().\r
36\r
2fc59a00 37 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
38 @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
e1f414b6 39\r
40 @retval RETURN_SUCCESS EntryPoint was returned.\r
41 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
42\r
43**/\r
44RETURN_STATUS\r
45EFIAPI\r
46PeCoffLoaderGetEntryPoint (\r
47 IN VOID *Pe32Data,\r
48 OUT VOID **EntryPoint\r
49 )\r
50{\r
3d7b0992
LG
51 EFI_IMAGE_DOS_HEADER *DosHdr;\r
52 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
e1f414b6 53\r
54 ASSERT (Pe32Data != NULL);\r
55 ASSERT (EntryPoint != NULL);\r
56\r
3d7b0992 57 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
afa22326 58 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
e1f414b6 59 //\r
60 // DOS image header is present, so read the PE header after the DOS image header.\r
61 //\r
3d7b0992 62 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
e1f414b6 63 } else {\r
64 //\r
65 // DOS image header is not present, so PE header is at the image base.\r
66 //\r
3d7b0992 67 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
e1f414b6 68 }\r
69\r
70 //\r
71 // Calculate the entry point relative to the start of the image.\r
72 // AddressOfEntryPoint is common for PE32 & PE32+\r
73 //\r
3d7b0992
LG
74 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
75 *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
76 return RETURN_SUCCESS;\r
77 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
78 *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));\r
79 return RETURN_SUCCESS;\r
80 }\r
81\r
82 return RETURN_UNSUPPORTED;\r
e1f414b6 83}\r
84\r
85\r
86/**\r
87 Returns the machine type of a PE/COFF image.\r
88\r
89 Returns the machine type from the PE/COFF image specified by Pe32Data.\r
90 If Pe32Data is NULL, then ASSERT().\r
91\r
2fc59a00 92 @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
e1f414b6 93 memory.\r
94\r
cb6cb44c 95 @return Machine type or zero if not a valid image.\r
e1f414b6 96\r
97**/\r
98UINT16\r
99EFIAPI\r
100PeCoffLoaderGetMachineType (\r
101 IN VOID *Pe32Data\r
102 )\r
103{\r
104 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
105 EFI_IMAGE_DOS_HEADER *DosHdr;\r
106\r
3d7b0992
LG
107 ASSERT (Pe32Data != NULL);\r
108\r
109 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
afa22326 110 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
3d7b0992
LG
111 //\r
112 // DOS image header is present, so read the PE header after the DOS image header.\r
113 //\r
114 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
e1f414b6 115 } else {\r
3d7b0992
LG
116 //\r
117 // DOS image header is not present, so PE header is at the image base.\r
118 //\r
119 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
e1f414b6 120 }\r
121\r
afa22326 122 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
3d7b0992 123 return Hdr.Te->Machine;\r
afa22326 124 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
e1f414b6 125 return Hdr.Pe32->FileHeader.Machine;\r
126 }\r
127\r
128 return 0x0000;\r
129}\r
130\r
131/**\r
132 Returns a pointer to the PDB file name for a PE/COFF image that has been\r
122e2191 133 loaded into system memory with the PE/COFF Loader Library functions. \r
e1f414b6 134\r
135 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If\r
136 the PE/COFF image specified by Pe32Data is not a valid, then NULL is\r
137 returned. If the PE/COFF image specified by Pe32Data does not contain a\r
138 debug directory entry, then NULL is returned. If the debug directory entry\r
139 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,\r
140 then NULL is returned.\r
141 If Pe32Data is NULL, then ASSERT().\r
142\r
2fc59a00 143 @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
e1f414b6 144 memory.\r
145\r
146 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL\r
147 if it cannot be retrieved.\r
148\r
149**/\r
150VOID *\r
151EFIAPI\r
152PeCoffLoaderGetPdbPointer (\r
153 IN VOID *Pe32Data\r
154 )\r
155{\r
3d7b0992 156 EFI_IMAGE_DOS_HEADER *DosHdr;\r
e1f414b6 157 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
158 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
159 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
160 UINTN DirCount;\r
161 VOID *CodeViewEntryPointer;\r
162 INTN TEImageAdjust;\r
163 UINT32 NumberOfRvaAndSizes;\r
164 UINT16 Magic;\r
165\r
166 ASSERT (Pe32Data != NULL);\r
167\r
168 TEImageAdjust = 0;\r
169 DirectoryEntry = NULL;\r
170 DebugEntry = NULL;\r
171 NumberOfRvaAndSizes = 0;\r
172\r
3d7b0992 173 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
afa22326 174 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
e1f414b6 175 //\r
176 // DOS image header is present, so read the PE header after the DOS image header.\r
177 //\r
3d7b0992 178 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
e1f414b6 179 } else {\r
180 //\r
181 // DOS image header is not present, so PE header is at the image base.\r
182 //\r
183 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
184 }\r
185\r
afa22326 186 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
e1f414b6 187 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
188 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
189 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
190 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +\r
191 Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +\r
192 TEImageAdjust);\r
193 }\r
afa22326 194 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
e1f414b6 195 //\r
196 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.\r
197 // It is due to backward-compatibility, for some system might\r
198 // generate PE32+ image with PE32 Magic.\r
199 //\r
200 switch (Hdr.Pe32->FileHeader.Machine) {\r
4ab0dff3 201 case IMAGE_FILE_MACHINE_I386:\r
e1f414b6 202 //\r
203 // Assume PE32 image with IA32 Machine field.\r
204 //\r
205 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
206 break;\r
4ab0dff3 207 case IMAGE_FILE_MACHINE_X64:\r
208 case IMAGE_FILE_MACHINE_IA64:\r
e1f414b6 209 //\r
4ab0dff3 210 // Assume PE32+ image with x64 or IA64 Machine field\r
e1f414b6 211 //\r
212 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
213 break;\r
214 default:\r
215 //\r
216 // For unknow Machine field, use Magic in optional Header\r
217 //\r
218 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
219 }\r
220\r
afa22326 221 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
e1f414b6 222 //\r
223 // Use PE32 offset get Debug Directory Entry\r
224 //\r
225 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
226 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
227 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
228 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
229 //\r
230 // Use PE32+ offset get Debug Directory Entry\r
231 //\r
232 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
233 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
234 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
235 }\r
236\r
237 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
238 DirectoryEntry = NULL;\r
239 DebugEntry = NULL;\r
240 }\r
241 } else {\r
242 return NULL;\r
243 }\r
244\r
afa22326 245 if (DebugEntry == NULL || DirectoryEntry == NULL) {\r
e1f414b6 246 return NULL;\r
247 }\r
248\r
38bbd3d9 249 //\r
250 // Scan the directory to find the debug entry.\r
251 // \r
3d7b0992 252 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {\r
2b1532df 253 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
e1f414b6 254 if (DebugEntry->SizeOfData > 0) {\r
255 CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);\r
256 switch (* (UINT32 *) CodeViewEntryPointer) {\r
257 case CODEVIEW_SIGNATURE_NB10:\r
258 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
259 case CODEVIEW_SIGNATURE_RSDS:\r
260 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
ebd04fc2 261 case CODEVIEW_SIGNATURE_MTOC:\r
262 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));\r
e1f414b6 263 default:\r
264 break;\r
265 }\r
266 }\r
267 }\r
268 }\r
269\r
270 return NULL;\r
271}\r
272\r
225290eb
A
273/**\r
274 Returns the size of the PE/COFF headers\r
275\r
276 Returns the size of the PE/COFF header specified by Pe32Data.\r
277 If Pe32Data is NULL, then ASSERT().\r
278\r
2fc59a00 279 @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
225290eb
A
280 memory.\r
281\r
cb6cb44c 282 @return Size of PE/COFF header in bytes or zero if not a valid image.\r
225290eb
A
283\r
284**/\r
42db19ac
A
285UINT32\r
286EFIAPI\r
287PeCoffGetSizeOfHeaders (\r
288 IN VOID *Pe32Data\r
289 )\r
290{\r
291 EFI_IMAGE_DOS_HEADER *DosHdr;\r
292 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
293 UINTN SizeOfHeaders;\r
294\r
225290eb 295 ASSERT (Pe32Data != NULL);\r
42db19ac
A
296 \r
297 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
298 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
299 //\r
300 // DOS image header is present, so read the PE header after the DOS image header.\r
301 //\r
302 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
303 } else {\r
304 //\r
305 // DOS image header is not present, so PE header is at the image base.\r
306 //\r
307 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
308 }\r
309\r
310 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
cb6cb44c 311 SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
42db19ac
A
312 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
313 SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
314 } else {\r
315 SizeOfHeaders = 0;\r
316 }\r
317\r
cded6218 318 return (UINT32) SizeOfHeaders;\r
225290eb 319}\r
e1f414b6 320\r
412e9dea
JF
321/**\r
322 Returns PE/COFF image base is loaded in system memory where the input address is in.\r
323\r
324 On DEBUG build, searches the PE/COFF image base forward the input address and\r
325 returns it.\r
326\r
327 @param Address Address located in one PE/COFF image.\r
328\r
329 @retval 0 RELEASE build or cannot find the PE/COFF image base.\r
330 @retval others PE/COFF image base found.\r
331\r
332**/\r
333UINTN\r
334EFIAPI\r
335PeCoffSerachImageBase (\r
336 IN UINTN Address\r
337 )\r
338{\r
339 UINTN Pe32Data;\r
340\r
341 Pe32Data = 0;\r
342\r
343 DEBUG_CODE (\r
344 EFI_IMAGE_DOS_HEADER *DosHdr;\r
345 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
346\r
347 //\r
348 // Find Image Base\r
349 //\r
350 Pe32Data = Address & ~(PE_COFF_IMAGE_ALIGN_SIZE - 1);\r
351 while (Pe32Data != 0) {\r
352 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
353 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
354 //\r
355 // DOS image header is present, so read the PE header after the DOS image header.\r
356 //\r
357 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
358 //\r
359 // Make sure PE header address does not overflow and is less than the initial address.\r
360 //\r
361 if (((UINTN)Hdr.Pe32 > Pe32Data) && ((UINTN)Hdr.Pe32 < Address)) {\r
362 if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
363 break;\r
364 }\r
365 }\r
366 } else {\r
367 //\r
368 // DOS image header is not present, TE header is at the image base.\r
369 //\r
370 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
371 if ((Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) &&\r
372 ((Hdr.Te->Machine == IMAGE_FILE_MACHINE_I386) || (Hdr.Te->Machine == IMAGE_FILE_MACHINE_IA64) ||\r
373 (Hdr.Te->Machine == IMAGE_FILE_MACHINE_EBC) || (Hdr.Te->Machine == IMAGE_FILE_MACHINE_X64) ||\r
374 (Hdr.Te->Machine == IMAGE_FILE_MACHINE_ARM64) || (Hdr.Te->Machine == IMAGE_FILE_MACHINE_ARMTHUMB_MIXED))\r
375 ) {\r
376 break;\r
377 }\r
378 }\r
379\r
380 //\r
381 // Not found the image base, check the previous aligned address\r
382 //\r
383 Pe32Data -= PE_COFF_IMAGE_ALIGN_SIZE;\r
384 }\r
385 );\r
386\r
387 return Pe32Data;\r
388}\r