`ltrace` yields "Couldn't find .dynsym or .dynstr in "/proc/*/exe" with binaries generated by "go build *.go"

2,152 views
Skip to first unread message

neh...@gmail.com

unread,
Sep 15, 2017, 9:15:40 AM9/15/17
to golang-nuts
Hi, I just found `ltrace` would yield "Couldn't find .dynsym or .dynstr in "/proc/*/exe" with executable binary generated by "go build *.go".

Is there any options in `go build` could solve this problem?

Thanks a lot.

PS:
$go version
go version go1
.9 linux/amd64
$ cat hi
.go
package main


import "fmt"


func main
() {
 fmt
.Println("hi!")
}
$ go build hi
.go
$ ltrace
./hi
Couldn't find .dynsym or .dynstr in "/proc/`*`/exe"


Konstantin Khomoutov

unread,
Sep 15, 2017, 9:49:58 AM9/15/17
to neh...@gmail.com, golang-nuts
From the description of the ltrace's Debian package, I gather that

| ltrace is a debugging program which runs a specified command until it
| exits. While the command is executing, ltrace intercepts and records
| the dynamic library calls which are called by
| the executed process and the signals received by that process.
| It can also intercept and print the system calls executed by the program.

The Go compiler (of the "gc" suite you seem to use) generates statically
compiled executable which link with no dynamic libraries (at least on
Linux/amd64, with the reasonably current Go versions).

Supposedly this explains why you don't see the those ".dyn*" sections in
the generated ELF file.

So what is your goal, exactly? What do you want to achieve?

Sen Han

unread,
Sep 15, 2017, 4:52:22 PM9/15/17
to Konstantin Khomoutov, golang-nuts
Thanks for your information. I want to use `ltrace` to find out if the golang binary is using 
the __vdso_clock_gettime_sym with CLOCK_MONOTONIC option for measuring time interval.

But it finally turns out currently the `ltrace` cannot works very well with go built binaries on 
vdso tracing. 

Is there some exist tools could trace the vdso call in golang? Or is there any recommend methods 
could achieve it on the runtime?

Thanks. 

PS:

With your information then I tried again:

$ cat hi.go 
package main

import (
        "fmt"
        "time"
)

func main() {
        fmt.Println("hi!")
        start := time.Now()
        t := time.Now()
        fmt.Println(t.Sub(start))
}
$ CGO_ENABLED=0 go build -a -x -linkshared hi.go
...

$ ldd hi
        linux-vdso.so.1 =>  (0x00007ffe96de7000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f721e492000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f721e85f000)

$ ltrace -s 1000 -tttTf ./hi
[pid 2305] 1505506857.418373 __libc_start_main(0x4bbcb0, 1, 0x7fff8d799738, 0x51a270hi!
540ns
 <no return ...>
[pid 2306] 1505506857.440419 +++ exited (status 0) +++
[pid 2307] 1505506857.440451 +++ exited (status 0) +++
[pid 2308] 1505506857.440946 +++ exited (status 0) +++
[pid 2305] 1505506857.440972 +++ exited (status 0) +++

$ readelf -r hi

Relocation section '.rela.dyn' at offset 0x65650 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
0000007e1fe8  000100000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
0000007e1ff0  115e00000012 R_X86_64_TPOFF64  0000000000000000 runtime.tlsg + 0

Relocation section '.rela.plt' at offset 0x65680 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
0000007e1fd8  000100000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0
0000007e1fe0  000300000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0


David Collier-Brown

unread,
Sep 17, 2017, 5:28:27 PM9/17/17
to golang-nuts
You may need to look and see what __vdso_clock_gettime_sym calls at the system-call level, and compare that with the system calls reported by strace from your executable. 

I assume you want some particular thing that __vdso_clock_gettime_sym does: try asking the folks about that, as they may already know.

Sen Han

unread,
Sep 17, 2017, 7:08:41 PM9/17/17
to David Collier-Brown, golang-nuts
In `go1.9 @ linux 3.10.0-327.el7.x86_64`, the call __vdso_clock_gettime_sym is 
completely in userspace, and does not involve any syscall in the kernel, and that is 
the reason __vdso_clock_gettime_sym with CLOCK_MONOTONIC is so fast. ( In C, 
the perf of __vdso_clock_gettime_sym is about 14,000,000 op/s, it drops to nearly 
7,000,000 op/s in golang's implementation. )

On Mon, Sep 18, 2017 at 5:28 AM, David Collier-Brown <dave...@gmail.com> wrote:
You may need to look and see what __vdso_clock_gettime_sym calls at the system-call level, and compare that with the system calls reported by strace from your executable. 

I assume you want some particular thing that __vdso_clock_gettime_sym does: try asking the folks about that, as they may already know.

--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sen Han

unread,
Sep 17, 2017, 7:12:05 PM9/17/17
to David Collier-Brown, golang-nuts
Which in this case, the `strace` cannot trace a single syscall that involves the time.

Dave Cheney

unread,
Sep 17, 2017, 8:33:33 PM9/17/17
to golang-nuts
What is the problem you are trying to solve?

Said another way. If you can confirm (or disprove, whichever suits) that Go uses __vdso_clock_gettime_sym with CLOCK_MONOTONIC, what would you do with that information?
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Konstantin Khomoutov

unread,
Sep 18, 2017, 5:48:17 AM9/18/17
to Sen Han, golang-nuts
On Sat, Sep 16, 2017 at 04:51:00AM +0800, Sen Han wrote:
> Thanks for your information. I want to use `ltrace` to find out if the
> golang binary is using
> the __vdso_clock_gettime_sym with CLOCK_MONOTONIC option for measuring time
> interval.
>
> But it finally turns out currently the `ltrace` cannot works very well with
> go built binaries on
> vdso tracing.
>
> Is there some exist tools could trace the vdso call in golang? Or is there
> any recommend methods
> could achieve it on the runtime?

Go is free software so instead of trying to trace the binaries its
compiler creates, you could just grep the runtime's source code. ;-)
Especially given the fact that since version 1.5 Go is entirely written
in Go (modulo some assembly code).

I have just grepped the checkout of 1.9 for CLOCK_MONOTONIC, and
I think devel/golang1.9/src/runtime/sys_linux_amd64.s is what you need.
Look for the "nanotime" function.

Note that at least on i386 and amd64, Linux maps the memory ranges
containing the data related to date/time information into the address
space of every process, so reading these data does not involves any
syscalls -- merely direct reads of the data located at a certain memory
address.

IIRC, on Windows, a similar mechanism is used. Don't know about other
supported kernels.

Sen Han

unread,
Sep 22, 2017, 8:15:10 AM9/22/17
to golang-nuts, Konstantin Khomoutov, da...@cheney.net
Sorry I've taken so long to reply. Thanks Konstantin and Dave.

In the implementation and usage of distributed lock leases, it is 
always essential to use the monotonic time API to measure the 
time interval. 

But in the implementation of the time package (go 1.9), there is 
fallback and the go application itself couldn't know whether it is 
actually using a monotonic time syscall or just the fallback 
`gettimeofday` which is unsafe for the strict lease measuring:

    TEXT runtime·nanotime(SB),NOSPLIT,$16
        // Duplicate time.now here to avoid using up precious stack space.
        // See comment above in time.now.
        MOVQ runtime·__vdso_clock_gettime_sym(SB), AX
        CMPQ AX, $0
        JEQ fallback
        MOVL $1, DI // CLOCK_MONOTONIC
        LEAQ 0(SP), SI
        CALL AX
        MOVQ 0(SP), AX // sec
        MOVQ 8(SP), DX // nsec
        // sec is in AX, nsec in DX
        // return nsec in AX
        IMULQ $1000000000, AX
        ADDQ DX, AX
        MOVQ AX, ret+0(FP)
        RET
    fallback:
        LEAQ 0(SP), DI
        MOVQ $0, SI
        MOVQ runtime·__vdso_gettimeofday_sym(SB), AX
        CALL AX
        MOVQ 0(SP), AX // sec
        MOVL 8(SP), DX // usec
        IMULQ $1000, DX
        // sec is in AX, nsec in DX
        // return nsec in AX
        IMULQ $1000000000, AX
        ADDQ DX, AX
        MOVQ AX, ret+0(FP)
        RET

(I think maybe it's better to add one api like 'time.IsMono' to tell the go app 
whether the monotonic clock is really & actually been used unmistakenly.)

Ps:

    Although there is a in time.Now().String()  for time has a monotonic 
    clock reading:

        1. Doesn't have monotonic clock reading:

            "2006-01-02 15:04:05.999999999 -0700 MST"

        2. Have monotonic clock reading:

            "2006-01-02 15:04:05.999999999 -0700 MST m=+2.006332106"

    But it is a little strange and not straight forward to use RE to match the 
    final field "m=±<value>", and most importantly, there isn't any guarantee 
    about how this format will be modified in the future.

Dave Cheney

unread,
Sep 27, 2017, 6:55:37 AM9/27/17
to Sen Han, golang-nuts, Konstantin Khomoutov
Using monotonic time for implementing a distributed locking system
seems fraught with difficulties.

If you're using the time package to time how long operations take, just do

t1 := time.Now()
// time passes
d := time.Since(t1)

d will have the most accurate value available.

David Collier-Brown

unread,
Sep 28, 2017, 9:36:53 AM9/28/17
to golang-nuts
Indeed: a monotonic increasing number is a good thing, but I wouldn't try to make it an actual time, just a relative time-like-thingie  that _you_ define with the properties you need and that you can implement.

--dave


On Wednesday, September 27, 2017 at 6:55:37 AM UTC-4, Dave Cheney wrote:
Using monotonic time for implementing a distributed locking system
seems fraught with difficulties.
 supported kernels.

Reply all
Reply to author
Forward
0 new messages