1 /*++ 2 3 Copyright (c) 2004 - 2006, 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 13 Module Name: 14 15 PeCoffGetEntryPoint.c 16 17 Abstract: 18 19 Pe/Coff loader 20 21 --*/ 22 23 #include "EdkIIGlueBase.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 Pointer to the PE/COFF image that is loaded in system memory. 36 @param EntryPoint 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 *DosHeader; 50 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Header; 51 52 ASSERT (Pe32Data != NULL); 53 ASSERT (EntryPoint != NULL); 54 55 DosHeader = (EFI_IMAGE_DOS_HEADER *)Pe32Data; 56 if (DosHeader->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 Header.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHeader->e_lfanew) & 0x0ffff)); 61 } else { 62 // 63 // DOS image header is not present, so PE header is at the image base. 64 // 65 Header.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 *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Header.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff)); 73 return RETURN_SUCCESS; 74 } 75 76 77 /** 78 Returns the machine type of a PE/COFF image. 79 80 Returns the machine type from the PE/COFF image specified by Pe32Data. 81 If Pe32Data is NULL, then ASSERT(). 82 83 @param Pe32Data Pointer to the PE/COFF image that is loaded in system 84 memory. 85 86 @return Machine type or zero if not a valid iamge. 87 88 **/ 89 UINT16 90 EFIAPI 91 PeCoffLoaderGetMachineType ( 92 IN VOID *Pe32Data 93 ) 94 { 95 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; 96 EFI_IMAGE_DOS_HEADER *DosHdr; 97 98 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; 99 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { 100 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + DosHdr->e_lfanew); 101 } else { 102 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data); 103 } 104 105 if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { 106 return Hdr.Pe32->FileHeader.Machine; 107 } 108 109 return 0x0000; 110 } 111 112 /** 113 Returns a pointer to the PDB file name for a PE/COFF image that has been 114 loaded into system memory with the PE/COFF Loader Library functions. 115 116 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If 117 the PE/COFF image specified by Pe32Data is not a valid, then NULL is 118 returned. If the PE/COFF image specified by Pe32Data does not contain a 119 debug directory entry, then NULL is returned. If the debug directory entry 120 in the PE/COFF image specified by Pe32Data does not contain a PDB file name, 121 then NULL is returned. 122 If Pe32Data is NULL, then ASSERT(). 123 124 @param Pe32Data Pointer to the PE/COFF image that is loaded in system 125 memory. 126 127 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL 128 if it cannot be retrieved. 129 130 **/ 131 VOID * 132 EFIAPI 133 PeCoffLoaderGetPdbPointer ( 134 IN VOID *Pe32Data 135 ) 136 { 137 EFI_IMAGE_DOS_HEADER *DosHeader; 138 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; 139 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; 140 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; 141 UINTN DirCount; 142 VOID *CodeViewEntryPointer; 143 INTN TEImageAdjust; 144 UINT32 NumberOfRvaAndSizes; 145 146 ASSERT (Pe32Data != NULL); 147 148 TEImageAdjust = 0; 149 DirectoryEntry = NULL; 150 DebugEntry = NULL; 151 NumberOfRvaAndSizes = 0; 152 153 DosHeader = (EFI_IMAGE_DOS_HEADER *)Pe32Data; 154 if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) { 155 // 156 // DOS image header is present, so read the PE header after the DOS image header. 157 // 158 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHeader->e_lfanew) & 0x0ffff)); 159 } else { 160 // 161 // DOS image header is not present, so PE header is at the image base. 162 // 163 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; 164 } 165 166 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { 167 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) { 168 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG]; 169 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; 170 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te + 171 Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress + 172 TEImageAdjust); 173 } 174 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { 175 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 176 // 177 // Use PE32 offset get Debug Directory Entry 178 // 179 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; 180 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); 181 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress); 182 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { 183 // 184 // Use PE32+ offset get Debug Directory Entry 185 // 186 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; 187 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); 188 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress); 189 } 190 191 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { 192 DirectoryEntry = NULL; 193 DebugEntry = NULL; 194 } 195 } else { 196 return NULL; 197 } 198 199 if (DebugEntry == NULL || DirectoryEntry == NULL) { 200 return NULL; 201 } 202 203 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount++, DebugEntry++) { 204 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { 205 if (DebugEntry->SizeOfData > 0) { 206 CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust); 207 switch (* (UINT32 *) CodeViewEntryPointer) { 208 case CODEVIEW_SIGNATURE_NB10: 209 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)); 210 case CODEVIEW_SIGNATURE_RSDS: 211 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)); 212 default: 213 break; 214 } 215 } 216 } 217 } 218 219 return NULL; 220 } 221 222 223