aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-01-30 07:31:44 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:44 -0500
commit3aba481fc94d83ff630d4b7cd2f7447010c4c6df (patch)
treef953d24b736fa9404ad1e8e6138c056f0717a297
parentbdf88217b70dbb18c4ee27a6c497286e040a6705 (diff)
elf core dump: notes reorg
This pulls out the code for writing the notes segment of an ELF core dump into separate functions. This cleanly isolates into one cluster of functions everything that deals with the note formats and the hooks into arch code to fill them. The top-level elf_core_dump function itself now deals purely with the generic ELF format and the memory segments. This only moves code around into functions that can be inlined away. It should not change any behavior at all. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--fs/binfmt_elf.c324
1 files changed, 194 insertions, 130 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index b8bca1ebc1a0..4510429b973e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1395,7 +1395,8 @@ static int writenote(struct memelfnote *men, struct file *file,
1395 if (!dump_seek(file, (off))) \ 1395 if (!dump_seek(file, (off))) \
1396 goto end_coredump; 1396 goto end_coredump;
1397 1397
1398static void fill_elf_header(struct elfhdr *elf, int segs) 1398static void fill_elf_header(struct elfhdr *elf, int segs,
1399 u16 machine, u32 flags, u8 osabi)
1399{ 1400{
1400 memcpy(elf->e_ident, ELFMAG, SELFMAG); 1401 memcpy(elf->e_ident, ELFMAG, SELFMAG);
1401 elf->e_ident[EI_CLASS] = ELF_CLASS; 1402 elf->e_ident[EI_CLASS] = ELF_CLASS;
@@ -1405,12 +1406,12 @@ static void fill_elf_header(struct elfhdr *elf, int segs)
1405 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); 1406 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
1406 1407
1407 elf->e_type = ET_CORE; 1408 elf->e_type = ET_CORE;
1408 elf->e_machine = ELF_ARCH; 1409 elf->e_machine = machine;
1409 elf->e_version = EV_CURRENT; 1410 elf->e_version = EV_CURRENT;
1410 elf->e_entry = 0; 1411 elf->e_entry = 0;
1411 elf->e_phoff = sizeof(struct elfhdr); 1412 elf->e_phoff = sizeof(struct elfhdr);
1412 elf->e_shoff = 0; 1413 elf->e_shoff = 0;
1413 elf->e_flags = ELF_CORE_EFLAGS; 1414 elf->e_flags = flags;
1414 elf->e_ehsize = sizeof(struct elfhdr); 1415 elf->e_ehsize = sizeof(struct elfhdr);
1415 elf->e_phentsize = sizeof(struct elf_phdr); 1416 elf->e_phentsize = sizeof(struct elf_phdr);
1416 elf->e_phnum = segs; 1417 elf->e_phnum = segs;
@@ -1517,6 +1518,16 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
1517 return 0; 1518 return 0;
1518} 1519}
1519 1520
1521static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
1522{
1523 elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv;
1524 int i = 0;
1525 do
1526 i += 2;
1527 while (auxv[i - 2] != AT_NULL);
1528 fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv);
1529}
1530
1520/* Here is the structure in which status of each thread is captured. */ 1531/* Here is the structure in which status of each thread is captured. */
1521struct elf_thread_status 1532struct elf_thread_status
1522{ 1533{
@@ -1569,6 +1580,174 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
1569 return sz; 1580 return sz;
1570} 1581}
1571 1582
1583struct elf_note_info {
1584 struct memelfnote *notes;
1585 struct elf_prstatus *prstatus; /* NT_PRSTATUS */
1586 struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */
1587 struct list_head thread_list;
1588 elf_fpregset_t *fpu;
1589#ifdef ELF_CORE_COPY_XFPREGS
1590 elf_fpxregset_t *xfpu;
1591#endif
1592 int thread_status_size;
1593 int numnote;
1594};
1595
1596static int fill_note_info(struct elfhdr *elf, int phdrs,
1597 struct elf_note_info *info,
1598 long signr, struct pt_regs *regs)
1599{
1600#define NUM_NOTES 6
1601 struct list_head *t;
1602 struct task_struct *g, *p;
1603
1604 info->notes = NULL;
1605 info->prstatus = NULL;
1606 info->psinfo = NULL;
1607 info->fpu = NULL;
1608#ifdef ELF_CORE_COPY_XFPREGS
1609 info->xfpu = NULL;
1610#endif
1611 INIT_LIST_HEAD(&info->thread_list);
1612
1613 info->notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote),
1614 GFP_KERNEL);
1615 if (!info->notes)
1616 return 0;
1617 info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
1618 if (!info->psinfo)
1619 return 0;
1620 info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL);
1621 if (!info->prstatus)
1622 return 0;
1623 info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
1624 if (!info->fpu)
1625 return 0;
1626#ifdef ELF_CORE_COPY_XFPREGS
1627 info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL);
1628 if (!info->xfpu)
1629 return 0;
1630#endif
1631
1632 info->thread_status_size = 0;
1633 if (signr) {
1634 struct elf_thread_status *tmp;
1635 rcu_read_lock();
1636 do_each_thread(g, p)
1637 if (current->mm == p->mm && current != p) {
1638 tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
1639 if (!tmp) {
1640 rcu_read_unlock();
1641 return 0;
1642 }
1643 tmp->thread = p;
1644 list_add(&tmp->list, &info->thread_list);
1645 }
1646 while_each_thread(g, p);
1647 rcu_read_unlock();
1648 list_for_each(t, &info->thread_list) {
1649 struct elf_thread_status *tmp;
1650 int sz;
1651
1652 tmp = list_entry(t, struct elf_thread_status, list);
1653 sz = elf_dump_thread_status(signr, tmp);
1654 info->thread_status_size += sz;
1655 }
1656 }
1657 /* now collect the dump for the current */
1658 memset(info->prstatus, 0, sizeof(*info->prstatus));
1659 fill_prstatus(info->prstatus, current, signr);
1660 elf_core_copy_regs(&info->prstatus->pr_reg, regs);
1661
1662 /* Set up header */
1663 fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS, ELF_OSABI);
1664
1665 /*
1666 * Set up the notes in similar form to SVR4 core dumps made
1667 * with info from their /proc.
1668 */
1669
1670 fill_note(info->notes + 0, "CORE", NT_PRSTATUS,
1671 sizeof(*info->prstatus), info->prstatus);
1672 fill_psinfo(info->psinfo, current->group_leader, current->mm);
1673 fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
1674 sizeof(*info->psinfo), info->psinfo);
1675
1676 info->numnote = 2;
1677
1678 fill_auxv_note(&info->notes[info->numnote++], current->mm);
1679
1680 /* Try to dump the FPU. */
1681 info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs,
1682 info->fpu);
1683 if (info->prstatus->pr_fpvalid)
1684 fill_note(info->notes + info->numnote++,
1685 "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
1686#ifdef ELF_CORE_COPY_XFPREGS
1687 if (elf_core_copy_task_xfpregs(current, info->xfpu))
1688 fill_note(info->notes + info->numnote++,
1689 "LINUX", ELF_CORE_XFPREG_TYPE,
1690 sizeof(*info->xfpu), info->xfpu);
1691#endif
1692
1693 return 1;
1694
1695#undef NUM_NOTES
1696}
1697
1698static size_t get_note_info_size(struct elf_note_info *info)
1699{
1700 int sz = 0;
1701 int i;
1702
1703 for (i = 0; i < info->numnote; i++)
1704 sz += notesize(info->notes + i);
1705
1706 sz += info->thread_status_size;
1707
1708 return sz;
1709}
1710
1711static int write_note_info(struct elf_note_info *info,
1712 struct file *file, loff_t *foffset)
1713{
1714 int i;
1715 struct list_head *t;
1716
1717 for (i = 0; i < info->numnote; i++)
1718 if (!writenote(info->notes + i, file, foffset))
1719 return 0;
1720
1721 /* write out the thread status notes section */
1722 list_for_each(t, &info->thread_list) {
1723 struct elf_thread_status *tmp =
1724 list_entry(t, struct elf_thread_status, list);
1725
1726 for (i = 0; i < tmp->num_notes; i++)
1727 if (!writenote(&tmp->notes[i], file, foffset))
1728 return 0;
1729 }
1730
1731 return 1;
1732}
1733
1734static void free_note_info(struct elf_note_info *info)
1735{
1736 while (!list_empty(&info->thread_list)) {
1737 struct list_head *tmp = info->thread_list.next;
1738 list_del(tmp);
1739 kfree(list_entry(tmp, struct elf_thread_status, list));
1740 }
1741
1742 kfree(info->prstatus);
1743 kfree(info->psinfo);
1744 kfree(info->notes);
1745 kfree(info->fpu);
1746#ifdef ELF_CORE_COPY_XFPREGS
1747 kfree(info->xfpu);
1748#endif
1749}
1750
1572static struct vm_area_struct *first_vma(struct task_struct *tsk, 1751static struct vm_area_struct *first_vma(struct task_struct *tsk,
1573 struct vm_area_struct *gate_vma) 1752 struct vm_area_struct *gate_vma)
1574{ 1753{
@@ -1604,29 +1783,15 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
1604 */ 1783 */
1605static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) 1784static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
1606{ 1785{
1607#define NUM_NOTES 6
1608 int has_dumped = 0; 1786 int has_dumped = 0;
1609 mm_segment_t fs; 1787 mm_segment_t fs;
1610 int segs; 1788 int segs;
1611 size_t size = 0; 1789 size_t size = 0;
1612 int i;
1613 struct vm_area_struct *vma, *gate_vma; 1790 struct vm_area_struct *vma, *gate_vma;
1614 struct elfhdr *elf = NULL; 1791 struct elfhdr *elf = NULL;
1615 loff_t offset = 0, dataoff, foffset; 1792 loff_t offset = 0, dataoff, foffset;
1616 int numnote;
1617 struct memelfnote *notes = NULL;
1618 struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
1619 struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */
1620 struct task_struct *g, *p;
1621 LIST_HEAD(thread_list);
1622 struct list_head *t;
1623 elf_fpregset_t *fpu = NULL;
1624#ifdef ELF_CORE_COPY_XFPREGS
1625 elf_fpxregset_t *xfpu = NULL;
1626#endif
1627 int thread_status_size = 0;
1628 elf_addr_t *auxv;
1629 unsigned long mm_flags; 1793 unsigned long mm_flags;
1794 struct elf_note_info info;
1630 1795
1631 /* 1796 /*
1632 * We no longer stop all VM operations. 1797 * We no longer stop all VM operations.
@@ -1644,52 +1809,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1644 elf = kmalloc(sizeof(*elf), GFP_KERNEL); 1809 elf = kmalloc(sizeof(*elf), GFP_KERNEL);
1645 if (!elf) 1810 if (!elf)
1646 goto cleanup; 1811 goto cleanup;
1647 prstatus = kmalloc(sizeof(*prstatus), GFP_KERNEL);
1648 if (!prstatus)
1649 goto cleanup;
1650 psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
1651 if (!psinfo)
1652 goto cleanup;
1653 notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL);
1654 if (!notes)
1655 goto cleanup;
1656 fpu = kmalloc(sizeof(*fpu), GFP_KERNEL);
1657 if (!fpu)
1658 goto cleanup;
1659#ifdef ELF_CORE_COPY_XFPREGS
1660 xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL);
1661 if (!xfpu)
1662 goto cleanup;
1663#endif
1664
1665 if (signr) {
1666 struct elf_thread_status *tmp;
1667 rcu_read_lock();
1668 do_each_thread(g,p)
1669 if (current->mm == p->mm && current != p) {
1670 tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
1671 if (!tmp) {
1672 rcu_read_unlock();
1673 goto cleanup;
1674 }
1675 tmp->thread = p;
1676 list_add(&tmp->list, &thread_list);
1677 }
1678 while_each_thread(g,p);
1679 rcu_read_unlock();
1680 list_for_each(t, &thread_list) {
1681 struct elf_thread_status *tmp;
1682 int sz;
1683
1684 tmp = list_entry(t, struct elf_thread_status, list);
1685 sz = elf_dump_thread_status(signr, tmp);
1686 thread_status_size += sz;
1687 }
1688 }
1689 /* now collect the dump for the current */
1690 memset(prstatus, 0, sizeof(*prstatus));
1691 fill_prstatus(prstatus, current, signr);
1692 elf_core_copy_regs(&prstatus->pr_reg, regs);
1693 1812
1694 segs = current->mm->map_count; 1813 segs = current->mm->map_count;
1695#ifdef ELF_CORE_EXTRA_PHDRS 1814#ifdef ELF_CORE_EXTRA_PHDRS
@@ -1700,42 +1819,16 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1700 if (gate_vma != NULL) 1819 if (gate_vma != NULL)
1701 segs++; 1820 segs++;
1702 1821
1703 /* Set up header */
1704 fill_elf_header(elf, segs + 1); /* including notes section */
1705
1706 has_dumped = 1;
1707 current->flags |= PF_DUMPCORE;
1708
1709 /* 1822 /*
1710 * Set up the notes in similar form to SVR4 core dumps made 1823 * Collect all the non-memory information about the process for the
1711 * with info from their /proc. 1824 * notes. This also sets up the file header.
1712 */ 1825 */
1826 if (!fill_note_info(elf, segs + 1, /* including notes section */
1827 &info, signr, regs))
1828 goto cleanup;
1713 1829
1714 fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); 1830 has_dumped = 1;
1715 fill_psinfo(psinfo, current->group_leader, current->mm); 1831 current->flags |= PF_DUMPCORE;
1716 fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
1717
1718 numnote = 2;
1719
1720 auxv = (elf_addr_t *)current->mm->saved_auxv;
1721
1722 i = 0;
1723 do
1724 i += 2;
1725 while (auxv[i - 2] != AT_NULL);
1726 fill_note(&notes[numnote++], "CORE", NT_AUXV,
1727 i * sizeof(elf_addr_t), auxv);
1728
1729 /* Try to dump the FPU. */
1730 if ((prstatus->pr_fpvalid =
1731 elf_core_copy_task_fpregs(current, regs, fpu)))
1732 fill_note(notes + numnote++,
1733 "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
1734#ifdef ELF_CORE_COPY_XFPREGS
1735 if (elf_core_copy_task_xfpregs(current, xfpu))
1736 fill_note(notes + numnote++,
1737 "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu);
1738#endif
1739 1832
1740 fs = get_fs(); 1833 fs = get_fs();
1741 set_fs(KERNEL_DS); 1834 set_fs(KERNEL_DS);
@@ -1748,12 +1841,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1748 /* Write notes phdr entry */ 1841 /* Write notes phdr entry */
1749 { 1842 {
1750 struct elf_phdr phdr; 1843 struct elf_phdr phdr;
1751 int sz = 0; 1844 size_t sz = get_note_info_size(&info);
1752
1753 for (i = 0; i < numnote; i++)
1754 sz += notesize(notes + i);
1755
1756 sz += thread_status_size;
1757 1845
1758 sz += elf_coredump_extra_notes_size(); 1846 sz += elf_coredump_extra_notes_size();
1759 1847
@@ -1798,23 +1886,12 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
1798#endif 1886#endif
1799 1887
1800 /* write out the notes section */ 1888 /* write out the notes section */
1801 for (i = 0; i < numnote; i++) 1889 if (!write_note_info(&info, file, &foffset))
1802 if (!writenote(notes + i, file, &foffset)) 1890 goto end_coredump;
1803 goto end_coredump;
1804 1891
1805 if (elf_coredump_extra_notes_write(file, &foffset)) 1892 if (elf_coredump_extra_notes_write(file, &foffset))
1806 goto end_coredump; 1893 goto end_coredump;
1807 1894
1808 /* write out the thread status notes section */
1809 list_for_each(t, &thread_list) {
1810 struct elf_thread_status *tmp =
1811 list_entry(t, struct elf_thread_status, list);
1812
1813 for (i = 0; i < tmp->num_notes; i++)
1814 if (!writenote(&tmp->notes[i], file, &foffset))
1815 goto end_coredump;
1816 }
1817
1818 /* Align to page */ 1895 /* Align to page */
1819 DUMP_SEEK(dataoff - foffset); 1896 DUMP_SEEK(dataoff - foffset);
1820 1897
@@ -1865,22 +1942,9 @@ end_coredump:
1865 set_fs(fs); 1942 set_fs(fs);
1866 1943
1867cleanup: 1944cleanup:
1868 while (!list_empty(&thread_list)) {
1869 struct list_head *tmp = thread_list.next;
1870 list_del(tmp);
1871 kfree(list_entry(tmp, struct elf_thread_status, list));
1872 }
1873
1874 kfree(elf); 1945 kfree(elf);
1875 kfree(prstatus); 1946 free_note_info(&info);
1876 kfree(psinfo);
1877 kfree(notes);
1878 kfree(fpu);
1879#ifdef ELF_CORE_COPY_XFPREGS
1880 kfree(xfpu);
1881#endif
1882 return has_dumped; 1947 return has_dumped;
1883#undef NUM_NOTES
1884} 1948}
1885 1949
1886#endif /* USE_ELF_CORE_DUMP */ 1950#endif /* USE_ELF_CORE_DUMP */