Logging C Functions
The Cosmopolitan Libc _start() function starts by intercepting the --ftrace flag. If it exists, then it opens and sorts of the symbol table from the elf binary. Then it changes the protection of memory so it’s able to iterate over the program’s memory to look for nop instructions it can mutate. Those NOPs were inserted by GCC. It’s easy to self-modify them in memory, since they have the same byte length as the CALL instruction. Think of it like a mini linker. It just relinks the profiling nops. Once they’ve been rewritten, functions will start calling ftrace_hook() which is an assembly function that saves the CPU state to the stack. That means ftrace kind of acts like an operating system kernel. Once the assembly saved the CPU it can call the ftracer() C code that acquires a reentrant mutex and unwinds the RBP backtrace pointer (via __builtin_frame_address(0)) to determine the address of the function that called it. Once it has the address of the function, it passes it along to kprintf() which has a special %t syntax for turning numbers into symbols.