⛏️ index : haiku.git

/*
 * 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 "CliDumpMemoryCommand.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"


CliDumpMemoryCommand::CliDumpMemoryCommand()
	:
	CliCommand("dump contents of debugged team's memory",
		"%s [\"]address|expression[\"] [num]\n"
		"Reads and displays the contents of memory 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();
}


CliDumpMemoryCommand::~CliDumpMemoryCommand()
{
	if (fLanguage != NULL)
		fLanguage->ReleaseReference();
}


void
CliDumpMemoryCommand::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;
	}

	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())
		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());
		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) {
		char *remainder;
		num = strtol(argv[2], &remainder, 0);
		if (*remainder != '\0') {
			printf("Error: invalid parameter \"%s\"\n", argv[2]);
		}
	}

	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());
	}
}