Every exercise from modules 01 to 13 in one place. The full wording and the "done when" criterion
are in each module's section 6; this file gives a one-line summary, the difficulty and a hint.
Build everything in WSL Ubuntu 24.04 with code/build_debug.sh unless the exercise says Windows.
Suggested path if short on time: do every easy one, then the medium ones in modules 04, 06,
07, 08, 10 and 12, then pick two hard ones that match your work (for example 07.5 and 12.6).
Map the program: match each address printed by m01_memory_layout to its line in the maps dump.
easy
Compare the address against the start-end range of each line; large malloc goes to an anonymous mmap region, not [heap] (threshold is 128 KiB by default).
1.2
Fault addresses: dereference 0x10, 0xFFFF...FF and one past a malloc(4096) block; record si_addr.
easy
The third one usually does not fault: the page after the block is still mapped heap. Faults happen at page granularity, not object granularity.
1.3
Find the guard page: crash m04_stack_overflow, compute si_addr - stack_start.
medium
info proc mappings gives the [stack] start; the fault is just below it, in the guard gap the kernel keeps under the stack.
1.4
ASLR on and off: run m01_memory_layout outside gdb, inside gdb, and under setarch -R.
medium
gdb disables ASLR by default (set disable-randomization on); that is why addresses repeat inside gdb.
1.5
Thread stacks: 4 threads print local addresses and pthread_getattr_np info; find each stack and guard in maps.
hard
Thread stacks are anonymous rw-p mappings of 8 MiB (default ulimit -s) with a ---p guard page just below; 9 MiB of use hits the guard and segfaults.
1.6
Windows comparison: map every VMMap category to a Linux maps line.
hard
Committed = backed by RAM or pagefile; Working Set = currently resident (like RSS); Private = not shareable (like anonymous mappings).
Read a frame: show [rbp+8] is the return address into level2.
easy
x/2xg $rbp shows saved rbp then return address; info symbol on the second word names the caller.
2.2
Registers at entry: watch $rdi change while p c stays.
easy
At -O0 the prologue spills rdi to the stack; info address c shows an rbp offset.
2.3
Inlining: compare gdb bt with backtrace() output in m02_frames_O2.
medium
gdb uses DWARF inline info to show inlined frames; backtrace() only sees real return addresses.
2.4
Separate debug file: objcopy --only-keep-debug, strip, --add-gnu-debuglink.
medium
readelf -n shows the same build id in both files; gdb matches by build id or debuglink.
2.5
Stack scan by hand: rebuild the call chain from x/40ag $rsp without bt.
hard
Look for words that info symbol resolves into .text just after a call instruction; those are return addresses. Ignore pointers into data.
2.6
Windows x64: kv, .frame /r 1, dv, .fnent @rip, dps @rsp L20 in an MSVC /O2 build.
hard
The 32 bytes above the return address belong to the callee's shadow space (home area for rcx, rdx, r8, r9); .fnent shows the unwind info that replaces frame pointers.
Heap overflow; null deref; race or uninitialised read; leak or unbounded growth; stack buffer overflow over the return address.
4.2
Run the suite: ./build_debug.sh run-asan, one report line per program.
easy
The first ERROR: AddressSanitizer: line names the class; the #0 frame below it names the line.
4.3
ASan vs Valgrind vs nothing on m04_uninit_read.
medium
ASan does not track initialisation (that is MSan, clang only); Valgrind Memcheck tracks definedness bit by bit.
4.4
Make the off-by-one in m04_heap_overflow abort every run.
medium
Control the layout: allocate the victim, then a neighbour of the same size class, so the stray byte hits the neighbour's size field.
4.5
Combination bug: integer overflow producing a small buffer, then a full-size copy.
hard
UBSan catches signed overflow (not unsigned wrap unless -fsanitize=unsigned-integer-overflow in clang); ASan catches the copy.
4.6
Turn a double free into silent corruption.
hard
Insert a same-size malloc between the frees: it takes the chunk out of tcache, so the second free releases a live object and the double-free check sees nothing.
Null deref in under 3 minutes: signal, address, instruction, frame, line, fix.
easy
run, bt, p $_siginfo._sifields._sigfault.si_addr, x/i $pc, frame N, list.
5.2
Stepping: predict each Value returned before finish prints it.
easy
Read the function body before finish; step enters, next steps over, finish returns.
5.3
Watchpoint hunt on the freed object.
medium
A hardware watchpoint on freed memory fires inside free because tcache writes its next pointer and key into the first 16 bytes; watch -l balance may never fire if that field is not overwritten.
5.4
Attach and deadlock statement with real LWPs.
medium
thread apply all bt, then in each waiting thread print the mutex: __owner is the holder's LWP.
5.5
Python pretty printer for Account.
hard
Subclass nothing: a class with to_string(), a lookup function matching str(val.type.strip_typedefs()), gdb.pretty_printers.append(...) from .gdbinit.
5.6
Scripted triage crash.gdb in batch mode.
hard
gdb -batch -x crash.gdb binary core > first_look.txt; include info registers, x/i $pc, thread apply all bt full, info sharedlibrary, info proc mappings.
Make a core happen and find NT_SIGINFO and NT_FILE notes.
easy
WSL may pipe cores to apport or nothing; set core_pattern to a file path; readelf -n core lists the notes.
6.2
Run the fixed procedure of section 2.6 on that core and write one line.
easy
Signal, si_code (1 = SEGV_MAPERR, 2 = SEGV_ACCERR), si_addr, x/i $pc, the register in the instruction, frame, line, class.
6.3
Analyse m06_crash_example at -O2 cold.
medium
Two bugs: the null and the stale pointer; the stale pointer is a reference into a vector taken before an erase shifted the elements.
6.4
Wrong binary: open an old core with a rebuilt binary.
medium
gdb warns about build-id mismatch (or not at all for the main binary on old versions); line numbers and local values are the first things that lie.
6.5
Analyse on another machine with set sysroot.
hard
Copy the libraries listed in info sharedlibrary (or the NT_FILE note) into a directory tree mirroring their absolute paths; set sysroot before loading the core.
6.6
gcore a hang of m10_deadlock and name both owners from the core.
hard
Same as 5.4 but from a static file; map __owner LWPs to gdb thread numbers with info threads.