Can we use DynamoRIO for golang

254 views
Skip to first unread message

Manoj Chauhan

unread,
Oct 25, 2021, 9:09:15 AM10/25/21
to DynamoRIO Users
As per https://github.com/DynamoRIO/dynamorio, it supports profiling, instrumentation, optimization etc. 
Can we use DynamoRIO for a go binary?
If binary contains a function say func1 then can i insert some code in func1 while the binary is running?

sharma...@google.com

unread,
Oct 25, 2021, 10:27:20 AM10/25/21
to DynamoRIO Users
Hi,
Yes, DynamoRIO does support Golang.

For your other question: yes, you can modify code during run-time using DynamoRIO. You can insert arbitrary code inside the app's basic blocks during run-time using drmgr's callbacks: https://dynamorio.org/page_drmgr.html. Example: https://github.com/DynamoRIO/dynamorio/blob/master/api/samples/countcalls.c; there are other samples in the same directory.

There's also an extension library called "drwrap", for run-time function wrapping and replacing. See https://dynamorio.org/page_drwrap.html; this page also links to APIs/libaries that can help you find the address of the target function, in case you want to do some custom instrumentation on your own.

Hopefully this helps.

Abhinav

Manoj Chauhan

unread,
Nov 16, 2021, 4:55:52 AM11/16/21
to DynamoRIO Users
Hi Abhinav,

Sorry for replying late.

Does DynamoRIO also handle unwinding issue in Go’s runtime?

GO runtime keeps the pc values for all the functions. Since any instrumented function (say func1) will not be in go runtime hence the application will crash. Does DynamoRIO add the pc values of instrumented function (func1) in go runtime?

Derek Bruening

unread,
Nov 16, 2021, 10:58:23 AM11/16/21
to dynamor...@googlegroups.com
DR preserves original PC values in all interactions with the application: the code cache is hidden from the app.  So the Go runtime's PC records and unwinding should all work fine.

--
You received this message because you are subscribed to the Google Groups "DynamoRIO Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dynamorio-use...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dynamorio-users/ef38cbe2-6da5-4b58-8ad6-7a243f7f85ddn%40googlegroups.com.

Manoj Chauhan

unread,
Nov 16, 2021, 11:22:54 PM11/16/21
to DynamoRIO Users
Hi Derek,
What about the case when the instrumented code calls multiple functions (which may be part of different libraries) ? Does DR use original PC in this case too? 
One more question,   If there is a function func1 and I want to instrument func2 at the entry point of func1 and func3 at the exit point of func1,  can I get the local/function parameters of func1 from stack and pass those in func2 & func3?  If yes then could you please give me some example of DR for golang.

Manoj Chauhan

unread,
Nov 18, 2021, 5:43:13 AM11/18/21
to DynamoRIO Users
Waiting for your reply.
I did not find any example of Dynamorio for golang. Please share the link

Derek Bruening

unread,
Nov 18, 2021, 10:34:59 AM11/18/21
to dynamor...@googlegroups.com
DR is a binary instrumentation technology so the language of the application is not usually relevant, so there would be little need to have examples of running a binary that was compiled from Go vs a binary compiled from C or C++ or Fortran or assembly.  It might matter for calling conventions: the library for intercepting functions and accessing parameters is drwrap and it has some built-in conventions to simplify argument access: https://dynamorio.org/group__drwrap.html#gae5c8c610a356f2dd2eaf27380a1645a0.  However, these are just convenience routines; the full register context is available so any convention's parameters can be accessed.

Manoj Chauhan

unread,
Nov 18, 2021, 1:16:21 PM11/18/21
to DynamoRIO Users
Thanks for your reply. I will go through it & reach you if needed.
I did not get a clear example of instrumentation. can I get any example of a binary(c/fortran/golang) which contains some methods and using Dynamorio I can instrument some methods in some functions of binary? 

Derek Bruening

unread,
Nov 18, 2021, 3:01:18 PM11/18/21
to dynamor...@googlegroups.com
Please look through the list of samples: https://dynamorio.org/API_samples.html
The wrap.c example uses drwrap to take actions on a particular function, and the instrcalls sample uses drsym to look up symbols for non-exported functions.

Manoj Chauhan

unread,
Nov 19, 2021, 4:36:06 AM11/19/21
to DynamoRIO Users
Thanks for replying. I will go through the links and reach you if needed.

Manoj Chauhan

unread,
Nov 19, 2021, 9:06:56 AM11/19/21
to DynamoRIO Users
After compiling DynamoRio from source code, I tried to attach to a process but couldn't succeed.

As per the link https://dynamorio.org/page_deploy.html, I can run following command and get some results.
 bin64/drrun -client ./api/bin/libwrap.so 0 -- ls

But when I'm trying to attach to a process, it does nothing and got stuck
bin64/drrun -attach 2144 -c ./api/bin/libwrap.so

Here 2144 is the process id of c/c++ process

Please help to solve this.

Once it got succeed, I think "mod->names.module_name" will  contain the name of process (pid=2144) and using dr_get_proc_address I can access the functions of that process.
module_load_event(void *drcontext, const module_data_t *mod, bool loaded)

Derek Bruening

unread,
Nov 19, 2021, 10:06:46 AM11/19/21
to dynamor...@googlegroups.com
On Fri, Nov 19, 2021 at 9:06 AM Manoj Chauhan <chauhan...@gmail.com> wrote:
After compiling DynamoRio from source code, I tried to attach to a process but couldn't succeed.

As per the link https://dynamorio.org/page_deploy.html, I can run following command and get some results.
 bin64/drrun -client ./api/bin/libwrap.so 0 -- ls

But when I'm trying to attach to a process, it does nothing and got stuck
bin64/drrun -attach 2144 -c ./api/bin/libwrap.so

This attach feature should have been more clearly marked as experimental and not yet for general reliable use.  Please see https://github.com/DynamoRIO/dynamorio/issues/5145#issuecomment-974144812 and https://github.com/DynamoRIO/dynamorio/issues/5054
 

Manoj Chauhan

unread,
Nov 23, 2021, 8:19:21 AM11/23/21
to DynamoRIO Users
Hi Derek,
Using following command, I'm able to wrap a function
bin64/drrun -client ./api/bin/libwrap.so 0 -- testclient

here testclient is a go binary. Golang contains 2 types of binaries: 1. Binary which contains elf format (linkshared binary) 2. Binary which are non-linkshared.

I found that Dynamorio supports only first type of binary. It does not support second type of go binary which is compiled using the command:
go build gofilename.go

Second type of binary is mostly used in go. Please correct me if i'm wrong.

Derek Bruening

unread,
Nov 23, 2021, 10:58:05 AM11/23/21
to dynamor...@googlegroups.com
DynamoRIO certainly supports pure-static executables.  We have a number of them in our regression test suite.

An example of successfully injecting into and running a static Go binary:

$ file ~/go/bin/hello
/home/bruening/go/bin/hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=8bda8c8360f1df2f2f79549d9b68695070b4fc76, with debug_info, not stripped
$ bin64/drrun -stderr_mask 15 -c api/bin/libbbcount.so -- ~/go/bin/hello
<Starting application /home/bruening/go/bin/hello (191699)>
Client bbcount is running
hello, world
<Stopping application /home/bruening/go/bin/hello (191699)>
Instrumentation results:
    106976 basic block executions
       992 basic blocks needed flag saving
      3109 basic blocks did not


Manoj Chauhan

unread,
Nov 23, 2021, 12:54:34 PM11/23/21
to DynamoRIO Users
I am getting problem for following case 2

case 1:
go build -linkshared testapp.go
file testapp
testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=eb3151384a6d7779ab0e7ee37a5b4c9a9005d243, not stripped


case2: 
go build testapp.go 
file testapp
testapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, not stripped

Using libwrap.so with testapp, dr_get_proc_address is able to get the functions of testapp for case1 but unable to find any function for case2.

Derek Bruening

unread,
Nov 23, 2021, 1:20:08 PM11/23/21
to dynamor...@googlegroups.com
This is as expected: as its documentation says, dr_get_proc_address() only looks at exported symbols in the dynamic symbol table.  A statically linked executable has no such symbols.  Debug information is needed to look at internal symbols and the drsyms library is provided for that: again, as the documentation states.

Message has been deleted

Manoj Chauhan

unread,
Nov 30, 2021, 6:03:17 AM11/30/21
to DynamoRIO Users
Hi Derek,

Thanks for sharing the link, now I can access the functions.

drwrap_wrap adds wrap_pre and wrap_post.  I want to use these functions from a shared library. Tried to load a shared library in module_load_event using dlopen but it did n't work.
I think the shared library will load into the address space of application. I did not find any example for that. Please share if there is any example.

Also I tried to access function arguments in wrap_pre using drwrap_get_arg but didn't get any result.

Derek Bruening

unread,
Nov 30, 2021, 11:36:10 AM11/30/21
to dynamor...@googlegroups.com
A client library is a shared library and that is where your pre and post wrap callback functions would normally live.  Are you saying you need a second shared library beyond your client library?  What is the reason for that?  There is some support via dr_load_aux_library() but this is almost never used or needed.

Manoj Chauhan

unread,
Nov 30, 2021, 1:07:33 PM11/30/21
to DynamoRIO Users
>>A client library is a shared library and that is where your pre and post wrap callback functions would normally live. 
If I need to instrument functions for a go/python binary then It will require to write the instrumented code in go/python. So This is the reason why I need a second library. I will go through dr_load_aux_library() .

What about drwrap_get_arg? I tried to use this function to access function parameters but didn't get any succees.

Derek Bruening

unread,
Nov 30, 2021, 5:15:11 PM11/30/21
to dynamor...@googlegroups.com
On Tue, Nov 30, 2021 at 1:07 PM Manoj Chauhan <chauhan...@gmail.com> wrote:
What about drwrap_get_arg? I tried to use this function to access function parameters but didn't get any succees.

Without details on what went wrong, what the client code looks like, what version of DR was used, what platform it was run on, what the app is, what the target function is, whether it works for other apps or contexts, etc., it is impossible to comment.  As you can see in our test suite and samples we use this function in multiple places and it works fine there; it is used in drcachesim and works fine on very large industry apps.

Derek Bruening

unread,
Nov 30, 2021, 6:54:54 PM11/30/21
to dynamor...@googlegroups.com
On Tue, Nov 30, 2021 at 1:07 PM Manoj Chauhan <chauhan...@gmail.com> wrote:
>>A client library is a shared library and that is where your pre and post wrap callback functions would normally live. 
If I need to instrument functions for a go/python binary then It will require to write the instrumented code in go/python. So This is the reason why I need a second library. I will go through dr_load_aux_library() .

I don't follow why you would need to write the instrumentation in Go or in Python.  DynamoRIO is a low-level instrumentation platform: you are looking at machine instructions.  If the goal is to access high-level language constructs in the target application, writing the instrumentation in a high-level language is not going to magically accomplish that: instrumentation must be isolated from the app so it's not like the runtimes can be merged or something.  If the goal is just to have some convenient libraries, I would suggest C++ if possible as asking the DynamoRIO private loader to support isolating a complex Python runtime environment inside a client is likely to have problems as client library isolation is hard enough for simple C or C++ libraries.
 
Message has been deleted

Manoj Chauhan

unread,
Dec 1, 2021, 3:39:26 AM12/1/21
to DynamoRIO Users
Instead of instrumenting all the functions, the better option is to instrument one function from which all other functions are called. Example is servehttp which is invoked before executing a web request. To do this it's required to make some changes in golang. There are some more reasons.
If I create a library in go then it's same like any c/++ library. I think there is no difference here.

Manoj Chauhan

unread,
Dec 1, 2021, 8:11:51 AM12/1/21
to DynamoRIO Users
Created a golang binary using the command "go build filename.go".  filename.go contains some functions like finc1, func2. Definition of func1 and func2

func func1(x int) {
func2(x)
}

func func2(x int) {
println(x)
}

func main() {
var x int = 1
func1(x)
}
When I tried to get the arguments for func2 in wrap_pre using drwrap_get_arg, it returned 0 value.
When I tried to get the arguments for func1 in wrap_pre using drwrap_get_arg, it returned some value but it was not 1.
size_t sz = (size_t)drwrap_get_arg(wrapcxt, 0);
I also tried to convert sz into int* address but the value at that address was not 1.
void *sz = (void *)drwrap_get_arg(wrapcxt, 0); //*sz is not 1

Is there any function which tells about the type of parameter? I know parameter of func1 is int but what about the case when I don't know about its type?

os - ubuntu 16
dynamorio branch- master

Derek Bruening

unread,
Dec 1, 2021, 11:35:09 AM12/1/21
to dynamor...@googlegroups.com
But what calling convention did you pass to drwrap_wrap_ex?  We already discussed this: https://groups.google.com/g/dynamorio-users/c/0n_cgKDPM_M/m/fV6iJN7GAgAJ.  As the documentation says, the default is DRWRAP_CALLCONV_DEFAULT which if you are on 64-bit x86 is the AMD64 C ABI where most parameters are in registers.  So you told drwrap that this was C code, so naturally it gave you values in a register for the args.  Looking online it looks like Go passes everything on the stack.  So you need to look on the stack.  If you would like to add a DRWRAP_CALLCONV_GO_AMD64 that automates the stack lookups we would be happy to take a PR.

--
You received this message because you are subscribed to the Google Groups "DynamoRIO Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dynamorio-use...@googlegroups.com.

Manoj Chauhan

unread,
Dec 2, 2021, 1:42:15 AM12/2/21
to DynamoRIO Users
It's working with DRWRAP_CALLCONV_STDCALL but there are few problems:
1. golang string argument is not NULL terminated when I get it in wrap_pre
2. If a golang function returns more than one value then drwrap_get_retval gives only one value in wrap_post
3. Did not find any function which tells about the type of function argument/return value
4. No function which tells about the 'Number of parameters in function' or 'number of return values'
 
I asked a different question about the library. I think if c/c++ library can be used for wrap_pre/wrap_post then I think golang library should also be used. I will try this

Derek Bruening

unread,
Dec 2, 2021, 11:45:28 AM12/2/21
to dynamor...@googlegroups.com
If you look at the docs there are many libraries: https://dynamorio.org/page_ext.html.  They include a symbol access library with a drsym_get_func_type() interface.  However it looks like it is only implemented for PDB.  Someone would need to volunteer to implement for DWARF; or you could directly use a libdwarf.  It sounds like no one has needed such information outside of Windows before.

Manoj Chauhan

unread,
Dec 3, 2021, 4:41:48 AM12/3/21
to DynamoRIO Users
Thanks for giving the link.

While using dr_load_aux_library to load a c/c++ library the application is crashing.

Entered in dr_load_aux_library
<Application /opt/build_dr/simpleapp_arg (752114). DynamoRIO Sample Client 'wrap' internal crash at PC 0x00007f4d13868f78. Please report this at http://dynamorio.org/issues. Program aborted.
Received SIGSEGV at pc 0x00007f4d13868f78 in thread 752114
Base: 0x00007f4d137aa000
Registers:eax=0x00007f4b12c80db8 ebx=0x0000000043e5e3d0 ecx=0x0000000000000015 edx=0x0000000000000000
esi=0x00007f4d13902787 edi=0x000000000000000a esp=0x00007ffe3f1fc408 ebp=0x00007f4b12c80db8
r8 =0x0000000000000000 r9 =0x000000000000006c r10=0x0000000000000000 r11=0x0000000043e5e308
r12=0x0000000000000000 r13=0x00007f4b12c80ff0 r14=0x00007ffe3f1fc42f r15=0x00007f4d13902787
eflags=0x0000000000010216
version 8.0.18960, custom build

Reply all
Reply to author
Forward
0 new messages