Skip to content

Commit bba6584

Browse files
authored
Switch to use .reload instead of .imgscan (#8)
.reload is more reliable and ensures that the loaded modules are available to composition extensions, which will be necessary to enable GCC built binaries to resolve their symbols. This commit switches use of .imgscan to use .reload, and will opportunistically load the composition extensions if GCC build binaries are detected.
1 parent 173367b commit bba6584

File tree

1 file changed

+221
-12
lines changed

1 file changed

+221
-12
lines changed

UefiDbgExt/modules.cpp

Lines changed: 221 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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

20222
HRESULT
21223
FindModuleBackwards (
@@ -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

Comments
 (0)