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