Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Debuggers in Lispy Languages

Suvrat Apte
November 16, 2019

Debuggers in Lispy Languages

This talk is about a unique way in which debuggers can be written in language which are lisp like.
With CIDER debug as an example, this talk takes you through how this approach works under the hood.
This talk was presented at Functional Conf 2019.

Suvrat Apte

November 16, 2019
Tweet

More Decks by Suvrat Apte

Other Decks in Programming

Transcript

  1. Outline • Why we need debuggers • Demo: Clojure debugging

    • How GDB works • REPL middleware • How cider-debug works • Limitations • Questions
  2. Debuggers • Examine state of programs as they run •

    Halt execution • Step through execution • Modify state at runtime • Change flow of execution
  3. GDB - GNU Debugger • Debugger runs as a separate

    process • Spawns the target program as a child • Examines state with process tracing calls • Implementing breakpoints is a trick! • Puts invalid instructions on breakpoints • Processor traps OS • OS signals the process which caused it • It passes the signal to its parent (GDB) • GDB checks IP and breaks • Some processors support breakpoints GDB Target OS Processor
  4. GDB - GNU Debugger • Dependence on OS for process

    tracing • Dependence on OS for signals • Dependence on processors for interrupts GDB Target OS Processor
  5. Lisps • Lisp has minimal syntax • Code is data

    • Code itself is a valid AST • Debuggers can use code as data (map sq-root (filter even? numbers)) map sq-root filter numbers even?
  6. What is a REPL? Read-Eval-Print-Loop (defn repl [] (let [input

    (read) result (eval input)] (println result) (recur)))
  7. Read Eval Print Loop (REPL) REPL Prompt: "=> (+ 1

    2) "=> 3 "=> REPL client REPL server Operation: “eval” Code: (+ 1 2)
  8. Read Eval Print Loop (REPL) REPL client REPL server Operation:

    “eval” Result: 3 REPL Prompt: "=> (+ 1 2) "=> 3 "=>
  9. Form based coords Coor: (3 1 1 1) (defn math-operations

    [n1 n2] (let [addition (+ n1 n2) subtraction (- n1 n2) exp (power n1 n2)] {:addition addition :subtraction subtraction :exp exp}))
  10. Coor: (3 1 1 1) (defn math-operations [n1 n2] (let

    [addition (+ n1 n2) subtraction (- n1 n2) exp (power n1 n2)] {:addition addition :subtraction subtraction :exp exp})) 0 1 2 3 Form based coords
  11. Coor: (3 1 1 1) (defn math-operations [n1 n2] (let

    [addition (+ n1 n2) subtraction (- n1 n2) exp (power n1 n2)] {:addition addition :subtraction subtraction :exp exp})) 0 1 2 Form based coords
  12. Coor: (3 1 1 1) (defn math-operations [n1 n2] (let

    [addition (+ n1 n2) subtraction (- n1 n2) exp (power n1 n2)] {:addition addition :subtraction subtraction :exp exp})) 0 1 2 3 4 5 Form based coords
  13. Coor: (3 1 1 1) (defn math-operations [n1 n2] (let

    [addition (+ n1 n2) subtraction (- n1 n2) exp (power n1 n2)] {:addition addition :subtraction subtraction :exp exp})) 0 1 2 Form based coords
  14. How does it work? 1. Walk through code 1. Mark

    forms/symbols with coordinates 2. Expand macros 3. Walk through code 1. Wrap forms/symbols with pre-breakpoint macro 4. Pre-breakpoint macro expansion 1. Put a breakpoint if necessary When a function is marked for debugging
  15. How does it work? 1. Necessary information is sent to

    client 1. Coordinates 2. Return value at current position 3. Values of local vars 4. Possible actions 2. Waits for response from client. . . When a breakpoint is hit
  16. How does it work? 1. Walk through code 1. Mark

    forms/symbols with coordinates 2. Expand macros 3. Walk through code 1. Wrap forms/symbols with pre-breakpoint macro 4. Pre-breakpoint macro expansion 1. Put a breakpoint if necessary When a function is marked for debugging
  17. How does it work? • Simple eval • Reader macro:

    #dbg • cider.nrepl.middleware.util.instrument/walk-indexed • Assigns coordinates to forms recursively
  18. How does it work? 1. Walk through code 1. Mark

    forms/symbols with coordinates 2. Expand macros 3. Walk through code 1. Wrap forms/symbols with pre-breakpoint macro 4. Pre-breakpoint macro expansion 1. Put a breakpoint if necessary When a function is marked for debugging
  19. How does it work? 1. Walk through code 1. Mark

    forms/symbols with coordinates 2. Expand macros 3. Walk through code 1. Wrap forms/symbols with pre-breakpoint macro 4. Pre-breakpoint macro expansion 1. Put a breakpoint if necessary When a function is marked for debugging
  20. How does it work? 1. Walk through code 1. Mark

    forms/symbols with coordinates 2. Expand macros 3. Walk through code 1. Wrap forms/symbols with pre-breakpoint macro 4. Pre-breakpoint macro expansion 1. Put a breakpoint if necessary When a function is marked for debugging
  21. How does it work? 1. Necessary information is sent to

    client 1. Coordinates 2. Return value at current position 3. Values of local vars 4. Possible actions 2. Waits for response from client. . . When a breakpoint is hit
  22. How does it work? 1. Necessary information is sent to

    client 1. Coordinates 2. Return value at current position 3. Values of local vars 4. Possible actions 2. Waits for response from client. . . When a breakpoint is hit
  23. GDB - GNU Debugger f (p, q, r) = y

    Debugger (code, os, processor) = debuggable code C Assembly
  24. cider-debug • Bozhidar Batsov • Artur Malabara • Vitalie Spinu

    • Chris Perkins • Neil Okamoto • Michael Griffiths • Lars Anderson • Dominic Monroe Thank you!
  25. Lisp is similar to Chess. It will take only a

    day to learn the rules. But years to master ! - Harold Abelson