Let’s quickly recap what we’ve done:

  1. We’ve modified our main-containing compilation module to:
    1. Define a file pointer to our memory accesses log
    2. Include opcodes at the entry point of main that initialize this file pointer
    3. Define an externally-linked function that performs the memory tracing logic
  2. We’ve gone over all functions across all compilation modules and:
    1. Filtered out load/store instructions
    2. Appended a call to our logging function after each instruction

Let’s see all this in action:


Let’s look at two files:

main.c

func.c

When we run these files unmodified:

> clang main.c func.c -o unmodified
> ./unmodified 
Address of ptr: 0x117d2a0, value of ptr: 0x5
5
Address of ptr: 0x117d2a0, value of ptr: 0x100

And with our pass:

> clang -S -emit-llvm main.c func.c
> opt -load-pass-plugin ./lib/libMemoryTrace.so -passes=memory-trace func.ll -S -o modified_func.ll
Did not find main in func.ll
> opt -load-pass-plugin ./lib/libMemoryTrace.so -passes=memory-trace main.ll -S -o modified_main.ll
Found main in module main.ll
> clang modified_main.ll modified_func.ll -o modified
>./modified
Address of ptr: 0x1366490, value of ptr: 0x5
5
Address of ptr: 0x1366490, value of ptr: 0x100

And - finally:

> cat memory-traces.log
[Write] Wrote value 0x13652a0 to address 0x4040d8
[Write] Wrote value 0x0 to address 0x7fff7305510c
[Write] Wrote value 0x1366490 to address 0x7fff73055100
[Read] Read value 0x1366490 from address 0x7fff73055100
[Write] Wrote value 0x5 to address 0x1366490
[Read] Read value 0x1366490 from address 0x7fff73055100
[Read] Read value 0x1366490 from address 0x7fff73055100
[Read] Read value 0x5 from address 0x1366490
[Read] Read value 0x1366490 from address 0x7fff73055100
[Read] Read value 0x5 from address 0x1366490
[Read] Read value 0x1366490 from address 0x7fff73055100
[Write] Wrote value 0x1366490 to address 0x7fff73055098
[Read] Read value 0x1366490 from address 0x7fff73055098
[Write] Wrote value 0x100 to address 0x1366490
[Read] Read value 0x1366490 from address 0x7fff73055100
[Read] Read value 0x1366490 from address 0x7fff73055100
[Read] Read value 0x100 from address 0x1366490

Untitled

We’ve traced all memory accesses in our program! We can see both memory reads & writes from/to the stack - and our own explicit reads & writes (notice the lines that contain 0x100/ 0x5).

Let’s finish up with some conclusions.