From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 610DB740039 for ; Sat, 23 Sep 2023 15:17:06 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=cpU3rKs5aaUx21Zhh6IaFxtCh6apt/P0N21AqF+LFT0=; c=relaxed/simple; d=groups.io; h=MIME-version:Subject:From:In-reply-to:Date:Cc:Message-id:References:To:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-type:Content-transfer-encoding; s=20140610; t=1695482225; v=1; b=JRBve8NePDLPrJ1cOw3uq1S6pxPIXH6m8n3DQrkbfRUHLWuYdphSHSyj3b8AHIfybba61Bf8 eJ2xmbsIRp5n4gxJjjEZzBk3sjxd8eeZb3JSGOoDDwjdNbjz4ZFAGMgMI/td3BKl9nGij6RLiP8 gZRmdXX5clcRXqkDMq5gMnc8= X-Received: by 127.0.0.2 with SMTP id 1wFuYY7687511xbj7BAubuwR; Sat, 23 Sep 2023 08:17:05 -0700 X-Received: from ma-mailsvcp-mx-lapp02.apple.com (ma-mailsvcp-mx-lapp02.apple.com [17.32.222.23]) by mx.groups.io with SMTP id smtpd.web10.22334.1695482224229022428 for ; Sat, 23 Sep 2023 08:17:04 -0700 X-Received: from rn-mailsvcp-mta-lapp03.rno.apple.com (rn-mailsvcp-mta-lapp03.rno.apple.com [10.225.203.151]) by ma-mailsvcp-mx-lapp02.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) with ESMTPS id <0S1G00S7O2GC9G00@ma-mailsvcp-mx-lapp02.apple.com> for devel@edk2.groups.io; Sat, 23 Sep 2023 08:17:03 -0700 (PDT) X-Proofpoint-ORIG-GUID: nY66ZL4wBi0rPz1Zw-xYO0QzIa0TecHC X-Proofpoint-GUID: nY66ZL4wBi0rPz1Zw-xYO0QzIa0TecHC X-Received: from rn-mailsvcp-mmp-lapp03.rno.apple.com (rn-mailsvcp-mmp-lapp03.rno.apple.com [17.179.253.16]) by rn-mailsvcp-mta-lapp03.rno.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) with ESMTPS id <0S1G006TD2GBD200@rn-mailsvcp-mta-lapp03.rno.apple.com>; Sat, 23 Sep 2023 08:16:59 -0700 (PDT) X-Received: from process_milters-daemon.rn-mailsvcp-mmp-lapp03.rno.apple.com by rn-mailsvcp-mmp-lapp03.rno.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) id <0S1G00P001WO1J00@rn-mailsvcp-mmp-lapp03.rno.apple.com>; Sat, 23 Sep 2023 08:16:59 -0700 (PDT) X-Va-A: X-Va-T-CD: e46d62b7dc3f91464ba9fc842ece509f X-Va-E-CD: 403381f92e4754b36d946912c4344d20 X-Va-R-CD: 1faef662c49b79954de570c456e176bf X-Va-ID: 764a8e4d-ec33-4aa0-9ba6-9402e6f2fb40 X-Va-CD: 0 X-V-A: X-V-T-CD: e46d62b7dc3f91464ba9fc842ece509f X-V-E-CD: 403381f92e4754b36d946912c4344d20 X-V-R-CD: 1faef662c49b79954de570c456e176bf X-V-ID: 658ad219-3565-4af0-b66d-380caba83014 X-V-CD: 0 X-Received: from smtpclient.apple (unknown [17.11.108.165]) by rn-mailsvcp-mmp-lapp03.rno.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) with ESMTPSA id <0S1G004622GAHS00@rn-mailsvcp-mmp-lapp03.rno.apple.com>; Sat, 23 Sep 2023 08:16:59 -0700 (PDT) MIME-version: 1.0 (Mac OS X Mail 16.0 \(3731.700.6\)) Subject: Re: [edk2-devel] [PATCH v1] EmulatorPkg: Fix Source Level Debug on Windows From: "Andrew Fish via groups.io" In-reply-to: <20230922224923.1978-1-nathaniel.l.desimone@intel.com> Date: Sat, 23 Sep 2023 08:16:54 -0700 Cc: Ray Ni , Mike Kinney , Chasel Chiu Message-id: References: <20230922224923.1978-1-nathaniel.l.desimone@intel.com> To: edk2-devel-groups-io , "Desimone, Nathaniel L" Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,afish@apple.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: ShLJHRo8054LDNDqaonLwxX0x7686176AA= Content-type: text/plain; charset=us-ascii Content-transfer-encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=JRBve8Ne; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io Very cool. Thank You! Thanks, Andrew Fish > On Sep 22, 2023, at 3:49 PM, Nate DeSimone wrote: >=20 > The Visual Studio Windows debugger will only load symbols for PE/COFF ima= ges > that Windows is aware of. Therefore, to enable source level debugging, al= l > PEI/DXE modules must be loaded via LoadLibrary() or LoadLibraryEx() and t= he > the instance in memory created by LoadLibrary() must be the one that is > actually executed. >=20 > The current source level debug implementation in EmulatorPkg for Windows = is > inherited from the old Nt32Pkg. This implementation makes the assumption = that > all PEI/DXE modules have a DLL export tables with a symbol named > InitializeDriver. Therefore, this source level debug implementation requi= res > all modules to be linked in a non-PI spec defined manner. Support for add= ing > the InitializeDriver symbol was removed in EmulatorPkg, which broke sourc= e > level debugging. >=20 > To fix this, the source level debugging implementation has been modified = to > use the PE/COFF entry point directly. This brings the implementation into > compliance with the PI spec and should work with any PEIM/DXE driver. > Implementing this requires parsing the in-memory instance of the PE/COFF = image > created by Windows to find the entrypoint and since PEIMs/DXE drivers are= not > garunteed to have 4KB aligned sections, it also requires explicit configu= ration > of the page table using VirtualProtect(). >=20 > With this fix, the debugging experience is now so good it is unprecedente= d! > In Visual Studio Code, add the following to launch.json: >=20 > { > "version": "0.2.0", > "configurations": [ > { > "name": "EmulatorPkg Launch", > "type": "cppvsdbg", > "request": "launch", > "program": "${workspaceFolder}//Build/EmulatorX64/DEBU= G_/X64/WinHost", > "args": [], > "stopAtEntry": false, > "cwd": "${workspaceFolder}//Build/EmulatorX64/DEBUG_/X64/", > "environment": [], > "console": false, > } > ] > } >=20 > Make modifications to the above template as nessesary and build EmulatorP= kg. > Now, just add breakpoints directly in Visual Studio Code the way you woul= d with > any other software project. When you start the debugger, it will halt at = the > breakpoint automatically without any extra configuration required. >=20 > Cc: Andrew Fish > Cc: Ray Ni > Cc: Michael D Kinney > Cc: Chasel Chiu > Signed-off-by: Nate DeSimone > --- > EmulatorPkg/Win/Host/WinHost.c | 206 +++++++++++++++++++++++++++++---- > 1 file changed, 182 insertions(+), 24 deletions(-) >=20 > diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHos= t.c > index 193a947fbd..e414da6c55 100644 > --- a/EmulatorPkg/Win/Host/WinHost.c > +++ b/EmulatorPkg/Win/Host/WinHost.c > @@ -8,7 +8,7 @@ > This code produces 128 K of temporary memory for the SEC stack by direct= ly > allocate memory space with ReadWrite and Execute attribute. >=20 > -Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
> +Copyright (c) 2006 - 2023, Intel Corporation. All rights reserved.
> (C) Copyright 2016-2020 Hewlett Packard Enterprise Development LP
> SPDX-License-Identifier: BSD-2-Clause-Patent > **/ > @@ -977,7 +977,7 @@ AddModHandle ( > for (Index =3D 0; Index < mPdbNameModHandleArraySize; Index++, Array++) = { > if (Array->PdbPointer =3D=3D NULL) { > // > - // Make a copy of the stirng and store the ModHandle > + // Make a copy of the string and store the ModHandle > // > Handle =3D GetProcessHeap (); > Size =3D AsciiStrLen (ImageContext->PdbPointer) + 1; > @@ -1056,26 +1056,45 @@ RemoveModHandle ( > return NULL; > } >=20 > +typedef struct { > + UINTN Base; > + UINT32 Size; > + UINT32 Flags; > +} IMAGE_SECTION_DATA; > + > VOID > EFIAPI > PeCoffLoaderRelocateImageExtraAction ( > IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext > ) > { > - EFI_STATUS Status; > - VOID *DllEntryPoint; > - CHAR16 *DllFileName; > - HMODULE Library; > - UINTN Index; > + EFI_STATUS Status; > + VOID *DllEntryPoint; > + CHAR16 *DllFileName; > + HMODULE Library; > + UINTN Index; > + PE_COFF_LOADER_IMAGE_CONTEXT PeCoffImageContext; > + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; > + EFI_IMAGE_SECTION_HEADER *FirstSection; > + EFI_IMAGE_SECTION_HEADER *Section; > + IMAGE_SECTION_DATA *SectionData; > + UINTN NumberOfSections; > + UINTN Base; > + UINTN End; > + UINTN RegionBase; > + UINTN RegionSize; > + UINT32 Flags; > + DWORD NewProtection; > + DWORD OldProtection; >=20 > ASSERT (ImageContext !=3D NULL); > // > - // If we load our own PE COFF images the Windows debugger can not sour= ce > - // level debug our code. If a valid PDB pointer exists use 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 a= bove), > - // but the entry point points into the DLL loaded by the code below. > + // If we load our own PE/COFF images the Windows debugger can not sour= ce > + // level debug our code. If a valid PDB pointer exists use 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 ab= ove), > + // but the entry point points into the DLL loaded by the code below. > // >=20 > DllEntryPoint =3D NULL; > @@ -1106,27 +1125,166 @@ PeCoffLoaderRelocateImageExtraAction ( > } >=20 > // > - // Replace .PDB with .DLL on the filename > + // Replace .PDB with .DLL in the filename > // > DllFileName[Index - 3] =3D 'D'; > DllFileName[Index - 2] =3D 'L'; > DllFileName[Index - 1] =3D 'L'; >=20 > // > - // Load the .DLL file into the user process's address space for sour= ce > - // level debug > + // Load the .DLL file into the process's address space for source le= vel > + // debug. > + // > + // EFI modules use the PE32 entry point for a different purpose than > + // Windows. For Windows DLLs, the PE entry point is used for the Dll= Main() > + // function. DllMain() has a very specific purpose; it initializes r= untime > + // libraries, instance data, and thread local storage. LoadLibrary()= / > + // LoadLibraryEx() will run the PE32 entry point and assume it to be= a > + // DllMain() implementation by default. By passing the > + // DONT_RESOLVE_DLL_REFERENCES argument to LoadLibraryEx(), the exec= ution > + // of the entry point as a DllMain() function will be suppressed. Th= is > + // also prevents other modules that are referenced by the DLL from b= eing > + // loaded. We use LoadLibraryEx() to create a copy of the PE32 > + // image that the OS (and therefore the debugger) is aware of. > + // Source level debugging is the only reason to do this. > // > Library =3D LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFEREN= CES); > if (Library !=3D NULL) { > // > - // InitializeDriver is the entry point we put in all our EFI DLL's= . The > - // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppres= ses the > - // normal DLL entry point of DllMain, and prevents other modules t= hat 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 > + // Parse the PE32 image loaded by the OS and find the entry point > // > - DllEntryPoint =3D (VOID *)(UINTN)GetProcAddress (Library, "Initial= izeDriver"); > + ZeroMem (&PeCoffImageContext, sizeof (PeCoffImageContext)); > + PeCoffImageContext.Handle =3D Library; > + PeCoffImageContext.ImageRead =3D PeCoffLoaderImageReadFromMemory; > + Status =3D PeCoffLoaderGetImageInfo (&PeCoffImageContext); > + if (EFI_ERROR (Status) || (PeCoffImageContext.ImageError !=3D IMAG= E_ERROR_SUCCESS)) { > + SecPrint ("DLL is not a valid PE/COFF image.\n\r"); > + FreeLibrary (Library); > + Library =3D NULL; > + } else { > + Hdr.Pe32 =3D (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Library + (UINTN)= PeCoffImageContext.PeCoffHeaderOffset); > + if (Hdr.Pe32->OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPTIONAL_= HDR32_MAGIC) { > + // > + // Use PE32 offset > + // > + DllEntryPoint =3D (VOID *) ((UINTN)Library + (UINTN)Hdr.Pe32->= OptionalHeader.AddressOfEntryPoint); > + } else { > + // > + // Use PE32+ offset > + // > + DllEntryPoint =3D (VOID *) ((UINTN)Library + (UINTN)Hdr.Pe32Pl= us->OptionalHeader.AddressOfEntryPoint); > + } > + // > + // Now we need to configure memory access for the copy of the PE= 32 image > + // loaded by the OS. > + // > + // Most Windows DLLs are linked with sections 4KB aligned but EF= I > + // modules are not to reduce size. Because of this we need to co= mpute > + // the union of memory access attributes and explicitly configur= e > + // each page. > + // > + FirstSection =3D (EFI_IMAGE_SECTION_HEADER *)( > + (UINTN)Library + > + PeCoffImageContext.PeCoffHea= derOffset + > + sizeof (UINT32) + > + sizeof (EFI_IMAGE_FILE_HEADE= R) + > + Hdr.Pe32->FileHeader.SizeOfO= ptionalHeader > + ); > + NumberOfSections =3D (UINTN)(Hdr.Pe32->FileHeader.NumberOfSectio= ns); > + Section =3D FirstSection; > + SectionData =3D malloc (NumberOfSections * sizeof (IMAGE_SECTION= _DATA)); > + if (SectionData =3D=3D NULL) { > + FreeLibrary (Library); > + Library =3D NULL; > + DllEntryPoint =3D NULL; > + } > + ZeroMem (SectionData, NumberOfSections * sizeof (IMAGE_SECTION_D= ATA)); > + // > + // Extract the section data from the PE32 image > + // > + for (Index =3D 0; Index < NumberOfSections; Index++) { > + SectionData[Index].Base =3D (UINTN)Library + Section->VirtualA= ddress; > + SectionData[Index].Size =3D Section->Misc.VirtualSize; > + if (SectionData[Index].Size =3D=3D 0) { > + SectionData[Index].Size =3D Section->SizeOfRawData; > + } > + SectionData[Index].Flags =3D (Section->Characteristics & > + (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_I= MAGE_SCN_MEM_WRITE)); > + Section +=3D 1; > + } > + // > + // Loop over every DWORD in memory and compute the union of the = memory > + // access bits. > + // > + End =3D (UINTN)Library + (UINTN)PeCoffImageContext.ImageSize; > + RegionBase =3D (UINTN)Library; > + RegionSize =3D 0; > + Flags =3D 0; > + for (Base =3D (UINTN)Library + sizeof (UINT32); Base < End; Base= +=3D sizeof (UINT32)) { > + for (Index =3D 0; Index < NumberOfSections; Index++) { > + if (SectionData[Index].Base <=3D Base && > + (SectionData[Index].Base + SectionData[Index].Size) > Ba= se) { > + Flags |=3D SectionData[Index].Flags; > + } > + } > + // > + // When a new page is reached configure the memory access for = the > + // previous page. > + // > + if (Base % SIZE_4KB =3D=3D 0) { > + RegionSize +=3D SIZE_4KB; > + if ((Flags & EFI_IMAGE_SCN_MEM_WRITE) =3D=3D EFI_IMAGE_SCN_M= EM_WRITE) { > + if ((Flags & EFI_IMAGE_SCN_MEM_EXECUTE) =3D=3D EFI_IMAGE_S= CN_MEM_EXECUTE) { > + NewProtection =3D PAGE_EXECUTE_READWRITE; > + } else { > + NewProtection =3D PAGE_READWRITE; > + } > + } else { > + if ((Flags & EFI_IMAGE_SCN_MEM_EXECUTE) =3D=3D EFI_IMAGE_S= CN_MEM_EXECUTE) { > + NewProtection =3D PAGE_EXECUTE_READ; > + } else { > + NewProtection =3D PAGE_READONLY; > + } > + } > + if (!VirtualProtect ((LPVOID)RegionBase, (SIZE_T) RegionSize= , NewProtection, &OldProtection)) { > + SecPrint ("Setting PE32 Section Access Failed\n\r"); > + FreeLibrary (Library); > + free (SectionData); > + Library =3D NULL; > + DllEntryPoint =3D NULL; > + break; > + } > + Flags =3D 0; > + RegionBase =3D Base; > + RegionSize =3D 0; > + } > + } > + free (SectionData); > + // > + // Configure the last partial page > + // > + if (Library !=3D NULL && (End - RegionBase) > 0) { > + if ((Flags & EFI_IMAGE_SCN_MEM_WRITE) =3D=3D EFI_IMAGE_SCN_MEM= _WRITE) { > + if ((Flags & EFI_IMAGE_SCN_MEM_EXECUTE) =3D=3D EFI_IMAGE_SCN= _MEM_EXECUTE) { > + NewProtection =3D PAGE_EXECUTE_READWRITE; > + } else { > + NewProtection =3D PAGE_READWRITE; > + } > + } else { > + if ((Flags & EFI_IMAGE_SCN_MEM_EXECUTE) =3D=3D EFI_IMAGE_SCN= _MEM_EXECUTE) { > + NewProtection =3D PAGE_EXECUTE_READ; > + } else { > + NewProtection =3D PAGE_READONLY; > + } > + } > + if (!VirtualProtect ((LPVOID)RegionBase, (SIZE_T) (End - Regio= nBase), NewProtection, &OldProtection)) { > + SecPrint ("Setting PE32 Section Access Failed\n\r"); > + FreeLibrary (Library); > + Library =3D NULL; > + DllEntryPoint =3D NULL; > + } > + } > + } > } >=20 > if ((Library !=3D NULL) && (DllEntryPoint !=3D NULL)) { > @@ -1142,7 +1300,7 @@ PeCoffLoaderRelocateImageExtraAction ( > // This DLL is not already loaded, so source level debugging is su= pported. > // > ImageContext->EntryPoint =3D (EFI_PHYSICAL_ADDRESS)(UINTN)DllEntry= Point; > - SecPrint ("LoadLibraryEx (\n\r %S,\n\r NULL, DONT_RESOLVE_DLL_= REFERENCES)\n\r", DllFileName); > + SecPrint ("LoadLibraryEx (\n\r %S,\n\r NULL, DONT_RESOLVE_DLL_= REFERENCES) @ 0x%X\n\r", DllFileName, (int) (UINTN) Library); > } > } else { > SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName); > --=20 > 2.39.2.windows.1 >=20 >=20 >=20 >=20 >=20 >=20 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109025): https://edk2.groups.io/g/devel/message/109025 Mute This Topic: https://groups.io/mt/101531560/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/19134562= 12/xyzzy [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-