| 1 |
# emacs-buffer.gdb --- gdb macros for recovering buffers from emacs coredumps |
|---|
| 2 |
|
|---|
| 3 |
# Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc. |
|---|
| 4 |
|
|---|
| 5 |
# Maintainer: Noah Friedman <friedman@splode.com> |
|---|
| 6 |
# Status: Works with Emacs 22.0.51.1 (prerelease) as of 2006-01-12. |
|---|
| 7 |
# Older cvs snapshots, and released versions, will not work due to |
|---|
| 8 |
# changes in lisp data structures. But there are older versions of |
|---|
| 9 |
# this gdb script which work with those versions. |
|---|
| 10 |
# Created: 2005-04-28 |
|---|
| 11 |
|
|---|
| 12 |
# This file is part of GNU Emacs. |
|---|
| 13 |
# |
|---|
| 14 |
# GNU Emacs is free software; you can redistribute it and/or modify |
|---|
| 15 |
# it under the terms of the GNU General Public License as published by |
|---|
| 16 |
# the Free Software Foundation; either version 3, or (at your option) |
|---|
| 17 |
# any later version. |
|---|
| 18 |
# |
|---|
| 19 |
# GNU Emacs is distributed in the hope that it will be useful, |
|---|
| 20 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 21 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 22 |
# GNU General Public License for more details. |
|---|
| 23 |
# |
|---|
| 24 |
# You should have received a copy of the GNU General Public License |
|---|
| 25 |
# along with GNU Emacs; see the file COPYING. If not, write to the |
|---|
| 26 |
# Free Software Foundation, Inc.; 51 Franklin Street, Fifth Floor; |
|---|
| 27 |
# Boston, MA 02110-1301, USA. |
|---|
| 28 |
|
|---|
| 29 |
# Commentary: |
|---|
| 30 |
|
|---|
| 31 |
# This is a set of gdb macros for recovering the contents of buffers from |
|---|
| 32 |
# an Emacs coredump; they may not always be file-backed or have a recent |
|---|
| 33 |
# autosave. |
|---|
| 34 |
# |
|---|
| 35 |
# The Emacs executable must have debugging symbols for this to work. |
|---|
| 36 |
# But you never strip Emacs, right? |
|---|
| 37 |
# |
|---|
| 38 |
# The main commands of interest are `ybuffer-list', `yfile-buffers', |
|---|
| 39 |
# `ysave-buffer', and `ybuffer-contents'. The `y' prefix avoids any |
|---|
| 40 |
# namespace collisions with emacs/src/.gdbinit. |
|---|
| 41 |
|
|---|
| 42 |
# Example usage: |
|---|
| 43 |
# |
|---|
| 44 |
# $ gdb /export/src/emacs/2005-05-02--03-17/src/emacs core.emacs.6.9845 |
|---|
| 45 |
# Current directory is /u/noah/ |
|---|
| 46 |
# GNU gdb (6.1post-1.20040607.43rh) |
|---|
| 47 |
# ... |
|---|
| 48 |
# #0 0x400007a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2 |
|---|
| 49 |
# (gdb) source emacs-buffer.gdb |
|---|
| 50 |
# (gdb) ybuffer-list |
|---|
| 51 |
# B# M Size Name Mode File |
|---|
| 52 |
# -- - ---- ---- ---- ---- |
|---|
| 53 |
# 0 * 556 mail to emacs-devel@gnu.org Mail |
|---|
| 54 |
# 1 * 0 *Minibuf-1* Fundamental |
|---|
| 55 |
# 2 145769 ChangeLog Change Log /u/noah/lib/elisp/noahf/ChangeLog |
|---|
| 56 |
# 3 6619 ascii-table.el Elisp /u/noah/lib/elisp/noahf/ascii-table.el |
|---|
| 57 |
# 4 * 48396 *Messages* Fundamental |
|---|
| 58 |
# 5 3191 *Apropos* Apropos |
|---|
| 59 |
# 6 17642 init-21.el Elisp /u/noah/etc/init/emacs/init-21.el |
|---|
| 60 |
# 7 333 cpuid.c C /u/noah/cpuid.c |
|---|
| 61 |
# 8 230 src Dired |
|---|
| 62 |
# 9 218 noah Dired |
|---|
| 63 |
# 10 * 21 *Echo Area 0* Fundamental |
|---|
| 64 |
# 11 * 0 *Echo Area 1* Fundamental |
|---|
| 65 |
# 12 319952 *bbdb data* Text /u/noah/.bbdb |
|---|
| 66 |
# (gdb) ysave-buffer 0 mail.save |
|---|
| 67 |
# [Wrote buffer "mail to emacs-devel@gnu.org" to file mail.save] |
|---|
| 68 |
# (gdb) quit |
|---|
| 69 |
# $ ls -l mail.save |
|---|
| 70 |
# -rw-rw-rw- 1 noah user 556 May 2 04:05 mail.save |
|---|
| 71 |
# $ |
|---|
| 72 |
|
|---|
| 73 |
# Code: |
|---|
| 74 |
|
|---|
| 75 |
# Force loading of symbols, enough to give us gdb_valbits etc. |
|---|
| 76 |
set main |
|---|
| 77 |
|
|---|
| 78 |
# When nonzero, display some extra diagnostics in various commands |
|---|
| 79 |
set $yverbose = 1 |
|---|
| 80 |
set $yfile_buffers_only = 0 |
|---|
| 81 |
|
|---|
| 82 |
set $tagmask = (((long)1 << gdb_gctypebits) - 1) |
|---|
| 83 |
set $valmask = gdb_use_lsb ? ~($tagmask) : ((long)1 << gdb_valbits) - 1 |
|---|
| 84 |
|
|---|
| 85 |
define ygetptr |
|---|
| 86 |
set $ptr = $arg0 |
|---|
| 87 |
set $ptr = (gdb_use_union ? $ptr.u.val : $ptr & $valmask) | gdb_data_seg_bits |
|---|
| 88 |
end |
|---|
| 89 |
|
|---|
| 90 |
define ybuffer-list |
|---|
| 91 |
set $files_only = $yfile_buffers_only |
|---|
| 92 |
set $yfile_buffers_only = 0 |
|---|
| 93 |
|
|---|
| 94 |
if $yverbose |
|---|
| 95 |
printf "B# M Size Name Mode File\n" |
|---|
| 96 |
printf "-- - ---- ---- ---- ----\n" |
|---|
| 97 |
end |
|---|
| 98 |
|
|---|
| 99 |
set $i = 0 |
|---|
| 100 |
set $alist = Vbuffer_alist |
|---|
| 101 |
while $alist != Qnil |
|---|
| 102 |
ygetptr $alist |
|---|
| 103 |
set $this = ((struct Lisp_Cons *) $ptr)->car |
|---|
| 104 |
set $alist = ((struct Lisp_Cons *) $ptr)->u.cdr |
|---|
| 105 |
|
|---|
| 106 |
# Vbuffer_alist elts are pairs of the form (name . buffer) |
|---|
| 107 |
ygetptr $this |
|---|
| 108 |
set $buf = ((struct Lisp_Cons *) $ptr)->u.cdr |
|---|
| 109 |
ygetptr $buf |
|---|
| 110 |
set $buf = (struct buffer *) $ptr |
|---|
| 111 |
|
|---|
| 112 |
if ! ($files_only && $buf->filename == Qnil) |
|---|
| 113 |
ygetptr $buf->name |
|---|
| 114 |
set $name = ((struct Lisp_String *) $ptr)->data |
|---|
| 115 |
set $modp = ($buf->text->modiff > $buf->text->save_modiff) ? '*' : ' ' |
|---|
| 116 |
|
|---|
| 117 |
ygetptr $buf->mode_name |
|---|
| 118 |
set $mode = ((struct Lisp_String *) $ptr)->data |
|---|
| 119 |
|
|---|
| 120 |
if $buf->filename != Qnil |
|---|
| 121 |
ygetptr $buf->filename |
|---|
| 122 |
printf "%2d %c %9d %-20s %-10s %s\n", \ |
|---|
| 123 |
$i, $modp, ($buf->text->z_byte - 1), $name, $mode, \ |
|---|
| 124 |
((struct Lisp_String *) $ptr)->data |
|---|
| 125 |
else |
|---|
| 126 |
printf "%2d %c %9d %-20s %-10s\n", \ |
|---|
| 127 |
$i, $modp, ($buf->text->z_byte - 1), $name, $mode |
|---|
| 128 |
end |
|---|
| 129 |
end |
|---|
| 130 |
|
|---|
| 131 |
set $i++ |
|---|
| 132 |
end |
|---|
| 133 |
end |
|---|
| 134 |
document ybuffer-list |
|---|
| 135 |
Display a list of buffer names, sizes, and other attributes. |
|---|
| 136 |
The buffer number in the first column is used as an argument |
|---|
| 137 |
to some other emacs-buffer recovery commands, e.g. `ysave-buffer'. |
|---|
| 138 |
end |
|---|
| 139 |
|
|---|
| 140 |
define yfile-buffers |
|---|
| 141 |
set $yfile_buffers_only = 1 |
|---|
| 142 |
ybuffer-list |
|---|
| 143 |
end |
|---|
| 144 |
document yfile-buffers |
|---|
| 145 |
Display a list of buffers which are associated with files. |
|---|
| 146 |
This is like `ybuffer-list', but only buffers that were visiting files |
|---|
| 147 |
are displayed. |
|---|
| 148 |
end |
|---|
| 149 |
|
|---|
| 150 |
define yset-buffer |
|---|
| 151 |
set $i = $arg0 |
|---|
| 152 |
|
|---|
| 153 |
set $alist = Vbuffer_alist |
|---|
| 154 |
while ($alist != Qnil && $i > 0) |
|---|
| 155 |
ygetptr $alist |
|---|
| 156 |
set $alist = ((struct Lisp_Cons *) $ptr)->u.cdr |
|---|
| 157 |
set $i-- |
|---|
| 158 |
end |
|---|
| 159 |
|
|---|
| 160 |
# Get car of alist; this is a pair (name . buffer) |
|---|
| 161 |
ygetptr $alist |
|---|
| 162 |
set $this = ((struct Lisp_Cons *) $ptr)->car |
|---|
| 163 |
|
|---|
| 164 |
# Get the buffer object |
|---|
| 165 |
ygetptr $this |
|---|
| 166 |
set $this = ((struct Lisp_Cons *) $ptr)->u.cdr |
|---|
| 167 |
|
|---|
| 168 |
ygetptr $this |
|---|
| 169 |
set $ycurrent_buffer = (struct buffer *) $ptr |
|---|
| 170 |
end |
|---|
| 171 |
document yset-buffer |
|---|
| 172 |
Set current buffer (for other emacs-buffer recovery commands) to the ARG'th |
|---|
| 173 |
buffer as displayed by `ybuffer-list'. |
|---|
| 174 |
end |
|---|
| 175 |
|
|---|
| 176 |
define yget-buffer-pointers |
|---|
| 177 |
yset-buffer $arg0 |
|---|
| 178 |
set $buf = $ycurrent_buffer->text |
|---|
| 179 |
|
|---|
| 180 |
set $beg = $buf->beg |
|---|
| 181 |
set $gap = $beg + $buf->gpt_byte |
|---|
| 182 |
set $gap_end = $gap + $buf->gap_size - 1 |
|---|
| 183 |
set $end = $gap_end + ($buf->z_byte - $buf->gpt_byte) |
|---|
| 184 |
|
|---|
| 185 |
set $modp = $buf->modiff > $buf->save_modiff |
|---|
| 186 |
|
|---|
| 187 |
#print *$beg@($gap - $beg) |
|---|
| 188 |
#print *$gap_end@($end - $gap_end) |
|---|
| 189 |
end |
|---|
| 190 |
document yget-buffer-pointers |
|---|
| 191 |
Update convenience variables with address pointers for the ARG'th buffer |
|---|
| 192 |
as displayed by `ybuffer-list'. |
|---|
| 193 |
|
|---|
| 194 |
This also sets the current buffer using `yset-buffer' (which see). |
|---|
| 195 |
end |
|---|
| 196 |
|
|---|
| 197 |
define yget-current-buffer-name |
|---|
| 198 |
set $this = $ycurrent_buffer->name |
|---|
| 199 |
ygetptr $this |
|---|
| 200 |
set $ycurrent_buffer_name = ((struct Lisp_String *) $ptr)->data |
|---|
| 201 |
end |
|---|
| 202 |
document yget-current-buffer-name |
|---|
| 203 |
Set $ycurrent_buffer_name to the name of the currently selected buffer. |
|---|
| 204 |
end |
|---|
| 205 |
|
|---|
| 206 |
define ycurrent-buffer |
|---|
| 207 |
yget-current-buffer-name |
|---|
| 208 |
printf "%s\n", $ycurrent_buffer_name |
|---|
| 209 |
end |
|---|
| 210 |
document ycurrent-buffer |
|---|
| 211 |
Display the currently selected buffer. |
|---|
| 212 |
end |
|---|
| 213 |
|
|---|
| 214 |
define ydump-buffer |
|---|
| 215 |
yget-buffer-pointers $arg0 |
|---|
| 216 |
if $buf->z_byte > 1 |
|---|
| 217 |
if $buf->z_byte <= $buf->gpt_byte |
|---|
| 218 |
set $endptr = $beg + $buf->gpt_byte - 1 |
|---|
| 219 |
dump binary memory $arg1 $beg $endptr |
|---|
| 220 |
else |
|---|
| 221 |
dump binary memory $arg1 $beg $gap-1 |
|---|
| 222 |
append binary memory $arg1 $gap_end $end |
|---|
| 223 |
set $endptr = $end |
|---|
| 224 |
end |
|---|
| 225 |
end |
|---|
| 226 |
end |
|---|
| 227 |
document ydump-buffer |
|---|
| 228 |
Write contents of buffer N (as numbered according to `ybuffer-list') to |
|---|
| 229 |
file FILE. |
|---|
| 230 |
|
|---|
| 231 |
This is mainly used as an internal subroutine for `ysave-buffer' and |
|---|
| 232 |
`ybuffer-contents', which see. |
|---|
| 233 |
end |
|---|
| 234 |
|
|---|
| 235 |
define ysave-buffer |
|---|
| 236 |
ydump-buffer $arg0 $arg1 |
|---|
| 237 |
if $yverbose |
|---|
| 238 |
yget-current-buffer-name |
|---|
| 239 |
if $buf->z_byte <= 1 |
|---|
| 240 |
printf "[Buffer \"%s\" is empty.]\n", $ycurrent_buffer_name |
|---|
| 241 |
else |
|---|
| 242 |
# Output string broken into separate calls as necessary to avoid |
|---|
| 243 |
# requiring a running process for evaluation. |
|---|
| 244 |
printf "[Wrote buffer \"%s\" to file ", $ycurrent_buffer_name |
|---|
| 245 |
echo $arg1]\n |
|---|
| 246 |
end |
|---|
| 247 |
end |
|---|
| 248 |
end |
|---|
| 249 |
document ysave-buffer |
|---|
| 250 |
Save contents of buffer N (as numbered according to `ybuffer-list') to |
|---|
| 251 |
file FILE. |
|---|
| 252 |
end |
|---|
| 253 |
|
|---|
| 254 |
define ybuffer-contents |
|---|
| 255 |
ydump-buffer $arg0 /dev/stdout |
|---|
| 256 |
if $yverbose && $buf->z_byte <= 1 |
|---|
| 257 |
yget-current-buffer-name |
|---|
| 258 |
printf "[Buffer \"%s\" is empty.]\n", $ycurrent_buffer_name |
|---|
| 259 |
else |
|---|
| 260 |
if *($endptr-1) != '\n' |
|---|
| 261 |
echo \n |
|---|
| 262 |
end |
|---|
| 263 |
end |
|---|
| 264 |
end |
|---|
| 265 |
document ybuffer-contents |
|---|
| 266 |
Write contents of buffer N (numbered according to `ybuffer-list') to stdout. |
|---|
| 267 |
end |
|---|
| 268 |
|
|---|
| 269 |
# local variables: |
|---|
| 270 |
# mode: gdb-script |
|---|
| 271 |
# end: |
|---|
| 272 |
|
|---|
| 273 |
# arch-tag: 02087f62-2663-4868-977a-1fbb2fc2e7ef |
|---|