Phase 0: Debugging Tools
Objective
Before writing complex C, learn to observe what programs do at the system level. These tools reveal the truth — not what you think your code does, but what it actually does.
xxd — Hex Dump
See the raw bytes of any file:
# Your compiled binary — machine code
xxd hello | head -20
# A text file — ASCII values
echo "Hello" > test.txt
xxd test.txt
xxd shows you that everything is bytes. Text files are bytes. Binaries are bytes. The only difference is interpretation.
strace — System Call Trace
Every program talks to the kernel via syscalls. strace shows every one:
strace ./hello
Look for:
-
execve— the program starts -
openat— opening files (including shared libraries) -
mmap— mapping memory -
write(1, "Hello from C\n", 14)— THIS is your printf. fd 1 = stdout, 14 bytes written. -
exit_group(0)— program exits with code 0
# Count syscalls by type
strace -c ./hello
# Only show write syscalls
strace -e trace=write ./hello
# Follow child processes
strace -f ./hello
ltrace — Library Call Trace
One level above syscalls — traces C library function calls:
ltrace ./hello
You’ll see printf("Hello from C\n") — the library call. strace shows the write() syscall underneath it.
gdb — GNU Debugger (basics)
Compile with -g first:
gcc -Wall -g hello.c -o hello
gdb ./hello
Inside gdb:
break main # Set breakpoint at main()
run # Start the program
next # Step one line
print argc # Print a variable
continue # Run to next breakpoint or end
quit # Exit gdb
Exercises
-
[ ] Run
strace ./hello— find thewritesyscall. What file descriptor? How many bytes? -
[ ] Run
strace -c ./hello— which syscall is called most? -
[ ] Run
ltrace ./hello— find theprintfcall -
[ ] Run
strace cat /etc/hostname— find theopenatandreadsyscalls for the file -
[ ] Compile with
-g, rungdb ./hello, set a breakpoint at main, step through
Notes
Write your observations here.