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