[RFC] Dynamically instrumentation Go binaries

658 views
Skip to first unread message

ju...@sqreen.io

unread,
Nov 15, 2018, 12:09:19 PM11/15/18
to golang-nuts
Hi,

I am working on dynamic instrumentation of Go programs at run time, possibly without static source-code instrumentation. As I would like a solution as close to Go and standard as possible, I was first thinking of using `go generate` to generate a file adding things `reflect` doesn't provide such as the list of packages, functions, global variables... That way, I should be able to use `reflect` to modify any dynamic calls by modifying the method tables of their underlying type representations.

But regarding statically linked calls, the less intrusive technique I found are uprobes, which is linux-specific. And at the opposite, there are user-space binary code instrumentation libraries such as dyninst that modify the code at run time...

So I am wondering if anyone here has any thoughts on this subject, that doesn't seem to be solved for Go programs.

Thanks!

Julio

Robert Engels

unread,
Nov 15, 2018, 12:15:30 PM11/15/18
to ju...@sqreen.io, golang-nuts
Go is statically compiled. Pretty sure you cant do dynamic instrumentation - like logging method entry and exit - much of this is even lost due to inlining. You could possibly have an instrumented stdlib and dynamically link to that, but that is still not dynamic instrumentation. The profiler works by using stack samples. 
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Steven Hartland

unread,
Nov 15, 2018, 12:28:08 PM11/15/18
to golan...@googlegroups.com
dtrace support?

Robert Engels

unread,
Nov 15, 2018, 12:34:16 PM11/15/18
to Steven Hartland, golan...@googlegroups.com
AFAIK dtrace support is compiled in. If not enabled there are some tricks to make is essentially zero cost, but it is still there from the start. Could be wrong but that’s my understanding. 

Sent from my iPhone

Michael Jones

unread,
Nov 15, 2018, 1:55:50 PM11/15/18
to Robert Engels, Steven Hartland, golan...@googlegroups.com
You could study Rob Pike’s coverage/profiling tool to see how he adds and exploits basic block counting.  Good work as always. 
Michael T. Jones
michae...@gmail.com

robert engels

unread,
Nov 15, 2018, 2:22:34 PM11/15/18
to Michael Jones, Steven Hartland, golan...@googlegroups.com
Pike’s “coverage" uses source code rewriting and recompiling, so it is not dynamic instrumentation - at least how I would define it. Dynamic instrumentation to me means to instrument at runtime on an existing binary/distribution.

Tristan Colgate

unread,
Nov 15, 2018, 3:57:10 PM11/15/18
to robert engels, Michael Jones, Steven Hartland, golan...@googlegroups.com
Maybe you mean something like support for linux uprobes? 
There is some discussion here:
Google for "golang uprobes" picks up a couple of other links:


robert engels

unread,
Nov 15, 2018, 4:23:44 PM11/15/18
to Tristan Colgate, Michael Jones, Steven Hartland, golan...@googlegroups.com
Can’t you just ptrace the process, and use the ptrace related tools ? 

robert engels

unread,
Nov 15, 2018, 4:30:42 PM11/15/18
to Tristan Colgate, Michael Jones, Steven Hartland, golan...@googlegroups.com
Even if you could get uprobes to work, I think you will still have problems with inlining, and if you are going to compile with inlining disabled, etc. you might as well use Pike’s “coverage” method.

Damian Gryski

unread,
Nov 15, 2018, 6:06:11 PM11/15/18
to golang-nuts
One approach would be to augment the compiler to instrument the binary with the techniques outlined in:

XRay: A Function Call Tracing System

Damian

Kevin Malachowski

unread,
Nov 15, 2018, 6:56:04 PM11/15/18
to golang-nuts
If you can't recompile the binary, an option is to use a generic dynamic instrumentation platform like DynamoRIO (which I think works for Go programs after a recent bugfix). It works on windows, mac, and linux, and has been used in the past for various security-based testing and verification. Plenty of papers available on the website: http://dynamorio.org/pubs.html

Julio Guerra

unread,
Nov 19, 2018, 11:51:54 AM11/19/18
to dgr...@gmail.com, golan...@googlegroups.com
On Fri, Nov 16, 2018 at 12:06 AM Damian Gryski <dgr...@gmail.com> wrote:
One approach would be to augment the compiler to instrument the binary with the techniques outlined in:

XRay: A Function Call Tracing System


Yes, this is very likely the best option for performance and to avoid code relocation at run time... Unfortunately, the go toolchain currently doesn't have any "plugin" interface to add extra compilation stages.

--
Julio Guerra

Julio Guerra

unread,
Nov 19, 2018, 11:55:43 AM11/19/18
to michae...@gmail.com, ren...@ix.netcom.com, ste...@multiplay.co.uk, golan...@googlegroups.com
On Thu, Nov 15, 2018 at 7:55 PM Michael Jones <michae...@gmail.com> wrote:
You could study Rob Pike’s coverage/profiling tool to see how he adds and exploits basic block counting.  Good work as always. 
 
Good idea, thanks. I had a look at the implementation of it, and at the way it is integrated into the go toolchain. Unfortunately, it doesn't seem possible to include extra compilation stages in the toolchain. I was hoping for a way to insert an extra step to be able to modify the AST to insert tracepoints.

So, for example, coverage is built inside `go test` by directly calling `go cover`, and it doesn't use any plugin interface :(

--
Julio Guerra

Julio Guerra

unread,
Nov 19, 2018, 11:59:52 AM11/19/18
to tcol...@gmail.com, golan...@googlegroups.com
On Thu, Nov 15, 2018 at 9:57 PM Tristan Colgate <tcol...@gmail.com> wrote:
Maybe you mean something like support for linux uprobes? 
There is some discussion here:
Google for "golang uprobes" picks up a couple of other links:

Ran a small benchmark using uprobes and there's no overhead for an io-bound function, for a cpu-bound function, it is twice slower. So it may be a very good solution for a first linux-only version, as I don't need return probes (uretprobes seem to be a problem with Go's dynamic stack management).

--
Julio Guerra
Reply all
Reply to author
Forward
0 new messages