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