paint-brush
Strace in 60 lines of Goby@lizrice
6,834 reads
6,834 reads

Strace in 60 lines of Go

by Liz RiceJuly 15th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

<em>This post is a walk-through of the simple </em><a href="http://github.com/lizrice/strace-from-scratch" target="_blank"><em>strace implementation</em></a><em> I wrote during my </em><a href="https://gophercon.com/speakers/27" target="_blank"><em>GopherCon talk, A Go Programmer’s Guide to Syscalls</em></a><em>. You’ll find the code </em><a href="http://github.com/lizrice/strace-from-scratch" target="_blank"><em>here</em></a><em>.</em>

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Strace in 60 lines of Go
Liz Rice HackerNoon profile picture

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.