/** * @file test.cpp * @author Sina Karvandi (sina@hyperdbg.org) * @brief test command * @details * @version 0.1 * @date 2020-06-11 * * @copyright This project is released under the GNU Public License v3. * */ #include "pch.h" #include #include #include #include namespace fs = std::filesystem; // // Global Variables // extern BOOLEAN g_IsKdModuleLoaded; extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee; extern BOOLEAN g_CurrentExprEvalResultHasError; struct CLI_SEMANTIC_EXPECTATION { std::set Cases; std::set Markers; std::string ExpectedError; }; struct CLI_SEMANTIC_RESULT { fs::path File; BOOLEAN Passed = FALSE; std::string Diagnostic; std::string Output; SIZE_T ExpectationCount = 0; UINT64 DurationMilliseconds = 0; }; static std::mutex g_CliSemanticOutputMutex; static std::string g_CliSemanticOutput; static VOID CommandTestCaptureSemanticOutput(CHAR* Message) { if (!Message) return; std::lock_guard Lock(g_CliSemanticOutputMutex); g_CliSemanticOutput.append(Message); } static std::string CommandTestLowerAscii(std::string Value) { std::transform(Value.begin(), Value.end(), Value.begin(), [](unsigned char Character) { return (CHAR)std::tolower(Character); }); return Value; } static BOOLEAN CommandTestParseSemanticFile(const fs::path& FilePath, const std::vector& Arguments, std::string& Expression, CLI_SEMANTIC_EXPECTATION& Expectation, std::string& Error) { std::ifstream File(FilePath, std::ios::binary); if (!File) { Error = "could not open file"; return FALSE; } std::string Content((std::istreambuf_iterator(File)), std::istreambuf_iterator()); if (File.bad()) { Error = "could not read file"; return FALSE; } // Match .script argument semantics. Replace higher indexes first so an // argument such as $arg10 cannot be partially consumed as $arg1. for (SIZE_T Index = Arguments.size(); Index > 0; --Index) ReplaceAll(Content, "$arg" + std::to_string(Index - 1), Arguments[Index - 1]); Expectation = {}; const std::regex CasePattern("test_case([0-9]+)[[:space:]]*=[[:space:]]*1"); const std::regex MarkerPattern("//[[:space:]]*semantic-test-marker:[[:space:]]*([^\\r\\n]+)"); const std::regex ErrorPattern("//[[:space:]]*semantic-test-expect-error:[[:space:]]*([^\\r\\n]+)"); for (std::sregex_iterator Match(Content.begin(), Content.end(), CasePattern), End; Match != End; ++Match) Expectation.Cases.insert((UINT32)std::stoul((*Match)[1].str())); for (std::sregex_iterator Match(Content.begin(), Content.end(), MarkerPattern), End; Match != End; ++Match) { std::string Marker = (*Match)[1].str(); while (!Marker.empty() && std::isspace((unsigned char)Marker.back())) Marker.pop_back(); if (!Marker.empty()) Expectation.Markers.insert(Marker); } { std::smatch Match; if (std::regex_search(Content, Match, ErrorPattern)) { Expectation.ExpectedError = Match[1].str(); while (!Expectation.ExpectedError.empty() && std::isspace((unsigned char)Expectation.ExpectedError.back())) Expectation.ExpectedError.pop_back(); } } if (Expectation.Cases.empty() && Expectation.Markers.empty() && Expectation.ExpectedError.empty()) { Error = "no enabled numbered case or semantic-test-marker"; return FALSE; } SIZE_T CommandStart = std::string::npos; for (SIZE_T LineStart = 0; LineStart < Content.size();) { SIZE_T LineEnd = Content.find('\n', LineStart); SIZE_T First = Content.find_first_not_of(" \t\r", LineStart); if (First != std::string::npos && (LineEnd == std::string::npos || First < LineEnd) && Content[First] == '?') { CommandStart = First; break; } if (LineEnd == std::string::npos) break; LineStart = LineEnd + 1; } if (CommandStart == std::string::npos) { Error = "semantic script has no '?' command"; return FALSE; } SIZE_T ExpressionStart = Content.find_first_not_of(" \t\r\n", CommandStart + 1); if (ExpressionStart == std::string::npos) { Error = "semantic script has no expression"; return FALSE; } Expression.assign(Content, ExpressionStart, std::string::npos); return TRUE; } static BOOLEAN CommandTestMalformedAggregatePush() { UINT64 Stack[MAX_STACK_BUFFER_COUNT] = { 0 }; UINT64 Globals[1] = { 0 }; ACTION_BUFFER Action = { 0 }; GUEST_REGS GuestRegs = { 0 }; SYMBOL ErrorOperator = { 0 }; auto RunMalformedCase = [&](SYMBOL* Symbols, UINT32 Count, UINT64 InitialStackIndex) { SYMBOL_BUFFER Buffer = { Symbols, Count, Count, NULL }; SCRIPT_ENGINE_GENERAL_REGISTERS Registers = { Stack, Globals, InitialStackIndex, 0, 0 }; UINT64 Index = 0; BOOLEAN HasError = ScriptEngineExecute(&GuestRegs, &Action, &Registers, &Buffer, &Index, &ErrorOperator); return HasError && Registers.StackIndx == InitialStackIndex; }; SYMBOL MissingOperands[] = { {SYMBOL_SEMANTIC_RULE_TYPE, 0, FUNC_PUSH_AGGREGATE} }; SYMBOL InvalidAddressSpace[] = { {SYMBOL_SEMANTIC_RULE_TYPE, 0, FUNC_PUSH_AGGREGATE}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, (UINT64)&Stack[0]}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, 99}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, 8} }; SYMBOL InvalidSize[] = { {SYMBOL_SEMANTIC_RULE_TYPE, 0, FUNC_PUSH_AGGREGATE}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, (UINT64)&Stack[0]}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, SCRIPT_ENGINE_ADDRESS_SPACE_LOCAL}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, 0} }; SYMBOL StackOverflow[] = { {SYMBOL_SEMANTIC_RULE_TYPE, 0, FUNC_PUSH_AGGREGATE}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, (UINT64)&Stack[0]}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, SCRIPT_ENGINE_ADDRESS_SPACE_LOCAL}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, 8} }; SYMBOL InvalidSourceRange[] = { {SYMBOL_SEMANTIC_RULE_TYPE, 0, FUNC_PUSH_AGGREGATE}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, (UINT64)((BYTE*)&Stack[MAX_STACK_BUFFER_COUNT] - 4)}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, SCRIPT_ENGINE_ADDRESS_SPACE_LOCAL}, {SYMBOL_NUM_TYPE, SYMBOL_VALUE_KIND_INTEGER, 8} }; return RunMalformedCase(MissingOperands, ARRAYSIZE(MissingOperands), 7) && RunMalformedCase(InvalidAddressSpace, ARRAYSIZE(InvalidAddressSpace), 7) && RunMalformedCase(InvalidSize, ARRAYSIZE(InvalidSize), 7) && RunMalformedCase(StackOverflow, ARRAYSIZE(StackOverflow), MAX_STACK_BUFFER_COUNT) && RunMalformedCase(InvalidSourceRange, ARRAYSIZE(InvalidSourceRange), 7); } static BOOLEAN CommandTestHasSemanticFailure(const std::string& Output) { std::istringstream Lines(Output); std::string Line; while (std::getline(Lines, Line)) { std::string Lower = CommandTestLowerAscii(Line); SIZE_T First = Lower.find_first_not_of(" \t\r"); if (First == std::string::npos) continue; Lower.erase(0, First); if (Lower.find("was failed") != std::string::npos || Lower.rfind("err,", 0) == 0 || Lower.rfind("error:", 0) == 0 || Lower.rfind("[x]", 0) == 0) return TRUE; } return FALSE; } static BOOLEAN CommandTestHasExpectedSemanticOutput(const CLI_SEMANTIC_EXPECTATION& Expectation, const std::string& Output, std::string& Missing) { if (CommandTestHasSemanticFailure(Output)) return FALSE; std::set SuccessfulCases; const std::regex Pattern("test case ([0-9]+) was successful"); std::istringstream Lines(Output); std::string Line; while (std::getline(Lines, Line)) { if (!Line.empty() && Line.back() == '\r') Line.pop_back(); std::smatch Match; if (std::regex_match(Line, Match, Pattern)) SuccessfulCases.insert((UINT32)std::stoul(Match[1].str())); } for (UINT32 Case : Expectation.Cases) { if (!SuccessfulCases.contains(Case)) { Missing = "missing test case " + std::to_string(Case) + " success output"; return FALSE; } } for (const std::string& Marker : Expectation.Markers) { if (Output.find(Marker) == std::string::npos) { Missing = "missing semantic marker: " + Marker; return FALSE; } } return TRUE; } static VOID CommandTestScriptSemantic() { CHAR Directory[MAX_PATH] = { 0 }; if (!SetupPathForFileName(SCRIPT_SEMANTIC_TEST_CASE_DIRECTORY, Directory, sizeof(Directory), FALSE)) { ShowMessages("err, could not resolve the semantic test directory\n"); return; } ShowMessages("[ RUN ] malformed FUNC_PUSH_AGGREGATE validation\n"); if (!CommandTestMalformedAggregatePush()) { ShowMessages("[ FAILED ] malformed FUNC_PUSH_AGGREGATE validation\n"); return; } ShowMessages("[ OK ] malformed FUNC_PUSH_AGGREGATE validation (5 expectations)\n"); std::vector Files; try { for (const fs::directory_entry& Entry : fs::directory_iterator(Directory)) if (Entry.is_regular_file() && CommandTestLowerAscii(Entry.path().extension().string()) == ".ds") Files.push_back(Entry.path()); std::sort(Files.begin(), Files.end(), [](const fs::path& Left, const fs::path& Right) { std::string L = CommandTestLowerAscii(Left.filename().string()); std::string R = CommandTestLowerAscii(Right.filename().string()); return L == R ? Left.filename().string() < Right.filename().string() : L < R; }); } catch (const fs::filesystem_error& Exception) { ShowMessages("err, could not enumerate semantic tests: %s\n", Exception.what()); return; } if (Files.empty()) { ShowMessages("err, no semantic .ds files were found in: %s\n", Directory); return; } std::vector Results; for (const fs::path& File : Files) { ShowMessages("[ RUN ] %s\n", File.filename().string().c_str()); CLI_SEMANTIC_RESULT Result; Result.File = File; CLI_SEMANTIC_EXPECTATION Expectation; std::string Expression; auto Started = std::chrono::steady_clock::now(); const std::vector Arguments = { File.string(), g_IsSerialConnectedToRemoteDebuggee ? "1" : "0", g_IsSerialConnectedToRemoteDebuggee ? "nt!ExAllocatePoolWithTag" : "0" }; if (CommandTestParseSemanticFile(File, Arguments, Expression, Expectation, Result.Diagnostic)) { Result.ExpectationCount = Expectation.Cases.size() + Expectation.Markers.size() + (Expectation.ExpectedError.empty() ? 0 : 1); { std::lock_guard Lock(g_CliSemanticOutputMutex); g_CliSemanticOutput.clear(); } BOOLEAN ExecutionSucceeded = TRUE; SetTextMessageCallback((PVOID)CommandTestCaptureSemanticOutput); if (g_IsSerialConnectedToRemoteDebuggee) { // Match the '?' command path in debugger mode so semantic cases // execute against the real debuggee registers and VMX-root // facilities instead of the simulated user-mode environment. ExecutionSucceeded = ScriptEngineExecuteSingleExpression( (CHAR*)Expression.c_str(), TRUE, FALSE); } else { ScriptEngineWrapperTestParser(Expression); ExecutionSucceeded = !g_CurrentExprEvalResultHasError; } UnsetTextMessageCallback(); { std::lock_guard Lock(g_CliSemanticOutputMutex); Result.Output = g_CliSemanticOutput; } if (!Expectation.ExpectedError.empty()) { std::string LowerOutput = CommandTestLowerAscii(Result.Output); std::string LowerExpected = CommandTestLowerAscii(Expectation.ExpectedError); Result.Passed = !ExecutionSucceeded && (LowerExpected == "any" || LowerOutput.find(LowerExpected) != std::string::npos); if (!Result.Passed) Result.Diagnostic = ExecutionSucceeded ? "script unexpectedly succeeded" : "expected error text was not reported"; } else if (!ExecutionSucceeded) Result.Diagnostic = g_IsSerialConnectedToRemoteDebuggee ? "remote script evaluator reported an error" : "local script evaluator reported an error"; else if (CommandTestHasSemanticFailure(Result.Output)) Result.Diagnostic = "semantic failure output was reported"; else Result.Passed = CommandTestHasExpectedSemanticOutput(Expectation, Result.Output, Result.Diagnostic); } Result.DurationMilliseconds = (UINT64)std::chrono::duration_cast( std::chrono::steady_clock::now() - Started).count(); std::string PassDetails = Result.Passed ? std::to_string(Result.ExpectationCount) + " expectations, " : ""; ShowMessages("[%s] %s (%s%llu ms)%s%s\n", Result.Passed ? " OK " : " FAILED ", File.filename().string().c_str(), PassDetails.c_str(), Result.DurationMilliseconds, Result.Diagnostic.empty() ? "" : " - ", Result.Diagnostic.c_str()); Results.push_back(std::move(Result)); } SIZE_T Passed = std::count_if(Results.begin(), Results.end(), [](const CLI_SEMANTIC_RESULT& Result) { return Result.Passed; }); ShowMessages("\nSemantic script suite: %llu files, %llu passed, %llu failed\n", (UINT64)Results.size(), (UINT64)Passed, (UINT64)(Results.size() - Passed)); if (Passed != Results.size()) { ShowMessages("Failed files:\n"); for (const CLI_SEMANTIC_RESULT& Result : Results) { if (Result.Passed) continue; ShowMessages(" %s\n %s\n", Result.File.filename().string().c_str(), Result.Diagnostic.c_str()); if (!Result.Output.empty()) ShowMessages("----- captured output -----\n%s%s----- end captured output -----\n", Result.Output.c_str(), Result.Output.back() == '\n' ? "" : "\n"); } } } /** * @brief help of the test command * * @return VOID */ VOID CommandTestHelp() { ShowMessages( "test : tests essential features of HyperDbg in current machine.\n"); ShowMessages("syntax : \ttest [Task (string)]\n"); ShowMessages("\n"); ShowMessages("\t\te.g : test query\n"); ShowMessages("\t\te.g : test trap-status\n"); ShowMessages("\t\te.g : test pool\n"); ShowMessages("\t\te.g : test query\n"); ShowMessages("\t\te.g : test breakpoint on\n"); ShowMessages("\t\te.g : test breakpoint off\n"); ShowMessages("\t\te.g : test trap on\n"); ShowMessages("\t\te.g : test trap off\n"); ShowMessages("\t\te.g : test script-semantic\n"); } /** * @brief Send an IOCTL to the kernel to run the * * @return BOOLEAN */ BOOLEAN CommandTestPerformKernelTestsIoctl() { BOOL Status; ULONG ReturnedLength; DEBUGGER_PERFORM_KERNEL_TESTS KernelTestRequest = { 0 }; AssertShowMessageReturnStmt(g_IsKdModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_KD_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); // // By the way, we don't need to send an input buffer // to the kernel, but let's keep it like this, if we // want to pass some other arguments to the kernel in // the future // Status = PlatformDeviceIoControl( g_DeviceHandle, // Handle to device IOCTL_PERFORM_KERNEL_SIDE_TESTS, // IO Control Code (IOCTL) &KernelTestRequest, // Input Buffer to driver. SIZEOF_DEBUGGER_PERFORM_KERNEL_TESTS, // Input buffer length &KernelTestRequest, // Output Buffer from driver. SIZEOF_DEBUGGER_PERFORM_KERNEL_TESTS, // Length of output buffer in // bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); return FALSE; } if (KernelTestRequest.KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL) { // // Nothing to show // return TRUE; } else { // // Show err message // ShowErrorMessage(KernelTestRequest.KernelStatus); return FALSE; } } /** * @brief perform test on for all functionalities * * @return VOID */ VOID CommandTestAllFunctionalities() { HANDLE ThreadHandle; HANDLE ProcessHandle; // // Test command parser // if (!OpenHyperDbgTestProcess(&ThreadHandle, &ProcessHandle, (CHAR*)TEST_CASE_PARAMETER_FOR_MAIN_COMMAND_PARSER)) { ShowMessages("err, start HyperDbg test process for testing the main command parser\n"); return; } // // Test PE parser helpers // if (!OpenHyperDbgTestProcess(&ThreadHandle, &ProcessHandle, (CHAR*)TEST_CASE_PARAMETER_FOR_PE_PARSER)) { ShowMessages("err, start HyperDbg test process for testing the PE parser\n"); return; } // // Test CodeView RSDS parser helpers // if (!OpenHyperDbgTestProcess(&ThreadHandle, &ProcessHandle, (CHAR*)TEST_CASE_PARAMETER_FOR_CODEVIEW_RSDS_PARSER)) { ShowMessages("err, start HyperDbg test process for testing the CodeView RSDS parser\n"); return; } // // Test script engine (script parser) using semantic tests // if (!OpenHyperDbgTestProcess(&ThreadHandle, &ProcessHandle, (CHAR*)TEST_CASE_PARAMETER_FOR_SCRIPT_SEMANTIC_TEST_CASES)) { ShowMessages("err, start HyperDbg test process for testing semantic tests\n"); return; } } /** * @brief perform test for all functionalities of hwdbg * * @return VOID */ VOID CommandTestAllHwdbg() { HANDLE ThreadHandle; HANDLE ProcessHandle; // // Test hwdbg functionalities // if (!OpenHyperDbgTestProcess(&ThreadHandle, &ProcessHandle, (CHAR*)TEST_HWDBG_FUNCTIONALITIES)) { ShowMessages("err, start HyperDbg test process for testing hwdbg functionalities\n"); return; } } /** * @brief perform test on the remote process * * @return BOOLEAN returns true if the results was true and false if the results * was not ok */ BOOLEAN CommandTestPerformTest() { BOOLEAN ResultOfTest = FALSE; HANDLE PipeHandle; HANDLE ThreadHandle; HANDLE ProcessHandle; UINT32 ReadBytes; CHAR* Buffer = NULL; // // Allocate memory // Buffer = (CHAR*)malloc(TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE); if (!Buffer) { ShowMessages("err, enable allocate communication buffer\n"); return FALSE; } PlatformZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE); // // Create tests process to create a thread for us // if (!CreateProcessAndOpenPipeConnection(&PipeHandle, &ThreadHandle, &ProcessHandle)) { ShowMessages("err, enable to connect to the test process\n"); free(Buffer); return FALSE; } // // ***** Perform test specific routines ***** // // // Wait for the result of test to be received // SendCommandAndWaitForResponse: CHAR TestCommand[] = "this is a test command"; BOOLEAN SentMessageResult = NamedPipeServerSendMessageToClient( PipeHandle, TestCommand, (UINT32)strlen(TestCommand) + 1); if (!SentMessageResult) { // // error in sending // return FALSE; } PlatformZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE); ReadBytes = NamedPipeServerReadClientMessage(PipeHandle, (CHAR*)Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE); if (!ReadBytes) { // // Nothing to read // free(Buffer); return FALSE; } goto SendCommandAndWaitForResponse; // // Close connection and remote process // CloseProcessAndClosePipeConnection(PipeHandle, ThreadHandle, ProcessHandle); free(Buffer); return ResultOfTest; } /** * @brief test command for query the state * * @return VOID */ VOID CommandTestQueryState() { if (!g_IsSerialConnectedToRemoteDebuggee) { ShowMessages("err, query state of the debuggee is only possible when you connected " "in debugger mode\n"); return; } // // Send the query to the debuggee // KdSendTestQueryPacketToDebuggee(TEST_QUERY_HALTING_CORE_STATUS); } /** * @brief test command for query the trap state * * @return VOID */ VOID CommandTestQueryTrapState() { if (!g_IsSerialConnectedToRemoteDebuggee) { ShowMessages("err, query state of the debuggee is only possible when you connected " "in debugger mode\n"); return; } // // Send the query to the debuggee // KdSendTestQueryPacketToDebuggee(TEST_QUERY_TRAP_STATE); } /** * @brief test command for query the state of pre-allocated pools * * @return VOID */ VOID CommandTestQueryPreAllocPoolsState() { if (!g_IsSerialConnectedToRemoteDebuggee) { ShowMessages("err, query state of the debuggee is only possible when you connected " "in debugger mode\n"); return; } // // Send the query to the debuggee // KdSendTestQueryPacketToDebuggee(TEST_QUERY_PREALLOCATED_POOL_STATE); } /** * @brief test command for setting target tasks to halted cores * @param Synchronous * * @return VOID */ VOID CommandTestSetTargetTaskToHaltedCores(BOOLEAN Synchronous) { if (!g_IsSerialConnectedToRemoteDebuggee) { ShowMessages("err, query state of the debuggee is only possible when you connected " "in debugger mode\n"); return; } // // Send the target tasks to the halted cores // KdSendTestQueryPacketToDebuggee(Synchronous ? TEST_SETTING_TARGET_TASKS_ON_HALTED_CORES_SYNCHRONOUS : TEST_SETTING_TARGET_TASKS_ON_HALTED_CORES_ASYNCHRONOUS); } /** * @brief test command for setting target task to the specified core * @param CoreNumber * * @return VOID */ VOID CommandTestSetTargetTaskToTargetCore(UINT32 CoreNumber) { if (!g_IsSerialConnectedToRemoteDebuggee) { ShowMessages("err, query state of the debuggee is only possible when you connected " "in debugger mode\n"); return; } // // Send the target task to the target halted core // KdSendTestQueryPacketWithContextToDebuggee(TEST_SETTING_TARGET_TASKS_ON_TARGET_HALTED_CORES, (UINT64)CoreNumber); } /** * @brief test command for turning on/off the breakpoints (#DB) * @param State * @return VOID */ VOID CommandTestSetBreakpointState(BOOLEAN State) { if (!g_IsSerialConnectedToRemoteDebuggee) { ShowMessages("err, query state of the debuggee is only possible when you connected " "in debugger mode\n"); return; } // // Send the breakpoint settings to the debuggee // if (State) { KdSendTestQueryPacketToDebuggee(TEST_BREAKPOINT_TURN_ON_BPS); } else { KdSendTestQueryPacketToDebuggee(TEST_BREAKPOINT_TURN_OFF_BPS); } } /** * @brief test command for turning on/off the debug breaks (#DB) * @param State * @return VOID */ VOID CommandTestSetDebugBreakState(BOOLEAN State) { if (!g_IsSerialConnectedToRemoteDebuggee) { ShowMessages("err, query state of the debuggee is only possible when you connected " "in debugger mode\n"); return; } // // Send the debug break settings to the debuggee // if (State) { KdSendTestQueryPacketToDebuggee(TEST_BREAKPOINT_TURN_ON_DBS); } else { KdSendTestQueryPacketToDebuggee(TEST_BREAKPOINT_TURN_OFF_DBS); } } /** * @brief test command handler * * @param CommandTokens * @param Command * * @return VOID */ VOID CommandTest(vector CommandTokens, string Command) { UINT64 Context = NULL; UINT32 CommandSize = (UINT32)CommandTokens.size(); if (CommandSize == 1) { ShowMessages("incorrect use of the '%s'\n\n", GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str()); CommandTestHelp(); } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "query")) { // // Query the state of debuggee in debugger mode // CommandTestQueryState(); } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "trap-status")) { // // Query the state of trap flag in debugger mode // CommandTestQueryTrapState(); } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "pool")) { // // Query the state of pre-allocated pools in debugger mode // CommandTestQueryPreAllocPoolsState(); } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "sync-task")) { // // Send target task to the halted cores in debugger mode (synchronous) // CommandTestSetTargetTaskToHaltedCores(TRUE); } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "async-task")) { // // Send target task to the halted cores in debugger mode (asynchronous) // CommandTestSetTargetTaskToHaltedCores(FALSE); } else if (CommandSize == 3 && CompareLowerCaseStrings(CommandTokens.at(1), "target-core-task")) { if (!ConvertTokenToUInt64(CommandTokens.at(2), &Context)) { ShowMessages("err, you should enter a valid hex number as the core id\n\n"); return; } // // Send target task to the specific halted core in debugger mode // CommandTestSetTargetTaskToTargetCore((UINT32)Context); } else if (CommandSize == 3 && CompareLowerCaseStrings(CommandTokens.at(1), "breakpoint")) { // // Change breakpoint state // if (CompareLowerCaseStrings(CommandTokens.at(2), "on")) { CommandTestSetBreakpointState(TRUE); } else if (CompareLowerCaseStrings(CommandTokens.at(2), "off")) { CommandTestSetBreakpointState(FALSE); } else { ShowMessages("err, couldn't resolve error at '%s'\n\n", GetCaseSensitiveStringFromCommandToken(CommandTokens.at(2)).c_str()); return; } } else if (CommandSize == 3 && CompareLowerCaseStrings(CommandTokens.at(1), "trap")) { // // Change debug break state // if (CompareLowerCaseStrings(CommandTokens.at(2), "on")) { CommandTestSetDebugBreakState(TRUE); } else if (CompareLowerCaseStrings(CommandTokens.at(2), "off")) { CommandTestSetDebugBreakState(FALSE); } else { ShowMessages("err, couldn't resolve error at '%s'\n\n", GetCaseSensitiveStringFromCommandToken(CommandTokens.at(2)).c_str()); return; } } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "all")) { // // For testing functionalities // CommandTestAllFunctionalities(); } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "script-semantic")) { CommandTestScriptSemantic(); } else if (CommandSize == 2 && CompareLowerCaseStrings(CommandTokens.at(1), "hwdbg")) { // // For testing functionalities of hwdbg // CommandTestAllHwdbg(); } else { ShowMessages("incorrect use of the '%s'\n\n", GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str()); CommandTestHelp(); return; } }