]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Library/PeiEmuPeCoffGetEntryPointLib/PeiEmuPeCoffGetEntryPointLib.c
EmulatorPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / Library / PeiEmuPeCoffGetEntryPointLib / PeiEmuPeCoffGetEntryPointLib.c
CommitLineData
949f388f 1/*++ @file\r
2\r
e148512e 3Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
949f388f 4Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>\r
e3ba31da 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
949f388f 6\r
7**/\r
8\r
9#include "PiPei.h"\r
10#include <Library/PeCoffGetEntryPointLib.h>\r
11#include <Library/PeiServicesLib.h>\r
12#include <IndustryStandard/PeImage.h>\r
13#include <Library/DebugLib.h>\r
14\r
15#include <Ppi/EmuThunk.h>\r
16#include <Protocol/EmuThunk.h>\r
17\r
18\r
19\r
20/**\r
21 Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
22 into system memory with the PE/COFF Loader Library functions.\r
23\r
24 Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry\r
25 point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then\r
26 return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.\r
27 If Pe32Data is NULL, then ASSERT().\r
28 If EntryPoint is NULL, then ASSERT().\r
29\r
30 @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
31 @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
32\r
33 @retval RETURN_SUCCESS EntryPoint was returned.\r
34 @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
35\r
36**/\r
37RETURN_STATUS\r
38EFIAPI\r
39PeCoffLoaderGetEntryPoint (\r
40 IN VOID *Pe32Data,\r
41 IN OUT VOID **EntryPoint\r
42 )\r
43{\r
44 EMU_THUNK_PPI *ThunkPpi;\r
45 EFI_STATUS Status;\r
46 EMU_THUNK_PROTOCOL *Thunk;\r
47\r
48 //\r
49 // Locate EmuThunkPpi for retrieving standard output handle\r
50 //\r
51 Status = PeiServicesLocatePpi (\r
52 &gEmuThunkPpiGuid,\r
65e3f333 53 0,\r
949f388f 54 NULL,\r
55 (VOID **) &ThunkPpi\r
56 );\r
57 ASSERT_EFI_ERROR (Status);\r
58\r
59 Thunk = (EMU_THUNK_PROTOCOL *)ThunkPpi->Thunk ();\r
60\r
61 return Thunk->PeCoffGetEntryPoint (Pe32Data, EntryPoint);\r
62}\r
63\r
64/**\r
d18d8a1d 65 Returns the machine type of PE/COFF image.\r
949f388f 66 This is copied from MDE BasePeCoffGetEntryPointLib, the code should be sync with it.\r
67 The reason is Emu package needs to load the image to memory to support source\r
68 level debug.\r
d18d8a1d 69\r
949f388f 70\r
71 @param Pe32Data Pointer to a PE/COFF header\r
72\r
73 @return Machine type or zero if not a valid iamge\r
74\r
75**/\r
76UINT16\r
77EFIAPI\r
78PeCoffLoaderGetMachineType (\r
79 IN VOID *Pe32Data\r
80 )\r
d18d8a1d 81{\r
949f388f 82 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
83 EFI_IMAGE_DOS_HEADER *DosHdr;\r
84\r
85 ASSERT (Pe32Data != NULL);\r
86\r
87 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
88 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
89 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
90\r
91 } else {\r
92 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data);\r
93 }\r
94\r
95 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
96 return Hdr.Te->Machine;\r
97 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
98 return Hdr.Pe32->FileHeader.Machine;\r
99 }\r
100\r
101 return 0x0000;\r
102}\r
103\r
104/**\r
105 Returns a pointer to the PDB file name for a PE/COFF image that has been\r
106 loaded into system memory with the PE/COFF Loader Library functions.\r
107\r
108 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If\r
109 the PE/COFF image specified by Pe32Data is not a valid, then NULL is\r
110 returned. If the PE/COFF image specified by Pe32Data does not contain a\r
111 debug directory entry, then NULL is returned. If the debug directory entry\r
112 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,\r
113 then NULL is returned.\r
114 If Pe32Data is NULL, then ASSERT().\r
115\r
116 @param Pe32Data Pointer to the PE/COFF image that is loaded in system\r
117 memory.\r
118\r
119 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL\r
120 if it cannot be retrieved.\r
121\r
122**/\r
123VOID *\r
124EFIAPI\r
125PeCoffLoaderGetPdbPointer (\r
126 IN VOID *Pe32Data\r
127 )\r
128{\r
129 EFI_IMAGE_DOS_HEADER *DosHdr;\r
130 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
131 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
132 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
133 UINTN DirCount;\r
134 VOID *CodeViewEntryPointer;\r
135 INTN TEImageAdjust;\r
136 UINT32 NumberOfRvaAndSizes;\r
137 UINT16 Magic;\r
138\r
139 ASSERT (Pe32Data != NULL);\r
140\r
141 TEImageAdjust = 0;\r
142 DirectoryEntry = NULL;\r
143 DebugEntry = NULL;\r
144 NumberOfRvaAndSizes = 0;\r
145\r
146 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
147 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
148 //\r
149 // DOS image header is present, so read the PE header after the DOS image header.\r
150 //\r
151 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
152 } else {\r
153 //\r
154 // DOS image header is not present, so PE header is at the image base.\r
155 //\r
156 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
157 }\r
158\r
159 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
160 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
161 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
162 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
163 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +\r
164 Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +\r
165 TEImageAdjust);\r
166 }\r
167 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
168 //\r
169 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.\r
170 // It is due to backward-compatibility, for some system might\r
171 // generate PE32+ image with PE32 Magic.\r
172 //\r
173 switch (Hdr.Pe32->FileHeader.Machine) {\r
174 case EFI_IMAGE_MACHINE_IA32:\r
175 //\r
176 // Assume PE32 image with IA32 Machine field.\r
177 //\r
178 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
179 break;\r
180 case EFI_IMAGE_MACHINE_X64:\r
181 case EFI_IMAGE_MACHINE_IA64:\r
182 //\r
183 // Assume PE32+ image with X64 or IA64 Machine field\r
184 //\r
185 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
186 break;\r
187 default:\r
188 //\r
189 // For unknow Machine field, use Magic in optional Header\r
190 //\r
191 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
192 }\r
193\r
194 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
195 //\r
196 // Use PE32 offset get Debug Directory Entry\r
197 //\r
198 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
199 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
200 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
201 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
202 //\r
203 // Use PE32+ offset get Debug Directory Entry\r
204 //\r
205 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
206 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
207 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
208 }\r
209\r
210 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
211 DirectoryEntry = NULL;\r
212 DebugEntry = NULL;\r
213 }\r
214 } else {\r
215 return NULL;\r
216 }\r
217\r
218 if (DebugEntry == NULL || DirectoryEntry == NULL) {\r
219 return NULL;\r
220 }\r
221\r
222 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {\r
223 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
224 if (DebugEntry->SizeOfData > 0) {\r
225 CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);\r
226 switch (* (UINT32 *) CodeViewEntryPointer) {\r
227 case CODEVIEW_SIGNATURE_NB10:\r
228 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
229 case CODEVIEW_SIGNATURE_RSDS:\r
230 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
231 case CODEVIEW_SIGNATURE_MTOC:\r
232 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));\r
233 default:\r
234 break;\r
235 }\r
236 }\r
237 }\r
238 }\r
239\r
240 return NULL;\r
241}\r
242\r
243\r
244/**\r
245 Returns the size of the PE/COFF headers\r
246\r
247 Returns the size of the PE/COFF header specified by Pe32Data.\r
248 If Pe32Data is NULL, then ASSERT().\r
249\r
250 @param Pe32Data Pointer to the PE/COFF image that is loaded in system\r
251 memory.\r
252\r
253 @return Size of PE/COFF header in bytes or zero if not a valid image.\r
254\r
255**/\r
256UINT32\r
257EFIAPI\r
258PeCoffGetSizeOfHeaders (\r
259 IN VOID *Pe32Data\r
260 )\r
261{\r
262 EFI_IMAGE_DOS_HEADER *DosHdr;\r
263 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
264 UINTN SizeOfHeaders;\r
265\r
266 ASSERT (Pe32Data != NULL);\r
d18d8a1d 267\r
949f388f 268 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
269 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
270 //\r
271 // DOS image header is present, so read the PE header after the DOS image header.\r
272 //\r
273 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
274 } else {\r
275 //\r
276 // DOS image header is not present, so PE header is at the image base.\r
277 //\r
278 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
279 }\r
280\r
281 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
282 SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
283 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
284 SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
285 } else {\r
286 SizeOfHeaders = 0;\r
287 }\r
288\r
e148512e 289 return (UINT32) SizeOfHeaders;\r
949f388f 290}\r
291\r