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