Home | History | Annotate | Download | only in BasePeCoffGetEntryPointLib
      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 
    319