Memory Operations
The Memory subsystem provides typed reads and writes at 8, 16, 32, and 64-bit widths, plus raw byte access, hexdump formatting, memory search, and file dump utilities. Access it through session.memory.
All memory operations use OpenOCD’s read_memory and write_memory TCL commands, which provide reliable structured I/O.
Typed reads
Section titled “Typed reads”Read one or more values at a specific width. All read methods return a list[int].
read_u8 / read_u16 / read_u32 / read_u64
Section titled “read_u8 / read_u16 / read_u32 / read_u64”async def read_u8(addr: int, count: int = 1) -> list[int]async def read_u16(addr: int, count: int = 1) -> list[int]async def read_u32(addr: int, count: int = 1) -> list[int]async def read_u64(addr: int, count: int = 1) -> list[int]async with Session.connect() as ocd: # Read a single 32-bit word values = await ocd.memory.read_u32(0x08000000) stack_pointer = values[0] print(f"Initial SP: 0x{stack_pointer:08X}")
# Read 8 consecutive 32-bit words (vector table) vectors = await ocd.memory.read_u32(0x08000000, count=8) for i, v in enumerate(vectors): print(f" Vector[{i}] = 0x{v:08X}")
# Read 16-bit values (useful for Thumb disassembly) instructions = await ocd.memory.read_u16(0x08001000, count=4)
# Read individual bytes header = await ocd.memory.read_u8(0x20000000, count=16)with Session.connect_sync() as ocd: values = ocd.memory.read_u32(0x08000000) stack_pointer = values[0] print(f"Initial SP: 0x{stack_pointer:08X}")
vectors = ocd.memory.read_u32(0x08000000, count=8) for i, v in enumerate(vectors): print(f" Vector[{i}] = 0x{v:08X}")
instructions = ocd.memory.read_u16(0x08001000, count=4) header = ocd.memory.read_u8(0x20000000, count=16)read_bytes
Section titled “read_bytes”For bulk data, read_bytes() returns raw bytes:
async def read_bytes(addr: int, size: int) -> bytesasync with Session.connect() as ocd: data = await ocd.memory.read_bytes(0x08000000, 1024) print(f"Read {len(data)} bytes") print(f"First 4 bytes: {data[:4].hex()}")with Session.connect_sync() as ocd: data = ocd.memory.read_bytes(0x08000000, 1024) print(f"Read {len(data)} bytes") print(f"First 4 bytes: {data[:4].hex()}")Internally, read_bytes reads using 8-bit width and converts the result to a bytes object.
Typed writes
Section titled “Typed writes”Write one or more values at a specific width. Accepts either a single integer or a list of integers.
write_u8 / write_u16 / write_u32
Section titled “write_u8 / write_u16 / write_u32”async def write_u8(addr: int, values: int | list[int]) -> Noneasync def write_u16(addr: int, values: int | list[int]) -> Noneasync def write_u32(addr: int, values: int | list[int]) -> Noneasync with Session.connect() as ocd: # Write a single 32-bit word await ocd.memory.write_u32(0x20000000, 0xDEADBEEF)
# Write multiple 32-bit words await ocd.memory.write_u32(0x20000000, [0x11111111, 0x22222222, 0x33333333])
# Write 16-bit values await ocd.memory.write_u16(0x20001000, [0x1234, 0x5678])
# Write individual bytes await ocd.memory.write_u8(0x20002000, [0x48, 0x65, 0x6C, 0x6C, 0x6F])with Session.connect_sync() as ocd: ocd.memory.write_u32(0x20000000, 0xDEADBEEF) ocd.memory.write_u32(0x20000000, [0x11111111, 0x22222222, 0x33333333]) ocd.memory.write_u16(0x20001000, [0x1234, 0x5678]) ocd.memory.write_u8(0x20002000, [0x48, 0x65, 0x6C, 0x6C, 0x6F])write_bytes
Section titled “write_bytes”For bulk data, write_bytes() accepts a bytes object:
async def write_bytes(addr: int, data: bytes) -> Noneasync with Session.connect() as ocd: payload = b"Hello, target!" await ocd.memory.write_bytes(0x20000000, payload)with Session.connect_sync() as ocd: payload = b"Hello, target!" ocd.memory.write_bytes(0x20000000, payload)Hexdump
Section titled “Hexdump”hexdump() reads memory and returns a formatted string with hex and ASCII columns, 16 bytes per line:
async def hexdump(addr: int, size: int) -> strasync with Session.connect() as ocd: dump = await ocd.memory.hexdump(0x08000000, 64) print(dump)with Session.connect_sync() as ocd: dump = ocd.memory.hexdump(0x08000000, 64) print(dump)Output format:
08000000: 00 50 00 20 A1 01 00 08 AB 01 00 08 AD 01 00 08 |.P. ............|08000010: AF 01 00 08 B1 01 00 08 B3 01 00 08 00 00 00 00 |................|08000020: 00 00 00 00 00 00 00 00 00 00 00 00 B5 01 00 08 |................|08000030: B7 01 00 08 00 00 00 00 B9 01 00 08 BB 01 00 08 |................|Each line shows:
- Address (8 hex digits)
- Hex bytes in two groups of 8, separated by a gap
- ASCII representation (non-printable bytes displayed as
.)
Memory search
Section titled “Memory search”search() scans a memory range for a byte pattern and returns all matching addresses:
async def search(pattern: bytes, start: int, end: int) -> list[int]async with Session.connect() as ocd: # Search for a magic number in flash matches = await ocd.memory.search( b"\xDE\xAD\xBE\xEF", start=0x08000000, end=0x08020000, ) for addr in matches: print(f" Found at 0x{addr:08X}")with Session.connect_sync() as ocd: matches = ocd.memory.search( b"\xDE\xAD\xBE\xEF", start=0x08000000, end=0x08020000, ) for addr in matches: print(f" Found at 0x{addr:08X}")The search reads memory in 4096-byte chunks with an overlap of len(pattern) - 1 bytes to handle patterns that span chunk boundaries. This is a client-side search since OpenOCD has no native memory search command.
File dump
Section titled “File dump”dump() reads memory and writes the raw bytes to a file:
async def dump(addr: int, size: int, path: Path) -> Nonefrom pathlib import Path
async with Session.connect() as ocd: # Dump the first 128KB of flash to a file await ocd.memory.dump(0x08000000, 128 * 1024, Path("flash_dump.bin"))from pathlib import Path
with Session.connect_sync() as ocd: ocd.memory.dump(0x08000000, 128 * 1024, Path("flash_dump.bin"))How it works
Section titled “How it works”Under the hood, all memory operations use the OpenOCD TCL RPC read_memory and write_memory commands:
read_memory 0x08000000 32 4 -> "00500020 080001A1 080001AB 080001AD"write_memory 0x20000000 32 {0xDEADBEEF}The response from read_memory is a space-separated list of hex values. The library parses these into Python integers. If the response contains “error”, a TargetError is raised.
Method summary
Section titled “Method summary”| Method | Returns | Description |
|---|---|---|
read_u8(addr, count=1) | list[int] | Read 8-bit values |
read_u16(addr, count=1) | list[int] | Read 16-bit values |
read_u32(addr, count=1) | list[int] | Read 32-bit values |
read_u64(addr, count=1) | list[int] | Read 64-bit values |
read_bytes(addr, size) | bytes | Read raw bytes |
write_u8(addr, values) | None | Write 8-bit values |
write_u16(addr, values) | None | Write 16-bit values |
write_u32(addr, values) | None | Write 32-bit values |
write_bytes(addr, data) | None | Write raw bytes |
search(pattern, start, end) | list[int] | Search for byte pattern |
dump(addr, size, path) | None | Dump memory to file |
hexdump(addr, size) | str | Formatted hex+ASCII dump |
Errors
Section titled “Errors”All memory operations raise TargetError if the OpenOCD command fails (e.g., target not halted, invalid address, bus fault).
Next steps
Section titled “Next steps”- Register Access — CPU register read/write
- Target Control — halt the target before memory operations
- CLI Reference — the
readcommand useshexdump()internally