--- linux-2.6.16.51/fs/binfmt_elf.c 2007-07-30 18:31:50.000000000 -0700 +++ linux-2.6.16.51/fs/binfmt_elf.c 2007-07-31 00:38:18.000000000 -0700 @@ -9,6 +9,7 @@ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). */ +#include #include #include #include @@ -60,6 +61,20 @@ */ #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) 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 + * Mano Pallewatta + */ +#include +#include +#include +#endif + + #else #define elf_core_dump NULL #endif @@ -1122,18 +1137,67 @@ /* * ELF core dumper * - * Modelled on fs/exec.c:aout_core_dump() - * Jeremy Fitzhardinge - */ -/* - * 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 + * Mano Pallewatta */ -static int dump_write(struct file *file, const void *addr, int nr) +#ifdef CONFIG_GZIP_COREDUMPS + +#define OUT_BUF_SIZE 100*1024 + +static int gz_dump_write(struct file *file, const void *addr, int nr, u32 *crc, z_streamp zstr, void *out_buf) { - return file->f_op->write(file, addr, nr, &file->f_pos) == nr; + int all_fine = 1; + + *crc = crc32_le (*crc, addr, nr); + + zstr->next_in = (void *)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); + + return all_fine; } +static int gz_finish (struct file *file, z_streamp zstr, void *out_buf) +{ + int all_fine = 1; + int ret; + + 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)); + + return all_fine; +} + +#else static int dump_seek(struct file *file, loff_t off) { if (file->f_op->llseek) { @@ -1143,6 +1207,15 @@ file->f_pos = off; return 1; } +#endif +/* + * 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_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 @@ -1189,12 +1262,55 @@ return sz; } +#ifdef CONFIG_GZIP_COREDUMPS +#define PAD_GZ(nr, buf, crc, str, out_buf) \ + do { \ + int cur=(nr); \ + while (cur>1024) { \ + gz_dump_write(file, (buf), 1024, (crc), (str), (out_buf)); \ + cur-=1024; \ + } \ + if (cur) { \ + gz_dump_write(file, (buf), cur, (crc), (str), (out_buf)); \ + } \ + } while(0) -#define DUMP_WRITE(addr, nr) \ - do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) +#define DUMP_GZ(addr, nr, crc, str, out_buf) \ + do { if (!gz_dump_write(file, (addr), (nr), (crc), (str), (out_buf))) 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, void *out_buf) +{ + struct elf_note en; + int dummy_bytes; + + en.n_namesz = strlen(men->name)+1; + en.n_descsz = men->datasz; + en.n_type = men->type; + + DUMP_GZ(&en, sizeof(en), crc, zstr, out_buf); + DUMP_GZ(men->name, en.n_namesz, crc, zstr, out_buf); + + dummy_bytes = roundup((unsigned long)zstr->total_in, 4) - zstr->total_in; + PAD_GZ(dummy_bytes, buf, crc, zstr, out_buf); + + DUMP_GZ(men->data, men->datasz, crc, zstr, out_buf); + + dummy_bytes = roundup((unsigned long)zstr->total_in, 4) - zstr->total_in; + PAD_GZ(dummy_bytes, buf, crc, zstr, out_buf); + return 1; +} +#undef DUMP_GZ +#else static int writenote(struct memelfnote *men, struct file *file) { struct elf_note en; @@ -1214,13 +1330,20 @@ } #undef DUMP_WRITE #undef DUMP_SEEK +#endif +#ifdef CONFIG_GZIP_COREDUMPS +#define DUMP_GZ(addr, nr, crc, str, out_buf) \ + if ((size += (nr)) > limit || !gz_dump_write(file, (addr), (nr), (crc), (str), (out_buf))) \ + 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 static void fill_elf_header(struct elfhdr *elf, int segs) { @@ -1424,6 +1547,52 @@ #endif int thread_status_size = 0; elf_addr_t *auxv; +#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 }; + void *out_buf = NULL; + void *empty_buf = NULL; + + out_buf = vmalloc(OUT_BUF_SIZE); + if (!out_buf) { + printk(KERN_WARNING "Failed to allocate deflate buffer"); + return -ENOMEM; + } + + empty_buf = vmalloc(1024); + if (!empty_buf) { + vfree(out_buf); + printk(KERN_WARNING "Failed to allocate memory for dummy buffer\n"); + return -ENOMEM; + } + + deflate_workspace = vmalloc(zlib_deflate_workspacesize()); + if (!deflate_workspace) { + vfree(out_buf); + vfree(empty_buf); + 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"); + vfree(out_buf); + vfree(empty_buf); + vfree(deflate_workspace); + return -ENOMEM; + } + + memset (empty_buf, 0, 1024); +#endif /* * We no longer stop all VM operations. @@ -1535,7 +1704,15 @@ fs = get_fs(); set_fs(KERNEL_DS); +#ifdef CONFIG_GZIP_COREDUMPS + /* write gzip header */ + DUMP_WRITE(gz_magic, 10); + + /* write elf header */ + DUMP_GZ(elf, sizeof(*elf), &crc, &gz_stream, out_buf); +#else DUMP_WRITE(elf, sizeof(*elf)); +#endif offset += sizeof(*elf); /* Elf header */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ @@ -1551,7 +1728,12 @@ fill_elf_note_phdr(&phdr, sz, offset); offset += sz; + +#ifdef CONFIG_GZIP_COREDUMPS + DUMP_GZ(&phdr, sizeof(phdr), &crc, &gz_stream, out_buf); +#else DUMP_WRITE(&phdr, sizeof(phdr)); +#endif } /* Page-align dumped data */ @@ -1576,7 +1758,11 @@ 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, out_buf); +#else DUMP_WRITE(&phdr, sizeof(phdr)); +#endif } #ifdef ELF_CORE_WRITE_EXTRA_PHDRS @@ -1585,18 +1771,30 @@ /* write out the notes section */ for (i = 0; i < numnote; i++) +#ifdef CONFIG_GZIP_COREDUMPS + if (!writenote_gz(notes + i, file, empty_buf, &crc, &gz_stream, out_buf)) +#else if (!writenote(notes + i, file)) +#endif goto end_coredump; /* write out the thread status notes section */ list_for_each(t, &thread_list) { struct elf_thread_status *tmp = list_entry(t, struct elf_thread_status, list); for (i = 0; i < tmp->num_notes; i++) +#ifdef CONFIG_GZIP_COREDUMPS + if (!writenote_gz(&tmp->notes[i], file, empty_buf, &crc, &gz_stream, out_buf)) +#else if (!writenote(&tmp->notes[i], file)) +#endif goto end_coredump; } +#ifdef CONFIG_GZIP_COREDUMPS + PAD_GZ (dataoff-gz_stream.total_in, empty_buf, &crc, &gz_stream, out_buf); +#else DUMP_SEEK(dataoff); +#endif for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { unsigned long addr; @@ -1612,17 +1810,30 @@ if (get_user_pages(current, current->mm, addr, 1, 0, 1, &page, &vma) <= 0) { +#ifdef CONFIG_GZIP_COREDUMPS + PAD_GZ(PAGE_SIZE, empty_buf, &crc, &gz_stream, out_buf); +#else DUMP_SEEK (file->f_pos + PAGE_SIZE); +#endif } else { if (page == ZERO_PAGE(addr)) { - DUMP_SEEK (file->f_pos + PAGE_SIZE); +#ifdef CONFIG_GZIP_COREDUMPS + PAD_GZ(PAGE_SIZE, empty_buf, &crc, &gz_stream, out_buf); +#else + DUMP_SEEK (file->f_pos + PAGE_SIZE); +#endif } else { void *kaddr; flush_cache_page(vma, addr, page_to_pfn(page)); kaddr = kmap(page); if ((size += PAGE_SIZE) > limit || +#ifdef CONFIG_GZIP_COREDUMPS + !gz_dump_write(file, kaddr, + PAGE_SIZE, &crc, &gz_stream, out_buf)) { +#else !dump_write(file, kaddr, PAGE_SIZE)) { +#endif kunmap(page); page_cache_release(page); goto end_coredump; @@ -1638,13 +1849,29 @@ ELF_CORE_WRITE_EXTRA_DATA; #endif +#ifndef CONFIG_GZIP_COREDUMPS if ((off_t)file->f_pos != offset) { /* Sanity check */ printk(KERN_WARNING "elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t)file->f_pos, offset); } +#endif end_coredump: +#ifdef CONFIG_GZIP_COREDUMPS + gz_finish (file, &gz_stream, out_buf); + 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); cleanup: @@ -1662,6 +1889,12 @@ #ifdef ELF_CORE_COPY_XFPREGS kfree(xfpu); #endif + +#ifdef CONFIG_GZIP_COREDUMPS + vfree (deflate_workspace); + vfree (empty_buf); + vfree (out_buf); +#endif return has_dumped; #undef NUM_NOTES } --- linux-2.6.16.51/fs/exec.c 2007-07-30 18:31:51.000000000 -0700 +++ linux-2.6.16.51/fs/exec.c 2007-07-31 00:25:05.000000000 -0700 @@ -1366,6 +1366,15 @@ out_ptr += rc; } out: +#ifdef CONFIG_GZIP_COREDUMPS + if (strncmp(out_ptr-3,".gz",3)) { + rc = snprintf(out_ptr, out_end - out_ptr,"%s",".gz"); + if (rc > out_end - out_ptr) + goto out1; + out_ptr += rc; + } +#endif + out1: *out_ptr = 0; } --- linux-2.6.16.51/fs/Kconfig 2007-07-30 18:31:50.000000000 -0700 +++ linux-2.6.16.51/fs/Kconfig 2007-07-31 00:25:05.000000000 -0700 @@ -802,6 +802,12 @@ help Exports the dump image of crashed kernel in ELF format. +config GZIP_COREDUMPS + bool "Write gzipped core dump files" + default n + select ZLIB_DEFLATE + select CRC32 + config SYSFS bool "sysfs file system support" if EMBEDDED default y --- linux-2.6.16.51/include/asm-i386/elf.h 2007-08-15 00:59:49.000000000 -0700 +++ linux-2.6.16.51/include/asm-i386/elf.h 2007-08-15 09:39:12.000000000 -0700 @@ -149,6 +149,8 @@ * a debugger needs to easily find how the vsyscall DSO was being used. */ #define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum) + +#ifdef CONFIG_GZIP_COREDUMPS #define ELF_CORE_WRITE_EXTRA_PHDRS \ do { \ const struct elf_phdr *const vsyscall_phdrs = \ @@ -168,9 +170,49 @@ else \ phdr.p_offset += ofs; \ phdr.p_paddr = 0; /* match other core phdrs */ \ - DUMP_WRITE(&phdr, sizeof(phdr)); \ + DUMP_GZ(&phdr, sizeof(phdr), &crc, &gz_stream, out_buf); \ } \ } while (0) +#else +#define ELF_CORE_WRITE_EXTRA_PHDRS \ +do { \ + const struct elf_phdr *const vsyscall_phdrs = \ + (const struct elf_phdr *) (VSYSCALL_BASE \ + + VSYSCALL_EHDR->e_phoff); \ + int i; \ + Elf32_Off ofs = 0; \ + for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + struct elf_phdr phdr = vsyscall_phdrs[i]; \ + if (phdr.p_type == PT_LOAD) { \ + BUG_ON(ofs != 0); \ + ofs = phdr.p_offset = offset; \ + phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz); \ + phdr.p_filesz = phdr.p_memsz; \ + offset += phdr.p_filesz; \ + } \ + else \ + phdr.p_offset += ofs; \ + phdr.p_paddr = 0; /* match other core phdrs */ \ + DUMP_WRITE(&phdr, sizeof(phdr)); \ + } \ +} while (0) +#endif + +#ifdef CONFIG_GZIP_COREDUMPS +#define ELF_CORE_WRITE_EXTRA_DATA \ +do { \ + const struct elf_phdr *const vsyscall_phdrs = \ + (const struct elf_phdr *) (VSYSCALL_BASE \ + + VSYSCALL_EHDR->e_phoff); \ + int i; \ + for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + if (vsyscall_phdrs[i].p_type == PT_LOAD) \ + DUMP_GZ((void *) vsyscall_phdrs[i].p_vaddr, \ + PAGE_ALIGN(vsyscall_phdrs[i].p_memsz), \ + &crc, &gz_stream, out_buf); \ + } \ +} while (0) +#else #define ELF_CORE_WRITE_EXTRA_DATA \ do { \ const struct elf_phdr *const vsyscall_phdrs = \ @@ -183,6 +225,7 @@ PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \ } \ } while (0) +#endif #endif