Skip to content

Will cwrap work with Nim? #2

@simonhf

Description

@simonhf

Yes, here's an example:

  • Clone and build Nim:
$ git clone https://github.com/nim-lang/Nim.git
$ pushd ./Nim/
$ time ./build_all.sh
...
real    4m24.324s
$ popd

$ ./Nim/bin/nim --version | egrep -i nim
Nim Compiler Version 1.7.1 [Linux: amd64]
  • Create an example Nim source file, and build and run it without cwrap:
$ cat helloworld.nim 
proc foo(): void =
  echo "Hello World from foo()"

proc bar(): void =
  foo()

echo "Hello World 2"
bar()

$ ./Nim/bin/nim c -r --verbosity:2 helloworld.nim
...
CC: helloworld.nim: gcc -c  -w -fmax-errors=3 -pthread   -I/home/simon/work/20220722-nim/Nim/lib -I/home/simon/work/20220722-nim -o /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c
Hint: gcc   -o /home/simon/work/20220722-nim/helloworld  /home/simon/.cache/nim/helloworld_d/@mNim@slib@sstd@sprivate@sdigitsutils.nim.c.o /home/simon/.cache/nim/helloworld_d/@mNim@slib@ssystem@sdollars.nim.c.o /home/simon/.cache/nim/helloworld_d/@mNim@slib@spure@scollections@ssharedlist.nim.c.o /home/simon/.cache/nim/helloworld_d/@mNim@slib@sstd@ssyncio.nim.c.o /home/simon/.cache/nim/helloworld_d/@mNim@slib@ssystem.nim.c.o /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o  -pthread   -ldl [Link]
/home/simon/work/20220722-nim/Nim/compiler/extccomp.nim(402, 13) compiler msg initiated here [MsgOrigin]
...
Hello World 2
Hello World from foo()

$ wc -c helloworld
116680 helloworld
  • Try to tell Nim to use a different compiler:
$ ./Nim/bin/nim c --cc:xyz -r --verbosity:2 helloworld.nim
...
command line(1, 2) Error: unknown C compiler: 'xyz'. Available options are: gcc, switch_gcc, llvm_gcc, clang, bcc, vcc, tcc, env, icl, icc, clang_cl
  • To get cwrap to wrap Nim compilation, we're going to have to trick Nim into thinking we want to to use one of its supported compilers, e.g. icc:
$ which icc
$

$ ./Nim/bin/nim c --cc:icc -r --verbosity:2 helloworld.nim
...
Error: execution of an external compiler program 'icc -c  -pthread   -I/home/simon/work/20220722-nim/Nim/lib -I/home/simon/work/20220722-nim -o /home/simon/.cache/nim/helloworld_d/@mNim@slib@sstd@sprivate@sdigitsutils.nim.c.o /home/simon/.cache/nim/helloworld_d/@mNim@slib@sstd@sprivate@sdigitsutils.nim.c' failed with exit code: 127
  • Create a dummy icc "compiler" for Nim to run:
$ PATH=$PATH:`pwd`

$ cat icc 
echo "hello from icc"
exit 1

$ chmod +x icc

$ ./Nim/bin/nim c --cc:icc --forceBuild:on -r --verbosity:2 helloworld.nim
...
Error: execution of an external compiler program 'icc -c  -pthread   -I/home/simon/work/20220722-nim/Nim/lib -I/home/simon/work/20220722-nim -o /home/simon/.cache/nim/helloworld_d/@mNim@slib@sstd@sprivate@sdigitsutils.nim.c.o /home/simon/.cache/nim/helloworld_d/@mNim@slib@sstd@sprivate@sdigitsutils.nim.c' failed with exit code: 1
...
hello from icc
  • Clone cwrap and install its dependencies:
$ git clone $ https://github.com/corelight/cwrap.git

$ sudo apt-get install liblist-moreutils-perl

$ sudo apt install cpanminus

$ sudo cpanm FFI::Platypus::Lang::CPP::Demangle::XS

$ sudo apt install llvm
$ which llvm-cxxfilt
/usr/bin/llvm-cxxfilt
  • Modify icc fake compiler to point to cwrap (which uses gcc under the covers):
$ cat icc
`pwd`/cwrap/cwrap.pl "$@"
  • Hot patch a small bug in cwrap:
$ git diff
diff --git a/cwrap.pl b/cwrap.pl
-        $gcc_4_s =~ s~$source_file_argument~$s_file.2.s~;
+        if    ($gcc_4_s =~ s~$source_file_argument[ ]~$s_file.2.s ~) {} # if source file is not at the end of the command line
+        elsif ($gcc_4_s =~ s~$source_file_argument$~$s_file.2.s~) {}    # if source file is     at the end of the command line
+        else { cwrap_die(sprintf qq[%f ERROR: cwrap regex failed to substitute source files; gcc_4_s=%s!\n], Time::HiRes::time() - $ts, $gcc_4_s); }
  • Tell Nim to force re-build helloworld.nim using icc:
$ ./Nim/bin/nim c --cc:icc --forceBuild:on -r --verbosity:2 helloworld.nim
...
Hello World 2
Hello World from foo()

$ wc -c helloworld
226696 helloworld
  • helloworld executable is now bigger because 100s of functions are instrumented by cwrap.
  • Run helloworld and ask cwrap to list all the instruction function (note: many functions are grepped away for brevity):
$ CWRAP_LOG_SHOW=1 ./helloworld | egrep -v "(system|sdigitsutils|ssyncio|ssharedlist)"
C0 + cwrap_log_show() { #1
C0   - func_addr=(nil)
C0   - #1: verbosity 9 for 1 of 1 function variation(s) for cwrap_log_show() from helloworld.cwrap.c
C0   - #2: verbosity 9 for 1 of 1 function variation(s) for cwrap_log_stats() from helloworld.cwrap.c
C0   - #3: verbosity 9 for 1 of 1 function variation(s) for cwrap_log_verbosity_set() from helloworld.cwrap.c
C0   - #4: verbosity 9 for 1 of 1 function variation(s) for cwrap_log_quiet_until() from helloworld.cwrap.c
C0   - #107: verbosity 9 for 1 of 1 function variation(s) for main() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #126: verbosity 9 for 1 of 1 function variation(s) for initStackBottomWith() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #153: verbosity 9 for 1 of 1 function variation(s) for foo__helloworld_1() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #194: verbosity 9 for 1 of 1 function variation(s) for bar__helloworld_2() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #225: verbosity 9 for 1 of 1 function variation(s) for PreMainInner() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #226: verbosity 9 for 1 of 1 function variation(s) for PreMain() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #227: verbosity 9 for 1 of 1 function variation(s) for NimMainModule() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #228: verbosity 9 for 1 of 1 function variation(s) for NimMainInner() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   - #229: verbosity 9 for 1 of 1 function variation(s) for NimMain() from /home/simon/.cache/nim/helloworld_d/@mhelloworld.nim.c.o
C0   } // cwrap_log_show() 
  • Run helloworld and ask cwrap to run with full verbosity except for functions in ssystem.nim.c and sdigitsutils.nim.c:
$ CWRAP_LOG_STATS=1 CWRAP_LOG_NUM=1 CWRAP_LOG_TIMESTAMP=1 CWRAP_LOG_THREAD_ID=1 CWRAP_LOG_CURT=1 CWRAP_LOG_VERBOSITY_SET=1/9=file-ssystem.nim.c/9=file-sdigitsutils.nim.c ./helloworld | less +G
cwrap_log_init() {} // CWRAP_LOG: _VERBOSITY_SET=1/9=file-ssystem.nim.c/9=file-sdigitsutils.nim.c (<verbosity>[={file|function}-<keyword>][/...]) _QUIET_UNTIL=(null) _STATS=1 _SHOW=0 _CURT=1 _FILE=0 _NUM=1 _COR_ID=1 _LIMIT=10,000 _THREAD_ID=1 _STACK_PTR=0
#1 T06822 C0 0.000011s + cwrap_log_verbosity_set(verbosity=1/9=file-ssystem.nim.c/9=file-sdigitsutils.nim.c) { // #1 [cwrap_log_verbosity_set() ignores verbosity!]
#2 T06822 C0 0.000029s   - verbosity 1 set for 240 matches in 240 functions for 1 byte clause '1' // type=FILE|FUNCTION keyword=(null)
#3 T06822 C0 0.000031s   - verbosity 9 set for 210 matches in 240 functions for 20 byte clause '9=file-ssystem.nim.c' // type=FILE keyword=ssystem.nim.c
#4 T06822 C0 0.000032s   - verbosity 9 set for 10 matches in 240 functions for 25 byte clause '9=file-sdigitsutils.nim.c' // type=FILE keyword=sdigitsutils.nim.c
#5 T06822 C0 0.000034s   } // cwrap_log_verbosity_set() 
#6 T06822 C0 0.000036s + main() { // #1 
#7 T06822 C0 0.000039s   + NimMain() { // #1 
#8 T06822 C0 0.000040s     + PreMain() { // #1 
#9 T06822 C0 0.000042s       + initStackBottomWith() {} // #1 
#10 T06822 C0 0.000102s       + init__system_6081() { // #1 
#11 T06822 C0 0.000105s         + initLock__coreZlocks_64() {} // #1 
#12 T06822 C0 0.000106s         } // init__system_6081() 
#13 T06822 C0 0.000109s       + PreMainInner() {} // #1 
#14 T06822 C0 0.000110s       } // PreMain() 
#15 T06822 C0 0.000111s     + initStackBottomWith() {} // #2 
#16 T06822 C0 0.000112s     + NimMainInner() { // #1 
#17 T06822 C0 0.000113s       + NimMainModule() { // #1 
#18 T06822 C0 0.000114s         + echoBinSafe() { // #1 
#19 T06822 C0 0.000115s           + nimToCStringConv() {} // #1 
Hello World 2
#20 T06822 C0 0.000120s           } // echoBinSafe() 
#21 T06822 C0 0.000121s         + bar__helloworld_2() { // #1 
#22 T06822 C0 0.000122s           + foo__helloworld_1() { // #1 
#23 T06822 C0 0.000122s             + echoBinSafe() { // #2 
#24 T06822 C0 0.000123s               + nimToCStringConv() {} // #2 
Hello World from foo()
#25 T06822 C0 0.000125s               } // echoBinSafe() 
#26 T06822 C0 0.000126s             } // foo__helloworld_1() 
#27 T06822 C0 0.000126s           } // bar__helloworld_2() 
#28 T06822 C0 0.000127s         } // NimMainModule() 
#29 T06822 C0 0.000128s       } // NimMainInner() 
#30 T06822 C0 0.000129s     } // NimMain() 
#31 T06822 C0 0.000129s   } // main() 
#32 T06822 C0 0.000131s + cwrap_log_stats() { // #1 [cwrap_log_stats() ignores verbosity!]
#33 T06822 C0 0.000132s   - 1 calls to 1 of 1 function variation(s) for cwrap_log_stats()
#34 T06822 C0 0.000133s   - 1 calls to 1 of 1 function variation(s) for cwrap_log_verbosity_set()
#35 T06822 C0 0.000135s   - 2 calls to 1 of 1 function variation(s) for nimToCStringConv()
#36 T06822 C0 0.000136s   - 1 calls to 1 of 1 function variation(s) for main()
#37 T06822 C0 0.000137s   - 1 calls to 1 of 1 function variation(s) for init__system_6081()
#38 T06822 C0 0.000138s   - 2 calls to 1 of 1 function variation(s) for initStackBottomWith()
#39 T06822 C0 0.000139s   - 1 calls to 1 of 1 function variation(s) for initLock__coreZlocks_64()
#40 T06822 C0 0.000140s   - 1 calls to 1 of 1 function variation(s) for foo__helloworld_1()
#41 T06822 C0 0.000140s   - 2 calls to 1 of 1 function variation(s) for echoBinSafe()
#42 T06822 C0 0.000142s   - 1 calls to 1 of 1 function variation(s) for bar__helloworld_2()
#43 T06822 C0 0.000143s   - 1 calls to 1 of 1 function variation(s) for PreMainInner()
#44 T06822 C0 0.000143s   - 1 calls to 1 of 1 function variation(s) for PreMain()
#45 T06822 C0 0.000144s   - 1 calls to 1 of 1 function variation(s) for NimMainModule()
#46 T06822 C0 0.000145s   - 1 calls to 1 of 1 function variation(s) for NimMainInner()
#47 T06822 C0 0.000146s   - 1 calls to 1 of 1 function variation(s) for NimMain()
#48 T06822 C0 0.000147s   - 18 calls to 15 of 240 functions instrumented
#49 T06822 C0 0.000148s   } // cwrap_log_stats() 
  • We get to see a hint into the inner life of the helloworld Nim executable.
  • Run helloworld and ask cwrap to run with no verbosity until function NimMainInner() is called for the first time.
  • Note: Now we can see a but more detail, e.g. previously hidden functions, e.g. nimFrame():
$ CWRAP_LOG_QUIET_UNTIL=NimMainInner CWRAP_LOG_STATS=1 CWRAP_LOG_NUM=1 CWRAP_LOG_TIMESTAMP=1 CWRAP_LOG_THREAD_ID=1 CWRAP_LOG_CURT=1 CWRAP_LOG_VERBOSITY_SET=1 ./helloworld
cwrap_log_init() {} // CWRAP_LOG: _VERBOSITY_SET=1 (<verbosity>[={file|function}-<keyword>][/...]) _QUIET_UNTIL=NimMainInner _STATS=1 _SHOW=0 _CURT=1 _FILE=0 _NUM=1 _COR_ID=1 _LIMIT=10,000 _THREAD_ID=1 _STACK_PTR=0 _TIMESTAMP=1 _UNWIND=0 _ON_VALGRIND=0
#1 T06837 C0 0.000036s + cwrap_log_verbosity_set(verbosity=1) { // #1 [cwrap_log_verbosity_set() ignores verbosity!]
#2 T06837 C0 0.000055s   - verbosity 1 set for 240 matches in 240 functions for 1 byte clause '1' // type=FILE|FUNCTION keyword=(null)
#3 T06837 C0 0.000062s   } // cwrap_log_verbosity_set() 
#4 T06837 C0 0.000064s + cwrap_log_quiet_until(name=NimMainInner) {} // #1 going quiet until function NimMainInner() [cwrap_log_quiet_until() ignores verbosity!]
#5 T06837 C0 0.000127s + NimMainInner() { // #1 
#6 T06837 C0 0.000129s   + NimMainModule() { // #1 
#7 T06837 C0 0.000147s     + nimFrame() {} // #1 
#8 T06837 C0 0.000150s     + echoBinSafe() { // #1 
#9 T06837 C0 0.000151s       + nimFrame() {} // #2 
#10 T06837 C0 0.000154s       + nimToCStringConv() {} // #1 
Hello World 2
#11 T06837 C0 0.000156s       + nimAddInt() {} // #1 
#12 T06837 C0 0.000158s       + popFrame() {} // #1 
#13 T06837 C0 0.000159s       } // echoBinSafe() 
#14 T06837 C0 0.000161s     + bar__helloworld_2() { // #1 
#15 T06837 C0 0.000162s       + nimFrame() {} // #3 
#16 T06837 C0 0.000164s       + foo__helloworld_1() { // #1 
#17 T06837 C0 0.000165s         + nimFrame() {} // #4 
#18 T06837 C0 0.000167s         + echoBinSafe() { // #2 
#19 T06837 C0 0.000168s           + nimFrame() {} // #5 
#20 T06837 C0 0.000170s           + nimToCStringConv() {} // #2 
Hello World from foo()
#21 T06837 C0 0.000172s           + nimAddInt() {} // #2 
#22 T06837 C0 0.000174s           + popFrame() {} // #2 
#23 T06837 C0 0.000175s           } // echoBinSafe() 
#24 T06837 C0 0.000177s         + popFrame() {} // #3 
#25 T06837 C0 0.000178s         } // foo__helloworld_1() 
#26 T06837 C0 0.000180s       + popFrame() {} // #4 
#27 T06837 C0 0.000181s       } // bar__helloworld_2() 
#28 T06837 C0 0.000183s     + popFrame() {} // #5 
#29 T06837 C0 0.000185s     } // NimMainModule() 
#30 T06837 C0 0.000187s   } // NimMainInner() 
#31 T06837 C0 0.000189s } // NimMain() 
#32 T06837 C0 0.000206s } // main() 
#33 T06837 C0 0.000208s + colonanonymous___system_5714() {} // #1 
#34 T06837 C0 0.000221s + cwrap_log_stats() { // #1 [cwrap_log_stats() ignores verbosity!]
#35 T06837 C0 0.000223s   - 1 calls to 1 of 1 function variation(s) for cwrap_log_stats()
#36 T06837 C0 0.000226s   - 1 calls to 1 of 1 function variation(s) for cwrap_log_verbosity_set()
#37 T06837 C0 0.000228s   - 1 calls to 1 of 1 function variation(s) for cwrap_log_quiet_until()
#38 T06837 C0 0.000230s   - 5 calls to 1 of 1 function variation(s) for popFrame()
#39 T06837 C0 0.000233s   - 2 calls to 1 of 1 function variation(s) for nimToCStringConv()
#40 T06837 C0 0.000234s   - 5 calls to 1 of 1 function variation(s) for nimFrame()
#41 T06837 C0 0.000236s   - 2 calls to 1 of 1 function variation(s) for nimAddInt()
#42 T06837 C0 0.000239s   - 1 calls to 1 of 1 function variation(s) for foo__helloworld_1()
#43 T06837 C0 0.000242s   - 2 calls to 1 of 1 function variation(s) for echoBinSafe()
#44 T06837 C0 0.000244s   - 1 calls to 1 of 1 function variation(s) for colonanonymous___system_5714()
#45 T06837 C0 0.000246s   - 1 calls to 1 of 1 function variation(s) for bar__helloworld_2()
#46 T06837 C0 0.000248s   - 1 calls to 1 of 1 function variation(s) for NimMainModule()
#47 T06837 C0 0.000249s   - 1 calls to 1 of 1 function variation(s) for NimMainInner()
#48 T06837 C0 0.000251s   - 24 calls to 13 of 240 functions instrumented
#49 T06837 C0 0.000253s   } // cwrap_log_stats() 
  • That's it :-)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions