Vishal Bhoj | 82c8071 | 2015-12-15 21:13:33 +0530 | [diff] [blame^] | 1 | /** @file
|
| 2 | Add custom commands for BeagleBoard development.
|
| 3 |
|
| 4 | Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
|
| 5 |
|
| 6 | This program and the accompanying materials
|
| 7 | are licensed and made available under the terms and conditions of the BSD License
|
| 8 | which accompanies this distribution. The full text of the license may be found at
|
| 9 | http://opensource.org/licenses/bsd-license.php
|
| 10 |
|
| 11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
| 12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
| 13 |
|
| 14 | **/
|
| 15 |
|
| 16 | #include <PiDxe.h>
|
| 17 | #include <Library/ArmLib.h>
|
| 18 | #include <Library/CacheMaintenanceLib.h>
|
| 19 | #include <Library/EblCmdLib.h>
|
| 20 | #include <Library/BaseLib.h>
|
| 21 | #include <Library/DebugLib.h>
|
| 22 | #include <Library/UefiBootServicesTableLib.h>
|
| 23 | #include <Library/UefiRuntimeServicesTableLib.h>
|
| 24 | #include <Library/MemoryAllocationLib.h>
|
| 25 | #include <Library/UefiLib.h>
|
| 26 | #include <Library/PcdLib.h>
|
| 27 | #include <Library/EfiFileLib.h>
|
| 28 | #include <Library/ArmDisassemblerLib.h>
|
| 29 | #include <Library/PeCoffGetEntryPointLib.h>
|
| 30 | #include <Library/PerformanceLib.h>
|
| 31 | #include <Library/TimerLib.h>
|
| 32 |
|
| 33 | #include <Guid/DebugImageInfoTable.h>
|
| 34 |
|
| 35 | #include <Protocol/DebugSupport.h>
|
| 36 | #include <Protocol/LoadedImage.h>
|
| 37 |
|
| 38 | /**
|
| 39 | Simple arm disassembler via a library
|
| 40 |
|
| 41 | Argv[0] - symboltable
|
| 42 | Argv[1] - Optional quoted format string
|
| 43 | Argv[2] - Optional flag
|
| 44 |
|
| 45 | @param Argc Number of command arguments in Argv
|
| 46 | @param Argv Array of strings that represent the parsed command line.
|
| 47 | Argv[0] is the command name
|
| 48 |
|
| 49 | @return EFI_SUCCESS
|
| 50 |
|
| 51 | **/
|
| 52 | EFI_STATUS
|
| 53 | EblSymbolTable (
|
| 54 | IN UINTN Argc,
|
| 55 | IN CHAR8 **Argv
|
| 56 | )
|
| 57 | {
|
| 58 | EFI_STATUS Status;
|
| 59 | EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageTableHeader = NULL;
|
| 60 | EFI_DEBUG_IMAGE_INFO *DebugTable;
|
| 61 | UINTN Entry;
|
| 62 | CHAR8 *Format;
|
| 63 | CHAR8 *Pdb;
|
| 64 | UINT32 PeCoffSizeOfHeaders;
|
| 65 | UINT32 ImageBase;
|
| 66 | BOOLEAN Elf;
|
| 67 |
|
| 68 | // Need to add lots of error checking on the passed in string
|
| 69 | // Default string is for RealView debugger or gdb depending on toolchain used.
|
| 70 | if (Argc > 1) {
|
| 71 | Format = Argv[1];
|
| 72 | } else {
|
| 73 | #if __GNUC__
|
| 74 | // Assume gdb
|
| 75 | Format = "add-symbol-file %a 0x%x";
|
| 76 | #else
|
| 77 | // Default to RVCT
|
| 78 | Format = "load /a /ni /np %a &0x%x";
|
| 79 | #endif
|
| 80 | }
|
| 81 | Elf = (Argc > 2) ? FALSE : TRUE;
|
| 82 |
|
| 83 | Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugImageTableHeader);
|
| 84 | if (EFI_ERROR (Status)) {
|
| 85 | return Status;
|
| 86 | }
|
| 87 |
|
| 88 | DebugTable = DebugImageTableHeader->EfiDebugImageInfoTable;
|
| 89 | if (DebugTable == NULL) {
|
| 90 | return EFI_SUCCESS;
|
| 91 | }
|
| 92 |
|
| 93 | for (Entry = 0; Entry < DebugImageTableHeader->TableSize; Entry++, DebugTable++) {
|
| 94 | if (DebugTable->NormalImage != NULL) {
|
| 95 | if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {
|
| 96 | ImageBase = (UINT32)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase;
|
| 97 | PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageBase);
|
| 98 | Pdb = PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase);
|
| 99 | if (Pdb != NULL) {
|
| 100 | if (Elf) {
|
| 101 | // ELF and Mach-O images don't include the header so the linked address does not include header
|
| 102 | ImageBase += PeCoffSizeOfHeaders;
|
| 103 | }
|
| 104 | AsciiPrint (Format, Pdb, ImageBase);
|
| 105 | AsciiPrint ("\n");
|
| 106 | } else {
|
| 107 | }
|
| 108 | }
|
| 109 | }
|
| 110 | }
|
| 111 |
|
| 112 | return EFI_SUCCESS;
|
| 113 | }
|
| 114 |
|
| 115 |
|
| 116 | /**
|
| 117 | Simple arm disassembler via a library
|
| 118 |
|
| 119 | Argv[0] - disasm
|
| 120 | Argv[1] - Address to start disassembling from
|
| 121 | ARgv[2] - Number of instructions to disassembly (optional)
|
| 122 |
|
| 123 | @param Argc Number of command arguments in Argv
|
| 124 | @param Argv Array of strings that represent the parsed command line.
|
| 125 | Argv[0] is the command name
|
| 126 |
|
| 127 | @return EFI_SUCCESS
|
| 128 |
|
| 129 | **/
|
| 130 | EFI_STATUS
|
| 131 | EblDisassembler (
|
| 132 | IN UINTN Argc,
|
| 133 | IN CHAR8 **Argv
|
| 134 | )
|
| 135 | {
|
| 136 | UINT8 *Ptr, *CurrentAddress;
|
| 137 | UINT32 Address;
|
| 138 | UINT32 Count;
|
| 139 | CHAR8 Buffer[80];
|
| 140 | UINT32 ItBlock;
|
| 141 |
|
| 142 | if (Argc < 2) {
|
| 143 | return EFI_INVALID_PARAMETER;
|
| 144 | }
|
| 145 |
|
| 146 | Address = AsciiStrHexToUintn (Argv[1]);
|
| 147 | Count = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 20;
|
| 148 |
|
| 149 | Ptr = (UINT8 *)(UINTN)Address;
|
| 150 | ItBlock = 0;
|
| 151 | do {
|
| 152 | CurrentAddress = Ptr;
|
| 153 | DisassembleInstruction (&Ptr, TRUE, TRUE, &ItBlock, Buffer, sizeof (Buffer));
|
| 154 | AsciiPrint ("0x%08x: %a\n", CurrentAddress, Buffer);
|
| 155 | } while (Count-- > 0);
|
| 156 |
|
| 157 |
|
| 158 | return EFI_SUCCESS;
|
| 159 | }
|
| 160 |
|
| 161 |
|
| 162 | CHAR8 *
|
| 163 | ImageHandleToPdbFileName (
|
| 164 | IN EFI_HANDLE Handle
|
| 165 | )
|
| 166 | {
|
| 167 | EFI_STATUS Status;
|
| 168 | EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
| 169 | CHAR8 *Pdb;
|
| 170 | CHAR8 *StripLeading;
|
| 171 |
|
| 172 | Status = gBS->HandleProtocol (Handle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);
|
| 173 | if (EFI_ERROR (Status)) {
|
| 174 | return "";
|
| 175 | }
|
| 176 |
|
| 177 | Pdb = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
|
| 178 | StripLeading = AsciiStrStr (Pdb, "\\ARM\\");
|
| 179 | if (StripLeading == NULL) {
|
| 180 | StripLeading = AsciiStrStr (Pdb, "/ARM/");
|
| 181 | if (StripLeading == NULL) {
|
| 182 | return Pdb;
|
| 183 | }
|
| 184 | }
|
| 185 | // Hopefully we hacked off the unneeded part
|
| 186 | return (StripLeading + 5);
|
| 187 | }
|
| 188 |
|
| 189 |
|
| 190 | CHAR8 *mTokenList[] = {
|
| 191 | "SEC",
|
| 192 | "PEI",
|
| 193 | "DXE",
|
| 194 | "BDS",
|
| 195 | NULL
|
| 196 | };
|
| 197 |
|
| 198 | /**
|
| 199 | Simple arm disassembler via a library
|
| 200 |
|
| 201 | Argv[0] - disasm
|
| 202 | Argv[1] - Address to start disassembling from
|
| 203 | ARgv[2] - Number of instructions to disassembly (optional)
|
| 204 |
|
| 205 | @param Argc Number of command arguments in Argv
|
| 206 | @param Argv Array of strings that represent the parsed command line.
|
| 207 | Argv[0] is the command name
|
| 208 |
|
| 209 | @return EFI_SUCCESS
|
| 210 |
|
| 211 | **/
|
| 212 | EFI_STATUS
|
| 213 | EblPerformance (
|
| 214 | IN UINTN Argc,
|
| 215 | IN CHAR8 **Argv
|
| 216 | )
|
| 217 | {
|
| 218 | UINTN Key;
|
| 219 | CONST VOID *Handle;
|
| 220 | CONST CHAR8 *Token, *Module;
|
| 221 | UINT64 Start, Stop, TimeStamp;
|
| 222 | UINT64 Delta, TicksPerSecond, Milliseconds, Microseconds;
|
| 223 | UINTN Index;
|
| 224 |
|
| 225 | TicksPerSecond = GetPerformanceCounterProperties (NULL, NULL);
|
| 226 |
|
| 227 | Key = 0;
|
| 228 | do {
|
| 229 | Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop);
|
| 230 | if (Key != 0) {
|
| 231 | if (AsciiStriCmp ("StartImage:", Token) == 0) {
|
| 232 | if (Stop == 0) {
|
| 233 | // The entry for EBL is still running so the stop time will be zero. Skip it
|
| 234 | AsciiPrint (" running %a\n", ImageHandleToPdbFileName ((EFI_HANDLE)Handle));
|
| 235 | } else {
|
| 236 | Delta = Stop - Start;
|
| 237 | Microseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000000), TicksPerSecond, NULL);
|
| 238 | AsciiPrint ("%10ld us %a\n", Microseconds, ImageHandleToPdbFileName ((EFI_HANDLE)Handle));
|
| 239 | }
|
| 240 | }
|
| 241 | }
|
| 242 | } while (Key != 0);
|
| 243 |
|
| 244 | AsciiPrint ("\n");
|
| 245 |
|
| 246 | TimeStamp = 0;
|
| 247 | Key = 0;
|
| 248 | do {
|
| 249 | Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop);
|
| 250 | if (Key != 0) {
|
| 251 | for (Index = 0; mTokenList[Index] != NULL; Index++) {
|
| 252 | if (AsciiStriCmp (mTokenList[Index], Token) == 0) {
|
| 253 | Delta = Stop - Start;
|
| 254 | TimeStamp += Delta;
|
| 255 | Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL);
|
| 256 | AsciiPrint ("%6a %6ld ms\n", Token, Milliseconds);
|
| 257 | break;
|
| 258 | }
|
| 259 | }
|
| 260 | }
|
| 261 | } while (Key != 0);
|
| 262 |
|
| 263 | AsciiPrint ("Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL));
|
| 264 |
|
| 265 | return EFI_SUCCESS;
|
| 266 | }
|
| 267 |
|
| 268 |
|
| 269 | GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mLibCmdTemplate[] =
|
| 270 | {
|
| 271 | {
|
| 272 | "disasm address [count]",
|
| 273 | " disassemble count instructions",
|
| 274 | NULL,
|
| 275 | EblDisassembler
|
| 276 | },
|
| 277 | {
|
| 278 | "performance",
|
| 279 | " Display boot performance info",
|
| 280 | NULL,
|
| 281 | EblPerformance
|
| 282 | },
|
| 283 | {
|
| 284 | "symboltable [\"format string\"] [PECOFF]",
|
| 285 | " show symbol table commands for debugger",
|
| 286 | NULL,
|
| 287 | EblSymbolTable
|
| 288 | }
|
| 289 | };
|
| 290 |
|
| 291 |
|
| 292 | VOID
|
| 293 | EblInitializeExternalCmd (
|
| 294 | VOID
|
| 295 | )
|
| 296 | {
|
| 297 | EblAddCommands (mLibCmdTemplate, sizeof (mLibCmdTemplate)/sizeof (EBL_COMMAND_TABLE));
|
| 298 | return;
|
| 299 | }
|