Debugger: improve command help text

Improve the help text of the db, dw, ds, dl, and string commands.

This is accomplished by
* Splitting CliDumpMemoryCommand into CliDumpMemoryCommand and
  CliDumpStringCommand
* Moving code shared between the two into CliContext
* Removing functions in CliContext that were replaced by this movement
* Allowing customizing the help text for CliDumpMemoryCommand for each
  command it represents
* Changing the help text for CliDumpStringCommand

Change-Id: If4f9e0c20f00f3e3d6c6769216fabb3160aea0a4
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6332
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Zardshard
2023-04-19 09:01:04 +00:00
committed by Adrien Destugues
parent 92f36c4a61
commit 44daad619e
9 changed files with 223 additions and 107 deletions
+1
View File
@@ -73,6 +73,7 @@ local sources =
CliContinueCommand.cpp CliContinueCommand.cpp
CliDebugReportCommand.cpp CliDebugReportCommand.cpp
CliDumpMemoryCommand.cpp CliDumpMemoryCommand.cpp
CliDumpStringCommand.cpp
CliPrintVariableCommand.cpp CliPrintVariableCommand.cpp
CliQuitCommand.cpp CliQuitCommand.cpp
CliStackFrameCommand.cpp CliStackFrameCommand.cpp
@@ -12,6 +12,7 @@
#include "StackTrace.h" #include "StackTrace.h"
#include "UserInterface.h" #include "UserInterface.h"
#include "Value.h"
#include "ValueNodeManager.h" #include "ValueNodeManager.h"
#include "Variable.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* const char*
CliContext::PromptUser(const char* prompt) CliContext::PromptUser(const char* prompt)
{ {
@@ -19,6 +19,7 @@
#include "ValueNodeContainer.h" #include "ValueNodeContainer.h"
class SourceLanguage;
class StackFrame; class StackFrame;
class StackTrace; class StackTrace;
class Team; class Team;
@@ -77,14 +78,11 @@ public:
{ return fCurrentStackFrameIndex; } { return fCurrentStackFrameIndex; }
void SetCurrentStackFrameIndex(int32 index); void SetCurrentStackFrameIndex(int32 index);
TeamMemoryBlock* CurrentBlock() const { return fCurrentBlock; } status_t EvaluateExpression(const char * expression,
SourceLanguage* language, target_addr_t& address);
ExpressionInfo* GetExpressionInfo() const status_t GetMemoryBlock(target_addr_t address,
{ return fExpressionInfo; } TeamMemoryBlock*& block);
status_t GetExpressionResult() const
{ return fExpressionResult; }
ExpressionResult* GetExpressionValue() const
{ return fExpressionValue; }
const char* PromptUser(const char* prompt); const char* PromptUser(const char* prompt);
void AddLineToInputHistory(const char* line); void AddLineToInputHistory(const char* line);
@@ -20,6 +20,7 @@
#include "CliContinueCommand.h" #include "CliContinueCommand.h"
#include "CliDebugReportCommand.h" #include "CliDebugReportCommand.h"
#include "CliDumpMemoryCommand.h" #include "CliDumpMemoryCommand.h"
#include "CliDumpStringCommand.h"
#include "CliPrintVariableCommand.h" #include "CliPrintVariableCommand.h"
#include "CliQuitCommand.h" #include "CliQuitCommand.h"
#include "CliStackFrameCommand.h" #include "CliStackFrameCommand.h"
@@ -300,8 +301,14 @@ CommandLineUserInterface::_RegisterCommands()
{ {
if (_RegisterCommand("bt sc", new(std::nothrow) CliStackTraceCommand) if (_RegisterCommand("bt sc", new(std::nothrow) CliStackTraceCommand)
&& _RegisterCommand("continue", new(std::nothrow) CliContinueCommand) && _RegisterCommand("continue", new(std::nothrow) CliContinueCommand)
&& _RegisterCommand("db ds dw dl string", new(std::nothrow) && _RegisterCommand("db", new(std::nothrow)
CliDumpMemoryCommand) 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("frame", new(std::nothrow) CliStackFrameCommand)
&& _RegisterCommand("help", new(std::nothrow) HelpCommand(this)) && _RegisterCommand("help", new(std::nothrow) HelpCommand(this))
&& _RegisterCommand("print", new(std::nothrow) CliPrintVariableCommand) && _RegisterCommand("print", new(std::nothrow) CliPrintVariableCommand)
@@ -309,6 +316,8 @@ CommandLineUserInterface::_RegisterCommands()
&& _RegisterCommand("save-report", && _RegisterCommand("save-report",
new(std::nothrow) CliDebugReportCommand) new(std::nothrow) CliDebugReportCommand)
&& _RegisterCommand("stop", new(std::nothrow) CliStopCommand) && _RegisterCommand("stop", new(std::nothrow) CliStopCommand)
&& _RegisterCommand("string", new(std::nothrow)
CliDumpStringCommand())
&& _RegisterCommand("thread", new(std::nothrow) CliThreadCommand) && _RegisterCommand("thread", new(std::nothrow) CliThreadCommand)
&& _RegisterCommand("threads", new(std::nothrow) CliThreadsCommand) && _RegisterCommand("threads", new(std::nothrow) CliThreadsCommand)
&& _RegisterCommand("variables", && _RegisterCommand("variables",
@@ -26,7 +26,7 @@ public:
virtual void Execute(int argc, const char* const* argv, virtual void Execute(int argc, const char* const* argv,
CliContext& context) = 0; CliContext& context) = 0;
private: protected:
const char* fSummary; const char* fSummary;
const char* fUsage; const char* fUsage;
}; };
@@ -26,12 +26,23 @@
#include "Variable.h" #include "Variable.h"
CliDumpMemoryCommand::CliDumpMemoryCommand() CliDumpMemoryCommand::CliDumpMemoryCommand(int itemSize,
const char* itemSizeNoun, int displayWidth)
: :
CliCommand("dump contents of debugged team's memory", CliCommand(NULL, NULL),
"%s [\"]address|expression[\"] [num]\n" itemSize(itemSize),
"Reads and displays the contents of memory at the target address.") 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 // TODO: this should be retrieved via some indirect helper rather
// than instantiating the specific language directly. // than instantiating the specific language directly.
fLanguage = new(std::nothrow) CppLanguage(); fLanguage = new(std::nothrow) CppLanguage();
@@ -59,61 +70,13 @@ CliDumpMemoryCommand::Execute(int argc, const char* const* argv,
return; return;
} }
ExpressionInfo* info = context.GetExpressionInfo(); target_addr_t address;
if (context.EvaluateExpression(argv[1], fLanguage, address) != B_OK)
target_addr_t address = 0;
info->SetTo(argv[1]);
context.GetUserInterfaceListener()->ExpressionEvaluationRequested(
fLanguage, info);
context.WaitForEvents(CliContext::EVENT_EXPRESSION_EVALUATED);
if (context.IsTerminating())
return; return;
BString errorMessage; TeamMemoryBlock* block = NULL;
ExpressionResult* result = context.GetExpressionValue(); if (context.GetMemoryBlock(address, block) != B_OK)
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());
return; 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; int32 num = 0;
if (argc == 3) { if (argc == 3) {
@@ -127,44 +90,8 @@ CliDumpMemoryCommand::Execute(int argc, const char* const* argv,
if (num <= 0) if (num <= 0)
num = displayWidth; num = displayWidth;
TeamMemoryBlock* block = context.CurrentBlock(); BString output;
if (block == NULL || !block->Contains(address)) { UiUtils::DumpMemory(output, 0, block, address, itemSize, displayWidth,
context.GetUserInterfaceListener()->InspectRequested(address, num);
&context); printf("%s\n", output.String());
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());
}
} }
@@ -8,13 +8,17 @@
#include "CliCommand.h" #include "CliCommand.h"
#include <String.h>
class SourceLanguage; class SourceLanguage;
class CliDumpMemoryCommand : public CliCommand { class CliDumpMemoryCommand : public CliCommand {
public: public:
CliDumpMemoryCommand(); CliDumpMemoryCommand(int itemSize,
const char* itemSizeNoun,
int displayWidth);
virtual ~CliDumpMemoryCommand(); virtual ~CliDumpMemoryCommand();
virtual void Execute(int argc, const char* const* argv, virtual void Execute(int argc, const char* const* argv,
@@ -22,6 +26,10 @@ public:
private: private:
SourceLanguage* fLanguage; SourceLanguage* fLanguage;
BString fSummaryString;
BString fUsageString;
int itemSize;
int displayWidth;
}; };
@@ -0,0 +1,93 @@
/*
* Copyright 2009-2011, Ingo Weinhold, [email protected].
* Copyright 2002-2010, Axel Dörfler, [email protected].
* Copyright 2012-2016, Rene Gollent, [email protected].
* 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 <ctype.h>
#include <stdio.h>
#include <AutoLocker.h>
#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");
}
@@ -0,0 +1,28 @@
/*
* Copyright 2012-2014, Rene Gollent, [email protected].
* 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