aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-10-17 02:27:02 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:42:52 -0400
commit82df39738ba9e02c057fa99b7461a56117d36119 (patch)
treeef4d37689eb31c59e03cc066cb1210a9ddb9f744
parente629a7ddc0188e1bb9e956e698a9bd00c19c9854 (diff)
Add MMF_DUMP_ELF_HEADERS
This adds the MMF_DUMP_ELF_HEADERS option to /proc/pid/coredump_filter. This dumps the first page (only) of a private file mapping if it appears to be a mapping of an ELF file. Including these pages in the core dump may give sufficient identifying information to associate the original DSO and executable file images and their debugging information with a core file in a generic way just from its contents (e.g. when those binaries were built with ld --build-id). I expect this to become the default behavior eventually. Existing versions of gdb can be confused by the core dumps it creates, so it won't enabled by default for some time to come. Soon many people will have systems with a gdb that handle these dumps, so they can arrange to set the bit at boot and have it inherited system-wide. This also cleans up the checking of the MMF_DUMP_* flag bits, which did not need to be using atomic macros. Signed-off-by: Roland McGrath <roland@redhat.com> Cc: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/binfmt_elf.c78
-rw-r--r--include/linux/sched.h3
2 files changed, 55 insertions, 26 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 66cd711a6b1a..4263326ede04 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1201,35 +1201,68 @@ static int dump_seek(struct file *file, loff_t off)
1201} 1201}
1202 1202
1203/* 1203/*
1204 * Decide whether a segment is worth dumping; default is yes to be 1204 * Decide what to dump of a segment, part, all or none.
1205 * sure (missing info is worse than too much; etc).
1206 * Personally I'd include everything, and use the coredump limit...
1207 *
1208 * I think we should skip something. But I am not sure how. H.J.
1209 */ 1205 */
1210static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) 1206static unsigned long vma_dump_size(struct vm_area_struct *vma,
1207 unsigned long mm_flags)
1211{ 1208{
1212 /* The vma can be set up to tell us the answer directly. */ 1209 /* The vma can be set up to tell us the answer directly. */
1213 if (vma->vm_flags & VM_ALWAYSDUMP) 1210 if (vma->vm_flags & VM_ALWAYSDUMP)
1214 return 1; 1211 goto whole;
1215 1212
1216 /* Do not dump I/O mapped devices or special mappings */ 1213 /* Do not dump I/O mapped devices or special mappings */
1217 if (vma->vm_flags & (VM_IO | VM_RESERVED)) 1214 if (vma->vm_flags & (VM_IO | VM_RESERVED))
1218 return 0; 1215 return 0;
1219 1216
1217#define FILTER(type) (mm_flags & (1UL << MMF_DUMP_##type))
1218
1220 /* By default, dump shared memory if mapped from an anonymous file. */ 1219 /* By default, dump shared memory if mapped from an anonymous file. */
1221 if (vma->vm_flags & VM_SHARED) { 1220 if (vma->vm_flags & VM_SHARED) {
1222 if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) 1221 if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0 ?
1223 return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); 1222 FILTER(ANON_SHARED) : FILTER(MAPPED_SHARED))
1224 else 1223 goto whole;
1225 return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); 1224 return 0;
1226 } 1225 }
1227 1226
1228 /* By default, if it hasn't been written to, don't write it out. */ 1227 /* Dump segments that have been written to. */
1229 if (!vma->anon_vma) 1228 if (vma->anon_vma && FILTER(ANON_PRIVATE))
1230 return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); 1229 goto whole;
1230 if (vma->vm_file == NULL)
1231 return 0;
1231 1232
1232 return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); 1233 if (FILTER(MAPPED_PRIVATE))
1234 goto whole;
1235
1236 /*
1237 * If this looks like the beginning of a DSO or executable mapping,
1238 * check for an ELF header. If we find one, dump the first page to
1239 * aid in determining what was mapped here.
1240 */
1241 if (FILTER(ELF_HEADERS) && vma->vm_file != NULL && vma->vm_pgoff == 0) {
1242 u32 __user *header = (u32 __user *) vma->vm_start;
1243 u32 word;
1244 /*
1245 * Doing it this way gets the constant folded by GCC.
1246 */
1247 union {
1248 u32 cmp;
1249 char elfmag[SELFMAG];
1250 } magic;
1251 BUILD_BUG_ON(SELFMAG != sizeof word);
1252 magic.elfmag[EI_MAG0] = ELFMAG0;
1253 magic.elfmag[EI_MAG1] = ELFMAG1;
1254 magic.elfmag[EI_MAG2] = ELFMAG2;
1255 magic.elfmag[EI_MAG3] = ELFMAG3;
1256 if (get_user(word, header) == 0 && word == magic.cmp)
1257 return PAGE_SIZE;
1258 }
1259
1260#undef FILTER
1261
1262 return 0;
1263
1264whole:
1265 return vma->vm_end - vma->vm_start;
1233} 1266}
1234 1267
1235/* An ELF note in memory */ 1268/* An ELF note in memory */
@@ -1669,16 +1702,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1669 for (vma = first_vma(current, gate_vma); vma != NULL; 1702 for (vma = first_vma(current, gate_vma); vma != NULL;
1670 vma = next_vma(vma, gate_vma)) { 1703 vma = next_vma(vma, gate_vma)) {
1671 struct elf_phdr phdr; 1704 struct elf_phdr phdr;
1672 size_t sz;
1673
1674 sz = vma->vm_end - vma->vm_start;
1675 1705
1676 phdr.p_type = PT_LOAD; 1706 phdr.p_type = PT_LOAD;
1677 phdr.p_offset = offset; 1707 phdr.p_offset = offset;
1678 phdr.p_vaddr = vma->vm_start; 1708 phdr.p_vaddr = vma->vm_start;
1679 phdr.p_paddr = 0; 1709 phdr.p_paddr = 0;
1680 phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0; 1710 phdr.p_filesz = vma_dump_size(vma, mm_flags);
1681 phdr.p_memsz = sz; 1711 phdr.p_memsz = vma->vm_end - vma->vm_start;
1682 offset += phdr.p_filesz; 1712 offset += phdr.p_filesz;
1683 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; 1713 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
1684 if (vma->vm_flags & VM_WRITE) 1714 if (vma->vm_flags & VM_WRITE)
@@ -1718,13 +1748,11 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1718 for (vma = first_vma(current, gate_vma); vma != NULL; 1748 for (vma = first_vma(current, gate_vma); vma != NULL;
1719 vma = next_vma(vma, gate_vma)) { 1749 vma = next_vma(vma, gate_vma)) {
1720 unsigned long addr; 1750 unsigned long addr;
1751 unsigned long end;
1721 1752
1722 if (!maydump(vma, mm_flags)) 1753 end = vma->vm_start + vma_dump_size(vma, mm_flags);
1723 continue;
1724 1754
1725 for (addr = vma->vm_start; 1755 for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
1726 addr < vma->vm_end;
1727 addr += PAGE_SIZE) {
1728 struct page *page; 1756 struct page *page;
1729 struct vm_area_struct *vma; 1757 struct vm_area_struct *vma;
1730 1758
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e643357eda05..cb952bc225e4 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -359,8 +359,9 @@ extern int get_dumpable(struct mm_struct *mm);
359#define MMF_DUMP_ANON_SHARED 3 359#define MMF_DUMP_ANON_SHARED 3
360#define MMF_DUMP_MAPPED_PRIVATE 4 360#define MMF_DUMP_MAPPED_PRIVATE 4
361#define MMF_DUMP_MAPPED_SHARED 5 361#define MMF_DUMP_MAPPED_SHARED 5
362#define MMF_DUMP_ELF_HEADERS 6
362#define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS 363#define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS
363#define MMF_DUMP_FILTER_BITS 4 364#define MMF_DUMP_FILTER_BITS 5
364#define MMF_DUMP_FILTER_MASK \ 365#define MMF_DUMP_FILTER_MASK \
365 (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) 366 (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT)
366#define MMF_DUMP_FILTER_DEFAULT \ 367#define MMF_DUMP_FILTER_DEFAULT \