microsoft/mu_tiano_platforms
Publicmirrored fromhttps://github.com/microsoft/mu_tiano_platformsAvailable
UefiDbgExt/modules.cpp
208lines · modecode
| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft Corporation |
| 4 | |
| 5 | SPDX-License-Identifier: BSD-2-Clause-Patent |
| 6 | |
| 7 | Module Name: |
| 8 | |
| 9 | modules.cpp |
| 10 | |
| 11 | Abstract: |
| 12 | |
| 13 | This file contains debug commands for enumerating UEFI modules and their |
| 14 | symbols. |
| 15 | |
| 16 | --*/ |
| 17 | |
| 18 | #include "uefiext.h" |
| 19 | |
| 20 | HRESULT |
| 21 | FindModuleBackwards(ULONG64 Address) |
| 22 | { |
| 23 | ULONG64 MinAddress; |
| 24 | CHAR Command[512]; |
| 25 | ULONG64 MaxSize; |
| 26 | ULONG32 Check; |
| 27 | CONST ULONG32 Magic = 0x5A4D; // MZ |
| 28 | ULONG BytesRead; |
| 29 | HRESULT Result; |
| 30 | |
| 31 | MaxSize = 0x400000; // 4 Mb |
| 32 | Address = PAGE_ALIGN_DOWN(Address); |
| 33 | if (Address > MaxSize) { |
| 34 | MinAddress = Address - MaxSize; |
| 35 | } |
| 36 | else { |
| 37 | MinAddress = 0; |
| 38 | } |
| 39 | |
| 40 | Result = ERROR_NOT_FOUND; |
| 41 | for (; Address >= MinAddress; Address -= PAGE_SIZE) { |
| 42 | Check = 0; |
| 43 | ReadMemory(Address, &Check, sizeof(Check), &BytesRead); |
| 44 | if ((BytesRead == sizeof(Check)) && (Check == Magic)) { |
| 45 | sprintf_s(&Command[0], sizeof(Command), ".imgscan /l /r %I64x %I64x", Address, Address + 0xFFF); |
| 46 | g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, |
| 47 | &Command[0], |
| 48 | DEBUG_EXECUTE_DEFAULT); |
| 49 | |
| 50 | Result = S_OK; |
| 51 | break; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | return Result; |
| 56 | } |
| 57 | |
| 58 | HRESULT CALLBACK |
| 59 | loadmodules(PDEBUG_CLIENT4 Client, PCSTR args) |
| 60 | { |
| 61 | ULONG64 HeaderAddress; |
| 62 | UINT32 TableSize; |
| 63 | ULONG64 Table; |
| 64 | ULONG64 Entry; |
| 65 | ULONG64 NormalImage; |
| 66 | ULONG64 ImageProtocol; |
| 67 | UINT64 ImageBase; |
| 68 | ULONG Index; |
| 69 | CHAR Command[512]; |
| 70 | INIT_API(); |
| 71 | |
| 72 | UNREFERENCED_PARAMETER(args); |
| 73 | |
| 74 | // |
| 75 | // TODO: Add support for PEI & MM |
| 76 | // |
| 77 | |
| 78 | if (gUefiEnv != DXE) { |
| 79 | dprintf("Only supported for DXE!\n"); |
| 80 | return ERROR_NOT_SUPPORTED; |
| 81 | } |
| 82 | |
| 83 | HeaderAddress = GetExpression("&mDebugInfoTableHeader"); |
| 84 | if (HeaderAddress == NULL) { |
| 85 | dprintf("Failed to find mDebugInfoTableHeader!\n"); |
| 86 | return ERROR_NOT_FOUND; |
| 87 | } |
| 88 | |
| 89 | GetFieldValue(HeaderAddress, "EFI_DEBUG_IMAGE_INFO_TABLE_HEADER", "TableSize", TableSize); |
| 90 | GetFieldValue(HeaderAddress, "EFI_DEBUG_IMAGE_INFO_TABLE_HEADER", "EfiDebugImageInfoTable", Table); |
| 91 | if ((Table == NULL) || (TableSize == 0)) { |
| 92 | dprintf("Debug table is empty!\n"); |
| 93 | return ERROR_NOT_FOUND; |
| 94 | } |
| 95 | |
| 96 | if (TableSize <= 1) { |
| 97 | dprintf("Debug info array is empty.\n"); |
| 98 | } |
| 99 | |
| 100 | // Skip the 0-index to avoid reloading DxeCore. There is probably a better way to do this. |
| 101 | for (Index = 1; Index < TableSize; Index++) { |
| 102 | Entry = Table + (Index * GetTypeSize("EFI_DEBUG_IMAGE_INFO")); |
| 103 | GetFieldValue(Entry, "EFI_DEBUG_IMAGE_INFO", "NormalImage", NormalImage); |
| 104 | if (NormalImage == NULL) { |
| 105 | dprintf("Skipping missing normal info!\n"); |
| 106 | continue; |
| 107 | } |
| 108 | |
| 109 | GetFieldValue(NormalImage, "EFI_DEBUG_IMAGE_INFO_NORMAL", "LoadedImageProtocolInstance", ImageProtocol); |
| 110 | if (ImageProtocol == NULL) { |
| 111 | dprintf("Skipping missing loaded image protocol!\n"); |
| 112 | continue; |
| 113 | } |
| 114 | |
| 115 | GetFieldValue(ImageProtocol, "EFI_LOADED_IMAGE_PROTOCOL", "ImageBase", ImageBase); |
| 116 | sprintf_s(Command, sizeof(Command), ".imgscan /l /r %I64x (%I64x + 0xFFF)", ImageBase, ImageBase); |
| 117 | g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, |
| 118 | Command, |
| 119 | DEBUG_EXECUTE_DEFAULT); |
| 120 | } |
| 121 | |
| 122 | EXIT_API(); |
| 123 | return S_OK; |
| 124 | } |
| 125 | |
| 126 | HRESULT CALLBACK |
| 127 | findmodule(PDEBUG_CLIENT4 Client, PCSTR args) |
| 128 | { |
| 129 | ULONG64 Address; |
| 130 | HRESULT Result; |
| 131 | INIT_API(); |
| 132 | |
| 133 | if (strlen(args) == 0) { |
| 134 | args = "@$ip"; |
| 135 | } |
| 136 | |
| 137 | Address = GetExpression(args); |
| 138 | if ((Address == 0) || (Address == (-1))) { |
| 139 | dprintf("Invalid address!\n"); |
| 140 | dprintf("Usage: !uefiext.findmodule [Address]\n"); |
| 141 | return ERROR_INVALID_PARAMETER; |
| 142 | } |
| 143 | |
| 144 | Result = FindModuleBackwards(Address); |
| 145 | |
| 146 | EXIT_API(); |
| 147 | return Result; |
| 148 | } |
| 149 | |
| 150 | HRESULT CALLBACK |
| 151 | findall(PDEBUG_CLIENT4 Client, PCSTR args) |
| 152 | { |
| 153 | HRESULT Result; |
| 154 | ULONG64 BsPtrAddr; |
| 155 | ULONG64 BsTableAddr; |
| 156 | INIT_API(); |
| 157 | |
| 158 | if (gUefiEnv != DXE) { |
| 159 | dprintf("Only supported for DXE!\n"); |
| 160 | return ERROR_NOT_SUPPORTED; |
| 161 | } |
| 162 | |
| 163 | // |
| 164 | // First find the current module |
| 165 | // |
| 166 | |
| 167 | Result = FindModuleBackwards(GetExpression("@$ip")); |
| 168 | if (Result != S_OK) { |
| 169 | return Result; |
| 170 | } |
| 171 | |
| 172 | g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, |
| 173 | "ld *", |
| 174 | DEBUG_EXECUTE_DEFAULT); |
| 175 | |
| 176 | // |
| 177 | // Find the core module. This might be the same as the executing one. |
| 178 | // |
| 179 | |
| 180 | BsPtrAddr = GetExpression("gBS"); |
| 181 | if (BsPtrAddr == NULL) { |
| 182 | dprintf("Failed to find boot services table pointer!\n"); |
| 183 | return ERROR_NOT_FOUND; |
| 184 | } |
| 185 | |
| 186 | if (!ReadPointer(BsPtrAddr, &BsTableAddr)) { |
| 187 | dprintf("Failed to find boot services table!\n"); |
| 188 | return ERROR_NOT_FOUND; |
| 189 | } |
| 190 | |
| 191 | Result = FindModuleBackwards(BsTableAddr); |
| 192 | if (Result != S_OK) { |
| 193 | return Result; |
| 194 | } |
| 195 | |
| 196 | g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, |
| 197 | "ld *", |
| 198 | DEBUG_EXECUTE_DEFAULT); |
| 199 | |
| 200 | // |
| 201 | // Load all the other modules. |
| 202 | // |
| 203 | |
| 204 | Result = loadmodules(Client, ""); |
| 205 | |
| 206 | EXIT_API(); |
| 207 | return S_OK; |
| 208 | } |
| 209 | |