Posts Tagged ‘Emacs’

elisp-ext.el

Well, if you use emacs long enough, eventually you realize that you have tens of thousands of lines of elisp lying around. I'm making a modest effort to dig myself out of this mess and what useful tidbits there are I will share with the world. Here is a very basic module that helps you get yourself in a predicament similar to my own.

;;;
;; elisp-ext.el
;;
;; Utilities for writing and debugging Emacs lisp. The
;; interactive functions are:
;;
;;   elisp:goto-definition - Jumps to the source for a
;;                           defun, defvar, etc.
;;
;;   elisp:edebug-at-point - Enable edebug for the symbol
;;                           nearest the cursor.
;;
;; When this is loaded, the sequence C-c C-g is bound to
;; elisp:goto-definition and C-c C-d is bound to
;; elisp:edebug-at-point in ielm and elisp-mode.
;;
;; by Dan McKinley, 2008
;; http://mcfunley.com
;;
;; This program is free software: you can redistribute it
;; and/or modify it under the terms of the GNU General Public
;; License as published by the Free Software Foundation, either
;; version 3 of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;
(eval-when-compile (require 'cl))

(defun* elisp:read-symbol (default &optional
                (prompt "Symbol")
                (test 'intern-soft))
  (let (val)
    (setq val (completing-read
           (if default (format "%s (default %s): " prompt default)
             (concat prompt ": "))
           obarray test t nil nil
           (and default (symbol-name default))))
    (if (equal val "")
        sym
      (intern val))))

(defun elisp:goto-definition (sym)
  "Extends find-func.el to find any symbol (defaulting
to the one at point)."
  (interactive (list (elisp:read-symbol (symbol-at-point))))
  (cond ((fboundp sym) (find-function sym))
    ((facep sym) (find-face-definition sym))
    (t (find-variable sym))))

(defun elisp:edebug-function (fun)
  "Enables edebug on a function given its symbol.
This necessarily leaves the file containing `fun' open, since
edebug will not open files on its own."
  (when (subrp fun)
    (error "Can't edebug a C function, sorry."))
  (save-excursion
    (let ((library (symbol-file fun nil)))
      (destructuring-bind (buf . pos)
      (find-function-search-for-symbol fun nil library)
    (set-buffer buf)
    (goto-char pos)
    (forward-sexp)
    (edebug-eval-top-level-form))))
  fun)

(defun elisp:edebug-at-point (fun)
  "Enables edebug on a function, defaulting to the
`function-called-at-point'."
  (interactive
   (list
    (elisp:read-symbol
     (function-called-at-point) "Debug function" 'fboundp)))
  (message "Enabled debugging on %s." (elisp:edebug-function fun)))

(defun elisp:local-keys ()
  (local-set-key "\C-c\C-g" 'elisp:goto-definition)
  (local-set-key "\C-c\C-d" 'elisp:edebug-at-point))
(add-hook 'emacs-lisp-mode-hook 'elisp:local-keys)
(add-hook 'ielm-mode-hook 'elisp:local-keys)

(provide 'elisp-ext)

How to Debug Python in GDB

Although I haven't found this to be necessary nearly as often as Windbg was for me on Windows, it's still somewhat handy to be able to look at a Python daemon or multithreaded program in GDB. I've had to set this up a few times now, and I've forgotten the steps each time, so here they are in one place.

Step 1 - Get a debug build of Python.

You need a debug version of the interpreter. This is what I do from source on *nix:

./configure --prefix=/usr/local/dbg
make OPT=-g
sudo make install

sudo ln -s /usr/local/bin/dbgpy /usr/local/dbg/bin/python

Step 2 - Fix the botched .gdbinit that comes with the Python source.

The Python source comes with a .gdbinit file (Misc/gdbinit), but it's broken in 2.5. Apply these changes, which will fix pystack to 1) work and 2) work on threads other than the main thread.

@@ -119,8 +122,8 @@

 # print the entire Python call stack
 define pystack
-    while $pc < Py_Main || $pc > Py_GetArgcArgv
-        if $pc > PyEval_EvalFrame && $pc < PyEval_EvalCodeEx
+    while ($pc < Py_Main || $pc > Py_GetArgcArgv) && ($pc < t_bootstrap || $pc > thread_PyThread_start_new_thread)
+        if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx
         pyframe
         end
         up-silently 1
@@ -130,8 +133,8 @@

 # print the entire Python call stack - verbose mode
 define pystackv
-    while $pc < Py_Main || $pc > Py_GetArgcArgv
-        if $pc > PyEval_EvalFrame && $pc < PyEval_EvalCodeEx
+    while ($pc < Py_Main || $pc > Py_GetArgcArgv) && ($pc < t_bootstrap || $pc > thread_PyThread_start_new_thread)
+        if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx
         pyframev
         end
         up-silently 1

Note that the locals still won't work. I'll post a diff that fixes those when I get around to doing that. In the meantime it's not too hard to poke through the python structures to get them.

On OS X you can just copy the result of this to ~/.gdbinit. Some linux distros might be cranky about where you put this and where you launch gdb.

Step 3 - Launch your program with the debug interpreter and attach.

From the command line you can attach with "gdb /usr/local/bin/dbgpy [pid]." I like gdba mode in emacs (see below - M-x gdba, then the same kind of command line).

gdba mode in Emacs