audk/BaseTools/ImageTool/UefiImageScan.c

291 lines
7.9 KiB
C

/** @file
Copyright (c) 2023, Marvin Häuser. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
#include <Uefi/UefiBaseType.h>
#include <Library/UefiImageLib.h>
#include "PeScan.h"
#include "UeScan.h"
static
bool
ScanUefiImageGetHeaderInfo (
OUT image_tool_header_info_t *HeaderInfo,
IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
RETURN_STATUS Status;
UINT64 Address;
HeaderInfo->BaseAddress = UefiImageGetBaseAddress (Context);
HeaderInfo->EntryPointAddress = UefiImageGetEntryPointAddress (Context);
HeaderInfo->Machine = UefiImageGetMachine (Context);
if (HeaderInfo->Machine == 0xFFFF) {
DEBUG_RAISE ();
return false;
}
HeaderInfo->Subsystem = UefiImageGetSubsystem (Context);
Status = UefiImageGetFixedAddress (Context, &Address);
if (!RETURN_ERROR (Status)) {
if (Address != HeaderInfo->BaseAddress) {
fprintf (
stderr,
"ImageTool: Images with a fixed address different from their base address are not supported.\n"
);
return false;
}
HeaderInfo->FixedAddress = true;
} else if (Status != RETURN_NOT_FOUND) {
return false;
}
return true;
}
static
RETURN_STATUS
ScanUefiImageGetRelocInfo (
OUT image_tool_reloc_info_t *RelocInfo,
IN const image_tool_segment_info_t *SegmentInfo,
IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
UINT8 FormatIndex;
FormatIndex = UefiImageGetFormat (Context);
RelocInfo->RelocsStripped = UefiImageGetRelocsStripped (Context);
if (FormatIndex == UefiImageFormatPe) {
return ScanPeGetRelocInfo (RelocInfo, &Context->Ctx.Pe);
}
// LCOV_EXCL_START
if (FormatIndex == UefiImageFormatUe) {
// LCOV_EXCL_STOP
return ScanUeGetRelocInfo (RelocInfo, SegmentInfo, &Context->Ctx.Ue);
}
// LCOV_EXCL_START
fprintf (
stderr,
"ImageTool: Unsupported UefiImage format %u\n",
FormatIndex
);
assert (false);
return RETURN_UNSUPPORTED;
// LCOV_EXCL_STOP
}
static
RETURN_STATUS
ScanUefiImageGetSegmentInfo (
OUT image_tool_segment_info_t *SegmentInfo,
IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
UINT8 FormatIndex;
FormatIndex = UefiImageGetFormat (Context);
SegmentInfo->SegmentAlignment = UefiImageGetSegmentAlignment (Context);
if (FormatIndex == UefiImageFormatPe) {
return ScanPeGetSegmentInfo (SegmentInfo, &Context->Ctx.Pe);
}
// LCOV_EXCL_START
if (FormatIndex == UefiImageFormatUe) {
// LCOV_EXCL_STOP
return ScanUeGetSegmentInfo (SegmentInfo, &Context->Ctx.Ue);
}
// LCOV_EXCL_START
fprintf (
stderr,
"ImageTool: Unsupported UefiImage format %u\n",
FormatIndex
);
assert (false);
return RETURN_UNSUPPORTED;
// LCOV_EXCL_STOP
}
RETURN_STATUS
ScanUefiImageGetDebugInfo (
OUT image_tool_debug_info_t *DebugInfo,
IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
RETURN_STATUS Status;
const CHAR8 *SymbolsPath;
UINT32 SymbolsPathSize;
Status = UefiImageGetSymbolsPath (Context, &SymbolsPath, &SymbolsPathSize);
if (Status == RETURN_NOT_FOUND || Status == RETURN_UNSUPPORTED) {
return RETURN_SUCCESS;
}
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not get SymbolsPath\n");
return Status;
}
assert (SymbolsPathSize >= 1);
DebugInfo->SymbolsPath = AllocateCopyPool (SymbolsPathSize, SymbolsPath);
if (DebugInfo->SymbolsPath == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for SymbolsPath\n");
return RETURN_OUT_OF_RESOURCES;
}
assert (DebugInfo->SymbolsPath[SymbolsPathSize - 1] == '\0');
DebugInfo->SymbolsPathLen = SymbolsPathSize - 1;
return RETURN_SUCCESS;
}
RETURN_STATUS
ScanUefiImageGetHiiInfo (
OUT image_tool_hii_info_t *HiiInfo,
IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
RETURN_STATUS Status;
UINT32 HiiRva;
UINT32 HiiSize;
const char *ImageBuffer;
Status = UefiImageGetHiiDataRva (Context, &HiiRva, &HiiSize);
if (Status == RETURN_NOT_FOUND) {
return RETURN_SUCCESS;
}
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Malformed HII data\n");
return Status;
}
ImageBuffer = (char *)UefiImageLoaderGetImageAddress (Context);
HiiInfo->Data = AllocateCopyPool (HiiSize, ImageBuffer + HiiRva);
if (HiiInfo->Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for HiiInfo Data\n");
return RETURN_OUT_OF_RESOURCES;
}
HiiInfo->DataSize = HiiSize;
return RETURN_SUCCESS;
}
RETURN_STATUS
ToolContextConstructUefiImage (
OUT image_tool_image_info_t *Image,
OUT int8_t *Format,
IN const void *File,
IN uint32_t FileSize
)
{
RETURN_STATUS Status;
UEFI_IMAGE_LOADER_IMAGE_CONTEXT Context;
UINT32 ImageSize;
UINT32 ImageAlignment;
UINT32 DestinationPages;
UINT32 DestinationSize;
void *Destination;
bool Success;
assert (File != NULL || FileSize == 0);
Status = UefiImageInitializeContext (
&Context,
File,
(UINT32)FileSize,
UEFI_IMAGE_SOURCE_FV,
UefiImageOriginFv
);
if (RETURN_ERROR (Status)) {
return Status;
}
*Format = (int8_t)UefiImageGetFormat (&Context);
ImageSize = UefiImageGetImageSize (&Context);
DestinationPages = EFI_SIZE_TO_PAGES (ImageSize);
DestinationSize = EFI_PAGES_TO_SIZE (DestinationPages);
ImageAlignment = UefiImageGetSegmentAlignment (&Context);
Destination = AllocateAlignedCodePages (DestinationPages, ImageAlignment);
if (Destination == NULL) {
fprintf (stderr, "ImageTool: Could not allocate Destination buffer\n");
return RETURN_OUT_OF_RESOURCES;
}
Status = UefiImageLoadImage (&Context, Destination, DestinationSize);
// LCOV_EXCL_START
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not Load Image\n");
FreeAlignedPages (Destination, DestinationPages);
return Status;
}
// LCOV_EXCL_STOP
memset (Image, 0, sizeof (*Image));
Success = ScanUefiImageGetHeaderInfo (&Image->HeaderInfo, &Context);
if (!Success) {
fprintf (stderr, "ImageTool: Could not retrieve header info\n");
ToolImageDestruct (Image);
FreeAlignedPages (Destination, DestinationPages);
return RETURN_VOLUME_CORRUPTED;
}
Status = ScanUefiImageGetSegmentInfo (&Image->SegmentInfo, &Context);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not retrieve segment info\n");
ToolImageDestruct (Image);
FreeAlignedPages (Destination, DestinationPages);
return Status;
}
Status = ScanUefiImageGetRelocInfo (
&Image->RelocInfo,
&Image->SegmentInfo,
&Context
);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not retrieve reloc info\n");
ToolImageDestruct (Image);
FreeAlignedPages (Destination, DestinationPages);
return Status;
}
Status = ScanUefiImageGetHiiInfo (&Image->HiiInfo, &Context);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not retrieve HII info\n");
ToolImageDestruct (Image);
FreeAlignedPages (Destination, DestinationPages);
return Status;
}
Status = ScanUefiImageGetDebugInfo (&Image->DebugInfo, &Context);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not retrieve debug info\n");
ToolImageDestruct (Image);
FreeAlignedPages (Destination, DestinationPages);
return Status;
}
FreeAlignedPages (Destination, DestinationPages);
return RETURN_SUCCESS;
}