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