# emacs-buffer.gdb --- gdb macros for recovering buffers from emacs coredumps # Copyright (C) 1992, 93, 94, 95, 96, 97, 1998, 2000, 01, 2004 # Free Software Foundation, Inc. # Copyright (C) 2005 Noah S. Friedman # Maintainer: Noah Friedman # Status: tested with Emacs 22. # Created: 2005-04-28 # $Id: emacs-buffer.gdb,v 1.1 2005/05/02 05:15:49 friedman Exp $ # 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 2, 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, you can either send email to this # program's maintainer or write to: The Free Software Foundation, # Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. # Commentary: # This is a set of gdb macros for recovering the contents of buffers from # an Emacs coredump; they may not always be file-backed or have a recent # autosave. # # The Emacs executable must have debugging symbols for this to work. But # you never strip Emacs, right? Right! # # The main commands of interest are `ybuffer-list' and `ysave-buffer'. The # `y' prefix avoids any namespace collisions with emacs/src/.gdbinit. # Example usage: # # $ gdb /usr/bin/emacs core # Current directory is /u/noah/ # GNU gdb Red Hat Linux (6.1post-1.20040607.43rh) # ... # #0 0x400007a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2 # (gdb) source emacs-buffer.gdb # (gdb) ybuffer-list # Buffer# Size Name # 0 556 mail to emacs-devel@gnu.org # 1 0 *Minibuf-1* # 2 0 *mail* # 3 0 *scratch* # 4 0 *Minibuf-0* # 5 3244 *Messages* # 6 27 *Echo Area 0* # 7 4 *Echo Area 1* # 8 8 *code-conversion-work* # 9 3158 *Completions* # 10 318080 *bbdb data* # 11 39 *canonical address* # 12 39 *extract address components* # (gdb) ysave-buffer 0 mail.save # [Wrote buffer "mail to emacs-devel@gnu.org" to file mail.save] # (gdb) quit # $ ls -l mail.save # -rw-rw-rw- 1 noah user 556 May 1 22:05 mail.save # $ # Code: # Force loading of symbols, enough to give us gdb_valbits etc. set main # When nonzero, display some extra diagnostics in various commands set $yverbose = 1 define yinit set $tagmask = (((long)1 << gdb_gctypebits) - 1) set $valmask = gdb_use_lsb ? ~($tagmask) : ((long)1 << gdb_valbits) - 1 end define ygetptr set $ptr = $arg0 set $ptr = (gdb_use_union ? $ptr.u.val : $ptr & $valmask) | gdb_data_seg_bits end define ygettype set $type = $arg0 set $type = gdb_use_union \ ? $type.s.type \ : (enum Lisp_Type) (gdb_use_lsb \ ? $type & $tagmask \ : $type >> gdb_valbits) end define ybuffer-list if $yverbose printf "Buffer# Size Name\n" end set $i = 0 set $alist = Vbuffer_alist while $alist != Qnil ygetptr $alist set $this = ((struct Lisp_Cons *) $ptr)->car set $alist = ((struct Lisp_Cons *) $ptr)->cdr # pair of the form (name . buffer) ygetptr $this set $name = ((struct Lisp_Cons *) $ptr)->car set $buf = ((struct Lisp_Cons *) $ptr)->cdr ygetptr $name set $name = ((struct Lisp_String *) $ptr)->data ygetptr $buf set $buf = ((struct buffer *) $ptr)->text set $bufsize = $buf->z_byte - 1 printf "%3d %9d %s\n", $i, $bufsize, $name set $i++ end end document ybuffer-list Display a list of buffer names and sizes. The buffer number in the first column is used as an argument to some other emacs-buffer recovery commands, e.g. `ysave-buffer'. end define yset-buffer set $i = $arg0 set $alist = Vbuffer_alist while ($alist != Qnil && $i > 0) ygetptr $alist set $alist = ((struct Lisp_Cons *) $ptr)->cdr set $i-- end # Get car of alist; this is a pair (name . buffer) ygetptr $alist set $this = ((struct Lisp_Cons *) $ptr)->car # Get the buffer object ygetptr $this set $this = ((struct Lisp_Cons *) $ptr)->cdr ygetptr $this set $ycurrent_buffer = (struct buffer *) $ptr end document yset-buffer Set current buffer (for other emacs-buffer recovery commands) to the ARG'th buffer as displayed by `ybuffer-list'. end define yget-buffer-pointers yset-buffer $arg0 set $buf = $ycurrent_buffer->text set $beg = $buf->beg set $gap = $beg + $buf->gpt_byte set $gap_end = $gap + $buf->gap_size - 1 set $end = $gap_end + ($buf->z_byte - $buf->gpt_byte) #print *$beg@($gap - $beg) #print *$gap_end@($end - $gap_end) end document yget-buffer-pointers Update convenience variables with address pointers for the ARG'th buffer as displayed by `ybuffer-list'. This also sets the current buffer using `yset-buffer' (which see). end define yget-current-buffer-name set $this = $ycurrent_buffer->name ygetptr $this set $ycurrent_buffer_name = ((struct Lisp_String *) $ptr)->data end document yget-current-buffer-name Set $ycurrent_buffer_name to the name of the currently selected buffer. end define ycurrent-buffer yget-current-buffer-name printf "%s\n", $ycurrent_buffer_name end document ycurrent-buffer Display the currently selected buffer. end define ydump-buffer yget-buffer-pointers $arg0 if $buf->z_byte > 1 if $buf->z_byte <= $buf->gpt_byte set $endptr = $beg + $buf->gpt_byte - 1 dump binary memory $arg1 $beg $endptr else dump binary memory $arg1 $beg $gap-1 append binary memory $arg1 $gap_end $end set $endptr = $end end end end document ydump-buffer Write contents of buffer N (as numbered according to `ybuffer-list') to file FILE. This is mainly used as an internal subroutine for `ysave-buffer' and `ybuffer-contents', which see. end define ysave-buffer ydump-buffer $arg0 $arg1 if $yverbose yget-current-buffer-name if $buf->z_byte <= 1 printf "[Buffer \"%s\" is empty.]\n", $ycurrent_buffer_name else # Output string broken into separate calls as necessary to avoid # requiring a running process for evaluation. printf "[Wrote buffer \"%s\" to file ", $ycurrent_buffer_name echo $arg1]\n end end end document ysave-buffer Save contents of buffer N (as numbered according to `ybuffer-list') to file FILE. end define ybuffer-contents ydump-buffer $arg0 /dev/stdout if $yverbose && $buf->z_byte <= 1 yget-current-buffer-name printf "[Buffer \"%s\" is empty.]\n", $ycurrent_buffer_name else if *($endptr-1) != '\n' echo \n end end end document ybuffer-contents Write contents of buffer N (numbered according to `ybuffer-list') to stdout. end # local variables: # mode: gdb-script # end: