@@ -16,6 +16,208 @@ Module Name:
1616--*/
1717
1818#include " uefiext.h"
19+ #include < winnt.h>
20+ #include < vector>
21+ #include < cstring>
22+
23+ VOID
24+ LoadCompositionExtensions (
25+ )
26+ {
27+ static BOOLEAN Loaded = FALSE ;
28+
29+ if (!Loaded) {
30+ dprintf (" Loading target composition extensions.\n " );
31+ g_ExtControl->Execute (
32+ DEBUG_OUTCTL_ALL_CLIENTS,
33+ " .load ELFBinComposition" ,
34+ DEBUG_EXECUTE_DEFAULT
35+ );
36+
37+ //
38+ // TODO: Load additional target composition binaries when completed.
39+ //
40+
41+ Loaded = TRUE ;
42+ }
43+ }
44+
45+ BOOLEAN
46+ ReloadModuleFromPeDebug (
47+ ULONG64 Address
48+ )
49+ {
50+ ULONG BytesRead;
51+ IMAGE_DOS_HEADER DosHeader;
52+ ULONG64 NtHeadersAddr;
53+ IMAGE_NT_HEADERS64 NtHeaders64;
54+ UINT32 DebugDirRVA;
55+ UINT32 DebugDirSize;
56+ UINT32 ImageSize;
57+ ULONG NumEntries;
58+ ULONG64 DebugDirAddr;
59+ std::vector<IMAGE_DEBUG_DIRECTORY> DebugEntries;
60+ ULONG i;
61+ IMAGE_DEBUG_DIRECTORY *Entry;
62+ ULONG64 CvAddr;
63+ CHAR Signature[5 ];
64+ ULONG CvHeaderSize;
65+ ULONG64 PdbPathAddr;
66+ CHAR PdbPath[1024 ];
67+ ULONG SizeToRead;
68+ CHAR *basename;
69+ CHAR *p;
70+ CHAR ModuleName[256 ];
71+ CHAR *dot;
72+ CHAR EfiName[256 ];
73+ CHAR Command[512 ];
74+
75+ BytesRead = 0 ;
76+
77+ // Read DOS header
78+ if (!ReadMemory (Address, &DosHeader, sizeof (DosHeader), &BytesRead) || (BytesRead != sizeof (DosHeader))) {
79+ dprintf (" Failed to read DOS header at %llx\n " , Address);
80+ return false ;
81+ }
82+
83+ if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
84+ dprintf (" Invalid DOS header magic at %llx\n " , Address);
85+ return false ;
86+ }
87+
88+ // Read NT headers
89+ NtHeadersAddr = Address + DosHeader.e_lfanew ;
90+ NtHeaders64 = { 0 };
91+
92+ if (!ReadMemory (NtHeadersAddr, &NtHeaders64, sizeof (NtHeaders64), &BytesRead)) {
93+ dprintf (" Failed to read NT headers at %llx\n " , NtHeadersAddr);
94+ return false ;
95+ }
96+
97+ // Ensure this is a 64-bit optional header
98+ if (NtHeaders64.OptionalHeader .Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
99+ dprintf (" Not a 64-bit PE image at %llx\n " , Address);
100+ return false ;
101+ }
102+
103+ // Determine Debug Directory RVA and size and image size from 64-bit OptionalHeader
104+ DebugDirRVA = NtHeaders64.OptionalHeader .DataDirectory [IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress ;
105+ DebugDirSize = NtHeaders64.OptionalHeader .DataDirectory [IMAGE_DIRECTORY_ENTRY_DEBUG].Size ;
106+ ImageSize = NtHeaders64.OptionalHeader .SizeOfImage ;
107+
108+ if ((DebugDirRVA == 0 ) || (DebugDirSize == 0 )) {
109+ dprintf (" No debug directory in PE image at %llx\n " , Address);
110+ return false ;
111+ }
112+
113+ // Read debug directory entries
114+ NumEntries = DebugDirSize / sizeof (IMAGE_DEBUG_DIRECTORY);
115+ DebugDirAddr = Address + DebugDirRVA;
116+ DebugEntries.resize (NumEntries);
117+ if (!ReadMemory (DebugDirAddr, DebugEntries.data (), DebugDirSize, &BytesRead) || (BytesRead != DebugDirSize)) {
118+ dprintf (" Failed to read debug directory at %llx\n " , DebugDirAddr);
119+ return false ;
120+ }
121+
122+ // Look for CodeView entry
123+ for (i = 0 ; i < NumEntries; i++) {
124+ Entry = &DebugEntries[i];
125+ if (Entry->Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
126+ CvAddr = 0 ;
127+ // If AddressOfRawData appears to be an absolute VA within the loaded image range, use it directly.
128+ if ((Entry->AddressOfRawData != 0 ) && (Entry->AddressOfRawData >= Address) && (Entry->AddressOfRawData < (Address + (ULONG64)NtHeaders64.OptionalHeader .SizeOfImage ))) {
129+ CvAddr = Entry->AddressOfRawData ;
130+ } else if (Entry->AddressOfRawData != 0 ) {
131+ // Treat as relative
132+ CvAddr = Address + Entry->AddressOfRawData ;
133+ } else if (Entry->PointerToRawData != 0 ) {
134+ // Treat PointerToRawData as file offset mapped into memory at image base
135+ CvAddr = Address + Entry->PointerToRawData ;
136+ } else {
137+ dprintf (" Debug entry has no raw data address for %llx\n " , Address);
138+ continue ;
139+ }
140+
141+ // Read the CodeView signature
142+ memset (Signature, 0 , sizeof (Signature));
143+ if (!ReadMemory (CvAddr, Signature, 4 , &BytesRead) || (BytesRead != 4 )) {
144+ continue ;
145+ }
146+
147+ CvHeaderSize = 0 ;
148+ if (strncmp (Signature, " RSDS" , 4 ) == 0 ) {
149+ CvHeaderSize = 24 ;
150+ } else if (strncmp (Signature, " NB10" , 4 ) == 0 ) {
151+ CvHeaderSize = 16 ;
152+ } else {
153+ dprintf (" Unsupported CodeView signature '%c%c%c%c' at %llx\n " , Signature[0 ], Signature[1 ], Signature[2 ], Signature[3 ], CvAddr);
154+ continue ;
155+ }
156+
157+ PdbPathAddr = CvAddr + CvHeaderSize;
158+
159+ // Read PDB path using the size from the debug directory
160+ memset (PdbPath, 0 , sizeof (PdbPath));
161+ if ((Entry->SizeOfData != 0 ) && (Entry->SizeOfData > CvHeaderSize)) {
162+ ULONG64 Rem = Entry->SizeOfData - CvHeaderSize;
163+ SizeToRead = (ULONG)((Rem < (sizeof (PdbPath) - 1 )) ? Rem : (sizeof (PdbPath) - 1 ));
164+ } else {
165+ SizeToRead = (ULONG)(sizeof (PdbPath) - 1 );
166+ }
167+
168+ if (!ReadMemory (PdbPathAddr, PdbPath, SizeToRead, &BytesRead) || (BytesRead == 0 )) {
169+ dprintf (" Failed to read PDB path at %llx (size %lu)\n " , PdbPathAddr, SizeToRead);
170+ continue ;
171+ }
172+
173+ // Ensure null termination even if partial read
174+ PdbPath[(BytesRead < (sizeof (PdbPath) - 1 )) ? BytesRead : (sizeof (PdbPath) - 1 )] = ' \0 ' ;
175+
176+ // Check for the .dll extension. This indicates that this is a GenFW converted module.
177+ // To load symbols for these, we need to load the compositions extensions.
178+ if (strstr (PdbPath, " .dll" ) != NULL ) {
179+ LoadCompositionExtensions ();
180+ }
181+
182+ // Extract the filename from the path
183+ basename = PdbPath;
184+ p = PdbPath;
185+ while (*p) {
186+ if ((*p == ' \\ ' ) || (*p == ' /' )) {
187+ basename = p + 1 ;
188+ }
189+
190+ p++;
191+ }
192+
193+ // Remove extension
194+ memset (ModuleName, 0 , sizeof (ModuleName));
195+ strncpy_s (ModuleName, sizeof (ModuleName), basename, _TRUNCATE);
196+ dot = strrchr (ModuleName, ' .' );
197+ if (dot) {
198+ *dot = ' \0 ' ;
199+ }
200+
201+ // Add a .efi extension, this is needed for the way symbols are resolved
202+ // for GenFW converted modules.
203+ memset (EfiName, 0 , sizeof (EfiName));
204+ sprintf_s (EfiName, sizeof (EfiName), " %s.efi" , ModuleName);
205+
206+ // Build .reload command. Include size if we have one.
207+ if (ImageSize != 0 ) {
208+ sprintf_s (Command, sizeof (Command), " .reload %s=%I64x,%I32x" , EfiName, Address, ImageSize);
209+ } else {
210+ sprintf_s (Command, sizeof (Command), " .reload %s=%I64x" , EfiName, Address);
211+ }
212+
213+ g_ExtControl->Execute (DEBUG_OUTCTL_ALL_CLIENTS, Command, DEBUG_EXECUTE_DEFAULT);
214+ return true ;
215+ }
216+ }
217+
218+ dprintf (" Failed to locate CodeView PDB path at %llx\n " , Address);
219+ return false ;
220+ }
19221
20222HRESULT
21223FindModuleBackwards (
@@ -56,6 +258,15 @@ FindModuleBackwards (
56258 }
57259
58260 if ((Check & 0xFFFF ) == Magic) {
261+ dprintf (" Found PE/COFF image at %llx\n " , Address);
262+ // First try to treat this as a PE/COFF image and reload using debug info (CodeView/PDB)
263+ if (ReloadModuleFromPeDebug (Address)) {
264+ Result = S_OK;
265+ break ;
266+ }
267+
268+ // If that fails, see if imgscan can find it.
269+ dprintf (" Falling back to .imgscan for module at %llx\n " , Address);
59270 sprintf_s (&Command[0 ], sizeof (Command), " .imgscan /l /r %I64x %I64x" , Address, Address + 0xFFF );
60271 g_ExtControl->Execute (
61272 DEBUG_OUTCTL_ALL_CLIENTS,
@@ -66,12 +277,7 @@ FindModuleBackwards (
66277 Result = S_OK;
67278 break ;
68279 } else if (Check == ElfMagic) {
69- sprintf_s (&Command[0 ], sizeof (Command), " !uefiext.elf %I64x" , Address);
70- g_ExtControl->Execute (
71- DEBUG_OUTCTL_ALL_CLIENTS,
72- &Command[0 ],
73- DEBUG_EXECUTE_DEFAULT
74- );
280+ dprintf (" Found ELF image at %llx. ELF images not yet supported.\n " , Address);
75281
76282 Result = S_OK;
77283 break ;
@@ -183,12 +389,15 @@ loadmodules (
183389 }
184390
185391 dprintf (" Loading module at %llx\n " , ImageBase);
186- sprintf_s (Command, sizeof (Command), " .imgscan /l /r %I64x (%I64x + 0xFFF)" , ImageBase, ImageBase);
187- g_ExtControl->Execute (
188- DEBUG_OUTCTL_ALL_CLIENTS,
189- Command,
190- DEBUG_EXECUTE_DEFAULT
191- );
392+ if (!ReloadModuleFromPeDebug (ImageBase)) {
393+ // If ReloadModuleFromPeDebug fails, fall back to .imgscan
394+ sprintf_s (Command, sizeof (Command), " .imgscan /l /r %I64x (%I64x + 0xFFF)" , ImageBase, ImageBase);
395+ g_ExtControl->Execute (
396+ DEBUG_OUTCTL_ALL_CLIENTS,
397+ Command,
398+ DEBUG_EXECUTE_DEFAULT
399+ );
400+ }
192401 }
193402
194403 return S_OK;
0 commit comments