diff options
-rw-r--r-- | python/src/tcf/services/stacktrace.py | 360 |
1 files changed, 269 insertions, 91 deletions
diff --git a/python/src/tcf/services/stacktrace.py b/python/src/tcf/services/stacktrace.py index 682a5c51c..0dca56afb 100644 --- a/python/src/tcf/services/stacktrace.py +++ b/python/src/tcf/services/stacktrace.py @@ -9,112 +9,188 @@ # * Wind River Systems - initial API and implementation #****************************************************************************** +"""TCF stacktrace service interface. + +.. |getChildren| replace:: :meth:`~StackTraceService.getChildren` +.. |getContext| replace:: :meth:`~StackTraceService.getContext` +.. |runcontrol| replace:: :mod:`~tcf.services.runcontrol` +.. |DoneGetChildren| replace:: :class:`DoneGetChildren` +.. |DoneGetContext| replace:: :class:`DoneGetContext` + + +The service implements thread stack back tracing. + +Properties +---------- + ++--------------------------+--------------+-----------------------------------+ +| Name | Type | Description | ++==========================+==============+===================================+ +| PROP_ARGUMENTS_ADDRESS | |int| | Memory address of function | +| | | arguments. | ++--------------------------+--------------+-----------------------------------+ +| PROP_ARGUMENTS_COUNT | |int| | Number of function arguments. | ++--------------------------+--------------+-----------------------------------+ +| PROP_FRAME_ADDRESS | |int| | Stack frame memory address. | ++--------------------------+--------------+-----------------------------------+ +| PROP_ID | |basestring| | String, stack frame ID. | ++--------------------------+--------------+-----------------------------------+ +| PROP_INSTRUCTION_ADDRESS | |int| | Instruction pointer. | ++--------------------------+--------------+-----------------------------------+ +| PROP_LEVEL | |int| | Stack frame level, starting from | +| | | stack bottom. | ++--------------------------+--------------+-----------------------------------+ +| PROP_NAME | |basestring| | Human readable name. | ++--------------------------+--------------+-----------------------------------+ +| PROP_PARENT_ID | |basestring| | Stack frame parent ID. | ++--------------------------+--------------+-----------------------------------+ +| PROP_PROCESS_ID | |basestring| | Stack frame process ID. | ++--------------------------+--------------+-----------------------------------+ +| PROP_RETURN_ADDRESS | |int| | Return address. | ++--------------------------+--------------+-----------------------------------+ +| PROP_TOP_FRAME | |bool| | **True** if the frame is top frame| +| | | on a stack. | ++--------------------------+--------------+-----------------------------------+ + +Service Methods +--------------- +.. autodata:: NAME +.. autoclass:: StackTraceService + +getName +^^^^^^^ +.. automethod:: StackTraceService.getName + +getContext +^^^^^^^^^^ +.. automethod:: StackTraceService.getContext + +getChildren +^^^^^^^^^^^ +.. automethod:: StackTraceService.getChildren + +Callback Classes +---------------- +DoneGetContext +^^^^^^^^^^^^^^^^^ +.. autoclass:: DoneGetContext + :members: + +DoneGetChildren +^^^^^^^^^^^^^^^ +.. autoclass:: DoneGetChildren + :members: + + +Helper Classes +-------------- +StackTraceContext +^^^^^^^^^^^^^^^^^ +.. autoclass:: StackTraceContext + :members: +""" + from .. import services NAME = "StackTrace" +"""StackTrace service name.""" -# -# Stack frame context property names. -# -# String, stack frame ID PROP_ID = "ID" - -# String, stack frame parent ID PROP_PARENT_ID = "ParentID" - -# String, stack frame process ID PROP_PROCESS_ID = "ProcessID" - -# String, human readable name PROP_NAME = "Name" - -# Boolean, true if the frame is top frame on a stack PROP_TOP_FRAME = "TopFrame" - -# Integer, stack frame level, starting from stack bottom PROP_LEVEL = "Level" - -# Number, stack frame memory address PROP_FRAME_ADDRESS = "FP" - -# Number, return address PROP_RETURN_ADDRESS = "RP" - -# Number, instruction pointer PROP_INSTRUCTION_ADDRESS = "IP" - -# Integer, number of function arguments PROP_ARGUMENTS_COUNT = "ArgsCnt" - -# Number, memory address of function arguments PROP_ARGUMENTS_ADDRESS = "ArgsAddr" +PROP_INDEX = "Index" +PROP_WALK = "Walk" class StackTraceService(services.Service): + """TCF stacktrace service interface.""" + def getName(self): + """Get this service name. + + :returns: This service name, which is the value of :const:`NAME` + """ return NAME def getContext(self, ids, done): - """ - Retrieve context info for given context IDs. + """Retrieve context info for given context IDs. - The command will fail if parent thread is not suspended. - Client can use Run Control service to suspend a thread. + The command will fail if parent thread is not suspended. Client can use + |runcontrol| service to suspend a thread. - @param ids - array of context IDs. - @param done - call back interface called when operation is completed. + :param ids: List of context IDs. + :type ids: |tuple| or |list| + :param done: call back interface called when operation is completed + :type done: |DoneGetContext| """ raise NotImplementedError("Abstract method") def getChildren(self, parent_context_id, done): - """ - Retrieve stack trace context list. + """Retrieve stack trace context list. + Parent context usually corresponds to an execution thread. - Some targets have more then one stack. In such case children of a + + Some targets have more than one stack. In such case children of a thread are stacks, and stack frames are deeper in the hierarchy - they - can be retrieved with additional getChildren commands. + can be retrieved with additional :meth:`getChildren` commands. - The command will fail if parent thread is not suspended. - Client can use Run Control service to suspend a thread. + The command will fail if parent thread is not suspended. Client can use + |runcontrol| service to suspend a thread. - @param parent_context_id - parent context ID. - @param done - call back interface called when operation is completed. + :param parent_context_id: Parent context ID. + :type parent_context_id: |basestring| + :param done: call back interface called when operation is completed + :type done: |DoneGetChildren| """ raise NotImplementedError("Abstract method") class DoneGetContext(object): - """ - Client call back interface for getContext(). - """ + """Client call back interface for |getContext|.""" + def doneGetContext(self, token, error, contexts): - """ - Called when context data retrieval is done. - @param error - error description if operation failed, None if - succeeded. - @param contexts - array of context data or None if error. + """Called when context data retrieval is done. + + :param error: Error description if operation failed, **None** if + succeeded. + :param contexts: A list of context data or **None** if error. + :type contexts: |tuple| or **None** """ pass class DoneGetChildren(object): - """ - Client call back interface for getChildren(). - """ + """Client call back interface for |getChildren|.""" + def doneGetChildren(self, token, error, context_ids): - """ - Called when context list retrieval is done. - @param error - error description if operation failed, None if - succeeded. - @param context_ids - array of available context IDs. - Stack frames are ordered from stack bottom to top. + """Called when context list retrieval is done. + + .. note:: Stack frames are ordered from stack bottom to top. + + :param error: error description if operation failed, **None** if + succeeded + :param context_ids: A list of available context IDs. + :type context_ids: |tuple| """ pass class StackTraceContext(object): - """ - StackTraceContext represents stack trace objects - stacks and stack frames. + """StackTrace context class. + + *StackTraceContext* represents stack trace objects : stacks and stack + frames. + + :param props: The properties to initialise object with. See `Properties`_. + :type props: |dict| """ def __init__(self, props): self._props = props or {} @@ -122,68 +198,170 @@ class StackTraceContext(object): def __str__(self): return "[Stack Trace Context %s]" % self._props + def __eq__(self, other): + # Two frames are considered equal if they have the same properties + if other and isinstance(other, StackTraceContext): + return self.getProperties() == other.getProperties() + return False + + def __getComparable(self, other): + assert isinstance(other, StackTraceContext) + + # levels from bottom to top, but we want top first when sorted + levels = (other.getLevel(), self.getLevel()) + # indexes from top to bottom + indexes = (self.getIndex(), other.getIndex()) + + # By default, use Level as it is more reliable to perform comparison, + # even between frames from successive runcontrol (Level is absolute, + # Index is function of the top frame which changes). + if -1 not in levels: + return levels + if -1 not in indexes: + return indexes + + return None + + def __ge__(self, other): + # Compare frames through their index or levels. + if other and isinstance(other, StackTraceContext): + comp = self.__getComparable(other) + return comp and comp[0] >= comp[1] + return False + + def __gt__(self, other): + # Compare frames through their index or levels. + if other and isinstance(other, StackTraceContext): + comp = self.__getComparable(other) + return comp and comp[0] > comp[1] + return True + + def __le__(self, other): + # Compare frames through their index or levels. + if other and isinstance(other, StackTraceContext): + comp = self.__getComparable(other) + return comp and comp[0] <= comp[1] + return False + + def __lt__(self, other): + # Compare frames through their index or levels. + if other and isinstance(other, StackTraceContext): + comp = self.__getComparable(other) + return comp and comp[0] < comp[1] + return False + + def __ne__(self, other): + # Two frames are considered equal if they have the same properties + if other and isinstance(other, StackTraceContext): + return self.getProperties() != other.getProperties() + return True + def getID(self): + """Get Context ID. + + :returns: A |basestring| representing this stack context ID. This is + the only mandatory field. + """ + return self._props.get(PROP_ID, '') + + def getIndex(self): + """Get stack index. + + :returns: An |int| representing this stack index, 0 being the top + frame, or **-1** if unknown. """ - Get Context ID. - @return context ID. + return self._props.get(PROP_INDEX, -1) + + def getLevel(self): + """Get stack level. + + :returns: An |int| representing this context stack level, or **-1** if + unknown. """ - return self._props.get(PROP_ID) + return self._props.get(PROP_LEVEL, -1) def getParentID(self): + """Get parent context ID. + + :returns: A |basestring| representing parent context ID, or an empty + |basestring| if unknown. """ - Get parent context ID. - @return parent context ID. + return self._props.get(PROP_PARENT_ID, '') + + def getProcessID(self): + """Get process context ID. + + :returns: A |basestring| representing process context ID, or an empty + |basestring| if unknown. """ - return self._props.get(PROP_PARENT_ID) + return self._props.get(PROP_PROCESS_ID, '') def getName(self): + """Get context name - if context represents a stack. + + :returns: A |basestring| representing this stack context name or + **None**. """ - Get context name - if context represents a stack. - @return context name or None. - """ - return self._props.get(PROP_NAME) + return self._props.get(PROP_NAME, None) def getFrameAddress(self): + """Get memory address of this frame. + + :returns: An |int| representing this frame address or **None** if not a + stack frame. """ - Get memory address of this frame. - @return address or None if not a stack frame. - """ - return self._props.get(PROP_FRAME_ADDRESS) + return self._props.get(PROP_FRAME_ADDRESS, None) def getReturnAddress(self): + """Get program counter saved in this stack frame. + + This return address is the address of instruction to be executed when + the function returns. + + :returns: An |int| representing the return address or **None** if not a + stack frame. """ - Get program counter saved in this stack frame - - it is address of instruction to be executed when the function returns. - @return return address or None if not a stack frame. - """ - return self._props.get(PROP_RETURN_ADDRESS) + return self._props.get(PROP_RETURN_ADDRESS, None) def getInstructionAddress(self): - """ - Get address of the next instruction to be executed in this stack frame. + """Get address of the next instruction to be executed in this stack + frame. + For top frame it is same as PC register value. + For other frames it is same as return address of the next frame. - @return instruction address or None if not a stack frame. + + :returns: An |int| representing this instruction address or **None** if + not a stack frame. """ - return self._props.get(PROP_INSTRUCTION_ADDRESS) + return self._props.get(PROP_INSTRUCTION_ADDRESS, None) def getArgumentsCount(self): + """Get number of function arguments for this frame. + + :returns: An |int| reprsenting this stack function arguments count. """ - Get number of function arguments for this frame. - @return function arguments count. - """ - return self._props.get(PROP_ARGUMENTS_COUNT) + return self._props.get(PROP_ARGUMENTS_COUNT, 0) def getArgumentsAddress(self): + """Get address of function arguments area in memory. + + :returns: An |int| representing this stack function arguments address + or **None** if not available. """ - Get address of function arguments area in memory. - @return function arguments address or None if not available. - """ - return self._props.get(PROP_ARGUMENTS_ADDRESS, 0) + return self._props.get(PROP_ARGUMENTS_ADDRESS, None) def getProperties(self): - """ - Get complete map of context properties. - @return map of context properties. + """Get complete map of context properties. + + :returns: A |dict| of context properties. See `Properties`_. """ return self._props + + def isTopFrame(self): + """Check if this stack frame is the top frame. + + :returns: A |bool| set to **True** if this stack is the toplevel + stack frame, **False** else. + """ + return self._props.get(PROP_TOP_FRAME, False) |