It's possible to call a janet cfun (e.g. the c bits that implement math/random
or math/cos
, but also see the end of this doc) from gdb and examine the results. What follows is a demonstration using janet_rand
and janet_cos
, which are the cfuns underlying math/random
and math/cos
respectively. See src/core/math.c
for details.
- Preparation
- Compile janet with debugging info
- Create sample janet source file
- Run janet with sample file under gdb
- Demos of calling cfuns
- Prepare some arguments for some janet cfuns
- Call the janet cfuns
- Examine the results
-
Get janet source
$ git clone https://github.com/janet-lang/janet $ cd janet
-
Compile janet with debugging info -- but first tweak Makefile
$ sed -i "s/^CFLAGS?=-O2/CFLAGS?=-O0 -g3/" Makefile $ make clean && make
-
Create a test janet script -- nothing special about
pp
here, just chose somethingecho "(pp {:a 1})" > test.janet
-
Start debug-enabled janet
$ gdb -quiet -cd . --args build/janet test.janet Reading symbols from build/janet...
-
Set an appropriate break point --
cfun_io_printf
is part ofpp
's implementation(gdb) b cfun_io_printf Breakpoint 1 at 0x2dfe9: file src/core/io.c, line 631.
-
Start the janet process via gdb
(gdb) r Starting program: /home/user/src/janet.internals/build/janet test.janet [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". Breakpoint 1, cfun_io_printf (argc=2, argv=0x55555566c738) at src/core/io.c:631 631 return cfun_io_printf_impl(argc, argv, 1, "out", stdout);
-
Call the
janet_rand
cfun -- like all janet cfuns, the signature is(int32_t argc, Janet *argv)
. Below,argc
is 0 andargv
is 0 (argv
is unused withinjanet_rand
)(gdb) p janet_rand(0, 0) $2 = {u64 = 4588835678547723040, i64 = 4588835678547723040, number = 0.060193915906785245, pointer = 0x3faed1bca879c320}
-
Determine the
JanetType
of the result(gdb) p janet_type($2) $3 = JANET_NUMBER
-
Peek inside the result
(gdb) p janet_unwrap_number($3) $4 = 0.48718118769171492
-
Allocate some memory to use for
argv
of length 1(gdb) p (Janet *)janet_malloc(sizeof(Janet) * (size_t) 1) $5 = (Janet *) 0x55555566cbb0
-
Put something in at the beginning of
argv
-- assigning toargv[0]
(gdb) $5[0] = janet_wrap_number(0) $6 = {u64 = 0, i64 = 0, number = 0, pointer = 0x0}
-
Call the
janet_cos
cfun -- below,argc
is 1 andargv
is $5(gdb) janet_cos(1, $5) $7 = {u64 = 4607182418800017408, i64 = 4607182418800017408, number = 1, pointer = 0x3ff0000000000000}
-
Determine the
JanetType
of the result(gdb) p janet_type($7) $8 = JANET_NUMBER
-
Peek inside the result
(gdb) p janet_unwrap_number($7) $9 = 1
-
Not using a test file and/or trying to do some of the steps above before janet has finished intializing may lead to various things not quite working, e.g.
- Being forced to cast the result of
janet_malloc
- Not being able to call
janet_type
successfully
So I suggest following the steps above as closely as possible on an initial attempt.
- Being forced to cast the result of
-
What is a
cfun
? Looking atsrc/include/janet.h
andsrc/core/fiber.h
, my guess is that it's another name forJanetCFunction
. According to the C functions section from the "The Janet Abstract Machine" page at the official janet documentation website:Janet uses C functions to bridge to native code. A C function (JanetCFunction * in C) is a C function pointer that can be called like a normal Janet closure. From the perspective of the bytecode instruction set, there is no difference in invoking a C function and invoking a normal Janet function.
On a tangential note, that last bit about there being no difference might be seen here.