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