| /******************************************************************************* |
| * 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); |
| } |
| } |