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