6

If I have a buffer with the contents

(defun foo()
  (interactive)
  (bar)
  (message "foo"))

(defun bar()
  (interactive)
  (message "bar"))

...and call eval-buffer with edebug-all-defs set to t, then both calls to foo and bar directly throw me into edebug-mode (despite not having set any breakpoints).

On the other hand, if I set edebug-all-defs to nil, evaluate the buffer with eval-buffer and then manually instrument the foo definition with edebug-eval-defun (C-u C-M-x) things work a little better: calling foo invokes the debugger, and calling bar does not. However, when stepping through foo, I'm now unable to step into the bar function (presumably because it hasn't been instrumented, the error is Don't know where `bar' is defined. Stepping over the call to bar works just fine and gives the correct result).

Is there a way to instrument all functions in a buffer without making them breakpoints at the same time?

Emacs 24.4.1 on Debian Jessie. Running with -Q does not seem to make a difference.

7
  • Are you sure you can't step into a function which wasn't instrumented? Because if by stepping you mean executing the function one expression at a time, as in by pressing SPC while in debug mode, then it works for me without instrumenting. All I need is to enter some instrumented function, which will call the function in question.
    – wvxvw
    May 20, 2015 at 7:57
  • The statements you describe are not what I get. If I do C-u C-M-x on a function, calling that function always invokes edebug, regardless of whether I've used edebug-on-entry.
    – Malabarba
    May 20, 2015 at 8:54
  • @Malabarba: then your emacs behaves differently. What version are you using?
    – Nikratio
    May 20, 2015 at 20:16
  • @wvxvw: yes, I'm sure.
    – Nikratio
    May 20, 2015 at 20:17
  • 1
    Myabe this is the problem of a function not being associated with a file... i.e. Emacs stores the location of a function source in some symbol property of the function name, but maybe if you define it in a buffer not associated with a file, then it doesn't know how to find it? Could you try doing the same thing but instead save the function definition in an actual file?
    – wvxvw
    May 20, 2015 at 20:46

3 Answers 3

4

So it appears that the problem in this case was related to the function being declared in a buffer which doesn't have a file associated with it, thus Emacs was unable to locate the definition. Here's how I discovered this:

  1. I started by looking into the definition of edebug-step-in (I figured out this is the function called in debug mode when I press i for stepping in by inspecting the help page for debug mode (available through pressing ? while in debug mode).
  2. Thus I found edebug-instrument-callee, then edebug-instrument-function, then find-function-noselect, then find-function-search-for-symbol, then find-function-library and finally, symbol-file.
  3. symbol-file is the same function used to locate the references whenever you see those references highlighted in a help buffer, or when you call describe-function (C-h f).
  4. Then I tried to copy what symbol-file does (roughly, just to convince myself that I am on the right track):

    (defun my/defined-in-file (s)
      (car 
       (cl-find-if
        (lambda (x)
          (cl-some
           (lambda (y) (eql s (if (symbolp y) y (cdr y))))
           (cdr x)))
        load-history)))
    
    (my/defined-in-file 'symbol-file)
    "/usr/local/share/emacs/25.0.50/lisp/subr.elc"
    

    The results turned out positive.

  5. When I tried to do the same thing with the functions, which were declared in *scratch* buffer, I've got no results.
  6. Hence, the conclusion: the automatic instrumentation during "step-in" operation must have failed due to Emacs not being able to locate the source file for the function.
3

You can step into bar (or any function call) with no previous preparation.

  1. eval-buffer (not necessary if everything's already defined).
  2. Invoke C-u C-M-x on foo to instrument it.
  3. Ivoke M-x foo and you'll be taken immediately into edebug, with point right before the (bar) expression.
  4. In edebug, with point right before a function call, you can hit i to instrument and step into that function, even if it was not prevously instrumented.

The i key is described in this manual page. More keys are described here and here.
I also have a couple of blog posts describing the keys I find most useful.

6
  • 1
    Sounds great, but does not work. Pressing "i" in step 4 gives a "Don't know where `bar' is defined" error. Emacs 24.4.1.
    – Nikratio
    May 20, 2015 at 20:14
  • @Nikratio did you eval-buffer first?
    – Malabarba
    May 20, 2015 at 20:20
  • Yes. Without eval-buffer, the error message is .. nothing. Instead emacs just hangs when I press i. Interesting.
    – Nikratio
    May 20, 2015 at 23:02
  • @Nikratio are you trying all this with emacs -Q?
    – Malabarba
    May 21, 2015 at 4:33
  • Yes, this also happens with emacs -Q
    – Nikratio
    May 21, 2015 at 15:13
2

I prefer to debug stuff with lispy instead of Edebug, possibly using Edebug for setup.

For me, the biggest advantage is that I can keep the debug state around, without worrying that if I mistype something in Edebug, all the debug context that I've worked on for 10 minutes will vanish and I would have to start from scratch. It's also great for setting test cases, sinks / mocks etc.

Stepping in and stepping through

You don't need to instrument anything, just press xj or C-x C-j to step in. All the debug state will be kept as global variables. Then just use e or C-x C-e to step.

Using Edebug for setup

If you're debugging a first function call, but actually are interested in how it affects a second function several layers down, just edebug the second function with xe, eval the first function call with e, and you'll end up in Edebug. Press Z to exit in Edebug, while storing the arguments of the current function in global vars. Now, you can continue as before.

If you expect the arguments to be modified in the debug process and don't wish to repeat the setup above, just generate a set of setq statements in *scratch*, so that you can reset them easily.

Starting from:

|(setq foo)

with foo e.g. having the value 42, by typing 2mE you get:

(setq foo
      42|)
  • 2m: mark second element of sexp
  • E: eval current selection (list or region) and insert the result

The standard equivalent for 2mE would be: M-f M-f SPC C-u C-x C-e.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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