ArmPlatformPkg/PL111LcdArmVExpressLib: use write-combine mapping for VRAM
[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
19388d29
HT
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
25/**\r
26 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
27 into system memory with the PE/COFF Loader Library functions.\r
28\r
29 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry\r
30 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then\r
31 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.\r
32 If Pe32Data is NULL, then ASSERT().\r
33 If EntryPoint is NULL, then ASSERT().\r
34\r
2fc59a00 35 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
36 @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
e1f414b6 37\r
38 @retval RETURN_SUCCESS EntryPoint was returned.\r
39 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
40\r
41**/\r
42RETURN_STATUS\r
43EFIAPI\r
44PeCoffLoaderGetEntryPoint (\r
45 IN VOID *Pe32Data,\r
46 OUT VOID **EntryPoint\r
47 )\r
48{\r
3d7b0992
LG
49 EFI_IMAGE_DOS_HEADER *DosHdr;\r
50 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
e1f414b6 51\r
52 ASSERT (Pe32Data != NULL);\r
53 ASSERT (EntryPoint != NULL);\r
54\r
3d7b0992 55 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
afa22326 56 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
e1f414b6 57 //\r
58 // DOS image header is present, so read the PE header after the DOS image header.\r
59 //\r
3d7b0992 60 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
e1f414b6 61 } else {\r
62 //\r
63 // DOS image header is not present, so PE header is at the image base.\r
64 //\r
3d7b0992 65 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
e1f414b6 66 }\r
67\r
68 //\r
69 // Calculate the entry point relative to the start of the image.\r
70 // AddressOfEntryPoint is common for PE32 & PE32+\r
71 //\r
3d7b0992
LG
72 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
73 *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
74 return RETURN_SUCCESS;\r
75 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
76 *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));\r
77 return RETURN_SUCCESS;\r
78 }\r
79\r
80 return RETURN_UNSUPPORTED;\r
e1f414b6 81}\r
82\r
83\r
84/**\r
85 Returns the machine type of a PE/COFF image.\r
86\r
87 Returns the machine type from the PE/COFF image specified by Pe32Data.\r
88 If Pe32Data is NULL, then ASSERT().\r
89\r
2fc59a00 90 @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
e1f414b6 91 memory.\r
92\r
cb6cb44c 93 @return Machine type or zero if not a valid image.\r
e1f414b6 94\r
95**/\r
96UINT16\r
97EFIAPI\r
98PeCoffLoaderGetMachineType (\r
99 IN VOID *Pe32Data\r
100 )\r
101{\r
102 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
103 EFI_IMAGE_DOS_HEADER *DosHdr;\r
104\r
3d7b0992
LG
105 ASSERT (Pe32Data != NULL);\r
106\r
107 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
afa22326 108 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
3d7b0992
LG
109 //\r
110 // DOS image header is present, so read the PE header after the DOS image header.\r
111 //\r
112 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
e1f414b6 113 } else {\r
3d7b0992
LG
114 //\r
115 // DOS image header is not present, so PE header is at the image base.\r
116 //\r
117 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
e1f414b6 118 }\r
119\r
afa22326 120 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
3d7b0992 121 return Hdr.Te->Machine;\r
afa22326 122 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
e1f414b6 123 return Hdr.Pe32->FileHeader.Machine;\r
124 }\r
125\r
126 return 0x0000;\r
127}\r
128\r
129/**\r
130 Returns a pointer to the PDB file name for a PE/COFF image that has been\r
122e2191 131 loaded into system memory with the PE/COFF Loader Library functions. \r
e1f414b6 132\r
133 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If\r
134 the PE/COFF image specified by Pe32Data is not a valid, then NULL is\r
135 returned. If the PE/COFF image specified by Pe32Data does not contain a\r
136 debug directory entry, then NULL is returned. If the debug directory entry\r
137 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,\r
138 then NULL is returned.\r
139 If Pe32Data is NULL, then ASSERT().\r
140\r
2fc59a00 141 @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
e1f414b6 142 memory.\r
143\r
144 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL\r
145 if it cannot be retrieved.\r
146\r
147**/\r
148VOID *\r
149EFIAPI\r
150PeCoffLoaderGetPdbPointer (\r
151 IN VOID *Pe32Data\r
152 )\r
153{\r
3d7b0992 154 EFI_IMAGE_DOS_HEADER *DosHdr;\r
e1f414b6 155 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
156 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
157 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
158 UINTN DirCount;\r
159 VOID *CodeViewEntryPointer;\r
160 INTN TEImageAdjust;\r
161 UINT32 NumberOfRvaAndSizes;\r
162 UINT16 Magic;\r
163\r
164 ASSERT (Pe32Data != NULL);\r
165\r
166 TEImageAdjust = 0;\r
167 DirectoryEntry = NULL;\r
168 DebugEntry = NULL;\r
169 NumberOfRvaAndSizes = 0;\r
170\r
3d7b0992 171 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
afa22326 172 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
e1f414b6 173 //\r
174 // DOS image header is present, so read the PE header after the DOS image header.\r
175 //\r
3d7b0992 176 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
e1f414b6 177 } else {\r
178 //\r
179 // DOS image header is not present, so PE header is at the image base.\r
180 //\r
181 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
182 }\r
183\r
afa22326 184 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
e1f414b6 185 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
186 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
187 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
188 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +\r
189 Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +\r
190 TEImageAdjust);\r
191 }\r
afa22326 192 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
e1f414b6 193 //\r
194 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.\r
195 // It is due to backward-compatibility, for some system might\r
196 // generate PE32+ image with PE32 Magic.\r
197 //\r
198 switch (Hdr.Pe32->FileHeader.Machine) {\r
4ab0dff3 199 case IMAGE_FILE_MACHINE_I386:\r
e1f414b6 200 //\r
201 // Assume PE32 image with IA32 Machine field.\r
202 //\r
203 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
204 break;\r
4ab0dff3 205 case IMAGE_FILE_MACHINE_X64:\r
206 case IMAGE_FILE_MACHINE_IA64:\r
e1f414b6 207 //\r
4ab0dff3 208 // Assume PE32+ image with x64 or IA64 Machine field\r
e1f414b6 209 //\r
210 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
211 break;\r
212 default:\r
213 //\r
214 // For unknow Machine field, use Magic in optional Header\r
215 //\r
216 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
217 }\r
218\r
afa22326 219 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
e1f414b6 220 //\r
221 // Use PE32 offset get Debug Directory Entry\r
222 //\r
223 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
224 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
225 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
226 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
227 //\r
228 // Use PE32+ offset get Debug Directory Entry\r
229 //\r
230 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
231 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
232 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
233 }\r
234\r
235 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
236 DirectoryEntry = NULL;\r
237 DebugEntry = NULL;\r
238 }\r
239 } else {\r
240 return NULL;\r
241 }\r
242\r
afa22326 243 if (DebugEntry == NULL || DirectoryEntry == NULL) {\r
e1f414b6 244 return NULL;\r
245 }\r
246\r
38bbd3d9 247 //\r
248 // Scan the directory to find the debug entry.\r
249 // \r
3d7b0992 250 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {\r
2b1532df 251 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
e1f414b6 252 if (DebugEntry->SizeOfData > 0) {\r
253 CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);\r
254 switch (* (UINT32 *) CodeViewEntryPointer) {\r
255 case CODEVIEW_SIGNATURE_NB10:\r
256 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
257 case CODEVIEW_SIGNATURE_RSDS:\r
258 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
ebd04fc2 259 case CODEVIEW_SIGNATURE_MTOC:\r
260 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));\r
e1f414b6 261 default:\r
262 break;\r
263 }\r
264 }\r
265 }\r
266 }\r
267\r
268 return NULL;\r
269}\r
270\r
225290eb
A
271/**\r
272 Returns the size of the PE/COFF headers\r
273\r
274 Returns the size of the PE/COFF header specified by Pe32Data.\r
275 If Pe32Data is NULL, then ASSERT().\r
276\r
2fc59a00 277 @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
225290eb
A
278 memory.\r
279\r
cb6cb44c 280 @return Size of PE/COFF header in bytes or zero if not a valid image.\r
225290eb
A
281\r
282**/\r
42db19ac
A
283UINT32\r
284EFIAPI\r
285PeCoffGetSizeOfHeaders (\r
286 IN VOID *Pe32Data\r
287 )\r
288{\r
289 EFI_IMAGE_DOS_HEADER *DosHdr;\r
290 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
291 UINTN SizeOfHeaders;\r
292\r
225290eb 293 ASSERT (Pe32Data != NULL);\r
42db19ac
A
294 \r
295 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
296 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
297 //\r
298 // DOS image header is present, so read the PE header after the DOS image header.\r
299 //\r
300 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
301 } else {\r
302 //\r
303 // DOS image header is not present, so PE header is at the image base.\r
304 //\r
305 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
306 }\r
307\r
308 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
cb6cb44c 309 SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
42db19ac
A
310 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
311 SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
312 } else {\r
313 SizeOfHeaders = 0;\r
314 }\r
315\r
cded6218 316 return (UINT32) SizeOfHeaders;\r
225290eb 317}\r
e1f414b6 318\r