root/src/kits/debugger/debugger_interface/remote/RemoteDebugRequest.cpp
/*
 * Copyright 2016, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */


#include "RemoteDebugRequest.h"

#include <stdlib.h>

#include <Message.h>

#include <debugger.h>

#include <AutoDeleter.h>

#include "Architecture.h"
#include "CpuState.h"


// #pragma mark - RemoteDebugRequest


RemoteDebugRequest::RemoteDebugRequest()
        :
        BReferenceable(),
        fArchitecture(NULL)
{
}


RemoteDebugRequest::~RemoteDebugRequest()
{
        if (fArchitecture != NULL)
                fArchitecture->ReleaseReference();
}


status_t
RemoteDebugRequest::LoadFromMessage(const BMessage& data)
{
        if (data.FindInt32("type") != Type())
                return B_BAD_VALUE;

        return LoadSpecificInfoFromMessage(data);
}


status_t
RemoteDebugRequest::SaveToMessage(BMessage& _output) const
{
        _output.MakeEmpty();

        status_t error = _output.AddInt32("type", Type());
        if (error != B_OK)
                return error;

        return SaveSpecificInfoToMessage(_output);
}


void
RemoteDebugRequest::SetArchitecture(Architecture* architecture)
{
        fArchitecture = architecture;
        fArchitecture->AcquireReference();
}


// #pragma mark - RemoteDebugResponse


RemoteDebugResponse::RemoteDebugResponse()
        :
        BReferenceable(),
        fRequest(NULL),
        fResult(B_OK)
{
}


RemoteDebugResponse::~RemoteDebugResponse()
{
        if (fRequest != NULL)
                fRequest->ReleaseReference();
}


void
RemoteDebugResponse::SetRequestInfo(RemoteDebugRequest* request,
        status_t result)
{
        fRequest = request;
        fRequest->AcquireReference();
        fResult = result;
}


status_t
RemoteDebugResponse::LoadFromMessage(const BMessage& data)
{
        if (data.FindInt32("type") != Request()->Type())
                return B_BAD_VALUE;

        if (!Succeeded())
                return B_OK;

        return LoadSpecificInfoFromMessage(data);
}


status_t
RemoteDebugResponse::SaveToMessage(BMessage& _output) const
{
        _output.MakeEmpty();

        status_t error = _output.AddInt32("type", Request()->Type());
        if (error != B_OK)
                return error;

        error = _output.AddInt32("result", Result());
        if (error != B_OK)
                return error;

        if (!Succeeded())
                return B_OK;

        return SaveSpecificInfoToMessage(_output);
}


status_t
RemoteDebugResponse::LoadSpecificInfoFromMessage(const BMessage& data)
{
        return B_OK;
}


status_t
RemoteDebugResponse::SaveSpecificInfoToMessage(BMessage& _output) const
{
        return B_OK;
}


// #pragma mark - RemoteDebugReadMemoryRequest


RemoteDebugReadMemoryRequest::RemoteDebugReadMemoryRequest()
        :
        RemoteDebugRequest(),
        fAddress(0),
        fSize(0)
{
}


RemoteDebugReadMemoryRequest::~RemoteDebugReadMemoryRequest()
{
}


void
RemoteDebugReadMemoryRequest::SetTo(target_addr_t address, target_size_t size)
{
        fAddress = address;
        fSize = size;
}


remote_request_type
RemoteDebugReadMemoryRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_READ_MEMORY;
}


status_t
RemoteDebugReadMemoryRequest::LoadSpecificInfoFromMessage(const BMessage& data)
{
        if (data.FindUInt64("address", &fAddress) != B_OK)
                return B_BAD_VALUE;

        if (data.FindUInt64("size", &fSize) != B_OK)
                return B_BAD_VALUE;

        return B_OK;
}


status_t
RemoteDebugReadMemoryRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        status_t error = _output.AddUInt64("address", fAddress);
        if (error != B_OK)
                return error;

        return _output.AddUInt64("size", fSize);
}


// #pragma mark - RemoteDebugWriteMemoryRequest


RemoteDebugWriteMemoryRequest::RemoteDebugWriteMemoryRequest()
        :
        RemoteDebugRequest(),
        fAddress(0),
        fData(NULL),
        fSize(0)
{
}


RemoteDebugWriteMemoryRequest::~RemoteDebugWriteMemoryRequest()
{
        if (fData != NULL)
                free(fData);
}


status_t
RemoteDebugWriteMemoryRequest::SetTo(target_addr_t address, const void* data,
        target_size_t size)
{
        if (size == 0 || data == NULL)
                return B_BAD_VALUE;

        fAddress = address;
        fSize = size;
        fData = malloc(fSize);
        if (fData == NULL)
                return B_NO_MEMORY;


        memcpy(fData, data, fSize);
        return B_OK;
}


remote_request_type
RemoteDebugWriteMemoryRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_WRITE_MEMORY;
}


status_t
RemoteDebugWriteMemoryRequest::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        if (data.FindUInt64("address", &fAddress) != B_OK)
                return B_BAD_VALUE;

        if (data.FindUInt64("size", &fSize) != B_OK)
                return B_BAD_VALUE;

        fData = malloc(fSize);
        if (fData == NULL)
                return B_NO_MEMORY;

        const void* messageData = NULL;
        ssize_t numBytes = -1;
        status_t error = data.FindData("data", B_RAW_TYPE, &messageData,
                &numBytes);
        if (error != B_OK)
                return error;

        if ((size_t)numBytes != fSize)
                return B_MISMATCHED_VALUES;

        memcpy(fData, messageData, numBytes);

        return B_OK;
}


status_t
RemoteDebugWriteMemoryRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        status_t error = _output.AddUInt64("address", fAddress);
        if (error != B_OK)
                return error;

        error = _output.AddUInt64("size", fSize);
        if (error != B_OK)
                return error;

        return _output.AddData("data", B_RAW_TYPE, fData, (ssize_t)fSize);
}


// #pragma mark - RemoteDebugSetTeamFlagsRequest


RemoteDebugSetTeamFlagsRequest::RemoteDebugSetTeamFlagsRequest()
        :
        RemoteDebugRequest(),
        fFlags(0)
{
}


RemoteDebugSetTeamFlagsRequest::~RemoteDebugSetTeamFlagsRequest()
{
}


void
RemoteDebugSetTeamFlagsRequest::SetTo(int32 flags)
{
        fFlags = flags;
}


remote_request_type
RemoteDebugSetTeamFlagsRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_SET_TEAM_FLAGS;
}


status_t
RemoteDebugSetTeamFlagsRequest::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        if (data.FindInt32("flags", &fFlags) != B_OK)
                return B_BAD_VALUE;

        return B_OK;
}


status_t
RemoteDebugSetTeamFlagsRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        return _output.AddInt32("flags", fFlags);
}


// #pragma mark - RemoteDebugSetThreadFlagsRequest


RemoteDebugSetThreadFlagsRequest::RemoteDebugSetThreadFlagsRequest()
        :
        RemoteDebugRequest(),
        fThread(-1),
        fFlags(0)
{
}


RemoteDebugSetThreadFlagsRequest::~RemoteDebugSetThreadFlagsRequest()
{
}


void
RemoteDebugSetThreadFlagsRequest::SetTo(thread_id thread, int32 flags)
{
        fThread = thread;
        fFlags = flags;
}


remote_request_type
RemoteDebugSetThreadFlagsRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_SET_THREAD_FLAGS;
}


status_t
RemoteDebugSetThreadFlagsRequest::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        if (data.FindInt32("thread", &fThread) != B_OK)
                return B_BAD_VALUE;

        if (data.FindInt32("flags", &fFlags) != B_OK)
                return B_BAD_VALUE;

        return B_OK;
}


status_t
RemoteDebugSetThreadFlagsRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        status_t error = _output.AddInt32("thread", fThread);
        if (error != B_OK)
                return error;

        return _output.AddInt32("flags", fFlags);
}


// #pragma mark - RemoteDebugThreadActionRequest


RemoteDebugThreadActionRequest::RemoteDebugThreadActionRequest()
        :
        RemoteDebugRequest(),
        fThread(-1)
{
}


RemoteDebugThreadActionRequest::~RemoteDebugThreadActionRequest()
{
}


void
RemoteDebugThreadActionRequest::SetTo(thread_id thread)
{
        fThread = thread;
}


status_t
RemoteDebugThreadActionRequest::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        if (data.FindInt32("thread", &fThread) != B_OK)
                return B_BAD_VALUE;

        return B_OK;
}


status_t
RemoteDebugThreadActionRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        return _output.AddInt32("thread", fThread);
}


// #pragma mark - RemoteDebugContinueThreadRequest


RemoteDebugContinueThreadRequest::RemoteDebugContinueThreadRequest()
        :
        RemoteDebugThreadActionRequest()
{
}


RemoteDebugContinueThreadRequest::~RemoteDebugContinueThreadRequest()
{
}

remote_request_type
RemoteDebugContinueThreadRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_CONTINUE_THREAD;
}


// #pragma mark - RemoteDebugStopThreadRequest


RemoteDebugStopThreadRequest::RemoteDebugStopThreadRequest()
        :
        RemoteDebugThreadActionRequest()
{
}


RemoteDebugStopThreadRequest::~RemoteDebugStopThreadRequest()
{
}

remote_request_type
RemoteDebugStopThreadRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_STOP_THREAD;
}


// #pragma mark - RemoteDebugSingleStepThreadRequest


RemoteDebugSingleStepThreadRequest::RemoteDebugSingleStepThreadRequest()
        :
        RemoteDebugThreadActionRequest()
{
}


RemoteDebugSingleStepThreadRequest::~RemoteDebugSingleStepThreadRequest()
{
}

remote_request_type
RemoteDebugSingleStepThreadRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_SINGLE_STEP_THREAD;
}


// #pragma mark - RemoteDebugGetCpuStateRequest


RemoteDebugGetCpuStateRequest::RemoteDebugGetCpuStateRequest()
        :
        RemoteDebugThreadActionRequest()
{
}


RemoteDebugGetCpuStateRequest::~RemoteDebugGetCpuStateRequest()
{
}


remote_request_type
RemoteDebugGetCpuStateRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_GET_CPU_STATE;
}


// #pragma mark - RemoteDebugSetCpuStateRequest


RemoteDebugSetCpuStateRequest::RemoteDebugSetCpuStateRequest()
        :
        RemoteDebugRequest(),
        fThread(-1),
        fCpuState(NULL)
{
}


RemoteDebugSetCpuStateRequest::~RemoteDebugSetCpuStateRequest()
{
        if (fCpuState != NULL)
                fCpuState->ReleaseReference();
}


void
RemoteDebugSetCpuStateRequest::SetTo(thread_id thread, CpuState* state)
{
        fThread = thread;
        fCpuState = state;
        if (fCpuState != NULL)
                fCpuState->AcquireReference();
}


remote_request_type
RemoteDebugSetCpuStateRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_SET_CPU_STATE;
}


status_t
RemoteDebugSetCpuStateRequest::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        if (data.FindInt32("thread", &fThread) != B_OK)
                return B_BAD_VALUE;

        if (fCpuState != NULL) {
                fCpuState->ReleaseReference();
                fCpuState = NULL;
        }

        const uint8* buffer = NULL;
        ssize_t numBytes = 0;
        size_t stateSize = GetArchitecture()->DebugCpuStateSize();
        status_t error = data.FindData("state", B_RAW_TYPE, (const void**)&buffer,
                &numBytes);
        if (error != B_OK || (size_t)numBytes != stateSize)
                return B_BAD_VALUE;

        return GetArchitecture()->CreateCpuState(buffer, stateSize, fCpuState);
}


status_t
RemoteDebugSetCpuStateRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        status_t error = _output.AddInt32("thread", fThread);
        if (error != B_OK)
                return error;

        size_t stateSize = GetArchitecture()->DebugCpuStateSize();
        uint8* buffer = new(std::nothrow) uint8[stateSize];
        if (buffer == NULL)
                return B_NO_MEMORY;

        ArrayDeleter<uint8> deleter(buffer);
        error = fCpuState->UpdateDebugState(buffer, stateSize);
        if (error != B_OK)
                return error;

        return _output.AddData("state", B_RAW_TYPE, buffer, (ssize_t)stateSize);
}


// #pragma mark - RemoteDebugAddressActionRequest


RemoteDebugAddressActionRequest::RemoteDebugAddressActionRequest()
        :
        RemoteDebugRequest(),
        fAddress(0)
{
}


RemoteDebugAddressActionRequest::~RemoteDebugAddressActionRequest()
{
}


void
RemoteDebugAddressActionRequest::SetTo(target_addr_t address)
{
        fAddress = address;
}


status_t
RemoteDebugAddressActionRequest::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        return data.FindUInt64("address", &fAddress);
}


status_t
RemoteDebugAddressActionRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        return _output.AddUInt64("address", fAddress);
}


// #pragma mark - RemoteDebugInstallBreakpointRequest


RemoteDebugInstallBreakpointRequest::RemoteDebugInstallBreakpointRequest()
        :
        RemoteDebugAddressActionRequest()
{
}


RemoteDebugInstallBreakpointRequest::~RemoteDebugInstallBreakpointRequest()
{
}


remote_request_type
RemoteDebugInstallBreakpointRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_INSTALL_BREAKPOINT;
}


// #pragma mark - RemoteDebugUninstallBreakpointRequest


RemoteDebugUninstallBreakpointRequest::RemoteDebugUninstallBreakpointRequest()
        :
        RemoteDebugAddressActionRequest()
{
}


RemoteDebugUninstallBreakpointRequest::~RemoteDebugUninstallBreakpointRequest()
{
}

remote_request_type
RemoteDebugUninstallBreakpointRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_UNINSTALL_BREAKPOINT;
}


// #pragma mark - RemoteDebugInstallWatchpointRequest


RemoteDebugInstallWatchpointRequest::RemoteDebugInstallWatchpointRequest()
        :
        RemoteDebugRequest(),
        fAddress(0),
        fWatchType(B_DATA_READ_WATCHPOINT),
        fLength(0)
{
}


RemoteDebugInstallWatchpointRequest::~RemoteDebugInstallWatchpointRequest()
{
}


void
RemoteDebugInstallWatchpointRequest::SetTo(target_addr_t address, uint32 type,
        int32 length)
{
        fAddress = address;
        fWatchType = type;
        fLength = length;
}


remote_request_type
RemoteDebugInstallWatchpointRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_INSTALL_WATCHPOINT;
}


status_t
RemoteDebugInstallWatchpointRequest::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        status_t error = data.FindUInt64("address", &fAddress);
        if (error != B_OK)
                return error;

        error = data.FindUInt32("watchtype", &fWatchType);
        if (error != B_OK)
                return error;

        return data.FindInt32("length", &fLength);
}


status_t
RemoteDebugInstallWatchpointRequest::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        status_t error = _output.AddUInt64("address", fAddress);
        if (error != B_OK)
                return error;

        error = _output.AddUInt32("watchtype", fWatchType);
        if (error != B_OK)
                return error;

        return _output.AddInt32("length", fLength);
}


// #pragma mark - RemoteDebugUninstallWatchpointRequest


RemoteDebugUninstallWatchpointRequest::RemoteDebugUninstallWatchpointRequest()
        :
        RemoteDebugAddressActionRequest()
{
}


RemoteDebugUninstallWatchpointRequest::~RemoteDebugUninstallWatchpointRequest()
{
}


remote_request_type
RemoteDebugUninstallWatchpointRequest::Type() const
{
        return REMOTE_REQUEST_TYPE_UNINSTALL_WATCHPOINT;
}


// #pragma mark - RemoteDebugReadMemoryResponse


RemoteDebugReadMemoryResponse::RemoteDebugReadMemoryResponse()
        :
        RemoteDebugResponse(),
        fData(NULL),
        fSize(0)
{
}


RemoteDebugReadMemoryResponse::~RemoteDebugReadMemoryResponse()
{
        if (fData != NULL)
                free(fData);
}


void
RemoteDebugReadMemoryResponse::SetTo(void* data, target_size_t size)
{
        fData = data;
        fSize = size;
}


status_t
RemoteDebugReadMemoryResponse::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        status_t error = data.FindUInt64("size", &fSize);
        if (error != B_OK)
                return error;

        fData = malloc(fSize);
        if (fData == NULL)
                return B_NO_MEMORY;

        const void* messageData = NULL;
        ssize_t numBytes = -1;
        error = data.FindData("data", B_RAW_TYPE, &messageData, &numBytes);
        if (error != B_OK)
                return error;

        if ((size_t)numBytes != fSize)
                return B_MISMATCHED_VALUES;

        memcpy(fData, messageData, numBytes);
        return B_OK;
}


status_t
RemoteDebugReadMemoryResponse::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        if (fData == NULL)
                return B_OK;

        status_t error = _output.AddUInt64("size", fSize);
        if (error != B_OK)
                return error;

        return _output.AddData("data", B_RAW_TYPE, fData, (ssize_t)fSize);
}


// #pragma mark - RemoteDebugGetCpuStateResponse


RemoteDebugGetCpuStateResponse::RemoteDebugGetCpuStateResponse()
        :
        RemoteDebugResponse(),
        fCpuState(NULL)
{
}


RemoteDebugGetCpuStateResponse::~RemoteDebugGetCpuStateResponse()
{
        if (fCpuState != NULL)
                fCpuState->ReleaseReference();
}


void
RemoteDebugGetCpuStateResponse::SetTo(CpuState* state)
{
        fCpuState = state;
        if (fCpuState != NULL)
                fCpuState->AcquireReference();
}


status_t
RemoteDebugGetCpuStateResponse::LoadSpecificInfoFromMessage(
        const BMessage& data)
{
        if (fCpuState != NULL) {
                fCpuState->ReleaseReference();
                fCpuState = NULL;
        }

        const uint8* buffer = NULL;
        ssize_t numBytes = 0;
        size_t stateSize = GetArchitecture()->DebugCpuStateSize();
        status_t error = data.FindData("state", B_RAW_TYPE, (const void**)&buffer,
                &numBytes);
        if (error != B_OK || (size_t)numBytes != stateSize)
                return B_BAD_VALUE;

        return GetArchitecture()->CreateCpuState(buffer, stateSize, fCpuState);
}


status_t
RemoteDebugGetCpuStateResponse::SaveSpecificInfoToMessage(
        BMessage& _output) const
{
        size_t stateSize = GetArchitecture()->DebugCpuStateSize();
        uint8* buffer = new(std::nothrow) uint8[stateSize];
        if (buffer == NULL)
                return B_NO_MEMORY;

        ArrayDeleter<uint8> deleter(buffer);
        status_t error = fCpuState->UpdateDebugState(buffer, stateSize);
        if (error != B_OK)
                return error;

        return _output.AddData("state", B_RAW_TYPE, buffer, (ssize_t)stateSize);
}