I compiled docker by myself with some modifications. I would like to perform some static analysis to the binary. Mostly to see which parts of the code take more memory, etc. It's on linux (elf). Any suggestion what free tools should I use? I don't have access to IDA.

And I would something more specific than:

size -A -d mydocker

I'm afraid your intentions to find memory usage may need both static and dynamic analysis. Run-time events can cause more or less memory usage. I will write my general findings about reversing Go binaries, you can choose for your application-specific solution from below.

There is no decompiling tool available for Go language. Although according to this discussion you can identify high-level structures from Go binaries which mostly based on DWARF debugging information.

You can use conventional tools like objdump and GDB with Go run-time support. After installing Go toolkit:

echo add-auto-load-safe-path /usr/share/go-1.6/src/runtime/runtime-gdb.py >> ~/.gdbinit

For sake of simplicity, I started to examine with functions example. I compiled functions example with standard build. Default build with Go compiler includes lots of DWARF information. You can see objdump source code-assembly intermix is really successful at using Go syntax imports, packages, and function representation.

0000000000401000 <main.main>:

func plusPlus(a, b, c int) int {
    return a + b + c

func main() {
  401000:       64 48 8b 0c 25 f8 ff    mov %fs:0xfffffffffffffff8,%rcx
  401007:       ff ff
  401009:       48 8d 44 24 d0          lea    -0x30(%rsp),%rax
  40100e:       48 3b 41 10             cmp    0x10(%rcx),%rax
  401012:       0f 86 f1 02 00 00       jbe    401309 <main.main+0x309>
  401018:       48 81 ec b0 00 00 00    sub    $0xb0,%rsp
    res := plus(1, 2)
  40101f:       48 c7 c3 01 00 00 00    mov    $0x1,%rbx
  401026:       48 c7 c0 02 00 00 00    mov    $0x2,%rax
  40102d:       48 01 c3                add    %rax,%rbx
  401030:       48 89 d8                mov    %rbx,%rax
    fmt.Println("1+2 =", res)
  401033:       48 8d 1d 6e b3 0f 00    lea    0xfb36e(%rip),%rbx        # 4fc3a8 <go.string.*+0x3b0>
401159:       e8 82 97 05 00          callq  45a8e0 <fmt.Println>

    res = plusPlus(1,2,3)
  40115e:       48 c7 c3 01 00 00 00    mov    $0x1,%rbx
  401165:       48 c7 c1 02 00 00 00    mov    $0x2,%rcx
  40116c:       48 c7 c0 03 00 00 00    mov    $0x3,%rax
  401173:       48 01 cb                add    %rcx,%rbx
  401176:       48 01 c3                add    %rax,%rbx
  401179:       48 89 d8                mov    %rbx,%rax
    fmt. Println("1+2+3 =", res)
  40117c:       48 8d 1d 2d b2 0f 00    lea    0xfb22d(%rip),%rbx        # 4fc3b0 <go.string.*+0x3b8>

If you have opportunity to build the application from a source I strongly recommend to use -ldflags "-w" arguments as suggested at documentation

You can use GDB to debugging and reversing Go programs easily. User-defined functions couldn't found by GDB unless you build it with debug information but, you can use the main function to track program flow.

gdb-peda$ list main.main
10 func plusPlus(a, b, c int) int {
11     return a + b + c
12 }
14 func main() {
15     res := plus(1, 2)
16     fmt.Println("1+2 =", res)
18     res = plusPlus(1,2,3)

I assume you build it with debug information:

void main(void);
void main.init(void);
void main.main(void);
void runtime.main(void);
void runtime.main.func1(void);
void runtime.main.func2(bool *);
0x0000000000401000  main.main
0x0000000000401320  main.init
0x0000000000429a20  runtime.main
0x000000000044aba0  runtime.main.func1
0x000000000044abe0  runtime.main.func2
0x0000000000456520  main

You can inspect functions and track their stack usage with help this blog post section about Go stack implementation. Set a breakpoint at the beginning of the function which you want to examine and runtime.morestack_noctxt for stack & runtime.mallocinit for heap allocations.

Another method which is much easy is using pprof package you find relevant documentation here.

  • How can I apply it to a big binary as docker – 0x90 Aug 1 '17 at 13:43
  • I think dynamic stack allocation force us to do runtime analysis. It may be feasible to use pprof for changed parts. GDB scripting can be another solution but, I don't know how to use it in a such big application. – Kerim Can Kalıpcıoğlu Aug 1 '17 at 15:14
  • I care only on the binary size. – 0x90 Aug 1 '17 at 15:15
  • If you care only binary size you can use nm --print-size option. – Kerim Can Kalıpcıoğlu Aug 1 '17 at 15:29
  • yes but I want something with better graphics. – 0x90 Aug 1 '17 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.