]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Nt32Pkg/Library/DxeNt32PeCoffExtraActionLib/DxeNt32PeCoffExtraActionLib.c
Remove PeRemove PeiPeCoffLoader.h and gPeiPeCoffLoaderGuid, and Add PeCoffExtraAction...
[mirror_edk2.git] / Nt32Pkg / Library / DxeNt32PeCoffExtraActionLib / DxeNt32PeCoffExtraActionLib.c
diff --git a/Nt32Pkg/Library/DxeNt32PeCoffExtraActionLib/DxeNt32PeCoffExtraActionLib.c b/Nt32Pkg/Library/DxeNt32PeCoffExtraActionLib/DxeNt32PeCoffExtraActionLib.c
new file mode 100644 (file)
index 0000000..24284ba
--- /dev/null
@@ -0,0 +1,380 @@
+/**@file\r
+\r
+Copyright (c) 2006, Intel Corporation\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
+\r
+Module Name:\r
+\r
+  PeiNt32PeCoffExtraActionLib.c\r
+\r
+Abstract:\r
+\r
+  Provides services to perform additional actions to relocate and unload\r
+  PE/Coff image for NT32 environment specific purpose such as souce level debug.\r
+  This version only works for DXE phase  \r
+\r
+\r
+**/\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <FrameworkDxe.h>\r
+#include <FrameworkModuleDxe.h>\r
+#include <WinNtDxe.h>\r
+\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/WinNtThunk.h>\r
+\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeCoffExtraActionLib.h>\r
+\r
+#define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100\r
+\r
+typedef struct {\r
+  CHAR8   *PdbPointer;\r
+  VOID    *ModHandle;\r
+} PDB_NAME_TO_MOD_HANDLE;\r
+\r
+\r
+//\r
+// Cache of WinNtThunk protocol\r
+//\r
+EFI_WIN_NT_THUNK_PROTOCOL   *mWinNt = NULL;\r
+\r
+//\r
+// An Array to hold the ModHandle\r
+//\r
+PDB_NAME_TO_MOD_HANDLE  *mPdbNameModHandleArray = NULL;\r
+UINTN                   mPdbNameModHandleArraySize = 0;\r
+\r
+\r
+/**\r
+  The constructor function gets  the pointer of the WinNT thunk functions\r
+  It will ASSERT() if NT thunk protocol is not installed.\r
+\r
+  @retval EFI_SUCCESS   WinNT thunk protocol is found and cached.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeNt32PeCoffLibExtraActionConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+       EFI_HOB_GUID_TYPE   *GuidHob;\r
+\r
+  //\r
+  // Retrieve WinNtThunkProtocol from GUID'ed HOB\r
+  //\r
+  GuidHob = GetFirstGuidHob (&gEfiWinNtThunkProtocolGuid);\r
+  ASSERT (GuidHob != NULL);\r
+  mWinNt = (EFI_WIN_NT_THUNK_PROTOCOL *)(*(UINTN *)(GET_GUID_HOB_DATA (GuidHob)));\r
+  ASSERT (mWinNt != NULL);\r
+\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Convert the passed in Ascii string to Unicode.\r
+  \r
+  This function  Convert the passed in Ascii string to Unicode.Optionally return\r
+   the length of the strings..\r
+\r
+  @param  AsciiString    Pointer to an AscII string\r
+  @param  StrLen         Length of string\r
+\r
+  @return  Pointer to malloc'ed Unicode version of Ascii\r
+\r
+**/\r
+CHAR16 *\r
+AsciiToUnicode (\r
+  IN  CHAR8   *Ascii,\r
+  IN  UINTN   *StrLen OPTIONAL\r
+  )\r
+{\r
+  UINTN   Index;\r
+  CHAR16  *Unicode;\r
+\r
+  //\r
+  // Allocate a buffer for unicode string\r
+  //\r
+  for (Index = 0; Ascii[Index] != '\0'; Index++)\r
+    ;\r
+  Unicode = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
+                                HEAP_ZERO_MEMORY,\r
+                                ((Index + 1) * sizeof (CHAR16))\r
+                               ); \r
+  if (Unicode == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
+    Unicode[Index] = (CHAR16) Ascii[Index];\r
+  }\r
+\r
+  Unicode[Index] = '\0';\r
+\r
+  if (StrLen != NULL) {\r
+    *StrLen = Index;\r
+  }\r
+\r
+  return Unicode;\r
+}\r
+/**\r
+  Store the ModHandle in an array indexed by the Pdb File name.\r
+  The ModHandle is needed to unload the image. \r
+\r
+\r
+  @param ImageContext - Input data returned from PE Laoder Library. Used to find the \r
+                 .PDB file name of the PE Image.\r
+  @param ModHandle    - Returned from LoadLibraryEx() and stored for call to \r
+                 FreeLibrary().\r
+\r
+  @return   return EFI_SUCCESS when ModHandle was stored. \r
+\r
+--*/\r
+EFI_STATUS\r
+AddModHandle (\r
+  IN  PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext,\r
+  IN  VOID                                 *ModHandle\r
+  )\r
+\r
+{\r
+  UINTN                   Index;\r
+  PDB_NAME_TO_MOD_HANDLE  *Array;\r
+  UINTN                   PreviousSize;\r
+  PDB_NAME_TO_MOD_HANDLE  *TempArray;\r
+\r
+  Array = mPdbNameModHandleArray;\r
+  for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+    if (Array->PdbPointer == NULL) {\r
+      //\r
+      // Make a copy of the stirng and store the ModHandle\r
+      //\r
+      Array->PdbPointer = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
+                                HEAP_ZERO_MEMORY,\r
+                                AsciiStrLen (ImageContext->PdbPointer) + 1\r
+                               ); \r
+                               \r
+      ASSERT (Array->PdbPointer != NULL);\r
+\r
+      AsciiStrCpy (Array->PdbPointer, ImageContext->PdbPointer);\r
+      Array->ModHandle = ModHandle;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // No free space in mPdbNameModHandleArray so grow it by \r
+  // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires. \r
+  //\r
+  PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);\r
+  mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;\r
+  //\r
+  // re-allocate a new buffer and copy the old values to the new locaiton. \r
+  //\r
+  TempArray = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
+                                HEAP_ZERO_MEMORY,\r
+                                mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)\r
+                               ); \r
\r
+  CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize);\r
+  \r
+  mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, mPdbNameModHandleArray);\r
+  \r
+  mPdbNameModHandleArray = TempArray;\r
+  if (mPdbNameModHandleArray == NULL) {\r
+    ASSERT (FALSE);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  \r
+  return AddModHandle (ImageContext, ModHandle);\r
+}\r
+/**\r
+  Return the ModHandle and delete the entry in the array.\r
+\r
+\r
+   @param  ImageContext - Input data returned from PE Laoder Library. Used to find the \r
+                 .PDB file name of the PE Image.\r
+\r
+  @return   \r
+    ModHandle - ModHandle assoicated with ImageContext is returned\r
+    NULL      - No ModHandle associated with ImageContext\r
+\r
+**/\r
+VOID *\r
+RemoveModeHandle (\r
+  IN  PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext\r
+  )\r
+{\r
+  UINTN                   Index;\r
+  PDB_NAME_TO_MOD_HANDLE  *Array;\r
+\r
+  if (ImageContext->PdbPointer == NULL) {\r
+    //\r
+    // If no PDB pointer there is no ModHandle so return NULL\r
+    //\r
+    return NULL;\r
+  }\r
+\r
+  Array = mPdbNameModHandleArray;\r
+  for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+    if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {\r
+      //\r
+      // If you find a match return it and delete the entry\r
+      //\r
+      mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, Array->PdbPointer);\r
+      Array->PdbPointer = NULL;\r
+      return Array->ModHandle;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Applies additional actions to relocate fixups to a PE/COFF image.\r
+\r
+  Generally this function is called after sucessfully Applying relocation fixups \r
+  to a PE/COFF image for some specicial purpose. \r
+  As a example, For NT32 emulator, the function should be implemented and called\r
+  to support source level debug.  \r
+  \r
+  @param  ImageContext        Pointer to the image context structure that describes the PE/COFF\r
+                              image that is being relocated.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderRelocateImageExtraAction (\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
+{\r
+  VOID              *DllEntryPoint;\r
+  CHAR16            *DllFileName;\r
+  HMODULE           Library;\r
+  UINTN             Index;\r
+  \r
+       //\r
+  // If we load our own PE COFF images the Windows debugger can not source\r
+  //  level debug our code. If a valid PDB pointer exists usw it to load\r
+  //  the *.dll file as a library using Windows* APIs. This allows \r
+  //  source level debug. The image is still loaded and reloaced\r
+  //  in the Framework memory space like on a real system (by the code above),\r
+  //  but the entry point points into the DLL loaded by the code bellow. \r
+  //\r
+\r
+  DllEntryPoint = NULL;\r
+\r
+  //\r
+  // Load the DLL if it's not an EBC image.\r
+  //\r
+  if ((ImageContext->PdbPointer != NULL) &&\r
+      (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
+    //\r
+    // Convert filename from ASCII to Unicode\r
+    //\r
+    DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);\r
+\r
+    //\r
+    // Check that we have a valid filename\r
+    //\r
+    if (Index < 5 || DllFileName[Index - 4] != '.') {\r
+      mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);\r
+\r
+      //\r
+      // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
+      // The image will run, but we just can't source level debug. If we\r
+      // return an error the image will not run.\r
+      //\r
+      return;\r
+    }\r
+    //\r
+    // Replace .PDB with .DLL on the filename\r
+    //\r
+    DllFileName[Index - 3]  = 'D';\r
+    DllFileName[Index - 2]  = 'L';\r
+    DllFileName[Index - 1]  = 'L';\r
+\r
+    //\r
+    // Load the .DLL file into the user process's address space for source \r
+    // level debug\r
+    //\r
+    Library = mWinNt->LoadLibraryEx  (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);\r
+    if (Library != NULL) {\r
+      //\r
+      // InitializeDriver is the entry point we put in all our EFI DLL's. The\r
+      // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the \r
+      // normal DLL entry point of DllMain, and prevents other modules that are\r
+      // referenced in side the DllFileName from being loaded. There is no error \r
+      // checking as the we can point to the PE32 image loaded by Tiano. This \r
+      // step is only needed for source level debuging\r
+      //\r
+      DllEntryPoint = (VOID *) (UINTN) mWinNt->GetProcAddress (Library, "InitializeDriver");\r
+\r
+    }\r
+\r
+    if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
+      AddModHandle (ImageContext, Library);\r
+      ImageContext->EntryPoint  = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
+      DEBUG ((EFI_D_INFO, "LoadLibraryEx (%s,\n               NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName));\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "WARNING: No source level debug %s. \n", DllFileName));\r
+    }\r
+\r
+    mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);\r
+  }\r
+\r
+  //\r
+  // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
+  // The image will run, but we just can't source level debug. If we\r
+  // return an error the image will not run.\r
+  //\r
+  return;\r
+}  \r
+\r
+/**\r
+  Unloads a loaded PE/COFF image from memory and releases its taken resource.\r
+  \r
+  Releases any environment specific resources that were allocated when the image \r
+  specified by ImageContext was loaded using PeCoffLoaderLoadImage(). \r
+  For NT32 emulator, the PE/COFF image loaded by system needs to release.\r
+  For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded, \r
+  \r
+  If ImageContext is NULL, then ASSERT().\r
+  \r
+  @param  ImageContext              Pointer to the image context structure that describes the PE/COFF\r
+                                    image to be unloaded.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderUnloadImageExtraAction (\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
+{\r
+       VOID *ModHandle;\r
+\r
+  ModHandle = RemoveModeHandle (ImageContext);\r
+  if (ModHandle != NULL) {\r
+    mWinNt->FreeLibrary (ModHandle);\r
+  }\r
+  return;\r
+}
\ No newline at end of file