Skip to content

Commit 98f742d

Browse files
committed
Add !findall Support for Rust
This patch adds !findall support for Rust. In addition, it removes the !loadmodules export as that is wrapped by !findall. Finally, it also updates the ARM64 PT parsing code to mark when a page has the access flag set.
1 parent d207a24 commit 98f742d

File tree

7 files changed

+412
-73
lines changed

7 files changed

+412
-73
lines changed

UefiDbgExt/dbgexts.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Module Name:
1717
#include <string>
1818
#include <vector>
1919

20+
#include "uefispec.h"
21+
2022
//
2123
// Define KDEXT_64BIT to make all wdbgexts APIs recognize 64 bit addresses
2224
// It is recommended for extensions to use 64 bit headers from wdbgexts so

UefiDbgExt/modules.cpp

Lines changed: 163 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -81,77 +81,108 @@ FindModuleBackwards (
8181
return Result;
8282
}
8383

84-
HRESULT CALLBACK
84+
HRESULT
8585
loadmodules (
86-
PDEBUG_CLIENT4 Client,
87-
PCSTR args
86+
ULONG64 SystemTableAddr
8887
)
8988
{
90-
ULONG64 HeaderAddress;
91-
UINT32 TableSize;
92-
ULONG64 Table;
93-
ULONG64 Entry;
94-
ULONG64 NormalImage;
95-
ULONG64 ImageProtocol;
96-
UINT64 ImageBase;
97-
ULONG Index;
98-
CHAR Command[512];
99-
ULONG64 Base;
100-
101-
INIT_API ();
102-
103-
UNREFERENCED_PARAMETER (args);
89+
UINT32 TableSize;
90+
ULONG64 Table;
91+
EFI_DEBUG_IMAGE_INFO *Entry;
92+
EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage;
93+
EFI_LOADED_IMAGE_PROTOCOL *ImageProtocol;
94+
UINT64 ImageBase;
95+
ULONG Index;
96+
CHAR Command[512];
97+
ULONG64 Base;
98+
ULONG BytesRead = 0;
10499

105100
//
106101
// TODO: Add support for PEI & MM
107102
//
108103

109-
if (gUefiEnv != DXE) {
110-
dprintf ("Only supported for DXE!\n");
111-
return ERROR_NOT_SUPPORTED;
104+
EFI_SYSTEM_TABLE SystemTable;
105+
EFI_CONFIGURATION_TABLE *ConfigTable;
106+
GUID DebugImageInfoTableGuid = EFI_DEBUG_IMAGE_INFO_TABLE_GUID;
107+
EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageInfoTableHeader = NULL;
108+
109+
// Read the EFI_SYSTEM_TABLE structure from the provided address
110+
if (!ReadMemory (SystemTableAddr, &SystemTable, sizeof (SystemTable), &BytesRead) || (BytesRead != sizeof (SystemTable))) {
111+
dprintf ("Failed to read EFI_SYSTEM_TABLE at %llx\n", SystemTableAddr);
112+
return ERROR_NOT_FOUND;
112113
}
113114

114-
HeaderAddress = GetExpression ("&mDebugInfoTableHeader");
115-
if (HeaderAddress == NULL) {
116-
dprintf ("Failed to find mDebugInfoTableHeader!\n");
115+
// Iterate through the configuration tables to find the debug image info table
116+
ConfigTable = SystemTable.ConfigurationTable;
117+
for (UINT64 i = 0; i < SystemTable.NumberOfTableEntries; i++) {
118+
EFI_CONFIGURATION_TABLE CurrentTable;
119+
if (!ReadMemory ((ULONG64)&ConfigTable[i], &CurrentTable, sizeof (CurrentTable), &BytesRead) || (BytesRead != sizeof (CurrentTable))) {
120+
dprintf ("Failed to read configuration table entry at index %llu\n", i);
121+
continue;
122+
}
123+
124+
if (memcmp (&CurrentTable.VendorGuid, &DebugImageInfoTableGuid, sizeof (GUID)) == 0) {
125+
DebugImageInfoTableHeader = (EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *)CurrentTable.VendorTable;
126+
break;
127+
}
128+
}
129+
130+
if (DebugImageInfoTableHeader == NULL) {
131+
dprintf ("Failed to locate EFI_DEBUG_IMAGE_INFO_TABLE_HEADER in configuration tables\n");
117132
return ERROR_NOT_FOUND;
118133
}
119134

120-
GetFieldValue (HeaderAddress, "EFI_DEBUG_IMAGE_INFO_TABLE_HEADER", "TableSize", TableSize);
121-
GetFieldValue (HeaderAddress, "EFI_DEBUG_IMAGE_INFO_TABLE_HEADER", "EfiDebugImageInfoTable", Table);
122-
if ((Table == NULL) || (TableSize == 0)) {
123-
dprintf ("Debug table is empty!\n");
135+
// Read the debug image info table header
136+
if (!ReadMemory ((ULONG64)&DebugImageInfoTableHeader->TableSize, &TableSize, sizeof (TableSize), &BytesRead) || (BytesRead != sizeof (TableSize))) {
137+
dprintf ("Failed to read EFI_DEBUG_IMAGE_INFO_TABLE_HEADER at %llx\n", (ULONG64)DebugImageInfoTableHeader);
124138
return ERROR_NOT_FOUND;
125139
}
126140

127-
if (TableSize <= 1) {
128-
dprintf ("Debug info array is empty.\n");
141+
if (!ReadMemory ((ULONG64)&DebugImageInfoTableHeader->EfiDebugImageInfoTable, &Table, sizeof (Table), &BytesRead) || (BytesRead != sizeof (Table))) {
142+
dprintf ("Failed to read EfiDebugImageInfoTable pointer\n");
143+
return ERROR_NOT_FOUND;
144+
}
145+
146+
if ((Table == NULL) || (TableSize == 0)) {
147+
dprintf ("Debug image info table is empty!\n");
148+
return ERROR_NOT_FOUND;
129149
}
130150

131-
// Skip the 0-index to avoid reloading DxeCore. There is probably a better way to do this.
132-
for (Index = 1; Index < TableSize; Index++) {
133-
Entry = Table + (Index * GetTypeSize ("EFI_DEBUG_IMAGE_INFO"));
134-
GetFieldValue (Entry, "EFI_DEBUG_IMAGE_INFO", "NormalImage", NormalImage);
151+
// Iterate through the debug image info table entries
152+
for (Index = 0; Index < TableSize; Index++) {
153+
Entry = (EFI_DEBUG_IMAGE_INFO *)(Table + (Index * sizeof (EFI_DEBUG_IMAGE_INFO)));
154+
if (!ReadMemory ((ULONG64)&Entry->NormalImage, &NormalImage, sizeof (NormalImage), &BytesRead) || (BytesRead != sizeof (NormalImage))) {
155+
dprintf ("Failed to read debug image info entry at index %lu\n", Index);
156+
continue;
157+
}
158+
135159
if (NormalImage == NULL) {
136-
dprintf ("Skipping missing normal info!\n");
160+
dprintf ("Skipping missing normal image info at index %lu\n", Index);
161+
continue;
162+
}
163+
164+
if (!ReadMemory ((ULONG64)&NormalImage->LoadedImageProtocolInstance, &ImageProtocol, sizeof (ImageProtocol), &BytesRead) || (BytesRead != sizeof (ImageProtocol))) {
165+
dprintf ("Failed to read loaded image protocol instance at index %lu\n", Index);
137166
continue;
138167
}
139168

140-
GetFieldValue (NormalImage, "EFI_DEBUG_IMAGE_INFO_NORMAL", "LoadedImageProtocolInstance", ImageProtocol);
141169
if (ImageProtocol == NULL) {
142-
dprintf ("Skipping missing loaded image protocol!\n");
170+
dprintf ("Skipping missing loaded image protocol at index %lu\n", Index);
143171
continue;
144172
}
145173

146-
GetFieldValue (ImageProtocol, "EFI_LOADED_IMAGE_PROTOCOL", "ImageBase", ImageBase);
174+
if (!ReadMemory ((ULONG64)&ImageProtocol->ImageBase, &ImageBase, sizeof (ImageBase), &BytesRead) || (BytesRead != sizeof (ImageBase))) {
175+
dprintf ("Failed to read image base at index %lu\n", Index);
176+
continue;
177+
}
147178

148-
// Check this hasn't already be loaded.
149-
if ((g_ExtSymbols->GetModuleByOffset (ImageBase, 0, NULL, &Base) == S_OK) &&
150-
(ImageBase == Base))
151-
{
179+
// Check if the module is already loaded
180+
if ((g_ExtSymbols->GetModuleByOffset (ImageBase, 0, NULL, &Base) == S_OK) && (ImageBase == Base)) {
181+
dprintf ("Module at %llx is already loaded\n", ImageBase);
152182
continue;
153183
}
154184

185+
dprintf ("Loading module at %llx\n", ImageBase);
155186
sprintf_s (Command, sizeof (Command), ".imgscan /l /r %I64x (%I64x + 0xFFF)", ImageBase, ImageBase);
156187
g_ExtControl->Execute (
157188
DEBUG_OUTCTL_ALL_CLIENTS,
@@ -160,7 +191,6 @@ loadmodules (
160191
);
161192
}
162193

163-
EXIT_API ();
164194
return S_OK;
165195
}
166196

@@ -199,56 +229,121 @@ findall (
199229
)
200230
{
201231
HRESULT Result;
202-
ULONG64 BsPtrAddr;
203-
ULONG64 BsTableAddr;
232+
ULONG64 SystemPtrAddr;
233+
ULONG64 SystemTableAddr;
234+
ULONG64 Signature = 0;
235+
ULONG BytesRead = 0;
236+
ULONG64 SystemTableSignature = (('I') | (static_cast<ULONG64>('B') << 8) | (static_cast<ULONG64>('I') << 16) | (static_cast<ULONG64>(' ') << 24) | (static_cast<ULONG64>('S') << 32) | (static_cast<ULONG64>('Y') << 40) | (static_cast<ULONG64>('S') << 48) | (static_cast<ULONG64>('T') << 56));
237+
PSTR Response;
204238

205239
INIT_API ();
206240

207-
if (gUefiEnv != DXE) {
208-
dprintf ("Only supported for DXE!\n");
241+
if ((gUefiEnv != DXE) && (gUefiEnv != RUST)) {
242+
dprintf ("Only supported for DXE and Rust!\n");
209243
return ERROR_NOT_SUPPORTED;
210244
}
211245

212246
//
213-
// First find the current module
247+
// First find the current module. We only do this to see if we are in the core to find the system table pointer
248+
// symbols. If we are not in the core, we will ask the monitor for the system table pointer address, failing that
249+
// we will scan memory for the EFI_SYSTEM_TABLE_SIGNATURE, per UEFI spec. The C DXE environment does not have the
250+
// monitor command, so relies on the core symbols having been loaded at the initial breakpoint (or us being broken
251+
// into the core now)
214252
//
215253

216-
Result = FindModuleBackwards (GetExpression ("@$ip"));
217-
if (Result != S_OK) {
218-
return Result;
219-
}
254+
FindModuleBackwards (GetExpression ("@$ip"));
255+
256+
g_ExtControl->Execute (
257+
DEBUG_OUTCTL_ALL_CLIENTS,
258+
"ld *ore*",
259+
DEBUG_EXECUTE_DEFAULT
260+
);
220261

221262
//
222-
// Find the core module. This might be the same as the executing one.
263+
// Find the system table pointer, which we may not find if we are not in the core module
223264
//
224265

225-
BsPtrAddr = GetExpression ("gBS");
226-
if (BsPtrAddr == NULL) {
227-
dprintf ("Failed to find boot services table pointer!\n");
228-
return ERROR_NOT_FOUND;
266+
if (gUefiEnv == DXE) {
267+
SystemPtrAddr = GetExpression ("mDebugTable");
268+
if (!ReadPointer (SystemPtrAddr, &SystemPtrAddr)) {
269+
dprintf ("Failed to read memory at %llx to get system table from ptr\n", SystemPtrAddr);
270+
return ERROR_NOT_FOUND;
271+
}
272+
} else if (gUefiEnv == RUST) {
273+
Response = MonitorCommandWithOutput (Client, "system_table_ptr", 0);
274+
SystemPtrAddr = strtoull (Response, NULL, 16);
275+
276+
if (SystemPtrAddr == 0) {
277+
// if we didn't get the monitor command response, we will try to read the system table pointer from the core
278+
// which may work, if we already have loaded the core symbols. If not, we will fail gracefully. This would be the
279+
// case for the QEMU debugger, where we don't have the monitor command available, but we do have the
280+
// system table pointer symbols loaded.
281+
SystemPtrAddr = GetExpression ("patina_dxe_core::config_tables::debug_image_info_table::DBG_SYSTEM_TABLE_POINTER_ADDRESS");
282+
if (!ReadPointer (SystemPtrAddr, &SystemPtrAddr)) {
283+
dprintf ("Failed to read memory at %llx to get system table from ptr\n", SystemPtrAddr);
284+
return ERROR_NOT_FOUND;
285+
}
286+
}
229287
}
230288

231-
if (!ReadPointer (BsPtrAddr, &BsTableAddr)) {
232-
dprintf ("Failed to find boot services table!\n");
289+
if (SystemPtrAddr == NULL) {
290+
// TODO: Add a flag to indicate whether we should scan memory for the system table pointer and then make the
291+
// scanning better, maybe binary search (though has issues). For now, C DXE has parity with before, Rust has
292+
// two cases, we don't have the monitor command yet, but that is only true at the initial breakpoint (gets set up
293+
// very soon after that, before other modules are loaded, so we have already succeeded) or we are in an older Rust
294+
// core that doesn't support the monitor command
233295
return ERROR_NOT_FOUND;
234-
}
235296

236-
Result = FindModuleBackwards (BsTableAddr);
237-
if (Result != S_OK) {
238-
return Result;
297+
/*
298+
// Locate the system table pointer, which is allocated on a 4MB boundary near the top of memory
299+
// with signature EFI_SYSTEM_TABLE_SIGNATURE SIGNATURE_64 ('I','B','I',' ','S','Y','S','T')
300+
// and the EFI_SYSTEM_TABLE structure.
301+
SystemPtrAddr = 0x80000000; // Start at the top of memory, well, as far as we want to go. This is pretty lazy, but it takes a long time to search the entire memory space.
302+
while (SystemPtrAddr >= 0x400000) { // Stop at 4MB boundary
303+
if (!ReadPointer(SystemPtrAddr, &Signature)) {
304+
SystemPtrAddr -= 0x400000; // Move to the next 4MB boundary
305+
continue;
306+
}
307+
308+
if (Signature == SystemTableSignature) {
309+
dprintf("Found EFI_SYSTEM_TABLE_SIGNATURE at %llx\n", SystemPtrAddr);
310+
break;
311+
}
312+
313+
SystemPtrAddr -= 0x400000; // Move to the next 4MB boundary
314+
}
315+
316+
if (SystemPtrAddr < 0x400000) {
317+
dprintf("Failed to locate EFI_SYSTEM_TABLE_SIGNATURE!\n");
318+
return ERROR_NOT_FOUND;
319+
}
320+
*/
321+
} else {
322+
// Check the signature at the system table pointer address
323+
if (!ReadPointer (SystemPtrAddr, &Signature)) {
324+
dprintf ("Failed to read memory at %llx to get system table signature\n", SystemPtrAddr);
325+
return ERROR_NOT_FOUND;
326+
}
327+
328+
if (Signature != SystemTableSignature) {
329+
dprintf ("Couldn't find EFI_SYSTEM_TABLE_SIGNATURE %llx at %llx, found %llx instead\n", SystemTableSignature, SystemPtrAddr, Signature);
330+
return ERROR_NOT_FOUND;
331+
}
239332
}
240333

241-
g_ExtControl->Execute (
242-
DEBUG_OUTCTL_ALL_CLIENTS,
243-
"ld *Core",
244-
DEBUG_EXECUTE_DEFAULT
245-
);
334+
// move past the signature to get the EFI_SYSTEM_TABLE structure
335+
SystemPtrAddr += sizeof (UINT64);
336+
337+
if (!ReadPointer (SystemPtrAddr, &SystemTableAddr)) {
338+
dprintf ("Failed to find the system table!\n");
339+
return ERROR_NOT_FOUND;
340+
}
246341

247342
//
248343
// Load all the other modules.
249344
//
250345

251-
Result = loadmodules (Client, "");
346+
Result = loadmodules (SystemTableAddr);
252347

253348
EXIT_API ();
254349
return S_OK;

UefiDbgExt/pt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ DisplayPte (
207207
IsPageWritable (Pte) ? 'W' : 'R',
208208
'_',
209209
'_',
210-
'_',
210+
Pte->Accessed ? 'A' : '_',
211211
Pte->UserNoExecute ? 'X' : 'E', // In the EL2 translation scheme UXN is the XN bit and is the only execute permission bit
212212
Pte->Valid ? 'V' : '-'
213213
);

UefiDbgExt/swdebug.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ monitor (
166166

167167
// Strip of the trailing newline character if it exists since this in injected
168168
// by windbg and is not part of the response.
169-
Len = strlen (Response);
169+
Len = (ULONG)strlen (Response);
170170
if ((Len > 0) && (Response[Len - 1] == '\n')) {
171171
Len--;
172172
}

UefiDbgExt/uefiext.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ help (
154154
"\nModule Discovery:\n"
155155
" findall - Attempts to detect environment and load all modules\n"
156156
" findmodule - Find the currently running module\n"
157-
" loadmodules - Find and loads symbols for all modules in the debug list\n"
158157
" elf - Dumps the headers of an ELF image\n"
159158
"\nData Parsing:\n"
160159
" memorymap - Prints the current memory map\n"
@@ -224,7 +223,7 @@ uefiext_init (
224223
}
225224

226225
dprintf ("Scanning for images.\n");
227-
if (gUefiEnv == DXE) {
226+
if (gUefiEnv == DXE || gUefiEnv == RUST) {
228227
g_ExtControl->Execute (
229228
DEBUG_OUTCTL_ALL_CLIENTS,
230229
"!uefiext.findall",

UefiDbgExt/uefiext.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ EXPORTS
2121
info
2222
init=uefiext_init
2323
linkedlist
24-
loadmodules
2524
memorymap
2625
modulebreak
2726
monitor

0 commit comments

Comments
 (0)