diff -ur linux-2.4.28/arch/i386/config.in linux-2.4.28-gzip-coredump/arch/i386/config.in --- linux-2.4.28/arch/i386/config.in 2004-11-17 12:54:21.000000000 +0100 +++ linux-2.4.28-gzip-coredump/arch/i386/config.in 2005-01-10 08:45:36.000000000 +0100 @@ -479,6 +479,7 @@ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER + bool ' Write gzipped core dump files' CONFIG_GZIP_COREDUMPS fi int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 diff -ur linux-2.4.28/Documentation/Configure.help linux-2.4.28-gzip-coredump/Documentation/Configure.help --- linux-2.4.28/Documentation/Configure.help 2004-11-17 12:54:20.000000000 +0100 +++ linux-2.4.28-gzip-coredump/Documentation/Configure.help 2005-01-10 08:45:45.000000000 +0100 @@ -29121,6 +29121,11 @@ If unsure, say N. +CONFIG_GZIP_COREDUMPS + Saying yes here makes the kernel writing core dump files in a + gzipped compressed format. You will have to uncompress core files + with gzip -d prior to usage (e.g. with gdb). + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -ur linux-2.4.28/fs/binfmt_elf.c linux-2.4.28-gzip-coredump/fs/binfmt_elf.c --- linux-2.4.28/fs/binfmt_elf.c 2004-11-17 12:54:21.000000000 +0100 +++ linux-2.4.28-gzip-coredump/fs/binfmt_elf.c 2005-01-13 15:42:45.000000000 +0100 @@ -9,6 +9,7 @@ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). */ +#include #include #include @@ -59,6 +60,18 @@ */ #ifdef USE_ELF_CORE_DUMP static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file); + +#ifdef CONFIG_GZIP_COREDUMPS + +/* + * Functions added to support writing core files in gzipped format, 2004 + * Jan Frey + */ +#include +#include +#include +#endif + #else #define elf_core_dump NULL #endif @@ -941,15 +954,83 @@ * Modelled on fs/exec.c:aout_core_dump() * Jeremy Fitzhardinge */ +#ifdef CONFIG_GZIP_COREDUMPS /* - * These are the only things you should do on a core-file: use only these - * functions to write out all the necessary info. + * gz writing support + * Jan Frey */ -static int dump_write(struct file *file, const void *addr, int nr) +static int gz_dump_write(struct file *file, const void *addr, int nr, u32 *crc, z_streamp zstr) { - return file->f_op->write(file, addr, nr, &file->f_pos) == nr; + const int OUT_BUF_SIZE = 100*1024; + int all_fine = 1; + void *out_buf = vmalloc(OUT_BUF_SIZE); + + if (!out_buf) { + printk(KERN_WARNING "Failed to allocate deflate buffer"); + return 0; + } + + *crc = crc32_le (*crc, addr, nr); + + zstr->next_in = addr; + zstr->avail_in = nr; + + do { + zstr->next_out = out_buf; + zstr->avail_out = OUT_BUF_SIZE; + + if (zlib_deflate (zstr, Z_NO_FLUSH) == Z_OK) { + /* new output generated */ + all_fine = (file->f_op->write (file, + out_buf, + OUT_BUF_SIZE - zstr->avail_out, + &file->f_pos) + == (OUT_BUF_SIZE - zstr->avail_out)); + } + } while ((zstr->avail_out != OUT_BUF_SIZE) && all_fine); + + vfree (out_buf); + return all_fine; } +static int gz_finish (struct file *file, z_streamp zstr) +{ + const int OUT_BUF_SIZE = 100*1024; + int all_fine = 1; + int ret; + void *out_buf = vmalloc(OUT_BUF_SIZE); + + if (!out_buf) { + printk(KERN_WARNING "Failed to allocate deflate buffer"); + return 0; + } + + zstr->next_in = 0; + zstr->avail_in = 0; + + do { + zstr->next_out = out_buf; + zstr->avail_out = OUT_BUF_SIZE; + + ret = zlib_deflate (zstr, Z_FINISH); + if ((ret == Z_OK) || (ret == Z_STREAM_END)) { + /* new output generated */ + all_fine = (file->f_op->write (file, + out_buf, + OUT_BUF_SIZE - zstr->avail_out, + &file->f_pos) + == (OUT_BUF_SIZE - zstr->avail_out)); + } + } while ((zstr->avail_out != OUT_BUF_SIZE) && all_fine && (ret != Z_STREAM_END)); + + vfree (out_buf); + return all_fine; +} +#else +/* + * These are the only things you should do on a core-file: use only these + * functions to write out all the necessary info. + */ static int dump_seek(struct file *file, off_t off) { if (file->f_op->llseek) { @@ -959,6 +1040,13 @@ file->f_pos = off; return 1; } +#endif + +static int dump_write(struct file *file, const void *addr, int nr) +{ + return file->f_op->write(file, addr, nr, &file->f_pos) == nr; +} + /* * Decide whether a segment is worth dumping; default is yes to be @@ -1030,11 +1118,54 @@ } #endif -#define DUMP_WRITE(addr, nr) \ - do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) +#ifdef CONFIG_GZIP_COREDUMPS +#define PAD_GZ(nr, buf, crc, str) \ + do { \ + int cur=(nr); \ + while (cur>1024) { \ + gz_dump_write(file, (buf), 1024, (crc), (str)); \ + cur-=1024; \ + } \ + if (cur) { \ + gz_dump_write(file, (buf), cur, (crc), (str)); \ + } \ + } while(0) + +#define DUMP_GZ(addr, nr, crc, str) \ + do { if (!gz_dump_write(file, (addr), (nr), (crc), (str))) return 0; } while(0) +#else #define DUMP_SEEK(off) \ do { if (!dump_seek(file, (off))) return 0; } while(0) +#endif + +#define DUMP_WRITE(addr, nr) \ + do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) +#ifdef CONFIG_GZIP_COREDUMPS +static int writenote_gz(struct memelfnote *men, struct file *file, char *buf, u32 *crc, z_streamp zstr) +{ + struct elf_note en; + int dummy_bytes; + + en.n_namesz = strlen(men->name); + en.n_descsz = men->datasz; + en.n_type = men->type; + + DUMP_GZ(&en, sizeof(en), crc, zstr); + DUMP_GZ(men->name, en.n_namesz, crc, zstr); + + dummy_bytes = roundup((unsigned long)zstr->total_in, 4) - zstr->total_in; + PAD_GZ(dummy_bytes, buf, crc, zstr); + + DUMP_GZ(men->data, men->datasz, crc, zstr); + + dummy_bytes = roundup((unsigned long)zstr->total_in, 4) - zstr->total_in; + PAD_GZ(dummy_bytes, buf, crc, zstr); + + return 1; +} +#undef DUMP_GZ +#else static int writenote(struct memelfnote *men, struct file *file) { struct elf_note en; @@ -1054,13 +1185,21 @@ } #undef DUMP_WRITE #undef DUMP_SEEK +#endif +#ifdef CONFIG_GZIP_COREDUMPS +#define DUMP_GZ(addr, nr, crc, str) \ + if ((size += (nr)) > limit || !gz_dump_write(file, (addr), (nr), (crc), (str))) \ + goto end_coredump; +#else #define DUMP_WRITE(addr, nr) \ if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ goto end_coredump; #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ goto end_coredump; +#endif + /* * Actual dumper * @@ -1085,6 +1224,39 @@ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ +#ifdef CONFIG_GZIP_COREDUMPS + z_stream gz_stream; + void *deflate_workspace; + u32 crc = ~0; /* init */ + unsigned char gz_magic[10] = { /* gzip magic header */ + 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 0x03 }; + unsigned char *empty_buf; + + deflate_workspace = vmalloc(zlib_deflate_workspacesize()); + if (!deflate_workspace) { + printk(KERN_WARNING "Failed to allocate deflate workspace\n"); + return -ENOMEM; + } + + gz_stream.workspace = deflate_workspace; + if (Z_OK != zlib_deflateInit2(&gz_stream, + 7, /* compression level */ + Z_DEFLATED, + -15, /* window bits */ + 6, /* mem level */ + Z_DEFAULT_STRATEGY)) { + printk(KERN_WARNING "deflateInit failed\n"); + return -ENOMEM; + } + + empty_buf = vmalloc(1024); + if (!empty_buf) { + printk(KERN_WARNING "Failed to allocate 1024 bytes for dummy buffer\n"); + return -ENOMEM; + } + memset (empty_buf, 0, 1024); +#endif + /* first copy the parameters from user space */ memset(&psinfo, 0, sizeof(psinfo)); { @@ -1154,7 +1326,15 @@ has_dumped = 1; current->flags |= PF_DUMPCORE; +#ifdef CONFIG_GZIP_COREDUMPS + /* write gzip header */ + DUMP_WRITE(gz_magic, 10); + + /* write elf header */ + DUMP_GZ(&elf, sizeof(elf), &crc, &gz_stream); +#else DUMP_WRITE(&elf, sizeof(elf)); +#endif offset += sizeof(elf); /* Elf header */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ @@ -1239,7 +1419,12 @@ phdr.p_align = 0; offset += phdr.p_filesz; + +#ifdef CONFIG_GZIP_COREDUMPS + DUMP_GZ(&phdr, sizeof(phdr), &crc, &gz_stream); +#else DUMP_WRITE(&phdr, sizeof(phdr)); +#endif } /* Page-align dumped data */ @@ -1264,14 +1449,27 @@ if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; phdr.p_align = ELF_EXEC_PAGESIZE; +#ifdef CONFIG_GZIP_COREDUMPS + DUMP_GZ(&phdr, sizeof(phdr), &crc, &gz_stream); +#else DUMP_WRITE(&phdr, sizeof(phdr)); +#endif } - for(i = 0; i < numnote; i++) + for(i = 0; i < numnote; i++) { +#ifdef CONFIG_GZIP_COREDUMPS + if (!writenote_gz(¬es[i], file, empty_buf, &crc, &gz_stream)) + goto end_coredump; +#else if (!writenote(¬es[i], file)) goto end_coredump; - +#endif + } +#ifdef CONFIG_GZIP_COREDUMPS + PAD_GZ (dataoff-gz_stream.total_in, empty_buf, &crc, &gz_stream); +#else DUMP_SEEK(dataoff); +#endif for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { unsigned long addr; @@ -1290,16 +1488,28 @@ struct vm_area_struct *vma; if (get_user_pages(current, current->mm, addr, 1, 0, 1, - &page, &vma) <= 0) { - DUMP_SEEK (file->f_pos + PAGE_SIZE); + &page, &vma) <= 0) { +#ifdef CONFIG_GZIP_COREDUMPS + PAD_GZ(PAGE_SIZE, empty_buf, &crc, &gz_stream); +#else + DUMP_SEEK (file->f_pos + PAGE_SIZE); +#endif } else { - if (page == ZERO_PAGE(addr)) { - DUMP_SEEK (file->f_pos + PAGE_SIZE); + if (page == ZERO_PAGE(addr)) { +#ifdef CONFIG_GZIP_COREDUMPS + PAD_GZ(PAGE_SIZE, empty_buf, &crc, &gz_stream); +#else + DUMP_SEEK (file->f_pos + PAGE_SIZE); +#endif } else { void *kaddr; flush_cache_page(vma, addr); kaddr = kmap(page); +#ifdef CONFIG_GZIP_COREDUMPS + DUMP_GZ(kaddr, PAGE_SIZE, &crc, &gz_stream); +#else DUMP_WRITE(kaddr, PAGE_SIZE); +#endif flush_page_to_ram(page); kunmap(page); } @@ -1308,15 +1518,37 @@ } } +#ifndef CONFIG_GZIP_COREDUMPS if ((off_t) file->f_pos != offset) { /* Sanity check */ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t) file->f_pos, offset); } +#endif - end_coredump: +end_coredump: +#ifdef CONFIG_GZIP_COREDUMPS + gz_finish (file, &gz_stream); + zlib_deflateEnd (&gz_stream); + + gz_magic[0] = (~crc & 0x000000FF); + gz_magic[1] = (~crc & 0x0000FF00) >> 8; + gz_magic[2] = (~crc & 0x00FF0000) >> 16; + gz_magic[3] = (~crc & 0xFF000000) >> 24; + gz_magic[4] = (gz_stream.total_in & 0x000000FF); + gz_magic[5] = (gz_stream.total_in & 0x0000FF00) >> 8; + gz_magic[6] = (gz_stream.total_in & 0x00FF0000) >> 16; + gz_magic[7] = (gz_stream.total_in & 0xFF000000) >> 24; + dump_write (file, gz_magic, 8); +#endif set_fs(fs); up_write(¤t->mm->mmap_sem); + +#ifdef CONFIG_GZIP_COREDUMPS + vfree (deflate_workspace); + vfree (empty_buf); +#endif + return has_dumped; } #endif /* USE_ELF_CORE_DUMP */ diff -ur linux-2.4.28/lib/Config.in linux-2.4.28-gzip-coredump/lib/Config.in --- linux-2.4.28/lib/Config.in 2003-11-28 19:26:21.000000000 +0100 +++ linux-2.4.28-gzip-coredump/lib/Config.in 2005-01-10 08:46:00.000000000 +0100 @@ -27,7 +27,8 @@ fi fi -if [ "$CONFIG_PPP_DEFLATE" = "y" -o \ +if [ "$CONFIG_GZIP_COREDUMPS" = "y" -o \ + "$CONFIG_PPP_DEFLATE" = "y" -o \ "$CONFIG_CRYPTO_DEFLATE" = "y" -o \ "$CONFIG_JFFS2_FS" = "y" ]; then define_tristate CONFIG_ZLIB_DEFLATE y