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
CliDebugReportCommand.cpp
CliDumpMemoryCommand.cpp
CliDumpStringCommand.cpp
CliPrintVariableCommand.cpp
CliQuitCommand.cpp
CliStackFrameCommand.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)
{
@@ -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);
@@ -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",
@@ -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;
};
@@ -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());
}
@@ -8,13 +8,17 @@
#include "CliCommand.h"
#include <String.h>
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;
};
@@ -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