From: Bernhard Walle <bwalle@suse.de>
To: kexec@lists.infradead.org
Subject: [PATCH] [makedumpfile] Follow debuginfo link of vmlinux file
Date: Tue, 1 May 2007 15:39:12 +0200 [thread overview]
Message-ID: <20070501133912.GA8247@suse.de> (raw)
This patch implements support for following the debug information link in the
.gnu_debuginfo section if the specified binary contains one. That makes it
possible to call makedumpfile with -x /boot/vmlinux-<version> on distributions
that ship extra -debuginfo packages for the kernel.
See GDB documentation, section 15.2 "Debugging Information in Separate Files"
for information about then contents of the .gnu_debuginfo section, the
algorithm used to find the debuginfo file and the CRC checksum implementation.
Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
makedumpfile.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
makedumpfile.h | 8 +
2 files changed, 302 insertions(+), 2 deletions(-)
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -339,17 +339,313 @@ open_config_file(struct DumpInfo *info,
return TRUE;
}
+unsigned long
+gnu_debuglink_crc32 (unsigned long crc, unsigned char *buf, size_t len)
+{
+ static const unsigned long crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ };
+ unsigned char *end;
+
+ crc = ~crc & 0xffffffff;
+ for (end = buf + len; buf < end; ++buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc & 0xffffffff;
+}
+
+int
+get_debuginfo_link(char *debuginfo_name, size_t len, uint32_t *crc)
+{
+ Elf *elfd = NULL;
+ Elf_Scn *scn = NULL;
+ Elf_Data *data;
+ GElf_Shdr shdr;
+ size_t shstrndx;
+ int n;
+ int found = FALSE;
+ char *debuglink_data = NULL;
+ int debuglink_data_size = 0;
+ int offset;
+
+ if (lseek(dwarf_info.vmlinux_fd, 0, SEEK_SET) == SEEK_FAILED) {
+ ERRMSG("Can't seek the kernel file(%s). %s\n",
+ dwarf_info.vmlinux_name, strerror(errno));
+ return -1;
+ }
+
+ elfd = elf_begin(dwarf_info.vmlinux_fd, ELF_C_READ, NULL);
+ if (!elfd) {
+ ERRMSG("Can't get first elf header of %s.\n",
+ dwarf_info.vmlinux_name);
+ }
+
+ if (elf_getshstrndx(elfd, &shstrndx) < 0) {
+ ERRMSG("Can't get the section index of the string table.\n");
+ goto out;
+ }
+
+ /* search a .gnu_debuglink section in all sections */
+ while ((scn = elf_nextscn(elfd, scn)) != NULL) {
+ char *name;
+
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ ERRMSG("Can't get section header.\n");
+ goto out;
+ }
+ name = elf_strptr(elfd, shstrndx, shdr.sh_name);
+
+ if (strcmp(name, ".gnu_debuglink") == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ goto out;
+
+ /* we got it :-) */
+
+ /* merge the data to one big buffer (if ever necessary ...) */
+ data = NULL; n = 0;
+ while (n < shdr.sh_size && (data = elf_getdata(scn, data)) != NULL) {
+
+ /* merge */
+ debuglink_data = (char *)realloc(debuglink_data,
+ debuglink_data_size + data->d_size);
+ if (!debuglink_data) {
+ ERRMSG("Unable to (re-)allocate memory in get_debuginfo_link()\n");
+ goto out;
+ }
+ memmove(debuglink_data + debuglink_data_size, data->d_buf, data->d_size);
+ debuglink_data_size += data->d_size;
+ }
+
+ /* now get the elements */
+ strncpy(debuginfo_name, debuglink_data, len);
+ debuginfo_name[len-1] = 0;
+
+ /* move to the CRC: "a four-byte CRC checksum, stored in the same
+ * endianness used for the executable file itself. The checksum is
+ * computed on the debugging information file's full contents by the
+ * function given below, passing zero as the CRC argument." */
+ offset = strlen(debuglink_data) + 1;
+ offset += 3;
+ offset &= ~3;
+
+ memcpy(crc, debuglink_data + offset, 4);
+
+out:
+ free(debuglink_data);
+ if (elfd)
+ elf_end(elfd);
+ return found ? 0 : -1;
+}
+
+
+void
+get_full_path(const char *executable, char *path, size_t len)
+{
+ if (executable[0] == '/') {
+ /* already a full path ... */
+ strncpy(path, executable, len);
+ path[len-1] = 0;
+ } else {
+ size_t tmp;
+
+ getcwd(path, len);
+ path[len-1] = 0;
+
+ tmp = strlen(path);
+ strncat(path + tmp, executable, len - tmp);
+ path[len-1] = 0;
+ }
+}
+
+int
+dirname(const char *filename, char *dirname, size_t len)
+{
+ char *c;
+ int n;
+
+ /* find the last '/' */
+ c = strrchr(filename, '/');
+ if (!c)
+ return -1;
+
+ /* preserve the trailing slash */
+ n = c - filename + 1;
+
+ /* check for enough size */
+ if (len <= n)
+ return -1;
+
+ strncpy(dirname, filename, n);
+ dirname[n] = 0;
+
+ return 0;
+}
+
+
+static int
+do_open_and_check_crc(const char *binary, uint32_t crc)
+{
+ int fd;
+ unsigned char buffer[BUFFER_SIZE];
+ int ret;
+ unsigned long calc_crc = 0;
+
+ fd = open(binary, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ while ((ret = read(fd, buffer, BUFFER_SIZE)) > 0) {
+ calc_crc = gnu_debuglink_crc32(calc_crc, buffer, ret);
+ }
+
+ if (calc_crc != crc) {
+ close(fd);
+ return -1;
+ }
+
+ /* back to the beginning */
+ lseek(fd, SEEK_SET, 0);
+
+ return fd;
+}
+
+int
+open_debuginfo_binary(const char *kernel_full_path,
+ const char *debuginfo_name,
+ uint32_t crc)
+{
+ int fd, ret;
+ char dir[PATH_MAX], tmp[PATH_MAX];
+
+ /* 1st: EXECDIR/DEBUGFILE */
+ ret = dirname(kernel_full_path, dir, PATH_MAX);
+ if (ret < 0) {
+ ERRMSG("Couldn't retrieve directory name for '%s'\n",
+ kernel_full_path);
+ return -1;
+ }
+ strcpy(tmp, dir);
+ strncat(tmp, debuginfo_name, PATH_MAX);
+ tmp[PATH_MAX-1] = 0;
+
+ fd = do_open_and_check_crc(tmp, crc);
+ if (fd >= 0)
+ return fd;
+
+ /* 2nd: EXECDIR/.debug/DEBUGFILE */
+ strcpy(tmp, dir);
+ strncat(tmp, ".debug/", PATH_MAX);
+ strncat(tmp, debuginfo_name, PATH_MAX);
+ tmp[PATH_MAX-1] = 0;
+
+ fd = do_open_and_check_crc(tmp, crc);
+ if (fd >= 0)
+ return fd;
+
+ /* 3rd: GLOBALDEBUGDIR/EXECDIR/DEBUGFILE */
+ strcpy(tmp, GLOBALDEBUGDIR);
+ strncat(tmp, dir, PATH_MAX);
+ strncat(tmp, debuginfo_name, PATH_MAX);
+ tmp[PATH_MAX-1] = 0;
+
+ fd = do_open_and_check_crc(tmp, crc);
+ if (fd >= 0)
+ return fd;
+
+ ERRMSG("Cound't find %s\n", debuginfo_name);
+
+ return -1;
+}
+
int
open_kernel_file()
{
int fd;
+ static char debuginfo_name[PATH_MAX];
+ uint32_t crc;
+ int ret;
if ((fd = open(dwarf_info.vmlinux_name, O_RDONLY)) < 0) {
ERRMSG("Can't open the kernel file(%s). %s\n",
dwarf_info.vmlinux_name, strerror(errno));
return FALSE;
}
+
+ /* (temporarily) set the fd */
dwarf_info.vmlinux_fd = fd;
+
+ /* check whether it contains a debuginfo link */
+ ret = get_debuginfo_link(debuginfo_name, PATH_MAX, &crc);
+ if (ret == 0) {
+ char kernel_full_path[PATH_MAX];
+ int debuginfo_fd;
+
+ /* make a full path because the debuginfo mechanism needs this */
+ get_full_path(dwarf_info.vmlinux_name, kernel_full_path, PATH_MAX);
+
+ debuginfo_fd = open_debuginfo_binary(kernel_full_path, debuginfo_name, crc);
+ if (debuginfo_fd < 0)
+ return FALSE;
+
+ dwarf_info.vmlinux_fd = debuginfo_fd;
+ dwarf_info.vmlinux_name = debuginfo_name;
+ }
+
return TRUE;
}
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -29,6 +29,7 @@
#include <libelf.h>
#include <dwarf.h>
#include <byteswap.h>
+#include <limits.h>
#include "diskdump_mod.h"
/*
@@ -297,8 +298,6 @@ do { \
#define FALSE (0)
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#define LONG_MAX ((long)(~0UL>>1))
-#define ULONG_MAX (~0UL)
#define ULONGLONG_MAX (~0ULL)
#define DEFAULT_ORDER (4)
#define TIMEOUT_STDIN (600)
@@ -658,3 +657,8 @@ struct dwarf_info {
extern struct dwarf_info dwarf_info;
+/* other constants */
+#define SEEK_FAILED ((off_t)-1)
+#define GLOBALDEBUGDIR "/usr/lib/debug"
+#define BUFFER_SIZE 20505
+
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
next reply other threads:[~2007-05-01 13:39 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-01 13:39 Bernhard Walle [this message]
2007-05-24 0:35 ` [PATCH] [makedumpfile] Follow debuginfo link of vmlinux file Ken'ichi Ohmichi
2007-05-24 6:54 ` Bernhard Walle
2007-05-24 7:09 ` Bernhard Walle
2007-05-24 17:21 ` Jay Lan
2007-05-24 18:31 ` Dave Anderson
2007-05-24 19:21 ` Bernhard Walle
2007-05-24 19:44 ` Jay Lan
2007-05-24 19:54 ` Bernhard Walle
2007-05-29 11:43 ` Ken'ichi Ohmichi
2007-05-29 17:44 ` Jay Lan
2007-05-29 18:42 ` Bernhard Walle
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070501133912.GA8247@suse.de \
--to=bwalle@suse.de \
--cc=kexec@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.