Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Roland McGrath and committed by
Ingo Molnar
3aba481f bdf88217

+194 -130
+194 -130
fs/binfmt_elf.c
··· 1395 1395 if (!dump_seek(file, (off))) \ 1396 1396 goto end_coredump; 1397 1397 1398 - static void fill_elf_header(struct elfhdr *elf, int segs) 1398 + static void fill_elf_header(struct elfhdr *elf, int segs, 1399 + u16 machine, u32 flags, u8 osabi) 1399 1400 { 1400 1401 memcpy(elf->e_ident, ELFMAG, SELFMAG); 1401 1402 elf->e_ident[EI_CLASS] = ELF_CLASS; ··· 1406 1405 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); 1407 1406 1408 1407 elf->e_type = ET_CORE; 1409 - elf->e_machine = ELF_ARCH; 1408 + elf->e_machine = machine; 1410 1409 elf->e_version = EV_CURRENT; 1411 1410 elf->e_entry = 0; 1412 1411 elf->e_phoff = sizeof(struct elfhdr); 1413 1412 elf->e_shoff = 0; 1414 - elf->e_flags = ELF_CORE_EFLAGS; 1413 + elf->e_flags = flags; 1415 1414 elf->e_ehsize = sizeof(struct elfhdr); 1416 1415 elf->e_phentsize = sizeof(struct elf_phdr); 1417 1416 elf->e_phnum = segs; ··· 1518 1517 return 0; 1519 1518 } 1520 1519 1520 + static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) 1521 + { 1522 + elf_addr_t *auxv = (elf_addr_t *) mm->saved_auxv; 1523 + int i = 0; 1524 + do 1525 + i += 2; 1526 + while (auxv[i - 2] != AT_NULL); 1527 + fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); 1528 + } 1529 + 1521 1530 /* Here is the structure in which status of each thread is captured. */ 1522 1531 struct elf_thread_status 1523 1532 { ··· 1580 1569 return sz; 1581 1570 } 1582 1571 1572 + struct elf_note_info { 1573 + struct memelfnote *notes; 1574 + struct elf_prstatus *prstatus; /* NT_PRSTATUS */ 1575 + struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ 1576 + struct list_head thread_list; 1577 + elf_fpregset_t *fpu; 1578 + #ifdef ELF_CORE_COPY_XFPREGS 1579 + elf_fpxregset_t *xfpu; 1580 + #endif 1581 + int thread_status_size; 1582 + int numnote; 1583 + }; 1584 + 1585 + static int fill_note_info(struct elfhdr *elf, int phdrs, 1586 + struct elf_note_info *info, 1587 + long signr, struct pt_regs *regs) 1588 + { 1589 + #define NUM_NOTES 6 1590 + struct list_head *t; 1591 + struct task_struct *g, *p; 1592 + 1593 + info->notes = NULL; 1594 + info->prstatus = NULL; 1595 + info->psinfo = NULL; 1596 + info->fpu = NULL; 1597 + #ifdef ELF_CORE_COPY_XFPREGS 1598 + info->xfpu = NULL; 1599 + #endif 1600 + INIT_LIST_HEAD(&info->thread_list); 1601 + 1602 + info->notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), 1603 + GFP_KERNEL); 1604 + if (!info->notes) 1605 + return 0; 1606 + info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); 1607 + if (!info->psinfo) 1608 + return 0; 1609 + info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL); 1610 + if (!info->prstatus) 1611 + return 0; 1612 + info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL); 1613 + if (!info->fpu) 1614 + return 0; 1615 + #ifdef ELF_CORE_COPY_XFPREGS 1616 + info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL); 1617 + if (!info->xfpu) 1618 + return 0; 1619 + #endif 1620 + 1621 + info->thread_status_size = 0; 1622 + if (signr) { 1623 + struct elf_thread_status *tmp; 1624 + rcu_read_lock(); 1625 + do_each_thread(g, p) 1626 + if (current->mm == p->mm && current != p) { 1627 + tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); 1628 + if (!tmp) { 1629 + rcu_read_unlock(); 1630 + return 0; 1631 + } 1632 + tmp->thread = p; 1633 + list_add(&tmp->list, &info->thread_list); 1634 + } 1635 + while_each_thread(g, p); 1636 + rcu_read_unlock(); 1637 + list_for_each(t, &info->thread_list) { 1638 + struct elf_thread_status *tmp; 1639 + int sz; 1640 + 1641 + tmp = list_entry(t, struct elf_thread_status, list); 1642 + sz = elf_dump_thread_status(signr, tmp); 1643 + info->thread_status_size += sz; 1644 + } 1645 + } 1646 + /* now collect the dump for the current */ 1647 + memset(info->prstatus, 0, sizeof(*info->prstatus)); 1648 + fill_prstatus(info->prstatus, current, signr); 1649 + elf_core_copy_regs(&info->prstatus->pr_reg, regs); 1650 + 1651 + /* Set up header */ 1652 + fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS, ELF_OSABI); 1653 + 1654 + /* 1655 + * Set up the notes in similar form to SVR4 core dumps made 1656 + * with info from their /proc. 1657 + */ 1658 + 1659 + fill_note(info->notes + 0, "CORE", NT_PRSTATUS, 1660 + sizeof(*info->prstatus), info->prstatus); 1661 + fill_psinfo(info->psinfo, current->group_leader, current->mm); 1662 + fill_note(info->notes + 1, "CORE", NT_PRPSINFO, 1663 + sizeof(*info->psinfo), info->psinfo); 1664 + 1665 + info->numnote = 2; 1666 + 1667 + fill_auxv_note(&info->notes[info->numnote++], current->mm); 1668 + 1669 + /* Try to dump the FPU. */ 1670 + info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, 1671 + info->fpu); 1672 + if (info->prstatus->pr_fpvalid) 1673 + fill_note(info->notes + info->numnote++, 1674 + "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); 1675 + #ifdef ELF_CORE_COPY_XFPREGS 1676 + if (elf_core_copy_task_xfpregs(current, info->xfpu)) 1677 + fill_note(info->notes + info->numnote++, 1678 + "LINUX", ELF_CORE_XFPREG_TYPE, 1679 + sizeof(*info->xfpu), info->xfpu); 1680 + #endif 1681 + 1682 + return 1; 1683 + 1684 + #undef NUM_NOTES 1685 + } 1686 + 1687 + static size_t get_note_info_size(struct elf_note_info *info) 1688 + { 1689 + int sz = 0; 1690 + int i; 1691 + 1692 + for (i = 0; i < info->numnote; i++) 1693 + sz += notesize(info->notes + i); 1694 + 1695 + sz += info->thread_status_size; 1696 + 1697 + return sz; 1698 + } 1699 + 1700 + static int write_note_info(struct elf_note_info *info, 1701 + struct file *file, loff_t *foffset) 1702 + { 1703 + int i; 1704 + struct list_head *t; 1705 + 1706 + for (i = 0; i < info->numnote; i++) 1707 + if (!writenote(info->notes + i, file, foffset)) 1708 + return 0; 1709 + 1710 + /* write out the thread status notes section */ 1711 + list_for_each(t, &info->thread_list) { 1712 + struct elf_thread_status *tmp = 1713 + list_entry(t, struct elf_thread_status, list); 1714 + 1715 + for (i = 0; i < tmp->num_notes; i++) 1716 + if (!writenote(&tmp->notes[i], file, foffset)) 1717 + return 0; 1718 + } 1719 + 1720 + return 1; 1721 + } 1722 + 1723 + static void free_note_info(struct elf_note_info *info) 1724 + { 1725 + while (!list_empty(&info->thread_list)) { 1726 + struct list_head *tmp = info->thread_list.next; 1727 + list_del(tmp); 1728 + kfree(list_entry(tmp, struct elf_thread_status, list)); 1729 + } 1730 + 1731 + kfree(info->prstatus); 1732 + kfree(info->psinfo); 1733 + kfree(info->notes); 1734 + kfree(info->fpu); 1735 + #ifdef ELF_CORE_COPY_XFPREGS 1736 + kfree(info->xfpu); 1737 + #endif 1738 + } 1739 + 1583 1740 static struct vm_area_struct *first_vma(struct task_struct *tsk, 1584 1741 struct vm_area_struct *gate_vma) 1585 1742 { ··· 1783 1604 */ 1784 1605 static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) 1785 1606 { 1786 - #define NUM_NOTES 6 1787 1607 int has_dumped = 0; 1788 1608 mm_segment_t fs; 1789 1609 int segs; 1790 1610 size_t size = 0; 1791 - int i; 1792 1611 struct vm_area_struct *vma, *gate_vma; 1793 1612 struct elfhdr *elf = NULL; 1794 1613 loff_t offset = 0, dataoff, foffset; 1795 - int numnote; 1796 - struct memelfnote *notes = NULL; 1797 - struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ 1798 - struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ 1799 - struct task_struct *g, *p; 1800 - LIST_HEAD(thread_list); 1801 - struct list_head *t; 1802 - elf_fpregset_t *fpu = NULL; 1803 - #ifdef ELF_CORE_COPY_XFPREGS 1804 - elf_fpxregset_t *xfpu = NULL; 1805 - #endif 1806 - int thread_status_size = 0; 1807 - elf_addr_t *auxv; 1808 1614 unsigned long mm_flags; 1615 + struct elf_note_info info; 1809 1616 1810 1617 /* 1811 1618 * We no longer stop all VM operations. ··· 1809 1644 elf = kmalloc(sizeof(*elf), GFP_KERNEL); 1810 1645 if (!elf) 1811 1646 goto cleanup; 1812 - prstatus = kmalloc(sizeof(*prstatus), GFP_KERNEL); 1813 - if (!prstatus) 1814 - goto cleanup; 1815 - psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); 1816 - if (!psinfo) 1817 - goto cleanup; 1818 - notes = kmalloc(NUM_NOTES * sizeof(struct memelfnote), GFP_KERNEL); 1819 - if (!notes) 1820 - goto cleanup; 1821 - fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); 1822 - if (!fpu) 1823 - goto cleanup; 1824 - #ifdef ELF_CORE_COPY_XFPREGS 1825 - xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL); 1826 - if (!xfpu) 1827 - goto cleanup; 1828 - #endif 1829 - 1830 - if (signr) { 1831 - struct elf_thread_status *tmp; 1832 - rcu_read_lock(); 1833 - do_each_thread(g,p) 1834 - if (current->mm == p->mm && current != p) { 1835 - tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); 1836 - if (!tmp) { 1837 - rcu_read_unlock(); 1838 - goto cleanup; 1839 - } 1840 - tmp->thread = p; 1841 - list_add(&tmp->list, &thread_list); 1842 - } 1843 - while_each_thread(g,p); 1844 - rcu_read_unlock(); 1845 - list_for_each(t, &thread_list) { 1846 - struct elf_thread_status *tmp; 1847 - int sz; 1848 - 1849 - tmp = list_entry(t, struct elf_thread_status, list); 1850 - sz = elf_dump_thread_status(signr, tmp); 1851 - thread_status_size += sz; 1852 - } 1853 - } 1854 - /* now collect the dump for the current */ 1855 - memset(prstatus, 0, sizeof(*prstatus)); 1856 - fill_prstatus(prstatus, current, signr); 1857 - elf_core_copy_regs(&prstatus->pr_reg, regs); 1858 1647 1859 1648 segs = current->mm->map_count; 1860 1649 #ifdef ELF_CORE_EXTRA_PHDRS ··· 1819 1700 if (gate_vma != NULL) 1820 1701 segs++; 1821 1702 1822 - /* Set up header */ 1823 - fill_elf_header(elf, segs + 1); /* including notes section */ 1703 + /* 1704 + * Collect all the non-memory information about the process for the 1705 + * notes. This also sets up the file header. 1706 + */ 1707 + if (!fill_note_info(elf, segs + 1, /* including notes section */ 1708 + &info, signr, regs)) 1709 + goto cleanup; 1824 1710 1825 1711 has_dumped = 1; 1826 1712 current->flags |= PF_DUMPCORE; 1827 - 1828 - /* 1829 - * Set up the notes in similar form to SVR4 core dumps made 1830 - * with info from their /proc. 1831 - */ 1832 - 1833 - fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); 1834 - fill_psinfo(psinfo, current->group_leader, current->mm); 1835 - fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); 1836 - 1837 - numnote = 2; 1838 - 1839 - auxv = (elf_addr_t *)current->mm->saved_auxv; 1840 - 1841 - i = 0; 1842 - do 1843 - i += 2; 1844 - while (auxv[i - 2] != AT_NULL); 1845 - fill_note(&notes[numnote++], "CORE", NT_AUXV, 1846 - i * sizeof(elf_addr_t), auxv); 1847 - 1848 - /* Try to dump the FPU. */ 1849 - if ((prstatus->pr_fpvalid = 1850 - elf_core_copy_task_fpregs(current, regs, fpu))) 1851 - fill_note(notes + numnote++, 1852 - "CORE", NT_PRFPREG, sizeof(*fpu), fpu); 1853 - #ifdef ELF_CORE_COPY_XFPREGS 1854 - if (elf_core_copy_task_xfpregs(current, xfpu)) 1855 - fill_note(notes + numnote++, 1856 - "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); 1857 - #endif 1858 1713 1859 1714 fs = get_fs(); 1860 1715 set_fs(KERNEL_DS); ··· 1841 1748 /* Write notes phdr entry */ 1842 1749 { 1843 1750 struct elf_phdr phdr; 1844 - int sz = 0; 1845 - 1846 - for (i = 0; i < numnote; i++) 1847 - sz += notesize(notes + i); 1848 - 1849 - sz += thread_status_size; 1751 + size_t sz = get_note_info_size(&info); 1850 1752 1851 1753 sz += elf_coredump_extra_notes_size(); 1852 1754 ··· 1886 1798 #endif 1887 1799 1888 1800 /* write out the notes section */ 1889 - for (i = 0; i < numnote; i++) 1890 - if (!writenote(notes + i, file, &foffset)) 1891 - goto end_coredump; 1801 + if (!write_note_info(&info, file, &foffset)) 1802 + goto end_coredump; 1892 1803 1893 1804 if (elf_coredump_extra_notes_write(file, &foffset)) 1894 1805 goto end_coredump; 1895 - 1896 - /* write out the thread status notes section */ 1897 - list_for_each(t, &thread_list) { 1898 - struct elf_thread_status *tmp = 1899 - list_entry(t, struct elf_thread_status, list); 1900 - 1901 - for (i = 0; i < tmp->num_notes; i++) 1902 - if (!writenote(&tmp->notes[i], file, &foffset)) 1903 - goto end_coredump; 1904 - } 1905 1806 1906 1807 /* Align to page */ 1907 1808 DUMP_SEEK(dataoff - foffset); ··· 1942 1865 set_fs(fs); 1943 1866 1944 1867 cleanup: 1945 - while (!list_empty(&thread_list)) { 1946 - struct list_head *tmp = thread_list.next; 1947 - list_del(tmp); 1948 - kfree(list_entry(tmp, struct elf_thread_status, list)); 1949 - } 1950 - 1951 1868 kfree(elf); 1952 - kfree(prstatus); 1953 - kfree(psinfo); 1954 - kfree(notes); 1955 - kfree(fpu); 1956 - #ifdef ELF_CORE_COPY_XFPREGS 1957 - kfree(xfpu); 1958 - #endif 1869 + free_note_info(&info); 1959 1870 return has_dumped; 1960 - #undef NUM_NOTES 1961 1871 } 1962 1872 1963 1873 #endif /* USE_ELF_CORE_DUMP */