blob: 12c828f3f4cab4969777aca8652867d8ebd34f73 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
#include "StdAfx.h"
#include "CrossfireBPManager.h"
const wchar_t* CrossfireBPManager::KEY_BREAKPOINTS = L"breakpoints";
CrossfireBPManager::CrossfireBPManager() {
m_breakpoints = new std::map<unsigned int, CrossfireBreakpoint*>;
}
CrossfireBPManager::~CrossfireBPManager() {
std::map<unsigned int,CrossfireBreakpoint*>::iterator iterator = m_breakpoints->begin();
while (iterator != m_breakpoints->end()) {
delete iterator->second;
iterator++;
}
delete m_breakpoints;
}
/* IBreakpointTarget */
bool CrossfireBPManager::breakpointAttributeChanged(unsigned int handle, wchar_t* name, Value* value) {
/* no further action required since this object just stores the breakpoint data */
return true;
}
bool CrossfireBPManager::deleteBreakpoint(unsigned int handle) {
std::map<unsigned int, CrossfireBreakpoint*>::iterator iterator = m_breakpoints->find(handle);
if (iterator == m_breakpoints->end()) {
return false;
}
delete iterator->second;
m_breakpoints->erase(iterator);
return true;
}
CrossfireBreakpoint* CrossfireBPManager::getBreakpoint(unsigned int handle) {
std::map<unsigned int, CrossfireBreakpoint*>::iterator iterator = m_breakpoints->find(handle);
if (iterator == m_breakpoints->end()) {
Logger::error("CrossfireBPManager.getBreakpoint(): unknown breakpoint handle", handle);
return NULL;
}
return iterator->second;
}
void CrossfireBPManager::getBreakpoints(CrossfireBreakpoint*** ___values) {
size_t size = m_breakpoints->size();
CrossfireBreakpoint** breakpoints = new CrossfireBreakpoint*[size + 1];
std::map<unsigned int, CrossfireBreakpoint*>::iterator it = m_breakpoints->begin();
int index = 0;
while (it != m_breakpoints->end()) {
it->second->clone(&breakpoints[index++]);
it++;
}
breakpoints[index] = NULL;
*___values = breakpoints;
}
bool CrossfireBPManager::setBreakpoint(CrossfireBreakpoint *breakpoint) {
CrossfireLineBreakpoint* lineBp = (CrossfireLineBreakpoint*)breakpoint;
CrossfireLineBreakpoint* copy = NULL;
lineBp->clone((CrossfireBreakpoint**)&copy);
unsigned int handle = lineBp->getHandle();
/* if a breakpoint with a duplicate handle exists then replace it with the new breakpoint */
std::map<unsigned int, CrossfireBreakpoint*>::iterator iterator = m_breakpoints->find(handle);
if (iterator != m_breakpoints->end()) {
delete iterator->second;
m_breakpoints->erase(iterator);
}
m_breakpoints->insert(std::pair<unsigned int, CrossfireBreakpoint*>(handle, copy));
return true;
}
/* CrossfireBPManager */
int CrossfireBPManager::commandChangeBreakpoints(Value* arguments, IBreakpointTarget** targets, Value** _responseBody, wchar_t** _message) {
*_responseBody = NULL;
Value* value_handles = arguments->getObjectValue(CrossfireBreakpoint::KEY_HANDLES);
if (!value_handles || value_handles->getType() != TYPE_ARRAY) {
*_message = _wcsdup(L"'changeBreakpoints' command does not have a valid 'handles' value");
return CODE_INVALID_ARGUMENT;
}
Value* value_attributes = arguments->getObjectValue(CrossfireBreakpoint::KEY_ATTRIBUTES);
if (!value_attributes || value_attributes->getType() != TYPE_OBJECT) {
*_message = _wcsdup(L"'changeBreakpoints' command does not have a valid 'attributes' value");
return CODE_INVALID_ARGUMENT;
}
int code = CODE_OK;
Value** handles = NULL;
value_handles->getArrayValues(&handles);
int handlesIndex = 0;
Value* value_handle = handles[handlesIndex++];
while (value_handle) {
if (value_handle->getType() != TYPE_NUMBER || value_handle->getNumberValue() < 1) {
*_message = _wcsdup(L"'changeBreakpoints' command specifies an invalid handle value");
code = CODE_INVALID_ARGUMENT;
break;
}
/* ensure that the handle is valid */
unsigned int handle = (unsigned int)value_handle->getNumberValue();
CrossfireBreakpoint* breakpoint = getBreakpoint(handle);
if (!breakpoint) {
*_message = _wcsdup(L"'changeBreakpoints' command specifies an unknown breakpoint handle");
code = CODE_COMMAND_FAILED;
break;
}
/* ensure that all attributes can be applied to the current breakpoint */
if (!breakpoint->attributesValueIsValid(value_attributes)) {
*_message = _wcsdup(L"'changeBreakpoints' command specifies an invalid breakpoint attribute");
code = CODE_COMMAND_FAILED;
break;
}
value_handle = handles[handlesIndex++];
}
if (code != CODE_OK) {
delete[] handles;
return code;
}
/* the request is valid, so now perform the changes */
handlesIndex = 0;
value_handle = handles[handlesIndex++];
while (value_handle) {
unsigned int handle = (unsigned int)value_handle->getNumberValue();
CrossfireBreakpoint* breakpoint = getBreakpoint(handle);
breakpoint->setAttributesFromValue(value_attributes);
/* it's valid for the breakpoint to not be set in some (or even all) of the targets */
if (targets) {
int targetsIndex = 0;
IBreakpointTarget* target = targets[targetsIndex++];
while (target != NULL) {
CrossfireBreakpoint* breakpoint = target->getBreakpoint(handle);
if (breakpoint) {
breakpoint->setAttributesFromValue(value_attributes);
}
target = targets[targetsIndex++];
}
}
value_handle = handles[handlesIndex++];
}
delete[] handles;
Value* result = new Value();
result->setType(TYPE_OBJECT);
*_responseBody = result;
return CODE_OK;
}
int CrossfireBPManager::commandDeleteBreakpoints(Value* arguments, IBreakpointTarget** targets, Value** _responseBody, wchar_t** _message) {
*_responseBody = NULL;
Value* value_handles = arguments->getObjectValue(CrossfireBreakpoint::KEY_HANDLES);
if (!value_handles || value_handles->getType() != TYPE_ARRAY) {
*_message = _wcsdup(L"'deleteBreakpoints' command does not have a valid 'handles' value");
return CODE_INVALID_ARGUMENT;
}
Value** handles = NULL;
value_handles->getArrayValues(&handles);
int index = 0;
Value* value_current = handles[index++];
while (value_current) {
if (value_current->getType() != TYPE_NUMBER || (unsigned int)value_current->getNumberValue() < 1) {
*_message = _wcsdup(L"'deleteBreakpoints' command specifies an invalid handle value");
delete[] handles;
return CODE_INVALID_ARGUMENT;
}
unsigned int handle = (unsigned int)value_current->getNumberValue();
/* look up the breakpoint in the local breakpoints table to ensure that the handle is valid */
std::map<unsigned int, CrossfireBreakpoint*>::iterator iterator = m_breakpoints->find(handle);
if (iterator == m_breakpoints->end()) {
*_message = _wcsdup(L"'deleteBreakpoints' command specifies an unknown breakpoint handle");
delete[] handles;
return CODE_COMMAND_FAILED;
}
value_current = handles[index++];
}
/* the request is valid, so now perform the deletions */
index = 0;
value_current = handles[index++];
while (value_current) {
unsigned int handle = (unsigned int)value_current->getNumberValue();
deleteBreakpoint(handle); /* delete from the global table */
/*
* It's valid for the breakpoint to not be set in some (or even all) of the targets,
* so a false result value for the deleteBreakpoint() call does not indicate a problem.
*/
if (targets) {
int targetsIndex = 0;
IBreakpointTarget* current = targets[targetsIndex++];
while (current != NULL) {
current->deleteBreakpoint(handle);
current = targets[targetsIndex++];
}
}
value_current = handles[index++];
}
delete[] handles;
Value* result = new Value();
result->setType(TYPE_OBJECT);
*_responseBody = result;
return CODE_OK;
}
int CrossfireBPManager::commandGetBreakpoints(Value* arguments, IBreakpointTarget* target, Value** _responseBody, wchar_t** _message) {
CrossfireBreakpoint** breakpoints = NULL;
Value* value_handles = arguments->getObjectValue(CrossfireBreakpoint::KEY_HANDLES);
if (value_handles) {
if (value_handles->getType() != TYPE_ARRAY) {
*_message = _wcsdup(L"'getBreakpoints' command has an invalid 'handles' value");
return CODE_INVALID_ARGUMENT;
}
std::vector<CrossfireBreakpoint*> breakpointsCollection;
Value** handles = NULL;
value_handles->getArrayValues(&handles);
int index = 0;
Value* value_current = handles[index++];
while (value_current) {
if (value_current->getType() == TYPE_NUMBER && value_current->getNumberValue() > 0) {
unsigned int handle = (unsigned int)value_current->getNumberValue();
CrossfireBreakpoint* breakpoint = target->getBreakpoint(handle);
if (breakpoint) {
breakpointsCollection.push_back(breakpoint);
}
}
value_current = handles[index++];
}
delete[] handles;
int length = breakpointsCollection.size();
breakpoints = new CrossfireBreakpoint*[length + 1];
for (int i = 0; i < length; i++) {
breakpoints[i] = breakpointsCollection.at(i);
}
breakpoints[length] = NULL;
} else {
target->getBreakpoints(&breakpoints);
}
Value breakpointsArray;
breakpointsArray.setType(TYPE_ARRAY);
int index = 0;
while (breakpoints[index]) {
CrossfireBreakpoint* current = breakpoints[index];
Value* value_breakpoint = NULL;
if (current->toValueObject(&value_breakpoint)) {
breakpointsArray.addArrayValue(value_breakpoint);
delete value_breakpoint;
}
delete current;
index++;
}
delete[] breakpoints;
Value* result = new Value();
result->addObjectValue(KEY_BREAKPOINTS, &breakpointsArray);
*_responseBody = result;
return CODE_OK;
}
int CrossfireBPManager::commandSetBreakpoints(Value* arguments, IBreakpointTarget** targets, Value** _responseBody, wchar_t** _message) {
*_responseBody = NULL;
Value* value_breakpoints = arguments->getObjectValue(KEY_BREAKPOINTS);
if (!value_breakpoints || value_breakpoints->getType() != TYPE_ARRAY) {
*_message = _wcsdup(L"'setBreakpoints' command does not have a valid 'breakpoints' value");
return CODE_INVALID_ARGUMENT;
}
std::vector<CrossfireBreakpoint*> bpObjects;
Value** breakpoints = NULL;
value_breakpoints->getArrayValues(&breakpoints);
int index = 0;
Value* current = breakpoints[index++];
int code = CODE_OK;
while (current) {
CrossfireBreakpoint* breakpoint = NULL;
code = createBreakpoint(current, &breakpoint, _message);
if (code != CODE_OK) {
break;
}
bpObjects.push_back(breakpoint);
current = breakpoints[index++];
}
delete[] breakpoints;
if (code == CODE_OK) {
Value value_array;
value_array.setType(TYPE_ARRAY);
std::vector<CrossfireBreakpoint*>::iterator iterator = bpObjects.begin();
while (iterator != bpObjects.end()) {
CrossfireBreakpoint* breakpoint = *iterator;
/* search registered breakpoints for a duplicate */
std::map<unsigned int,CrossfireBreakpoint*>::iterator iterator2 = m_breakpoints->begin();
while (iterator2 != m_breakpoints->end()) {
CrossfireBreakpoint* current = iterator2->second;
if (current->matchesLocation(breakpoint)) {
breakpoint->setHandle(current->getHandle());
break;
}
iterator2++;
}
breakpoint->setTarget(this);
setBreakpoint(breakpoint);
if (targets) {
int index = 0;
IBreakpointTarget* current = targets[index++];
while (current != NULL) {
breakpoint->setTarget(current);
current->setBreakpoint(breakpoint);
current = targets[index++];
}
}
Value* value_breakpoint = NULL;
breakpoint->toValueObject(&value_breakpoint);
value_array.addArrayValue(value_breakpoint);
delete value_breakpoint;
delete *iterator;
iterator++;
}
Value* result = new Value();
result->addObjectValue(KEY_BREAKPOINTS, &value_array);
*_responseBody = result;
}
return code;
}
int CrossfireBPManager::createBreakpoint(Value* arguments, CrossfireBreakpoint** _result, wchar_t** _message) {
*_result = NULL;
Value* value_type = arguments->getObjectValue(CrossfireBreakpoint::KEY_TYPE);
if (!value_type || value_type->getType() != TYPE_STRING) {
*_message = _wcsdup(L"breakpoint creation arguments do not have a valid 'type' value");
return CODE_INVALID_ARGUMENT;
}
Value* value_attributes = arguments->getObjectValue(CrossfireBreakpoint::KEY_ATTRIBUTES);
if (value_attributes && value_attributes->getType() != TYPE_OBJECT) {
*_message = _wcsdup(L"breakpoint creation arguments have an invalid 'attributes' value");
return CODE_INVALID_ARGUMENT;
}
Value* value_location = arguments->getObjectValue(CrossfireBreakpoint::KEY_LOCATION);
if (!value_location || value_location->getType() != TYPE_OBJECT) {
*_message = _wcsdup(L"breakpoint creation arguments do not have a valid 'location' value");
return CODE_INVALID_ARGUMENT;
}
CrossfireBreakpoint* breakpoint = NULL;
wchar_t* type = (wchar_t*)value_type->getStringValue()->c_str();
if (CrossfireLineBreakpoint::CanHandleBPType(type)) {
breakpoint = new CrossfireLineBreakpoint();
} else {
*_message = _wcsdup(L"breakpoint creation arguments specify an unknown 'type' value");
return CODE_COMMAND_FAILED;
}
if (value_attributes) {
if (!breakpoint->attributesValueIsValid(value_attributes)) {
*_message = _wcsdup(L"breakpoint creation arguments specify an invalid attribute name or value");
delete breakpoint;
return CODE_COMMAND_FAILED;
}
breakpoint->setAttributesFromValue(value_attributes);
}
if (!breakpoint->setLocationFromValue(value_location)) {
*_message = _wcsdup(L"breakpoint creation arguments do not validly specify a location");
delete breakpoint;
return CODE_COMMAND_FAILED;
}
*_result = breakpoint;
return CODE_OK;
}
void CrossfireBPManager::setBreakpointsForScript(URL* url, IBreakpointTarget* target) {
std::map<unsigned int,CrossfireBreakpoint*>::iterator iterator = m_breakpoints->begin();
while (iterator != m_breakpoints->end()) {
CrossfireBreakpoint* breakpoint = iterator->second;
if (breakpoint->appliesToUrl(url)) {
target->setBreakpoint(breakpoint);
}
iterator++;
}
}