From d8f0c070056adcf3466107686d98f54cd965bef2 Mon Sep 17 00:00:00 2001 From: aleherbau Date: Wed, 25 May 2011 09:54:35 +0000 Subject: TCF Python: Implemented Disassembly and ProcessesV1 service proxies --- python/src/tcf/services/disassembly.py | 131 +++++++++++++++++++++ python/src/tcf/services/processes_v1.py | 47 ++++++++ python/src/tcf/services/remote/DisassemblyProxy.py | 58 +++++++++ python/src/tcf/services/remote/ProcessesV1Proxy.py | 32 +++++ python/src/tcf/services/streams.py | 2 +- python/src/tcf/services/sysmonitor.py | 4 +- python/src/tcf/services/terminals.py | 26 ++-- python/src/tcf/tests/BasicTests.py | 25 +++- python/todo.twiki | 3 +- 9 files changed, 309 insertions(+), 19 deletions(-) create mode 100644 python/src/tcf/services/disassembly.py create mode 100644 python/src/tcf/services/processes_v1.py create mode 100644 python/src/tcf/services/remote/DisassemblyProxy.py create mode 100644 python/src/tcf/services/remote/ProcessesV1Proxy.py diff --git a/python/src/tcf/services/disassembly.py b/python/src/tcf/services/disassembly.py new file mode 100644 index 000000000..66ce50628 --- /dev/null +++ b/python/src/tcf/services/disassembly.py @@ -0,0 +1,131 @@ +# ******************************************************************************* +# * Copyright (c) 2011 Wind River Systems, Inc. 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: +# * Wind River Systems - initial API and implementation +# ******************************************************************************* + +""" +TCF Disassembly service interface. +""" + +from tcf import services + +NAME = "Disassembly" + +# The name of the instruction set architecture, String +CAPABILITY_ISA = "ISA" + +# If true, simplified mnemonics are supported or requested, Boolean +CAPABILITY_SIMPLIFIED = "Simplified" + +# If true, pseudo-instructions are supported or requested, Boolean +CAPABILITY_PSEUDO = "Pseudo" + + +# Instruction field properties +# The type of the instruction field. See FTYPE_*, String. +FIELD_TYPE = "Type" + +# Value of the field for "String" and "Register" types, String. +FIELD_TEXT = "Text" + +# Value of the field for "Address," "Displacement," or "Immediate" types, Number. +FIELD_VALUE = "Value" + +# Context ID of the address space used with "Address" types, String. +FIELD_ADDRESS_SPACE = "AddressSpace" + +# Instruction field types +FTYPE_STRING = "String" +FTYPE_Register = "Register" +FTYPE_ADDRESS = "Address" +FTYPE_DISPLACEMENT = "Displacement" +FTYPE_IMMEDIATE = "Immediate" + + +class DisassemblyService(services.Service): + def getName(self): + return NAME + + def getCapabilities(self, context_id, done): + """ + Retrieve disassembly service capabilities a given context-id. + @param context_id - a context ID, usually one returned by Run Control or Memory services. + @param done - command result call back object. + @return - pending command handle. + """ + raise NotImplementedError("Abstract method") + + def disassemble(self, context_id, addr, size, params, done): + """ + Disassemble instruction code from a specified range of memory addresses, in a specified context. + @param context_id - a context ID, usually one returned by Run Control or Memory services. + @param addr - address of first instruction to disassemble. + @param size - size in bytes of the address range. + @param params - properties to control the disassembly output, an element of capabilities array, see getCapabilities. + @param done - command result call back object. + @return - pending command handle. + """ + + +class DoneGetCapabilities(object): + """ + Call back interface for 'getCapabilities' command. + """ + def doneGetCapabilities(self, token, error, capabilities): + """ + Called when capabilities retrieval is done. + @param token - command handle. + @param error - error object or null. + @param capabilities - array of capabilities, see CAPABILITY_* for contents of each array element. + """ + pass + +class DoneDisassemble(object): + """ + Call back interface for 'disassemble' command. + """ + def doneDisassemble(self, token, error, disassembly): + """ + Called when disassembling is done. + @param token - command handle. + @param error - error object or null. + @param disassembly - array of disassembly lines. + """ + pass + +class DisassemblyLine(object): + """ + Represents a single disassembly line. + """ + def __init__(self, addr, size, instruction): + self.addr = addr + self.size = size or 0 + self.instruction = instruction + + def getAddress(self): + """ + @return instruction address. + """ + return self.addr + + def getSize(self): + """ + @return instruction size in bytes. + """ + return self.size + + def getInstruction(self): + """ + @return array of instruction fields, each field is a collection of field properties, see FIELD_*. + """ + return self.instruction + + def __str__(self): + instr = "".join(map(str, self.instruction)) + return "[%s %s %s]" % (self.addr, self.size, instr) diff --git a/python/src/tcf/services/processes_v1.py b/python/src/tcf/services/processes_v1.py new file mode 100644 index 000000000..d77706124 --- /dev/null +++ b/python/src/tcf/services/processes_v1.py @@ -0,0 +1,47 @@ +# ******************************************************************************* +# * Copyright (c) 2011 Wind River Systems, Inc. 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: +# * Wind River Systems - initial API and implementation +# ******************************************************************************* + +""" +Extension of Processes service. +It provides new "start" command that supports additional parameters. +""" + +from . import processes + +NAME = "ProcessesV1" + +# Process start parameters +# Boolean, attach the debugger to the process +START_ATTACH = "Attach" +# Boolean, auto-attach process children +START_ATTACH_CHILDREN = "AttachChildren" +# Boolean, Use pseudo-terminal for the process standard I/O +START_USE_TERMINAL = "UseTerminal" + +class ProcessesV1Service(processes.ProcessesService): + def getName(self): + return NAME + + def start(self, directory, file, command_line, environment, params, done): + """ + Start a new process on remote machine. + @param directory - initial value of working directory for the process. + @param file - process image file. + @param command_line - command line arguments for the process. + Note: the service does NOT add image file name as first argument for the process. + If a client wants first parameter to be the file name, it should add it itself. + @param environment - map of environment variables for the process, + if null then default set of environment variables will be used. + @param params - additional process start parameters, see START_*. + @param done - call back interface called when operation is completed. + @return pending command handle, can be used to cancel the command. + """ + raise NotImplementedError("Abstract method") diff --git a/python/src/tcf/services/remote/DisassemblyProxy.py b/python/src/tcf/services/remote/DisassemblyProxy.py new file mode 100644 index 000000000..0ef9bbb04 --- /dev/null +++ b/python/src/tcf/services/remote/DisassemblyProxy.py @@ -0,0 +1,58 @@ +# ******************************************************************************* +# * Copyright (c) 2011 Wind River Systems, Inc. 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: +# * Wind River Systems - initial API and implementation +# ******************************************************************************* + +from tcf.services import disassembly +from tcf.channel.Command import Command + +class DisassemblyProxy(disassembly.DisassemblyService): + def __init__(self, channel): + self.channel = channel + + def getCapabilities(self, context_id, done): + done = self._makeCallback(done) + service = self + class GetCapabilitiesCommand(Command): + def __init__(self): + super(GetCapabilitiesCommand, self).__init__(service.channel, service, "getCapabilities", (context_id,)) + def done(self, error, args): + arr = None + if not error: + assert len(args) == 2 + error = self.toError(args[0]) + arr = args[1] + done.doneGetCapabilities(self.token, error, arr) + return GetCapabilitiesCommand().token + + def disassemble(self, context_id, addr, size, params, done): + done = self._makeCallback(done) + service = self + class DisassembleCommand(Command): + def __init__(self): + super(DisassembleCommand, self).__init__(service.channel, service, "disassemble", (context_id, addr, size, params)) + def done(self, error, args): + arr = None + if not error: + assert len(args) == 2 + error = self.toError(args[0]) + arr = _toDisassemblyArray(args[1]) + done.doneDisassemble(self.token, error, arr) + return DisassembleCommand().token + + +def _toDisassemblyArray(o): + if o is None: return None + return map(_toDisassemblyLine, o) + +def _toDisassemblyLine(m): + addr = m.get("Address") + size = m.get("Size") + instruction = m.get("Instruction") + return disassembly.DisassemblyLine(addr, size, instruction) diff --git a/python/src/tcf/services/remote/ProcessesV1Proxy.py b/python/src/tcf/services/remote/ProcessesV1Proxy.py new file mode 100644 index 000000000..5ebf28a3e --- /dev/null +++ b/python/src/tcf/services/remote/ProcessesV1Proxy.py @@ -0,0 +1,32 @@ +# ******************************************************************************* +# * Copyright (c) 2011 Wind River Systems, Inc. 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: +# * Wind River Systems - initial API and implementation +# ******************************************************************************* + +from . import ProcessesProxy +from tcf.services import processes_v1 +from tcf.channel.Command import Command + +class ProcessesV1Proxy(ProcessesProxy.ProcessesProxy, processes_v1.ProcessesV1Service): + def start(self, directory, file, command_line, environment, params, done): + done = self._makeCallback(done) + service = self + env = ProcessesProxy._toEnvStringArray(environment) + class StartCommand(Command): + def __init__(self): + super(StartCommand, self).__init__(service.channel, service, + "start", (directory, file, command_line, env, params)) + def done(self, error, args): + ctx = None + if not error: + assert len(args) == 2 + error = self.toError(args[0]) + if args[1]: ctx = ProcessesProxy.ProcessContext(service, args[1]) + done.doneStart(self.token, error, ctx) + return StartCommand().token diff --git a/python/src/tcf/services/streams.py b/python/src/tcf/services/streams.py index 77a210b86..1385ca0b4 100644 --- a/python/src/tcf/services/streams.py +++ b/python/src/tcf/services/streams.py @@ -118,7 +118,7 @@ class StreamsListener(object): """ Clients can implement StreamsListener interface to be notified when a stream is created or disposed. The interface is registered with 'subscribe' command. - + When new stream is created, client must decide if it is interested in that particular stream instance. If not interested, client should send 'disconnect' command to allow remote peer to free resources and bandwidth. If not disconnected, client is required to send 'read' commands as necessary to prevent stream buffer overflow. diff --git a/python/src/tcf/services/sysmonitor.py b/python/src/tcf/services/sysmonitor.py index 0b5c4f71c..2eb05ec18 100644 --- a/python/src/tcf/services/sysmonitor.py +++ b/python/src/tcf/services/sysmonitor.py @@ -339,7 +339,7 @@ class SysMonitorService(services.Service): def getContext(self, id, done): """ Retrieve context info for given context ID. - + @param id - context ID. @param done - callback interface called when operation is completed. """ @@ -348,7 +348,7 @@ class SysMonitorService(services.Service): def getChildren(self, parent_context_id, done): """ Retrieve children of given context. - + @param parent_context_id - parent context ID. Can be null - to retrieve top level of the hierarchy, or one of context IDs retrieved by previous getContext or getChildren commands. diff --git a/python/src/tcf/services/terminals.py b/python/src/tcf/services/terminals.py index f63f6decb..28c49896b 100644 --- a/python/src/tcf/services/terminals.py +++ b/python/src/tcf/services/terminals.py @@ -56,42 +56,42 @@ class TerminalContext(object): def getID(self): """ Get context ID. - Same as getProperties().get(“ID”) + Same as getProperties().get("ID") """ return self._props.get(PROP_ID) def getProcessID(self): """ Get process ID of the login process of the terminal. - Same as getProperties().get(“ProcessID”) + Same as getProperties().get("ProcessID") """ return self._props.get(PROP_PROCESS_ID) def getPtyType(self): """ Get terminal type. - Same as getProperties().get(“PtyType”) + Same as getProperties().get("PtyType") """ return self._props.get(PROP_PTY_TYPE) def getEncoding(self): """ Get encoding. - Same as getProperties().get(“Encoding”) + Same as getProperties().get("Encoding") """ return self._props.get(PROP_ENCODING) def getWidth(self): """ Get width. - Same as getProperties().get(“Width”) + Same as getProperties().get("Width") """ return self._props.get(PROP_WIDTH) def getHeight(self): """ Get height. - Same as getProperties().get(“Height”) + Same as getProperties().get("Height") """ return self._props.get(PROP_HEIGHT) @@ -109,7 +109,7 @@ class TerminalContext(object): @return pending command handle, can be used to cancel the command. """ raise NotImplementedError("Abstract method") - + class TerminalsService(services.Service): def getName(self): return NAME @@ -124,8 +124,8 @@ class TerminalsService(services.Service): However, 'ITerminals.getContext' is supposed to return only terminal specific data, If the ID is not a terminal ID, 'ITerminals.getContext' may not return any useful information - - @param id – context ID. + + @param id - context ID. @param done - call back interface called when operation is completed. """ raise NotImplementedError("Abstract method") @@ -183,8 +183,8 @@ class DoneGetContext(object): def doneGetContext(self, token, error, context): """ Called when contexts data retrieval is done. - @param error – error description if operation failed, null if succeeded. - @param context – context data. + @param error - error description if operation failed, null if succeeded. + @param context - context data. """ pass @@ -216,7 +216,7 @@ class TerminalsListener(object): """ Called when a terminal exits. @param terminal_id - terminal context ID - @param newWidth – new terminal width - @param newHeight – new terminal height + @param newWidth - new terminal width + @param newHeight - new terminal height """ pass diff --git a/python/src/tcf/tests/BasicTests.py b/python/src/tcf/tests/BasicTests.py index fd151f2f2..2db495a52 100644 --- a/python/src/tcf/tests/BasicTests.py +++ b/python/src/tcf/tests/BasicTests.py @@ -42,6 +42,7 @@ def test(): try: testRunControl(c) testStackTrace(c) + testDisassembly(c) testBreakpoints(c) testSymbols(c) testRegisters(c) @@ -218,6 +219,26 @@ def testStackTrace(c): for ctx_id in _suspended: protocol.invokeLater(stackTest, ctx_id) +def testDisassembly(c): + if not _suspended: return + ctl = sync.CommandControl(c) + try: + dis = ctl.Disassembly + except AttributeError: + # no Disassembly service + return + for ctx_id in _suspended: + frames = ctl.StackTrace.getChildren(ctx_id).get() + if frames: + frameData = ctl.StackTrace.getContext(frames).get() + if frameData: + addr = frameData[0].get("IP") + if addr: + print "Disassemble context %s from 0x%x" % (ctx_id, addr) + lines = dis.disassemble(ctx_id, addr, 256, None).get() + for line in lines: + print line + def testSymbols(c): from tcf.services import symbols def symTest(ctx_id): @@ -409,9 +430,9 @@ def testDataCache(c): protocol.invokeLater(contextsCache.validate, done) def testProcesses(c): - from tcf.services import processes + from tcf.services import processes, processes_v1 def processTest(): - proc = c.getRemoteService(processes.NAME) + proc = c.getRemoteService(processes_v1.NAME) or c.getRemoteService(processes.NAME) if not proc: return class DoneGetChildren(processes.DoneGetChildren): diff --git a/python/todo.twiki b/python/todo.twiki index 0d0e9ed2f..824f4c280 100644 --- a/python/todo.twiki +++ b/python/todo.twiki @@ -17,12 +17,13 @@ * [done] Expressions * [done] LineNumbers * [done] Processes + * [done] ProcessesV1 * [done] FileSystem * [done] MemoryMap * [done] Memory * [done] PathMap * [done] Diagnostics - * Disassembly + * [done] Disassembly * [done] Streams * [done] Terminals * [done] SysMonitor -- cgit v1.2.3