Creating a Jython script

Jython is a Java implementation of the Python scripting language. It provides extensive support for data types, conditional execution, loops and organisation of code into functions, classes and modules, as well as access to the standard Jython libraries. Jython is an ideal choice for larger or more complex scripts.

These are important concepts that are required in order to write a debugger Jython script.

Imports

The debugger module provides a Debugger class for initial access to the DS-5 Debugger, with further classes, known as services, to access registers and memory, . Here is an example showing the full set of module imports that are typically placed at the top of the jython script:

from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugException
Execution Contexts

Most operations on DS-5 Debugger Jython interfaces require an execution context. The execution context represents the state of the target system. Separate execution contexts exist for each process, thread, or processor that is accessible in the debugger. You can obtain an execution context from the Debugger class instance, :

# Obtain the first execution context
debugger = Debugger()
ec = debugger.getExecutionContext(0)
Registers

You can access processor registers, coprocessor registers and peripheral registers using the debugger Jython interface. To access a register you must know its name. The name can be obtained from the Registers view in the graphical debugger. The RegisterService enables you to read and write register values, for a given execution context, :

# Print the Program Counter (PC) from execution context ec
value = ec.getRegisterService().getValue('PC')
print 'The PC is ', value
Memory

You can access memory using the debugger Jython interface. You must specify an address and the number of bytes to access. The address and size can be an absolute numeric value or a string containing an expression to be evaluated within the specified execution context. Here is an example:

# Print 16 bytes at address 0x0 from execution context ec
print ec.getMemoryService().read(0x0, 16)
DS Commands

The debugger jython interface enables you to execute arbitrary DS-5 commands. This is useful when the required functionality is not directly provided in the Jython interface. You must specify the execution context, the command and any arguments that you want to execute. The return value includes the textual output from the command and any errors. Here is an example:

# Execute the DS-5 command 'print $ENTRYPOINT' and print the result
print ec.executeDSCommand('print $ENTRYPOINT')
Error Handling

The methods on the debugger Jython interfaces throw DebugException whenever an error occurs. You can catch exceptions to handle errors in order to provide more information. Here is an example:

# Catch a DebugException and print the error message
try:
  ec.getRegisterService().getValue('ThisRegisterDoesNotExist')
except DebugException, de:
  print "Caught DebugException: %s" % (de.getMessage())

The .py file extension must be used to identify this type of script.

Example 7. Jython script

# Filename: myScript.py

import sys

from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugException

# Debugger object for accessing the debugger
debugger = Debugger()

# Initialisation commands
ec = debugger.getExecutionContext(0)
ec.getExecutionService().stop()
ec.getExecutionService().waitForStop()
# in case the execution context reference is out of date
ec = debugger.getExecutionContext(0)
# load image if provided in script arguments
if len(sys.argv) == 2:
    image = sys.argv[1]
    ec.getImageService().loadImage(image)
    ec.getExecutionService().setExecutionAddressToEntryPoint()
    ec.getImageService().loadSymbols(image)

    # we can use all the DS commands available
    print "Entry point: ",
    print ec.executeDSCommand("print $ENTRYPOINT")
    # Sample output:
    #         Entry point: $8 = 32768
else:
    pass # assuming image and symbols are loaded

# sets a temporary breakpoint at main and resumes
ec.getExecutionService().resumeTo("main") # this method is non-blocking
try:
    ec.getExecutionService().waitForStop(500) # wait for 500ms

except DebugException, e:
    if e.getErrorCode() == "JYI31": # code of "Wait for stop timed out" message
        print "Waiting timed out!"
        sys.exit()
    else:
        raise # re-raise the exception if it is a different error
ec = debugger.getExecutionContext(0)

def getRegisterValue(executionContext, name):
    """Get register value and return string with unsigned hex and signed
    integer, possibly string "error" if there was a problem reading
    the register.
    """
    try:
        value = executionContext.getRegisterService().getValue(name)
        # the returned value behaves like a numeric type,
        # and even can be accessed like an array of bytes, e.g. 'print value[:]'
        return "%s (%d)" % (str(value), int(value))

    except DebugException, e:
        return "error"

# print Core registers on all execution contexts
for i in range(debugger.getExecutionContextCount()):
    ec = debugger.getExecutionContext(i)
    # filter register names starting with "Core::"
    coreRegisterNames = filter(lambda name: name.startswith("Core::"),
                            ec.getRegisterService().getRegisterNames())
    # using Jython list comprehension get values of all these registers
    registerInfo = ["%s = %s" % (name, getRegisterValue(ec, name))
                                        for name in coreRegisterNames]

    registers = ", ".join(registerInfo[:3]) # only first three
    print "Identifier: %s, Registers: %s" % (ec.getIdentifier(), registers)
# Output:
#         Identifier: 1, Registers: Core::R0 = 0x00000010 (16), Core::R1 = 0x00000000 (0), Core::R2 = 0x0000A4A4 (42148)
#         ...

Show/hideSee also

Copyright © 2010, 2011 ARM. All rights reserved.ARM DUI 0446H
Non-ConfidentialID111711