Convert bare .md path references in 29 files to proper [name](relative/path) markdown links for GitHub navigation.
3.3 KiB
Live Memory Probing
Overview
Live memory probing on a running Amiga means directly reading exec structures — SysBase, LibList, TaskReady, MemList — to observe system state without a traditional debugger.
SysBase: The Root of Everything
SysBase is always at absolute address $4 (a pointer to the ExecBase structure):
struct ExecBase *SysBase = *((struct ExecBase **)4);
printf("exec version: %d.%d\n",
SysBase->LibNode.lib_Version,
SysBase->LibNode.lib_Revision);
In assembly:
MOVEA.L 4.W, A6 ; A6 = SysBase (exec.library base)
MOVE.W ($16,A6), D0 ; lib_Version
MOVE.W ($18,A6), D1 ; lib_Revision
Walking the Library List
struct Node *n = SysBase->LibList.lh_Head;
while (n->ln_Succ != NULL) {
struct Library *lib = (struct Library *)n;
printf("%-30s v%d.%d opens=%d\n",
lib->lib_Node.ln_Name,
lib->lib_Version, lib->lib_Revision,
lib->lib_OpenCnt);
n = n->ln_Succ;
}
This enumerates all currently loaded libraries. Useful for:
- Finding if a target library is loaded
- Reading
lib_OpenCntto detect if your hook is installed - Checking
lib_Flags & LIBF_DELEXP(expunge pending)
Reading lib_OpenCnt Live
/* Check if bsdsocket.library is loaded and its open count */
struct Library *base = FindName(&SysBase->LibList, "bsdsocket.library");
if (base) {
printf("bsdsocket: OpenCnt=%d, Version=%d\n",
base->lib_OpenCnt, base->lib_Version);
}
FindName scans ln_Name in a linked list — it is an exec function at LVO −276.
Memory Region Map
SysBase->MemList lists all memory regions:
struct MemHeader *mh = (struct MemHeader *)SysBase->MemList.lh_Head;
while (mh->mh_Node.ln_Succ) {
printf("Region: %s %08lx–%08lx free=%ld\n",
mh->mh_Node.ln_Name,
(ULONG)mh->mh_Lower,
(ULONG)mh->mh_Upper,
mh->mh_Free);
mh = (struct MemHeader *)mh->mh_Node.ln_Succ;
}
Output example:
Region: chip memory $000000–$1FFFFF free=524288
Region: fast memory $200000–$9FFFFF free=6291456
Task List Inspection
/* Running tasks: */
Forbid();
struct Task *t = (struct Task *)SysBase->TaskReady.lh_Head;
while (t->tc_Node.ln_Succ) {
printf("Task: %-20s pri=%d state=%d\n",
t->tc_Node.ln_Name,
t->tc_Node.ln_Pri,
t->tc_State);
t = (struct Task *)t->tc_Node.ln_Succ;
}
Permit();
Forbid() / Permit() are mandatory — the task list must not change while walking it.
Patching Memory Live (Surgical Writes)
For RE/patching: direct longword write to an OS structure:
/* Example: force a library's version to 99 */
Forbid();
target_lib->lib_Version = 99;
Permit();
Caution
Direct memory writes to OS structures bypass all synchronization. Always use
Forbid()at minimum; useDisable()if modifying interrupt-visible data.
References
- NDK39:
exec/execbase.h,exec/memory.h,exec/tasks.h - exec_base.md — full ExecBase offset table
- memory_management.md — MemHeader structure
- setfunction_patching.md — Forbid/Permit patterns