diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 5baf313679..f65f876644 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -73,6 +73,7 @@ local sources = CliContinueCommand.cpp CliDebugReportCommand.cpp CliDumpMemoryCommand.cpp + CliDumpStringCommand.cpp CliPrintVariableCommand.cpp CliQuitCommand.cpp CliStackFrameCommand.cpp diff --git a/src/apps/debugger/user_interface/cli/CliContext.cpp b/src/apps/debugger/user_interface/cli/CliContext.cpp index fa287fc03f..cb915fbf18 100644 --- a/src/apps/debugger/user_interface/cli/CliContext.cpp +++ b/src/apps/debugger/user_interface/cli/CliContext.cpp @@ -12,6 +12,7 @@ #include "StackTrace.h" #include "UserInterface.h" +#include "Value.h" #include "ValueNodeManager.h" #include "Variable.h" @@ -288,6 +289,57 @@ CliContext::SetCurrentStackFrameIndex(int32 index) } +status_t +CliContext::EvaluateExpression(const char* expression, + SourceLanguage* language, target_addr_t& address) +{ + fExpressionInfo->SetTo(expression); + + fListener->ExpressionEvaluationRequested( + language, fExpressionInfo); + WaitForEvents(CliContext::EVENT_EXPRESSION_EVALUATED); + if (fTerminating) + return B_INTERRUPTED; + + BString errorMessage; + if (fExpressionValue != NULL) { + if (fExpressionValue->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) { + Value* value = fExpressionValue->PrimitiveValue(); + BVariant variantValue; + value->ToVariant(variantValue); + if (variantValue.Type() == B_STRING_TYPE) + errorMessage.SetTo(variantValue.ToString()); + else + address = variantValue.ToUInt64(); + } + } else + errorMessage = strerror(fExpressionResult); + + if (!errorMessage.IsEmpty()) { + printf("Unable to evaluate expression: %s\n", + errorMessage.String()); + return B_ERROR; + } + + return B_OK; +} + + +status_t +CliContext::GetMemoryBlock(target_addr_t address, TeamMemoryBlock*& block) +{ + if (fCurrentBlock == NULL || !fCurrentBlock->Contains(address)) { + GetUserInterfaceListener()->InspectRequested(address, this); + WaitForEvents(CliContext::EVENT_TEAM_MEMORY_BLOCK_RETRIEVED); + if (fTerminating) + return B_INTERRUPTED; + } + + block = fCurrentBlock; + return B_OK; +} + + const char* CliContext::PromptUser(const char* prompt) { diff --git a/src/apps/debugger/user_interface/cli/CliContext.h b/src/apps/debugger/user_interface/cli/CliContext.h index 1891ce830e..77f1bfb6fd 100644 --- a/src/apps/debugger/user_interface/cli/CliContext.h +++ b/src/apps/debugger/user_interface/cli/CliContext.h @@ -19,6 +19,7 @@ #include "ValueNodeContainer.h" +class SourceLanguage; class StackFrame; class StackTrace; class Team; @@ -77,14 +78,11 @@ public: { return fCurrentStackFrameIndex; } void SetCurrentStackFrameIndex(int32 index); - TeamMemoryBlock* CurrentBlock() const { return fCurrentBlock; } + status_t EvaluateExpression(const char * expression, + SourceLanguage* language, target_addr_t& address); - ExpressionInfo* GetExpressionInfo() const - { return fExpressionInfo; } - status_t GetExpressionResult() const - { return fExpressionResult; } - ExpressionResult* GetExpressionValue() const - { return fExpressionValue; } + status_t GetMemoryBlock(target_addr_t address, + TeamMemoryBlock*& block); const char* PromptUser(const char* prompt); void AddLineToInputHistory(const char* line); diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp index b4964c6c77..371eb3f9c9 100644 --- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp +++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp @@ -20,6 +20,7 @@ #include "CliContinueCommand.h" #include "CliDebugReportCommand.h" #include "CliDumpMemoryCommand.h" +#include "CliDumpStringCommand.h" #include "CliPrintVariableCommand.h" #include "CliQuitCommand.h" #include "CliStackFrameCommand.h" @@ -300,8 +301,14 @@ CommandLineUserInterface::_RegisterCommands() { if (_RegisterCommand("bt sc", new(std::nothrow) CliStackTraceCommand) && _RegisterCommand("continue", new(std::nothrow) CliContinueCommand) - && _RegisterCommand("db ds dw dl string", new(std::nothrow) - CliDumpMemoryCommand) + && _RegisterCommand("db", new(std::nothrow) + CliDumpMemoryCommand(1, "byte", 16)) + && _RegisterCommand("ds", new(std::nothrow) + CliDumpMemoryCommand(2, "short", 8)) + && _RegisterCommand("dw", new(std::nothrow) + CliDumpMemoryCommand(4, "word", 4)) + && _RegisterCommand("dl", new(std::nothrow) + CliDumpMemoryCommand(8, "long", 2)) && _RegisterCommand("frame", new(std::nothrow) CliStackFrameCommand) && _RegisterCommand("help", new(std::nothrow) HelpCommand(this)) && _RegisterCommand("print", new(std::nothrow) CliPrintVariableCommand) @@ -309,6 +316,8 @@ CommandLineUserInterface::_RegisterCommands() && _RegisterCommand("save-report", new(std::nothrow) CliDebugReportCommand) && _RegisterCommand("stop", new(std::nothrow) CliStopCommand) + && _RegisterCommand("string", new(std::nothrow) + CliDumpStringCommand()) && _RegisterCommand("thread", new(std::nothrow) CliThreadCommand) && _RegisterCommand("threads", new(std::nothrow) CliThreadsCommand) && _RegisterCommand("variables", diff --git a/src/apps/debugger/user_interface/cli/commands/CliCommand.h b/src/apps/debugger/user_interface/cli/commands/CliCommand.h index d04d235c30..7721da54ab 100644 --- a/src/apps/debugger/user_interface/cli/commands/CliCommand.h +++ b/src/apps/debugger/user_interface/cli/commands/CliCommand.h @@ -26,7 +26,7 @@ public: virtual void Execute(int argc, const char* const* argv, CliContext& context) = 0; -private: +protected: const char* fSummary; const char* fUsage; }; diff --git a/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.cpp b/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.cpp index 9a627c6200..ab5d7192cc 100644 --- a/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.cpp +++ b/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.cpp @@ -26,12 +26,23 @@ #include "Variable.h" -CliDumpMemoryCommand::CliDumpMemoryCommand() +CliDumpMemoryCommand::CliDumpMemoryCommand(int itemSize, + const char* itemSizeNoun, int displayWidth) : - CliCommand("dump contents of debugged team's memory", - "%s [\"]address|expression[\"] [num]\n" - "Reads and displays the contents of memory at the target address.") + CliCommand(NULL, NULL), + itemSize(itemSize), + displayWidth(displayWidth) { + // BString manages the lifetime of the const char* put in fSummary and fUsage + fSummaryString.SetToFormat("dump contents of debugged team's memory in %s-sized increments", + itemSizeNoun); + fUsageString.SetToFormat("%%s [\"]address|expression[\"] [num]\n" + "Reads and displays the contents of memory at the target address in %d-byte increments", + itemSize); + + fSummary = fSummaryString.String(); + fUsage = fUsageString.String(); + // TODO: this should be retrieved via some indirect helper rather // than instantiating the specific language directly. fLanguage = new(std::nothrow) CppLanguage(); @@ -59,61 +70,13 @@ CliDumpMemoryCommand::Execute(int argc, const char* const* argv, return; } - ExpressionInfo* info = context.GetExpressionInfo(); - - target_addr_t address = 0; - info->SetTo(argv[1]); - - context.GetUserInterfaceListener()->ExpressionEvaluationRequested( - fLanguage, info); - context.WaitForEvents(CliContext::EVENT_EXPRESSION_EVALUATED); - if (context.IsTerminating()) + target_addr_t address; + if (context.EvaluateExpression(argv[1], fLanguage, address) != B_OK) return; - BString errorMessage; - ExpressionResult* result = context.GetExpressionValue(); - if (result != NULL) { - if (result->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) { - Value* value = result->PrimitiveValue(); - BVariant variantValue; - value->ToVariant(variantValue); - if (variantValue.Type() == B_STRING_TYPE) - errorMessage.SetTo(variantValue.ToString()); - else - address = variantValue.ToUInt64(); - } - } else - errorMessage = strerror(context.GetExpressionResult()); - - if (!errorMessage.IsEmpty()) { - printf("Unable to evaluate expression: %s\n", - errorMessage.String()); + TeamMemoryBlock* block = NULL; + if (context.GetMemoryBlock(address, block) != B_OK) return; - } - - int32 itemSize = 0; - int32 displayWidth = 0; - - // build the format string - if (strcmp(argv[0], "db") == 0) { - itemSize = 1; - displayWidth = 16; - } else if (strcmp(argv[0], "ds") == 0) { - itemSize = 2; - displayWidth = 8; - } else if (strcmp(argv[0], "dw") == 0) { - itemSize = 4; - displayWidth = 4; - } else if (strcmp(argv[0], "dl") == 0) { - itemSize = 8; - displayWidth = 2; - } else if (strcmp(argv[0], "string") == 0) { - itemSize = 1; - displayWidth = -1; - } else { - printf("dump called in an invalid way!\n"); - return; - } int32 num = 0; if (argc == 3) { @@ -127,44 +90,8 @@ CliDumpMemoryCommand::Execute(int argc, const char* const* argv, if (num <= 0) num = displayWidth; - TeamMemoryBlock* block = context.CurrentBlock(); - if (block == NULL || !block->Contains(address)) { - context.GetUserInterfaceListener()->InspectRequested(address, - &context); - context.WaitForEvents(CliContext::EVENT_TEAM_MEMORY_BLOCK_RETRIEVED); - if (context.IsTerminating()) - return; - block = context.CurrentBlock(); - } - - if (!strcmp(argv[0], "string")) { - printf("%p \"", (char*)address); - - target_addr_t offset = address; - char c; - while (block->Contains(offset)) { - c = *(block->Data() + offset - block->BaseAddress()); - - if (c == '\0') - break; - if (c == '\n') - printf("\\n"); - else if (c == '\t') - printf("\\t"); - else { - if (!isprint(c)) - c = '.'; - - printf("%c", c); - } - ++offset; - } - - printf("\"\n"); - } else { - BString output; - UiUtils::DumpMemory(output, 0, block, address, itemSize, displayWidth, - num); - printf("%s\n", output.String()); - } + BString output; + UiUtils::DumpMemory(output, 0, block, address, itemSize, displayWidth, + num); + printf("%s\n", output.String()); } diff --git a/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.h b/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.h index 79a66ce611..97fd1d19e1 100644 --- a/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.h +++ b/src/apps/debugger/user_interface/cli/commands/CliDumpMemoryCommand.h @@ -8,13 +8,17 @@ #include "CliCommand.h" +#include + class SourceLanguage; class CliDumpMemoryCommand : public CliCommand { public: - CliDumpMemoryCommand(); + CliDumpMemoryCommand(int itemSize, + const char* itemSizeNoun, + int displayWidth); virtual ~CliDumpMemoryCommand(); virtual void Execute(int argc, const char* const* argv, @@ -22,6 +26,10 @@ public: private: SourceLanguage* fLanguage; + BString fSummaryString; + BString fUsageString; + int itemSize; + int displayWidth; }; diff --git a/src/apps/debugger/user_interface/cli/commands/CliDumpStringCommand.cpp b/src/apps/debugger/user_interface/cli/commands/CliDumpStringCommand.cpp new file mode 100644 index 0000000000..f55b18b3f9 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/commands/CliDumpStringCommand.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2012-2016, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + + +#include "CliDumpStringCommand.h" + +#include +#include + +#include + +#include "CliContext.h" +#include "CppLanguage.h" +#include "Team.h" +#include "TeamMemoryBlock.h" +#include "UiUtils.h" +#include "UserInterface.h" +#include "Value.h" +#include "Variable.h" + + +CliDumpStringCommand::CliDumpStringCommand() + : + CliCommand("dump contents of a string in the debugged team's memory", + "%s [\"]address|expression[\"]\n" + "Reads and displays the contents of a null-terminated string at the target address.") +{ + // TODO: this should be retrieved via some indirect helper rather + // than instantiating the specific language directly. + fLanguage = new(std::nothrow) CppLanguage(); +} + + +CliDumpStringCommand::~CliDumpStringCommand() +{ + if (fLanguage != NULL) + fLanguage->ReleaseReference(); +} + + +void +CliDumpStringCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + if (argc < 2) { + PrintUsage(argv[0]); + return; + } + + if (fLanguage == NULL) { + printf("Unable to evaluate expression: %s\n", strerror(B_NO_MEMORY)); + return; + } + + target_addr_t address; + if (context.EvaluateExpression(argv[1], fLanguage, address) != B_OK) + return; + + TeamMemoryBlock* block = NULL; + if (context.GetMemoryBlock(address, block) != B_OK) + return; + + printf("%p \"", (char*)address); + + target_addr_t offset = address; + char c; + while (block->Contains(offset)) { + c = *(block->Data() + offset - block->BaseAddress()); + + if (c == '\0') + break; + if (c == '\n') + printf("\\n"); + else if (c == '\t') + printf("\\t"); + else { + if (!isprint(c)) + c = '.'; + + printf("%c", c); + } + ++offset; + } + + printf("\"\n"); +} diff --git a/src/apps/debugger/user_interface/cli/commands/CliDumpStringCommand.h b/src/apps/debugger/user_interface/cli/commands/CliDumpStringCommand.h new file mode 100644 index 0000000000..b26b388d47 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/commands/CliDumpStringCommand.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2014, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef CLI_DUMP_STRING_COMMAND_H +#define CLI_DUMP_STRING_COMMAND_H + + +#include "CliCommand.h" + + +class SourceLanguage; + + +class CliDumpStringCommand : public CliCommand { +public: + CliDumpStringCommand(); + virtual ~CliDumpStringCommand(); + + virtual void Execute(int argc, const char* const* argv, + CliContext& context); + +private: + SourceLanguage* fLanguage; +}; + + +#endif // CLI_DUMP_STRING_COMMAND_H