UINTN EdbDisplayMemoryUnit ( IN UINTN Address, IN EDB_DATA_WIDTH Width ) /*++ Routine Description: Display memory unit Arguments: Address - Memory Address Width - Memory Width Returns: Length of the memory unit --*/ { UINT8 Data8; UINT16 Data16; UINT32 Data32; UINT64 Data64; // // Print accroding to width // switch (Width) { case EdbWidthUint8: CopyMem (&Data8, (VOID *)Address, sizeof(UINT8)); EDBPrint (L"%02x ", Data8); return sizeof(UINT8); case EdbWidthUint16: CopyMem (&Data16, (VOID *)Address, sizeof(UINT16)); EDBPrint (L"%04x ", Data16); return sizeof(UINT16); case EdbWidthUint32: CopyMem (&Data32, (VOID *)Address, sizeof(UINT32)); EDBPrint (L"%08x ", Data32); return sizeof(UINT32); case EdbWidthUint64: CopyMem (&Data64, (VOID *)Address, sizeof(UINT64)); EDBPrint (L"%016lx ", Data64); return sizeof(UINT64); default: ASSERT (FALSE); break; } // // something wrong // return 0; }
/** DebuggerCommand - InstructionBranch. @param CommandArg The argument for this command @param DebuggerPrivate EBC Debugger private data structure @param ExceptionType Exception type. @param SystemContext EBC system context. @retval EFI_DEBUG_CONTINUE formal return value **/ EFI_DEBUG_STATUS DebuggerInstructionBranch ( IN CHAR16 *CommandArg, IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, IN EFI_EXCEPTION_TYPE ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext ) { UINTN Index; // // Check argument // if (CommandArg != NULL) { if (StriCmp (CommandArg, L"c") == 0) { // // Clear Trace // DebuggerPrivate->TraceEntryCount = 0; ZeroMem (DebuggerPrivate->TraceEntry, sizeof(DebuggerPrivate->TraceEntry)); EDBPrint (L"Instruction Trace is cleared\n"); } else { EDBPrint (L"Trace argument Invalid\n"); } return EFI_DEBUG_CONTINUE; } // // Check Trace Entry Count // if (DebuggerPrivate->TraceEntryCount == 0) { EDBPrint (L"No Instruction Trace\n"); return EFI_DEBUG_CONTINUE; } else if (DebuggerPrivate->TraceEntryCount > EFI_DEBUGGER_TRACE_MAX) { EDBPrint (L"Instruction Trace Crash, re-initialize!\n"); DebuggerPrivate->TraceEntryCount = 0; return EFI_DEBUG_CONTINUE; } // // Go through each Trace entry and print // EDBPrint (L"Instruction Trace (->Latest):\n"); EDBPrint (L" Source Addr Destination Addr Type\n"); EDBPrint (L" ================== ================== ========\n"); //EDBPrint (L" 0x00000000FFFFFFFF 0xFFFFFFFF00000000 (CALLEX)\n"); for (Index = 0; Index < DebuggerPrivate->TraceEntryCount; Index++) { EDBPrint ( L" 0x%016lx 0x%016lx %s\n", DebuggerPrivate->TraceEntry[Index].SourceAddress, DebuggerPrivate->TraceEntry[Index].DestAddress, EdbBranchTypeToStr (DebuggerPrivate->TraceEntry[Index].Type) ); } // // Done // return EFI_DEBUG_CONTINUE; }
/** DebuggerCommand - Help. @param CommandArg - The argument for this command @param DebuggerPrivate - EBC Debugger private data structure @param ExceptionType - Interrupt type. @param SystemContext - EBC system context. @retval EFI_DEBUG_CONTINUE - formal return value **/ EFI_DEBUG_STATUS DebuggerHelp ( IN CHAR16 *CommandArg, IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, IN EFI_EXCEPTION_TYPE ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext ) { UINTN Index; // // if no argument, print all the command title // if (CommandArg == NULL) { for (Index = 0; DebuggerPrivate->DebuggerCommandSet[Index].CommandName != NULL; Index++) { EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].ClassName); if (StrCmp (DebuggerPrivate->DebuggerCommandSet[Index].CommandTitle, L"") != 0) { EDBPrint (L" "); EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandTitle); } } return EFI_DEBUG_CONTINUE; } // // If there is argument, the argument should be command name. // Find the command and print the detail information. // for (Index = 0; DebuggerPrivate->DebuggerCommandSet[Index].CommandName != NULL; Index++) { if (StriCmp (CommandArg, DebuggerPrivate->DebuggerCommandSet[Index].CommandName) == 0) { EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandHelp); EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandSyntax); return EFI_DEBUG_CONTINUE; } } // // Command not found. // EDBPrint (L"No help info for this command\n"); // // Done // return EFI_DEBUG_CONTINUE; }
EFI_STATUS ReadFileToBuffer ( IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, IN CHAR16 *FileName, OUT UINTN *BufferSize, OUT VOID **Buffer, IN BOOLEAN ScanFs ) /*++ Routine Description: Read a file. If ScanFs is FLASE, it will use DebuggerPrivate->Vol as default Fs. If ScanFs is TRUE, it will scan all FS and check the file. If there is only one file match the name, it will be read. If there is more than one file match the name, it will return Error. Arguments: DebuggerPrivate - EBC Debugger private data structure FileName - The file to be read. BufferSize - The file buffer size Buffer - The file buffer ScanFs - Need Scan all FS Returns: EFI_SUCCESS - read file successfully EFI_NOT_FOUND - file not found EFI_NO_MAPPING - there is duplicated files found --*/ { EFI_STATUS Status; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol; UINTN TempBufferSize; VOID *TempBuffer; UINTN NoHandles; EFI_HANDLE *HandleBuffer; UINTN Index; // // Check parameters // if ((FileName == NULL) || (Buffer == NULL)) { return EFI_INVALID_PARAMETER; } // // not scan fs // if (!ScanFs) { if (DebuggerPrivate->Vol == NULL) { return EFI_INVALID_PARAMETER; } // // Read file directly from Vol // return ReadFileFromVol (DebuggerPrivate->Vol, FileName, BufferSize, Buffer); } // // need scan fs // // // Get all Vol handle // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &NoHandles, &HandleBuffer ); if (EFI_ERROR (Status) && (NoHandles == 0)) { return EFI_NOT_FOUND; } // // Walk through each Vol // DebuggerPrivate->Vol = NULL; *BufferSize = 0; *Buffer = NULL; for (Index = 0; Index < NoHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, &Vol ); if (EFI_ERROR(Status)) { continue; } Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer); if (!EFI_ERROR (Status)) { // // Read file OK, check duplication // if (DebuggerPrivate->Vol != NULL) { // // Find the duplicated file // gBS->FreePool (TempBuffer); gBS->FreePool (*Buffer); EDBPrint (L"Duplicated FileName found!\n"); return EFI_NO_MAPPING; } else { // // Record value // DebuggerPrivate->Vol = Vol; *BufferSize = TempBufferSize; *Buffer = TempBuffer; } } } // // Scan Fs done // if (DebuggerPrivate->Vol == NULL) { return EFI_NOT_FOUND; } // // Done // return EFI_SUCCESS; }
EFI_DEBUG_STATUS DebuggerCallStack ( IN CHAR16 *CommandArg, IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, IN EFI_EXCEPTION_TYPE ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext ) /*++ Routine Description: DebuggerCommand - CallStack Arguments: CommandArg - The argument for this command DebuggerPrivate - EBC Debugger private data structure InterruptType - Interrupt type. SystemContext - EBC system context. Returns: EFI_DEBUG_CONTINUE - formal return value --*/ { INTN Index; UINTN SubIndex; CHAR8 *FuncName; EFI_DEBUGGER_CALLSTACK_CONTEXT *CallStackEntry; BOOLEAN ShowParameter; UINTN ParameterNumber; ShowParameter = FALSE; ParameterNumber = EFI_DEBUGGER_CALL_DEFAULT_PARAMETER; // // Check argument // if (CommandArg != NULL) { if (EfiStriCmp (CommandArg, L"c") == 0) { // // Clear Call-Stack // DebuggerPrivate->CallStackEntryCount = 0; EfiZeroMem (DebuggerPrivate->CallStackEntry, sizeof(DebuggerPrivate->CallStackEntry)); EDBPrint (L"Call-Stack is cleared\n"); return EFI_DEBUG_CONTINUE; } else if (EfiStriCmp (CommandArg, L"p") == 0) { // // Print Call-Stack with parameter // ShowParameter = TRUE; CommandArg = StrGetNextTokenLine (L" "); if (CommandArg != NULL) { // // Try to get the parameter number // ParameterNumber = Atoi (CommandArg); if (ParameterNumber > 16) { EDBPrint (L"Call-Stack argument Invalid\n"); return EFI_DEBUG_CONTINUE; } } } else { EDBPrint (L"Call-Stack argument Invalid\n"); return EFI_DEBUG_CONTINUE; } } // // Check CallStack Entry Count // if (DebuggerPrivate->CallStackEntryCount == 0) { EDBPrint (L"No Call-Stack\n"); return EFI_DEBUG_CONTINUE; } else if (DebuggerPrivate->CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) { EDBPrint (L"Call-Stack Crash, re-initialize!\n"); DebuggerPrivate->CallStackEntryCount = 0; return EFI_DEBUG_CONTINUE; } // // Go through each CallStack entry and print // EDBPrint (L"Call-Stack (TOP):\n"); EDBPrint (L" Caller Callee Name\n"); EDBPrint (L" ================== ================== ========\n"); //EDBPrint (L" 0x00000000FFFFFFFF 0xFFFFFFFF00000000 EfiMain\n"); for (Index = (INTN)(DebuggerPrivate->CallStackEntryCount - 1); Index >= 0; Index--) { // // Get CallStack and print // CallStackEntry = &DebuggerPrivate->CallStackEntry[Index]; EDBPrint ( L" 0x%016lx 0x%016lx", CallStackEntry->SourceAddress, CallStackEntry->DestAddress ); FuncName = FindSymbolStr ((UINTN)CallStackEntry->DestAddress); if (FuncName != NULL) { EDBPrint (L" %a()", FuncName); } EDBPrint (L"\n"); if (ShowParameter) { // // Print parameter // if (sizeof(UINTN) == sizeof(UINT64)) { EDBPrint ( L" Parameter Address (0x%016lx) (\n", CallStackEntry->ParameterAddr ); if (ParameterNumber == 0) { EDBPrint (L" )\n"); continue; } // // Print each parameter // for (SubIndex = 0; SubIndex < ParameterNumber - 1; SubIndex++) { if (SubIndex % 2 == 0) { EDBPrint (L" "); } EDBPrint ( L"0x%016lx, ", CallStackEntry->Parameter[SubIndex] ); if (SubIndex % 2 == 1) { EDBPrint (L"\n"); } } if (SubIndex % 2 == 0) { EDBPrint (L" "); } EDBPrint ( L"0x%016lx\n", CallStackEntry->Parameter[SubIndex] ); EDBPrint (L" )\n"); // // break only for parameter // if ((((DebuggerPrivate->CallStackEntryCount - Index) % (16 / ParameterNumber)) == 0) && (Index != 0)) { if (SetPageBreak ()) { break; } } } else { EDBPrint ( L" Parameter Address (0x%08x) (\n", CallStackEntry->ParameterAddr ); if (ParameterNumber == 0) { EDBPrint (L" )\n"); continue; } // // Print each parameter // for (SubIndex = 0; SubIndex < ParameterNumber - 1; SubIndex++) { if (SubIndex % 4 == 0) { EDBPrint (L" "); } EDBPrint ( L"0x%08x, ", CallStackEntry->Parameter[SubIndex] ); if (SubIndex % 4 == 3) { EDBPrint (L"\n"); } } if (SubIndex % 4 == 0) { EDBPrint (L" "); } EDBPrint ( L"0x%08x\n", CallStackEntry->Parameter[SubIndex] ); EDBPrint (L" )\n"); // // break only for parameter // if ((((DebuggerPrivate->CallStackEntryCount - Index) % (32 / ParameterNumber)) == 0) && (Index != 0)) { if (SetPageBreak ()) { break; } } } } } // // Done // return EFI_DEBUG_CONTINUE; }
/** The default Exception Callback for the VM interpreter. In this function, we report status code, and print debug information about EBC_CONTEXT, then dead loop. @param ExceptionType Exception type. @param SystemContext EBC system context. **/ VOID EFIAPI EdbExceptionHandler ( IN EFI_EXCEPTION_TYPE ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext ) { CHAR16 InputBuffer[EFI_DEBUG_INPUS_BUFFER_SIZE]; CHAR16 *CommandArg; EFI_DEBUGGER_COMMAND DebuggerCommand; EFI_DEBUG_STATUS DebugStatus; STATIC BOOLEAN mInitialized; mInitialized = FALSE; DEBUG ((DEBUG_ERROR, "Hello EBC Debugger!\n")); if (!mInitialized) { // // Print version // EDBPrint ( L"EBC Interpreter Version - %d.%d\n", (UINTN)VM_MAJOR_VERSION, (UINTN)VM_MINOR_VERSION ); EDBPrint ( L"EBC Debugger Version - %d.%d\n", (UINTN)EBC_DEBUGGER_MAJOR_VERSION, (UINTN)EBC_DEBUGGER_MINOR_VERSION ); } // // Init Private Data // InitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized); // // EDBPrint basic info // PrintExceptionReason (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized); EdbShowDisasm (&mDebuggerPrivate, SystemContext); // EFI_BREAKPOINT (); if (!mInitialized) { // // Interactive with user // EDBPrint (L"\nPlease enter command now, \'h\' for help.\n"); EDBPrint (L"(Using <Command> -b <...> to enable page break.)\n"); } mInitialized = TRUE; // // Dispatch each command // while (TRUE) { // // Get user input // Input (L"\n\r" EFI_DEBUG_PROMPT_STRING, InputBuffer, EFI_DEBUG_INPUS_BUFFER_SIZE); EDBPrint (L"\n"); // // Get command // DebuggerCommand = MatchDebuggerCommand (InputBuffer, &CommandArg); if (DebuggerCommand == NULL) { EDBPrint (L"ERROR: Command not found!\n"); continue; } // // Check PageBreak; // if (CommandArg != NULL) { if (StriCmp (CommandArg, L"-b") == 0) { CommandArg = StrGetNextTokenLine (L" "); mDebuggerPrivate.EnablePageBreak = TRUE; } } // // Dispatch command // DebugStatus = DebuggerCommand (CommandArg, &mDebuggerPrivate, ExceptionType, SystemContext); mDebuggerPrivate.EnablePageBreak = FALSE; // // Check command return status // if (DebugStatus == EFI_DEBUG_RETURN) { mInitialized = FALSE; break; } else if (DebugStatus == EFI_DEBUG_BREAK) { break; } else if (DebugStatus == EFI_DEBUG_CONTINUE) { continue; } else { ASSERT (FALSE); } } // // Deinit Private Data // DeinitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized); DEBUG ((DEBUG_ERROR, "Goodbye EBC Debugger!\n")); return; }
/** Print the reason of current break to EbcDebugger. @param DebuggerPrivate EBC Debugger private data structure @param ExceptionType Exception type. @param SystemContext EBC system context. @param Initialized Whether the DebuggerPrivate data is initialized. **/ VOID PrintExceptionReason ( IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, IN EFI_EXCEPTION_TYPE ExceptionType, IN EFI_SYSTEM_CONTEXT SystemContext, IN BOOLEAN Initialized ) { // // Print break status // if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_GT) == EFI_DEBUG_FLAG_EBC_GT) { EDBPrint (L"Break on GoTil\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) { EDBPrint (L"Break on CALL\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) { EDBPrint (L"Break on CALLEX\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) { EDBPrint (L"Break on RET\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) { EDBPrint (L"Break on Entrypoint\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) { EDBPrint (L"Break on Thunk\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER) { EDBPrint (L"Break on StepOver\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT) { EDBPrint (L"Break on StepOut\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BP) == EFI_DEBUG_FLAG_EBC_BP) { EDBPrint (L"Break on Breakpoint\n"); } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) { EDBPrint (L"Break on Key\n"); } else { EDBPrint (L"Exception Type - %x", (UINTN)ExceptionType); if ((ExceptionType >= EXCEPT_EBC_UNDEFINED) && (ExceptionType <= EXCEPT_EBC_STEP)) { EDBPrint (L" (%s)\n", mExceptionStr[ExceptionType]); } else { EDBPrint (L"\n"); } } return ; }
EFI_DEBUG_STATUS DebuggerGo ( IN CHAR16 *CommandArg, IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, IN EFI_EXCEPTION_TYPE ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext ) /*++ Routine Description: DebuggerCommand - Go Arguments: CommandArg - The argument for this command DebuggerPrivate - EBC Debugger private data structure InterruptType - Interrupt type. SystemContext - EBC system context. Returns: EFI_DEBUG_BREAK - formal return value EFI_DEBUG_CONTINUE - something wrong --*/ { UINTN Address; CHAR16 *CommandStr; EFI_STATUS Status; // // Check argument // if (CommandArg != NULL) { if (EfiStriCmp (CommandArg, L"til") == 0) { CommandStr = StrGetNextTokenLine (L" "); if (CommandStr != NULL) { // // Enable GoTil break now // set BreakAddress, and set feature flag. // Status = Symboltoi (CommandStr, &Address); if (EFI_ERROR (Status)) { if (Status == EFI_NOT_FOUND) { Address = Xtoi(CommandStr); } else { // // Something wrong, let Symboltoi print error info. // EDBPrint (L"Command Argument error!\n"); return EFI_DEBUG_CONTINUE; } } DebuggerPrivate->GoTilContext.BreakAddress = Address; DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_GT; } else { EDBPrint (L"Command Argument error!\n"); return EFI_DEBUG_CONTINUE; } } else { EDBPrint (L"Command Argument error!\n"); return EFI_DEBUG_CONTINUE; } } // // Done // return EFI_DEBUG_BREAK; }
VOID EdbDisplayMemory ( IN UINTN Address, IN UINTN Count, IN EDB_DATA_WIDTH Width ) /*++ Routine Description: Display memory Arguments: Address - Memory Address Count - Memory Count Width - Memory Width Returns: None --*/ { UINTN LineNumber; UINTN ByteNumber; UINTN LineIndex; UINTN ByteIndex; UINTN NumberInLine; if (Count == 0) { return ; } // // Get line number and byte number // switch (Width) { case EdbWidthUint8: NumberInLine = 16; break; case EdbWidthUint16: NumberInLine = 8; break; case EdbWidthUint32: NumberInLine = 4; break; case EdbWidthUint64: NumberInLine = 2; break; default: return; } LineNumber = Count / NumberInLine; ByteNumber = Count % NumberInLine; if (ByteNumber == 0) { LineNumber -= 1; ByteNumber = NumberInLine; } // // Print each line // for (LineIndex = 0; LineIndex < LineNumber; LineIndex++) { // // Break check // if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) && (LineIndex != 0)) { if (SetPageBreak ()) { break; } } EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address); for (ByteIndex = 0; ByteIndex < NumberInLine; ByteIndex++) { Address += EdbDisplayMemoryUnit (Address, Width); } EDBPrint (L"\n"); } // // Break check // if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) && (LineIndex != 0)) { if (SetPageBreak ()) { return; } } // // Print last line // EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address); for (ByteIndex = 0; ByteIndex < ByteNumber; ByteIndex++) { Address += EdbDisplayMemoryUnit (Address, Width); } return ; }
EFI_STATUS EdbGetMemoryAddressValue ( IN CHAR16 *CommandArg, IN UINTN *Address, IN UINT64 *Value ) /*++ Routine Description: Get memory address and value Arguments: CommandArg - The argument for this command Address - Memory Address Value - Memory Value Returns: EFI_SUCCESS - memory address and value are got EFI_INVALID_PARAMETER - something wrong --*/ { CHAR16 *CommandStr; UINTN MemAddress; EFI_STATUS Status; // // Get Address // CommandStr = CommandArg; if (CommandStr == NULL) { EDBPrint (L"Memory: Address error!\n"); return EFI_INVALID_PARAMETER; } Status = Symboltoi (CommandStr, &MemAddress); if (EFI_ERROR (Status)) { if (Status == EFI_NOT_FOUND) { MemAddress = Xtoi(CommandStr); } else { // // Something wrong, let Symboltoi print error info. // EDBPrint (L"Command Argument error!\n"); return EFI_INVALID_PARAMETER; } } *Address = MemAddress; // // Get Value // CommandStr = StrGetNextTokenLine (L" "); if (CommandStr == NULL) { EDBPrint (L"Memory: Value error!\n"); return EFI_INVALID_PARAMETER; } *Value = LXtoi(CommandStr); // // Done // return EFI_SUCCESS; }