Mystery Coder
Mystery Coder

Reputation: 21

How to write a value to a memory address in python using a T32_WriteMemory function

I am trying to automate the Trace32 functions using python. And I am trying to write a value to a memory address using T32_WriteMemory() function. Can someone help me how to go ahead with this function?

Below is the reference from the T32 Api pdf (api_remote.pdf):

int T32_WriteMemory(
   uint32_t  byteAddress
   int       access,
   uint8_t  *buffer,
   int       byteSize
); 

byteAddress : target memory address to start write

access : memory access specifier

buffer : output

byteSize : number of bytes to read

Upvotes: 2

Views: 3677

Answers (1)

Holger
Holger

Reputation: 4183

To write memory from a python script via TRACE32 do the following:

  1. Enable the port for remote control at TRACE32
  2. Get the compiled shared libraries for TRACE32 remote access (t32api.dll/.so)
  3. Load the t32api library in your python script (using ctypes)
  4. Connect via the t32api library to your TRACE32 GUI
  5. Declare the parameter types of T32_WriteMemory
  6. Create a byte buffer with the data to write in your target endianness
  7. Call the T32_WriteMemory from the t32api library (using ctypes)
  8. Close the connection to TRACE32 before ending your script

In detail:

1. Enable the port for remote control at TRACE32

Add the following lines to your TRACE32 configuration file (config.t32):

RCL=NETASSIST
PORT=20000

There must be an empty line before and after that block. Of course you can also choose an other number for port. A TRACE32 GUI started with these setting opens a UDP/IP port to listen for possible requests to remote control TRACE32.

2. Get the compiled shared libraries for TRACE32 remote access

You'll find the required shared libraries in your TRACE32 installation at <T32>/demo/api/capi/dll (On Windows this is usually C:\t32\demo\api\capi\dll) You can also download it at http://www.lauterbach.com/scripts.html (search there for "capi" or "python")

For Windows there is t32api.dll and t32api64.dll. For Linux there is t32api.so or t32api64.so. (t32api64.* is for a 64-bit python interpreter, while t32api.* is for a 32-bit python interpreter.)

In the following I assume that you place the t32api-library at the same directory than your python script.

3. Load the t32api library in your python script

import platform
import ctypes

ostype = ctypes.sizeof(ctypes.c_voidp) * 8
if (platform.system()=='Windows') or (platform.system()[0:6]=='CYGWIN') :
    # WINDOWS
    t32api = ctypes.CDLL("./t32api64.dll" if ostype==64 else "./t32api.dll")
elif platform.system()=='Darwin' :
    # Mac OS X
    t32api = ctypes.CDLL("./t32api.dylib")
else :
    # Linux
    t32api = ctypes.CDLL("./t32api64.so" if ostype==64 else  "./t32api.so")

In the t32api-library is not at the same directory than your python script, you have to adapt the paths of course.

4. Connect via the t32api library to your TRACE32 GUI

# Declare UDP/IP socket of the TRACE32 instance to access
t32api.T32_Config(b"NODE=",b"localhost")
t32api.T32_Config(b"PORT=",b"20000")

# Connect to TRACE32
error = t32api.T32_Init()
if error != 0 :
    sys.exit("Can't connect to TRACE32!")

# Select to debugger component of TRACE32 (B:: prompt)
t32api.T32_Attach(1)

If you've chosen another port in step 1, you have to change the line t32api.T32_Config(b"PORT=",b"20000") accordingly.

5. Declare the parameter types of T32_WriteMemory

t32api.T32_WriteMemory.argtypes = [ctypes.c_uint32, ctypes.c_int, ctypes.c_char_p, ctypes.c_int]
t32api.T32_WriteMemory.restype  = ctypes.c_int

The first line tells python that T32_WriteMemory is a C-function which has four parameters with the types uint32_t, int, char* and int. The second line tells python that the return value is of type int.

6. Create a byte buffer with the data to write in your target endianness

wdata = 0x12345678  # <- Your own value here !
wbuffer = wdata.to_bytes(4, byteorder='little')

Here, 0x12345678 is the value I have choose to write. My target CPU, which I debug via TRACE32, has it's memory organized in little-endian byte-order. So I've chosen "byteorder='little'" in the second line which creates the byte-buffer.

7. Call the T32_WriteMemory from the t32api library

# Set parameters for the memory access
byteAddress = 0x46c8  # <- Your address here !
access      = 0x20
byteSize    = 4  # amount of bytes to write (e.g. 4 bytes)

# Write data to memory via TRACE32
error = t32api.T32_WriteMemory(byteAddress, access, wbuffer, byteSize)
if error != 0 :
    print("write failed")

access = 0x20 enables memory access while the CPU is running (if SYStem.MemAccess is enabled in TRACE32 and the CPU supports run-time access) Set it to 0 otherwise, or see the TRACE32 API documentation (api_remote.pdf) for other values.

8. Close connection to TRACE32 before ending your script

t32api.T32_Exit()

Reading memory goes like this:

# Declare argument types of T32_T32_ReadMemory
t32api.T32_T32_ReadMemory.argtypes = [ctypes.c_uint32,ctypes.c_int, ctypes.c_char_p,ctypes.c_int]
t32api.T32_T32_ReadMemory.restype  = ctypes.c_int

# Create a buffer for the result
rbuffer = ctypes.create_string_buffer(byteSize)

# Request memory content via TRACE32
error = t32api.T32_ReadMemory(byteAddress, access, rbuffer, byteSize)
if error == 0 :
  # Extract 32-bit value in little endian order from the buffer
  data32 = int.from_bytes(rbuffer[0:4], byteorder='little')
  print("read  0x%08X from D:0x%08X" % (data32, byteAddress))
else:
  print("read failed")

Upvotes: 6

Related Questions