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