/**@file Copyright (c) 2006, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent Module Name: PeiNt32PeCoffExtraActionLib.c Abstract: Provides services to perform additional actions to relocate and unload PE/Coff image for NT32 environment specific purpose such as souce level debug. This version only works for PEI phase **/ // // The package level header files this module uses // #include #include // // The protocols, PPI and GUID defintions for this module // #include #include #include #include #include #include #include // // Cache of WinNtThunk protocol // EFI_WIN_NT_THUNK_PROTOCOL *mWinNt = NULL; /** The function caches the pointer of the WinNT thunk functions It will ASSERT() if NT thunk ppi is not installed. @retval EFI_SUCCESS WinNT thunk protocol is found and cached. **/ EFI_STATUS EFIAPI Nt32PeCoffGetWinNtThunkStucture ( ) { PEI_NT_THUNK_PPI *NtThunkPpi; EFI_STATUS Status; // // Locate NtThunkPpi for retrieving standard output handle // Status = PeiServicesLocatePpi ( &gPeiNtThunkPpiGuid, 0, NULL, (VOID **) &NtThunkPpi ); ASSERT_EFI_ERROR (Status); mWinNt = (EFI_WIN_NT_THUNK_PROTOCOL *) NtThunkPpi->NtThunk (); return EFI_SUCCESS; } /** Convert the passed in Ascii string to Unicode. This function Convert the passed in Ascii string to Unicode.Optionally return the length of the strings.. @param AsciiString Pointer to an AscII string @param StrLen Length of string @return Pointer to malloc'ed Unicode version of Ascii **/ CHAR16 * AsciiToUnicode ( IN CHAR8 *Ascii, IN UINTN *StrLen OPTIONAL ) { UINTN Index; CHAR16 *Unicode; // // Allocate a buffer for unicode string // for (Index = 0; Ascii[Index] != '\0'; Index++) ; Unicode = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (), HEAP_ZERO_MEMORY, ((Index + 1) * sizeof (CHAR16)) ); if (Unicode == NULL) { return NULL; } for (Index = 0; Ascii[Index] != '\0'; Index++) { Unicode[Index] = (CHAR16) Ascii[Index]; } Unicode[Index] = '\0'; if (StrLen != NULL) { *StrLen = Index; } return Unicode; } /** Performs additional actions after a PE/COFF image has been loaded and relocated. For NT32, this function load symbols to support source level debugging. If ImageContext is NULL, then ASSERT(). @param ImageContext Pointer to the image context structure that describes the PE/COFF image that has already been loaded and relocated. **/ VOID EFIAPI PeCoffLoaderRelocateImageExtraAction ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { VOID *DllEntryPoint; CHAR16 *DllFileName; HMODULE Library; UINTN Index; ASSERT (ImageContext != NULL); if (mWinNt == NULL) { Nt32PeCoffGetWinNtThunkStucture (); } // // If we load our own PE COFF images the Windows debugger can not source // level debug our code. If a valid PDB pointer exists usw it to load // the *.dll file as a library using Windows* APIs. This allows // source level debug. The image is still loaded and relocated // in the Framework memory space like on a real system (by the code above), // but the entry point points into the DLL loaded by the code bellow. // DllEntryPoint = NULL; // // Load the DLL if it's not an EBC image. // if ((ImageContext->PdbPointer != NULL) && (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) { // // Convert filename from ASCII to Unicode // DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index); // // Check that we have a valid filename // if (Index < 5 || DllFileName[Index - 4] != '.') { mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName); // // Never return an error if PeCoffLoaderRelocateImage() succeeded. // The image will run, but we just can't source level debug. If we // return an error the image will not run. // return; } // // Replace .PDB with .DLL on the filename // DllFileName[Index - 3] = 'D'; DllFileName[Index - 2] = 'L'; DllFileName[Index - 1] = 'L'; // // Load the .DLL file into the user process's address space for source // level debug // Library = mWinNt->LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES); if (Library != NULL) { // // InitializeDriver is the entry point we put in all our EFI DLL's. The // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the // normal DLL entry point of DllMain, and prevents other modules that are // referenced in side the DllFileName from being loaded. There is no error // checking as the we can point to the PE32 image loaded by Tiano. This // step is only needed for source level debugging // DllEntryPoint = (VOID *) (UINTN) mWinNt->GetProcAddress (Library, "InitializeDriver"); } if ((Library != NULL) && (DllEntryPoint != NULL)) { ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint; DEBUG ((EFI_D_INFO, "LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName)); } else { DEBUG ((EFI_D_ERROR, "WARNING: No source level debug %s. \n", DllFileName)); } mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName); } // // Never return an error if PeCoffLoaderRelocateImage() succeeded. // The image will run, but we just can't source level debug. If we // return an error the image will not run. // return; } /** Performs additional actions just before a PE/COFF image is unloaded. Any resources that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed. For NT32, this function unloads symbols for source level debugging. If ImageContext is NULL, then ASSERT(). @param ImageContext Pointer to the image context structure that describes the PE/COFF image that is being unloaded. **/ VOID EFIAPI PeCoffLoaderUnloadImageExtraAction ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { ASSERT (ImageContext != NULL); }