/** @file\r
- Provides the services to get the entry point to a PE/COFF image that has either been \r
+ Provides the services to get the entry point to a PE/COFF image that has either been\r
loaded into memory or is executing at it's linked address.\r
\r
- Copyright (c) 2006 - 2008, Intel Corporation<BR>\r
- Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>\r
- All rights reserved. This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
-\r
#include <Base.h>\r
\r
#include <Library/PeCoffGetEntryPointLib.h>\r
\r
#include <IndustryStandard/PeImage.h>\r
\r
+#define PE_COFF_IMAGE_ALIGN_SIZE 4\r
+\r
/**\r
Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded\r
into system memory with the PE/COFF Loader Library functions.\r
If Pe32Data is NULL, then ASSERT().\r
If EntryPoint is NULL, then ASSERT().\r
\r
- @param Pe32Data Pointer to the PE/COFF image that is loaded in system memory.\r
- @param EntryPoint Pointer to entry point to the PE/COFF image to return.\r
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.\r
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.\r
\r
@retval RETURN_SUCCESS EntryPoint was returned.\r
@retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.\r
OUT VOID **EntryPoint\r
)\r
{\r
- EFI_IMAGE_DOS_HEADER *DosHdr;\r
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
\r
ASSERT (Pe32Data != NULL);\r
ASSERT (EntryPoint != NULL);\r
//\r
// DOS image header is present, so read the PE header after the DOS image header.\r
//\r
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));\r
} else {\r
//\r
// DOS image header is not present, so PE header is at the image base.\r
// AddressOfEntryPoint is common for PE32 & PE32+\r
//\r
if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
- *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
+ *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
return RETURN_SUCCESS;\r
} else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
*EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));\r
return RETURN_UNSUPPORTED;\r
}\r
\r
-\r
/**\r
Returns the machine type of a PE/COFF image.\r
\r
Returns the machine type from the PE/COFF image specified by Pe32Data.\r
If Pe32Data is NULL, then ASSERT().\r
\r
- @param Pe32Data Pointer to the PE/COFF image that is loaded in system\r
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
memory.\r
\r
- @return Machine type or zero if not a valid iamge.\r
+ @return Machine type or zero if not a valid image.\r
\r
**/\r
UINT16\r
//\r
// DOS image header is present, so read the PE header after the DOS image header.\r
//\r
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));\r
} else {\r
//\r
// DOS image header is not present, so PE header is at the image base.\r
\r
if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
return Hdr.Te->Machine;\r
- } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
return Hdr.Pe32->FileHeader.Machine;\r
}\r
\r
\r
/**\r
Returns a pointer to the PDB file name for a PE/COFF image that has been\r
- loaded into system memory with the PE/COFF Loader Library functions. \r
+ loaded into system memory with the PE/COFF Loader Library functions.\r
\r
Returns the PDB file name for the PE/COFF image specified by Pe32Data. If\r
the PE/COFF image specified by Pe32Data is not a valid, then NULL is\r
then NULL is returned.\r
If Pe32Data is NULL, then ASSERT().\r
\r
- @param Pe32Data Pointer to the PE/COFF image that is loaded in system\r
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
memory.\r
\r
@return The PDB file name for the PE/COFF image specified by Pe32Data or NULL\r
IN VOID *Pe32Data\r
)\r
{\r
- EFI_IMAGE_DOS_HEADER *DosHdr;\r
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
- EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
- EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
- UINTN DirCount;\r
- VOID *CodeViewEntryPointer;\r
- INTN TEImageAdjust;\r
- UINT32 NumberOfRvaAndSizes;\r
- UINT16 Magic;\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
+ UINTN DirCount;\r
+ VOID *CodeViewEntryPointer;\r
+ INTN TEImageAdjust;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ UINT16 Magic;\r
\r
ASSERT (Pe32Data != NULL);\r
\r
//\r
// DOS image header is present, so read the PE header after the DOS image header.\r
//\r
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));\r
} else {\r
//\r
// DOS image header is not present, so PE header is at the image base.\r
\r
if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
- DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
- TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
- DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +\r
- Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +\r
- TEImageAdjust);\r
+ DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
+ TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
+ DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Hdr.Te +\r
+ Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +\r
+ TEImageAdjust);\r
}\r
} else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
//\r
// generate PE32+ image with PE32 Magic.\r
//\r
switch (Hdr.Pe32->FileHeader.Machine) {\r
- case IMAGE_FILE_MACHINE_I386:\r
- //\r
- // Assume PE32 image with IA32 Machine field.\r
- //\r
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
- break;\r
- case IMAGE_FILE_MACHINE_X64:\r
- case IMAGE_FILE_MACHINE_IA64:\r
- //\r
- // Assume PE32+ image with x64 or IA64 Machine field\r
- //\r
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
- break;\r
- default:\r
- //\r
- // For unknow Machine field, use Magic in optional Header\r
- //\r
- Magic = Hdr.Pe32->OptionalHeader.Magic;\r
+ case IMAGE_FILE_MACHINE_I386:\r
+ //\r
+ // Assume PE32 image with IA32 Machine field.\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
+ break;\r
+ case IMAGE_FILE_MACHINE_X64:\r
+ case IMAGE_FILE_MACHINE_IA64:\r
+ //\r
+ // Assume PE32+ image with x64 or IA64 Machine field\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ break;\r
+ default:\r
+ //\r
+ // For unknow Machine field, use Magic in optional Header\r
+ //\r
+ Magic = Hdr.Pe32->OptionalHeader.Magic;\r
}\r
\r
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
// Use PE32 offset get Debug Directory Entry\r
//\r
NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
- DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+ DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Pe32Data + DirectoryEntry->VirtualAddress);\r
} else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
//\r
// Use PE32+ offset get Debug Directory Entry\r
//\r
NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
- DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+ DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Pe32Data + DirectoryEntry->VirtualAddress);\r
}\r
\r
if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
DirectoryEntry = NULL;\r
- DebugEntry = NULL;\r
+ DebugEntry = NULL;\r
}\r
} else {\r
return NULL;\r
}\r
\r
- if (DebugEntry == NULL || DirectoryEntry == NULL) {\r
+ if ((DebugEntry == NULL) || (DirectoryEntry == NULL)) {\r
return NULL;\r
}\r
\r
//\r
// Scan the directory to find the debug entry.\r
- // \r
+ //\r
for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {\r
if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
if (DebugEntry->SizeOfData > 0) {\r
- CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);\r
- switch (* (UINT32 *) CodeViewEntryPointer) {\r
- case CODEVIEW_SIGNATURE_NB10:\r
- return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
- case CODEVIEW_SIGNATURE_RSDS:\r
- return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
- case CODEVIEW_SIGNATURE_MTOC:\r
- return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));\r
- default:\r
- break;\r
+ CodeViewEntryPointer = (VOID *)((UINTN)DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);\r
+ switch (*(UINT32 *)CodeViewEntryPointer) {\r
+ case CODEVIEW_SIGNATURE_NB10:\r
+ return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
+ case CODEVIEW_SIGNATURE_RSDS:\r
+ return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
+ case CODEVIEW_SIGNATURE_MTOC:\r
+ return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));\r
+ default:\r
+ break;\r
}\r
}\r
}\r
return NULL;\r
}\r
\r
+/**\r
+ Returns the size of the PE/COFF headers\r
+\r
+ Returns the size of the PE/COFF header specified by Pe32Data.\r
+ If Pe32Data is NULL, then ASSERT().\r
+\r
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system\r
+ memory.\r
+\r
+ @return Size of PE/COFF header in bytes or zero if not a valid image.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+PeCoffGetSizeOfHeaders (\r
+ IN VOID *Pe32Data\r
+ )\r
+{\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ UINTN SizeOfHeaders;\r
+\r
+ ASSERT (Pe32Data != NULL);\r
+\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+ //\r
+ // DOS image header is present, so read the PE header after the DOS image header.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));\r
+ } else {\r
+ //\r
+ // DOS image header is not present, so PE header is at the image base.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
+ }\r
+\r
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+ SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+ SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
+ } else {\r
+ SizeOfHeaders = 0;\r
+ }\r
+\r
+ return (UINT32)SizeOfHeaders;\r
+}\r
+\r
+/**\r
+ Returns PE/COFF image base is loaded in system memory where the input address is in.\r
+\r
+ On DEBUG build, searches the PE/COFF image base forward the input address and\r
+ returns it.\r
+\r
+ @param Address Address located in one PE/COFF image.\r
+\r
+ @retval 0 RELEASE build or cannot find the PE/COFF image base.\r
+ @retval others PE/COFF image base found.\r
\r
+**/\r
+UINTN\r
+EFIAPI\r
+PeCoffSearchImageBase (\r
+ IN UINTN Address\r
+ )\r
+{\r
+ UINTN Pe32Data;\r
+\r
+ Pe32Data = 0;\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+\r
+ //\r
+ // Find Image Base\r
+ //\r
+ Pe32Data = Address & ~(PE_COFF_IMAGE_ALIGN_SIZE - 1);\r
+ while (Pe32Data != 0) {\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+ //\r
+ // DOS image header is present, so read the PE header after the DOS image header.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));\r
+ //\r
+ // Make sure PE header address does not overflow and is less than the initial address.\r
+ //\r
+ if (((UINTN)Hdr.Pe32 > Pe32Data) && ((UINTN)Hdr.Pe32 < Address)) {\r
+ if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+ break;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // DOS image header is not present, TE header is at the image base.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
+ if ((Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) &&\r
+ ((Hdr.Te->Machine == IMAGE_FILE_MACHINE_I386) || (Hdr.Te->Machine == IMAGE_FILE_MACHINE_IA64) ||\r
+ (Hdr.Te->Machine == IMAGE_FILE_MACHINE_EBC) || (Hdr.Te->Machine == IMAGE_FILE_MACHINE_X64) ||\r
+ (Hdr.Te->Machine == IMAGE_FILE_MACHINE_ARM64) || (Hdr.Te->Machine == IMAGE_FILE_MACHINE_ARMTHUMB_MIXED))\r
+ )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Not found the image base, check the previous aligned address\r
+ //\r
+ Pe32Data -= PE_COFF_IMAGE_ALIGN_SIZE;\r
+ }\r
+\r
+ DEBUG_CODE_END ();\r
+\r
+ return Pe32Data;\r
+}\r