Blending Guile and GDB together

2014-02-16 Thread Ludovic Courtès
Hello!

As a gift for Guile 2.0’s third birthday [0], here’s a quick hack to
enhance the debugging experience for Guile hackers in GDB!

The attached code is a GDB extension, written in Guile, using the nice
Guile API that landed into GDB master last week (thanks, Doug!).  Once
you have GDB master (7.8) built with Guile support, just type this at
the GDB prompt:

  (gdb) guile (load "scmpp.scm")

From there on, life in GDB is different.  :-)

The main feature is printing of ‘SCM’ values.  As you know, ‘SCM’ values
are bit patterns, sometimes with pointers in disguise and so on–to the
experienced Guile hacker, “404” is synonymous with #t, not “page not
found”.

So, before:

--8<---cut here---start->8---
Breakpoint 1, scm_display (obj=0xf04310, port=0x6f9f30) at print.c:1437
1437{
(gdb) bt
#0  scm_display (obj=0xf04310, port=0x6f9f30) at print.c:1437
#1  0x77b28ef1 in vm_debug_engine (vm=, 
program=0x6eb240, argv=, nargs=2)
at vm-i-system.c:855
#2  0x77aaafe3 in scm_primitive_eval (exp=exp@entry=0x8e1440) at 
eval.c:685
#3  0x77aab043 in scm_eval (exp=0x8e1440, 
module_or_state=module_or_state@entry=0x8a8c60) at eval.c:719
#4  0x77afa26d in scm_shell (argc=1, argv=0x7fffd118) at 
script.c:441
#5  0x77ac753d in invoke_main_func (body_data=0x7fffcfe0) at 
init.c:337
#6  0x77aa14ca in c_body (d=0x7fffcf20) at continuations.c:511
#7  0x77b33ac8 in vm_regular_engine (vm=, 
program=0x6f57e0, argv=, nargs=2)
at vm-i-system.c:855
#8  0x77a3 in scm_call_4 (proc=0x7d2570, arg1=arg1@entry=0x404, 
arg2=, arg3=, 
arg4=) at eval.c:507
--8<---cut here---end--->8---

After:

--8<---cut here---start->8---
(gdb) gu (load "scmpp.scm")
(gdb) bt
#0  scm_display (obj=("happy" birthday Guile (2 . 0)), port=#) at print.c:1437
#1  0x77b28ef1 in vm_debug_engine (vm=, 
program=#, argv=, nargs=2)
at vm-i-system.c:855
#2  0x77aaafe3 in scm_primitive_eval (
exp=exp@entry=((@ (ice-9 control) %) (begin (load-user-init) ((@ (ice-9 
top-repl) top-repl) at eval.c:685
#3  0x77aab043 in scm_eval (exp=((@ (ice-9 control) %) (begin 
(load-user-init) ((@ (ice-9 top-repl) top-repl, 
module_or_state=module_or_state@entry=# 
(# (# () 
#f #f # (ice-9 deprecated) interface #f # () 
# #f # #f #f #f300b840> # () #f #f # (srfi srfi-4) interface #f 
# () # #f # #f #f 
#f300b0e0>) #f #f # (guile) interface #f # 
() # #f # #f # #f3055dc0> 
# () #f #f # (system base 
compile) interface #f # () # #f 
# #f #f #f30554a0> # () 
#f #f # (ice-9 readline) interface #f # () 
# #f # #f #f #f30626c0> # () #f #f # (ice-9 history) interface #f 
# () # #f # #f #f 
#f3063540> # () #f #f # 
(srfi srfi-1) interface #f # () # #f 
# #f #f #f3066500> # () 
#f #f # (srfi srfi-26) interface #f # () 
# #f # #f #f #f3075b00> # () #f #f # (texinfo reflection) interface 
#f # () # #f # #f #f 
#f3075360> # (# (# () #f #f # (ice-9 
null) interface #f # () # #f # #f #f #f3083560>) #f #f # (ice-9 safe-r5rs) interface 
#f # () # #f # #f #f 
#f30830e0>) #f #f # (ice-9 r5rs) interface #f # () # #f # #f #f #f3088120> 
# () #f #f # (ice-9 session) 
interface #f # () # #f # #f #f #f3094160> # () #f #f 
# (ice-9 regex) interface #f # () 
# #f # #f #f #f30987c0> # () #f #f # (ice-9 threads) interface #f 
# () # #f # #f #f 
#f309bd20> # () #f #f # 
(value-history) interface #f # () # #f 
# #f #f #f309b680>) #f #f # (guile-user) 
directory #f # () # #f # #f # () #f #f # 
(guile-user) interface #f # () # #f 
# #f #f #f30b3d20> #f30b3d00>) at eval.c:719
#4  0x77afa26d in scm_shell (argc=1, argv=0x7fffd118) at 
script.c:441
#5  0x77ac753d in invoke_main_func (body_data=0x7fffcfe0) at 
init.c:337
#6  0x77aa14ca in c_body (d=0x7fffcf20) at continuations.c:511
#7  0x77b33ac8 in vm_regular_engine (vm=, 
program=#, argv=, nargs=2)
at vm-i-system.c:855
#8  0x77a3 in scm_call_4 (proc=#, 
arg1=arg1@entry=#t, arg2=, arg3=, 
arg4=) at eval.c:507
--8<---cut here---end--->8---

(I hear some say: “is this huge dump of ‘module_or_state’ really an
improvement?”  Well, granted, this one is a bit annoying, we’ll have to
think of a way to truncate it, maybe.  But it shows that many data types
are pretty-printed, including all the structure fields.  :-))

Traditionally, people would typically type ‘call scm_write(x, 0x204)’ to
print the value of ‘x’.  But in addition to being tedious, this won’t
work on a core file, and can otherwise destabilize the Guile process
being debugged.

So scmpp.scm teaches GDB about Guile’s type tagging so that it can print
‘SCM’ values.

A decade ago or so, an SCM value printer was available in GDB itself
(with ‘set language scheme’).  But that was tricky C code, and since it
was maintained outside of Guile, it inevitably went out of sync.

The good

Potluck dish - Simple functional reactive programming

2014-02-16 Thread David Thompson
Hello Guilers,

I didn't have time to put together a proper potluck dish, but I wanted
to find something to share anyway.

Lately I've been playing around with functional reactive programming
(FRP) applied to video games.  This style of programming allows for a
declarative, functional way of describing time-varying values.  Contrast
this method of programming with more traditional hooks and callbacks.
My FRP module can be used on top of hooks to escape callback hell.

And now for a simple example.  This morning I was writing a program
using my game engine, guile-2d, and I wanted to display the number of
times the GC has been run in the game window.  Without FRP I could have
done something like:

(define gc-label-position (vector2 0 40))
(define gc-counter 0)
(define (make-gc-label)
  (let ((text (format #f "GCs: ~d" counter)))
(make-label font text gc-label-position)))
(define gc-label (make-gc-label))

(add-hook! after-gc-hook
   (lambda ()
 (set! gc-counter (1+ gc-counter))
 (set! gc-label (make-gc-label

This code isn't terrible, but wouldn't it be nice to declare that
'gc-label' will always contain a string with the number of GC runs in
it instead?  Enter FRP:

(define gc-label-position (vector2 0 40))
(define gc-counter (make-root-signal 0))
(define gc-label
  (signal-map (lambda (counter)
(let ((text (format #f "GCs: ~d" counter)))
  (make-label font text gc-label-position)))
  gc-counter))

(add-hook! after-gc-hook
   (lambda ()
 (signal-set! gc-counter (1+ (signal-ref gc-counter)

'gc-counter' and 'gc-label' both become 'signals', or time-varying
values.  Now, when the GC runs, the 'gc-counter' signal is incremented
by 1.  The act of setting 'gc-counter' triggers propagation of the
counter to the 'gc-label' signal which maps the counter to a new label
that prints the current number of GC runs.  Magic!  Note that
'after-gc-hook' is still needed to bootstrap the signal graph, but once
that is out of the way it's signals all the way down.

This example was fairly trivial, but what if the desired chain reaction
was more complicated?  Writing the logic using regular callback
procedures would become a nightmare.  The nightmare that JavaScript
programmers constantly find themselves in.

And that's my potluck dish!  I'm currently working on a new version of
this API that will allow the signal graph to handle the dynamic
environment of the REPL, but it's not ready yet.

Thanks to all of the Guile maintainers and contributors for the great
work these past 3 years!

- David Thompson


signals.scm
Description: Binary data


Re: Potluck dish - Simple functional reactive programming

2014-02-16 Thread Ludovic Courtès
David Thompson  skribis:

> This code isn't terrible, but wouldn't it be nice to declare that
> 'gc-label' will always contain a string with the number of GC runs in
> it instead?  Enter FRP:
>
> (define gc-label-position (vector2 0 40))
> (define gc-counter (make-root-signal 0))
> (define gc-label
>   (signal-map (lambda (counter)
> (let ((text (format #f "GCs: ~d" counter)))
>   (make-label font text gc-label-position)))
>   gc-counter))
>
> (add-hook! after-gc-hook
>(lambda ()
>  (signal-set! gc-counter (1+ (signal-ref gc-counter)

Neat!  I’m a big fan.

I think we should consider adding an FRP module to Guile eventually.

Cheers,
Ludo’.




Re: Blending Guile and GDB together

2014-02-16 Thread Nala Ginrut
Cheers!


On Sun, 2014-02-16 at 17:22 +0100, Ludovic Courtès wrote:
> Hello!
> 
> As a gift for Guile 2.0’s third birthday [0], here’s a quick hack to
> enhance the debugging experience for Guile hackers in GDB!
> 
> The attached code is a GDB extension, written in Guile, using the nice
> Guile API that landed into GDB master last week (thanks, Doug!).  Once
> you have GDB master (7.8) built with Guile support, just type this at
> the GDB prompt:
> 
>   (gdb) guile (load "scmpp.scm")
> 
> From there on, life in GDB is different.  :-)
> 
> The main feature is printing of ‘SCM’ values.  As you know, ‘SCM’ values
> are bit patterns, sometimes with pointers in disguise and so on–to the
> experienced Guile hacker, “404” is synonymous with #t, not “page not
> found”.
> 
> So, before:
> 
> --8<---cut here---start->8---
> Breakpoint 1, scm_display (obj=0xf04310, port=0x6f9f30) at print.c:1437
> 1437  {
> (gdb) bt
> #0  scm_display (obj=0xf04310, port=0x6f9f30) at print.c:1437
> #1  0x77b28ef1 in vm_debug_engine (vm=, 
> program=0x6eb240, argv=, nargs=2)
> at vm-i-system.c:855
> #2  0x77aaafe3 in scm_primitive_eval (exp=exp@entry=0x8e1440) at 
> eval.c:685
> #3  0x77aab043 in scm_eval (exp=0x8e1440, 
> module_or_state=module_or_state@entry=0x8a8c60) at eval.c:719
> #4  0x77afa26d in scm_shell (argc=1, argv=0x7fffd118) at 
> script.c:441
> #5  0x77ac753d in invoke_main_func (body_data=0x7fffcfe0) at 
> init.c:337
> #6  0x77aa14ca in c_body (d=0x7fffcf20) at continuations.c:511
> #7  0x77b33ac8 in vm_regular_engine (vm=, 
> program=0x6f57e0, argv=, nargs=2)
> at vm-i-system.c:855
> #8  0x77a3 in scm_call_4 (proc=0x7d2570, arg1=arg1@entry=0x404, 
> arg2=, arg3=, 
> arg4=) at eval.c:507
> --8<---cut here---end--->8---
> 
> After:
> 
> --8<---cut here---start->8---
> (gdb) gu (load "scmpp.scm")
> (gdb) bt
> #0  scm_display (obj=("happy" birthday Guile (2 . 0)), port=# 6f9f30>) at print.c:1437
> #1  0x77b28ef1 in vm_debug_engine (vm=, 
> program=#, argv=, nargs=2)
> at vm-i-system.c:855
> #2  0x77aaafe3 in scm_primitive_eval (
> exp=exp@entry=((@ (ice-9 control) %) (begin (load-user-init) ((@ (ice-9 
> top-repl) top-repl) at eval.c:685
> #3  0x77aab043 in scm_eval (exp=((@ (ice-9 control) %) (begin 
> (load-user-init) ((@ (ice-9 top-repl) top-repl, 
> module_or_state=module_or_state@entry=# 8b5240> (# (# 871ac0> () #f #f # (ice-9 deprecated) interface #f 
> # () # #f # #f #f 
> #f300b840> # () #f #f # 
> (srfi srfi-4) interface #f # () # #f 
> # #f #f #f300b0e0>) #f #f # (guile) 
> interface #f # () # #f # 8466e0> #f # #f3055dc0> # () 
> #f #f # (system base compile) interface #f # 883640> () # #f # #f #f #f30554a0> 
> # () #f #f # (ice-9 
> readline) interface #f # () # #f 
> # #f #f #f30626c0> # () 
> #f #f # (ice-9 history) interface #f # () 
> # #f # #f #f #f3063540> # # () #f #f # (srfi srfi-1) interface #f 
> # () # #f # #f #f 
> #f3066500> # () #f #f # 
> (srfi srfi-26) interface #f # () # #f 
> # #f #f #f3075b00> # () 
> #f #f # (texinfo reflection) interface #f # bdd420> () # #f # #f #f #f3075360> 
> # (# 
> (# () #f #f # (ice-9 null) 
> interface #f # () # #f # dbec40> #f #f #f3083560>) #f #f # (ice-9 safe-r5rs) interface 
> #f # () # #f # #f #f 
> #f30830e0>) #f #f # (ice-9 r5rs) interface #f # d99ae0> () # #f # #f #f #f3088120> 
> # () #f #f # (ice-9 
> session) interface #f # () # #f 
> # #f #f #f3094160> # () 
> #f #f # (ice-9 regex) interface #f # () 
> # #f # #f #f #f30987c0> # # () #f #f # (ice-9 threads) interface #f 
> # () # #f # #f #f 
> #f309bd20> # () #f #f # 
> (value-history) interface #f # () # #f 
> # #f #f #f309b680>) #f #f # (guile-user) 
> directory #f # () # #f # 8b51c0> #f # () #f #f # 
> (guile-user) interface #f # () # #f 
> # #f #f #f30b3d20> #f30b3d00>) at eval.c:719
> #4  0x77afa26d in scm_shell (argc=1, argv=0x7fffd118) at 
> script.c:441
> #5  0x77ac753d in invoke_main_func (body_data=0x7fffcfe0) at 
> init.c:337
> #6  0x77aa14ca in c_body (d=0x7fffcf20) at continuations.c:511
> #7  0x77b33ac8 in vm_regular_engine (vm=, 
> program=#, argv=, nargs=2)
> at vm-i-system.c:855
> #8  0x77a3 in scm_call_4 (proc=#, 
> arg1=arg1@entry=#t, arg2=, arg3=, 
> arg4=) at eval.c:507
> --8<---cut here---end--->8---
> 
> (I hear some say: “is this huge dump of ‘module_or_state’ really an
> improvement?”  Well, granted, this one is a bit annoying, we’ll have to
> think of a way to truncate it, maybe.  But it shows that many data types
> are pretty-printed, including all the structure fields.  :-))
> 
> Traditionally, people would typically type ‘call scm_write(x, 0x204)’ to
> print the value of ‘x’.  But in addition to being tedious, this won’t
> work on a core fi

Potluck, midi -> chiptune

2014-02-16 Thread Mike Gran
Hi,

For this year's potluck, I wrote prog that converts a MIDI file
into an 8-bit-era chiptune, such as might have been rendered by
a Game Boy or SNES.


It is here:

  https://github.com/spk121/furry-nemesis

Specifically it converts a file named tmp.midi
(that must be in the current directory) to a file named
tmp.wav.

I'll be honest: this code is just a couple of days old, and
it is really raw. Incomplete and painfully slow.  But, it
is good for a laugh.

I'll fix it up over the next couple of weeks, if I can
find some spare time.


-Mike Gran

[PATCH] Improved ^c support for gdb/guile

2014-02-16 Thread Doug Evans
Hi.

Here's my modest contribution to the Guile anniversary potluck.

The patch to selftest-support.exp could be done differently,
I've tried to keep it simple.  The problem is that gdb with guile
will get SIGPWR from time to time when Guile's GC kicks in,
and we need this to not alter test behaviour.  The patch just
tells the parent gdb to ignore SIGPWR, which is simple enough
without loss of coverage.  A good question is what other signals
Guile GC might use.

Regression tested on amd64-linux with guile 2.0.9.

2014-02-17  Doug Evans  

* Makefile.in (SUBDIR_GUILE_OBS): Add scm-sigint.o.
(SUBDIR_GUILE_SRCS): Add scm-sigint.c.
(scm-sigint.o): New rule.
* guile/guile-internal.h (gdbscm_make_sigint_exception): Declare.
(gdbscm_install_sigint_handler): Declare.
(gdbscm_enable_sigint, gdbscm_disable_sigint): Declare.
(gdbscm_initialize_sigint): Declare.
* guile/guile.c (initialize_gdb_module): Call gdbscm_initialize_sigint.
* guile/scm-exception.c (gdbscm_make_sigint_exception): New function.
(gdbscm_scm_from_gdb_exception): Call it.
* guile/scm-safe-call.c: #include "guile.h".
(gdbscm_enter_guile_mode, gdbscm_exit_guile_mode): New functions.
(gdbscm_with_guile, gdbscm_call_guile): Call them.
* guile/scm-sigint.c: New file.

testsuite/
* gdb.gdb/guile-interrupts.exp: New file.
* gdb.gdb/guile-interrupts.gdb: New file.
* lib/selftest-support.exp (selftest_setup): Don't stop for SIGPWR.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2884725..2871e47 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -299,6 +299,7 @@ SUBDIR_GUILE_OBS = \
scm-ports.o \
scm-pretty-print.o \
scm-safe-call.o \
+   scm-sigint.o \
scm-string.o \
scm-symbol.o \
scm-symtab.o \
@@ -322,6 +323,7 @@ SUBDIR_GUILE_SRCS = \
guile/scm-ports.c \
guile/scm-pretty-print.c \
guile/scm-safe-call.c \
+   guile/scm-sigint.c \
guile/scm-string.c \
guile/scm-symbol.c \
guile/scm-symtab.c \
@@ -2280,6 +2282,10 @@ scm-frame.o: $(srcdir)/guile/scm-frame.c
$(COMPILE) $(srcdir)/guile/scm-frame.c
$(POSTCOMPILE)
 
+scm-sigint.o: $(srcdir)/guile/scm-sigint.c
+   $(COMPILE) $(srcdir)/guile/scm-sigint.c
+   $(POSTCOMPILE)
+
 scm-gsmob.o: $(srcdir)/guile/scm-gsmob.c
$(COMPILE) $(srcdir)/guile/scm-gsmob.c
$(POSTCOMPILE)
diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h
index dcdd422..d4d718d 100644
--- a/gdb/guile/guile-internal.h
+++ b/gdb/guile/guile-internal.h
@@ -288,6 +288,8 @@ extern SCM gdbscm_out_of_range_error (const char *subr, int 
arg_pos,
 extern SCM gdbscm_make_misc_error (const char *subr, int arg_pos,
   SCM bad_value, const char *error);
 
+extern SCM gdbscm_make_sigint_exception (void);
+
 extern void gdbscm_throw (SCM exception) ATTRIBUTE_NORETURN;
 
 extern SCM gdbscm_scm_from_gdb_exception (struct gdb_exception exception);
@@ -341,6 +343,14 @@ extern char *gdbscm_safe_eval_string (const char *string, 
int display_result);
 extern char *gdbscm_safe_source_script (const char *filename);
 
 extern void gdbscm_enter_repl (void);
+
+/* scm-sigint.c */
+
+extern void gdbscm_install_sigint_handler (struct signal_handler *previous);
+
+extern void gdbscm_enable_sigint (void);
+
+extern void gdbscm_disable_sigint (void);
 
 /* Interface to various GDB objects, in alphabetical order.  */
 
@@ -533,6 +543,7 @@ extern void gdbscm_initialize_math (void);
 extern void gdbscm_initialize_objfiles (void);
 extern void gdbscm_initialize_pretty_printers (void);
 extern void gdbscm_initialize_ports (void);
+extern void gdbscm_initialize_sigint (void);
 extern void gdbscm_initialize_smobs (void);
 extern void gdbscm_initialize_strings (void);
 extern void gdbscm_initialize_symbols (void);
diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c
index b7134f7..8f71c0a 100644
--- a/gdb/guile/guile.c
+++ b/gdb/guile/guile.c
@@ -545,6 +545,7 @@ initialize_gdb_module (void *data)
   gdbscm_initialize_objfiles ();
   gdbscm_initialize_ports ();
   gdbscm_initialize_pretty_printers ();
+  gdbscm_initialize_sigint ();
   gdbscm_initialize_strings ();
   gdbscm_initialize_symbols ();
   gdbscm_initialize_symtabs ();
diff --git a/gdb/guile/scm-exception.c b/gdb/guile/scm-exception.c
index a96a350..f752da8 100644
--- a/gdb/guile/scm-exception.c
+++ b/gdb/guile/scm-exception.c
@@ -404,6 +404,16 @@ gdbscm_memory_error_p (SCM key)
   return scm_is_eq (key, memory_error_symbol);
 }
 
+/* Create a SIGINT .  */
+
+SCM
+gdbscm_make_sigint_exception (void)
+{
+  /* This is copied from top-repl.scm.  */
+  return gdbscm_make_error (signal_symbol, NULL, _("User interrupt"),
+   SCM_EOL, scm_list_1 (scm_from_int (SIGINT)));
+}
+
 /* Wrapper around scm_throw to throw a gdb:exception.
This function does not return.
Thi