Strace in 60 lines of Go

Written by lizrice | Published 2017/07/15
Tech Story Tags: golang | linux | syscalls | ptrace

TLDRvia the TL;DR App

This post is a walk-through of the simple strace implementation I wrote during my GopherCon talk, A Go Programmer’s Guide to Syscalls. You’ll find the code here.

To explore some of the features of the Linux ptrace syscall I thought it would be fun to write my own implementation of a basic strace — a tool that shows which syscalls an executable uses. This article is a quick breakdown of how the program works. If you have time, there’s more detail and colour in the talk:

I added a boolean called exit to keep track of whether it’s an exit or entry, and simply flipped its state each time through the for loop. I only count the syscall on exit. Here’s the loop, including keeping track of the exit.

for {if exit {err = syscall.PtraceGetRegs(pid, &regs)if err != nil {break}

    name, \_ := sec.ScmpSyscall(regs.Orig\_rax).GetName()  
    fmt.Printf("%s\\n", name)  
}

err = syscall.PtraceSyscall(pid, 0)  
if err != nil {  
    panic(err)  
}

\_, err = syscall.Wait4(pid, nil, 0, nil)  
if err != nil {  
    panic(err)  
}

exit = !exit  

}

Summing up the syscalls

I wrote some utility code to keep count of the number of times each syscall code is used, and to print out a summary.

Et voilà

If you try this out you’ll see this gives something that corresponds to what strace gives us. Here’s a very short demo showing the output from this code when we use it on echo hello, and the output from strace -c for the same thing. You’ll see they show the same counts for each syscall.

Strace from scratch demo_https://github.com/lizrice/strace-from-scratch_asciinema.org

The full implementation also shows the parameters for each syscall. If you wanted to build out our simple version to do this, we could map them from other registers.

In the talk I went on to demonstrate how you can use the seccomp security module to prevent specific syscalls. You can try this out for yourself by uncommenting the call to disallow(). This is really just to give an idea of what happens when you use seccomp filters — I wouldn’t recommend that everyone should start handcrafting code within production applications to determine which syscalls they can call! If you like the idea of self-sandboxing applications, you should check out this talk by Jessie Frazelle.

Massive thanks for the inspiration and information in @nelhage’s implementation of strace in C and Michał Łowicki’s deep dives into making a debugger in Go, and to everyone at Gophercon who made me feel so welcome.


Published by HackerNoon on 2017/07/15