/******************************************************************************* | |
* Copyright (c) 2010 Nokia 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: | |
* Nokia - Initial API and implementation | |
*******************************************************************************/ | |
#include "RegistersService.h" | |
#include "DebugMonitor.h" | |
#include "ContextManager.h" | |
#include "EventClientNotifier.h" | |
#include "Logger.h" | |
#include "TCFChannel.h" | |
#include "WinThread.h" | |
#include "RegisterInfoX86.h" | |
#include "RegisterGroupInAgent.h" | |
#include "RegisterInAgent.h" | |
#include "AgentUtils.h" | |
static const char* sServiceName = "Registers"; | |
/** | |
* Add register group & register contexts for the give thread context. | |
* | |
* @param threadContextID | |
* @return list of register group contexts. | |
*/ | |
static void addRegisterContextsForThread(std::string threadContextID) { | |
// Get static register info first. | |
std::list<RegisterGroupInfo *>& rgInfoList = RegisterInfoX86::getRegisterGroupInfo(); | |
// Now add thread-specific register contexts. | |
// | |
std::list<RegisterGroupInfo *>::iterator it; | |
for (it = rgInfoList.begin(); it != rgInfoList.end(); it++) { | |
Properties& props = (*it)->getProperties(); | |
// This will be added as child context of the thread. | |
RegisterGroupInAgent* rgContext = new RegisterGroupInAgent( | |
props[PROP_NAME].getStringValue(), threadContextID, props); | |
ContextID rgContextID = rgContext->GetID(); | |
// Now add register contexts under the register group context | |
// | |
std::list<RegisterInfo*>& regs = (*it)->getRegisters(); | |
for (std::list<RegisterInfo*>::iterator it2 = regs.begin(); it2 != regs.end(); it2++) { | |
Properties& regProps = (*it2)->getProperties(); | |
new RegisterInAgent(regProps[PROP_NAME].getStringValue(), rgContextID, regProps); | |
} | |
} | |
} | |
RegistersService::RegistersService(Protocol * proto) : | |
TCFService(proto) | |
{ | |
AddCommand("getContext", command_get_context); | |
AddCommand("getChildren", command_get_children); | |
AddCommand("get", command_get); | |
AddCommand("set", command_set); | |
} | |
RegistersService::~RegistersService() { | |
// TODO Auto-generated destructor stub | |
} | |
const char* RegistersService::GetName() { | |
return sServiceName; | |
} | |
void RegistersService::command_get_context(const char * token, Channel * c) { | |
LogTrace("RegistersService::command_get_context", "token: %s", token); | |
TCFChannel channel(c); | |
std::string id = channel.readString(); | |
channel.readZero(); | |
channel.readComplete(); | |
Context* context = ContextManager::findContext(id); | |
if (context == NULL) { | |
// Return an invalid context ID error. | |
channel.writeCompleteReply(token, ERR_INV_CONTEXT, 1); | |
return; | |
} | |
channel.writeReplyHeader(token); | |
channel.writeError(0); | |
EventClientNotifier::WriteContext(*context, channel); | |
channel.writeZero(); // end of context | |
channel.writeComplete(); | |
} | |
void RegistersService::command_get_children(const char * token, Channel * c) { | |
LogTrace("RunControl::command_get_children", "token: %s", token); | |
TCFChannel channel(c); | |
std::string id = channel.readString(); | |
channel.readZero(); | |
channel.readComplete(); | |
std::string parentID = id; | |
if (parentID.length() == 0) | |
parentID = "root"; | |
Context* parent = ContextManager::findContext(parentID); | |
if (parent == NULL) { | |
// Return an invalid context ID error. | |
channel.writeCompleteReply(token, ERR_INV_CONTEXT, 1); | |
return; | |
} | |
channel.writeReplyHeader(token); | |
channel.writeError(0); | |
channel.writeCharacter('['); | |
std::list<Context*>& children = parent->GetChildren(); | |
if (NULL != dynamic_cast<WinThread*>(parent)) { | |
// Currently it's assumed thread only has register group | |
// contexts as children. | |
// And we hook up the register children to a thread only | |
// when requested. This way we don't bother adding registers | |
// for a thread that user does not care about. | |
// ..................02/11/10 | |
if (children.size() == 0) { | |
// Add register contexts for the thread when accessed. | |
addRegisterContextsForThread(parentID); | |
children = parent->GetChildren(); | |
} | |
} | |
std::list<Context*>::iterator itr; | |
for (itr = children.begin(); itr != children.end(); itr++) { | |
if (itr != children.begin()) | |
channel.writeCharacter(','); | |
std::string contextID = ((Context*) *itr)->GetID(); | |
channel.writeString(contextID); | |
} | |
channel.writeCharacter(']'); | |
channel.writeZero(); // end of context | |
channel.writeComplete(); | |
} | |
/** | |
* Find the owner thread context for a register or register group context. | |
* Return NULL if not found. | |
* @param regCxt register or register group context. | |
*/ | |
WinThread* getThreadForRegisterContext(Context* regCxt) { | |
RegisterGroupInAgent* regGroup; | |
if (NULL != dynamic_cast<RegisterInAgent *>(regCxt)) | |
regGroup = dynamic_cast<RegisterGroupInAgent*>(ContextManager::findContext(regCxt->GetParentID())); | |
else | |
regGroup = dynamic_cast<RegisterGroupInAgent *>(regCxt); | |
if (regGroup == NULL) // invalid context | |
return NULL; | |
std::string threadID = regGroup->GetParentID(); | |
WinThread* thread = dynamic_cast<WinThread *>(ContextManager::findContext(threadID)); | |
return thread; | |
} | |
/* | |
* register values are passed as hex-string in big-endian | |
*/ | |
void RegistersService::command_get(const char * token, Channel * c) { | |
TCFChannel channel(c); | |
std::string regCxtID = channel.readString(); | |
channel.readZero(); | |
channel.readComplete(); | |
RegisterInAgent* regCxt = dynamic_cast<RegisterInAgent *>(ContextManager::findContext(regCxtID)); | |
WinThread* thread = getThreadForRegisterContext(regCxt); | |
if (regCxt == NULL || thread == NULL || !thread->IsDebugging()) { | |
// Return invalid-context-ID error. | |
channel.writeCompleteReply(token, ERR_INV_CONTEXT, 1); | |
return; | |
} | |
int regSize = regCxt->GetProperties()[PROP_SIZE].getIntValue(); | |
char *valueBuff = thread->GetRegisterValue( | |
regCxt->GetProperties()[PROP_NAME].getStringValue(), | |
regSize); | |
if (valueBuff == NULL) { | |
// no values got. Assuming target is running. | |
channel.writeCompleteReply(token, ERR_IS_RUNNING, 1); | |
return; | |
} | |
// Currently EDC host expects big-endian. | |
AgentUtils::SwapBytes(valueBuff, regSize); | |
channel.writeReplyHeader(token); | |
channel.writeError(0); | |
channel.writeBinaryData(valueBuff, regSize); | |
delete[] valueBuff; | |
channel.writeComplete(); | |
} | |
/* | |
*/ | |
void RegistersService::command_set(const char * token, Channel * c) { | |
TCFChannel channel(c); | |
std::string regCxtID = channel.readString(); | |
channel.readZero(); | |
RegisterInAgent* regCxt = dynamic_cast<RegisterInAgent *>(ContextManager::findContext(regCxtID)); | |
int regSize = 4; | |
if (regCxt != NULL) { | |
regSize = regCxt->GetProperties()[PROP_SIZE].getIntValue(); | |
} | |
char* val = channel.readBinaryData(regSize); | |
channel.readZero(); | |
channel.readComplete(); | |
WinThread* thread = getThreadForRegisterContext(regCxt); | |
if (regCxt == NULL || thread == NULL || !thread->IsDebugging()) { | |
// Return invalid-context-ID error. | |
channel.writeCompleteReply(token, ERR_INV_CONTEXT); | |
return; | |
} | |
// Currently EDC host sends big-endian data. | |
AgentUtils::SwapBytes(val, regSize); | |
bool ok = thread->SetRegisterValue( | |
regCxt->GetProperties()[PROP_NAME].getStringValue(), | |
regSize, val); | |
delete[] val; | |
if (!ok) { | |
// Assuming target is running. | |
channel.writeCompleteReply(token, ERR_IS_RUNNING); | |
} | |
else { | |
channel.writeCompleteReply(token, 0); | |
} | |
} |