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

elf core dump: notes user_regset

This modifies the ELF core dump code under #ifdef CORE_DUMP_USE_REGSET.
It changes nothing when this macro is not defined. When it's #define'd
by some arch header (e.g. asm/elf.h), the arch must support the
user_regset (linux/regset.h) interface for reading thread state.

This provides an alternate version of note segment writing that is based
purely on the user_regset interfaces. When CORE_DUMP_USE_REGSET is set,
the arch need not define macros such as ELF_CORE_COPY_REGS and ELF_ARCH.
All that information is taken from the user_regset data structures.
The core dumps come out exactly the same if arch's definitions for its
user_regset details are correct.

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
4206d3aa 3aba481f

+224
+224
fs/binfmt_elf.c
··· 1528 1528 fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); 1529 1529 } 1530 1530 1531 + #ifdef CORE_DUMP_USE_REGSET 1532 + #include <linux/regset.h> 1533 + 1534 + struct elf_thread_core_info { 1535 + struct elf_thread_core_info *next; 1536 + struct task_struct *task; 1537 + struct elf_prstatus prstatus; 1538 + struct memelfnote notes[0]; 1539 + }; 1540 + 1541 + struct elf_note_info { 1542 + struct elf_thread_core_info *thread; 1543 + struct memelfnote psinfo; 1544 + struct memelfnote auxv; 1545 + size_t size; 1546 + int thread_notes; 1547 + }; 1548 + 1549 + static int fill_thread_core_info(struct elf_thread_core_info *t, 1550 + const struct user_regset_view *view, 1551 + long signr, size_t *total) 1552 + { 1553 + unsigned int i; 1554 + 1555 + /* 1556 + * NT_PRSTATUS is the one special case, because the regset data 1557 + * goes into the pr_reg field inside the note contents, rather 1558 + * than being the whole note contents. We fill the reset in here. 1559 + * We assume that regset 0 is NT_PRSTATUS. 1560 + */ 1561 + fill_prstatus(&t->prstatus, t->task, signr); 1562 + (void) view->regsets[0].get(t->task, &view->regsets[0], 1563 + 0, sizeof(t->prstatus.pr_reg), 1564 + &t->prstatus.pr_reg, NULL); 1565 + 1566 + fill_note(&t->notes[0], "CORE", NT_PRSTATUS, 1567 + sizeof(t->prstatus), &t->prstatus); 1568 + *total += notesize(&t->notes[0]); 1569 + 1570 + /* 1571 + * Each other regset might generate a note too. For each regset 1572 + * that has no core_note_type or is inactive, we leave t->notes[i] 1573 + * all zero and we'll know to skip writing it later. 1574 + */ 1575 + for (i = 1; i < view->n; ++i) { 1576 + const struct user_regset *regset = &view->regsets[i]; 1577 + if (regset->core_note_type && 1578 + (!regset->active || regset->active(t->task, regset))) { 1579 + int ret; 1580 + size_t size = regset->n * regset->size; 1581 + void *data = kmalloc(size, GFP_KERNEL); 1582 + if (unlikely(!data)) 1583 + return 0; 1584 + ret = regset->get(t->task, regset, 1585 + 0, size, data, NULL); 1586 + if (unlikely(ret)) 1587 + kfree(data); 1588 + else { 1589 + if (regset->core_note_type != NT_PRFPREG) 1590 + fill_note(&t->notes[i], "LINUX", 1591 + regset->core_note_type, 1592 + size, data); 1593 + else { 1594 + t->prstatus.pr_fpvalid = 1; 1595 + fill_note(&t->notes[i], "CORE", 1596 + NT_PRFPREG, size, data); 1597 + } 1598 + *total += notesize(&t->notes[i]); 1599 + } 1600 + } 1601 + } 1602 + 1603 + return 1; 1604 + } 1605 + 1606 + static int fill_note_info(struct elfhdr *elf, int phdrs, 1607 + struct elf_note_info *info, 1608 + long signr, struct pt_regs *regs) 1609 + { 1610 + struct task_struct *dump_task = current; 1611 + const struct user_regset_view *view = task_user_regset_view(dump_task); 1612 + struct elf_thread_core_info *t; 1613 + struct elf_prpsinfo *psinfo; 1614 + struct task_struct *g, *p; 1615 + unsigned int i; 1616 + 1617 + info->size = 0; 1618 + info->thread = NULL; 1619 + 1620 + psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); 1621 + fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); 1622 + 1623 + if (psinfo == NULL) 1624 + return 0; 1625 + 1626 + /* 1627 + * Figure out how many notes we're going to need for each thread. 1628 + */ 1629 + info->thread_notes = 0; 1630 + for (i = 0; i < view->n; ++i) 1631 + if (view->regsets[i].core_note_type != 0) 1632 + ++info->thread_notes; 1633 + 1634 + /* 1635 + * Sanity check. We rely on regset 0 being in NT_PRSTATUS, 1636 + * since it is our one special case. 1637 + */ 1638 + if (unlikely(info->thread_notes == 0) || 1639 + unlikely(view->regsets[0].core_note_type != NT_PRSTATUS)) { 1640 + WARN_ON(1); 1641 + return 0; 1642 + } 1643 + 1644 + /* 1645 + * Initialize the ELF file header. 1646 + */ 1647 + fill_elf_header(elf, phdrs, 1648 + view->e_machine, view->e_flags, view->ei_osabi); 1649 + 1650 + /* 1651 + * Allocate a structure for each thread. 1652 + */ 1653 + rcu_read_lock(); 1654 + do_each_thread(g, p) 1655 + if (p->mm == dump_task->mm) { 1656 + t = kzalloc(offsetof(struct elf_thread_core_info, 1657 + notes[info->thread_notes]), 1658 + GFP_ATOMIC); 1659 + if (unlikely(!t)) { 1660 + rcu_read_unlock(); 1661 + return 0; 1662 + } 1663 + t->task = p; 1664 + if (p == dump_task || !info->thread) { 1665 + t->next = info->thread; 1666 + info->thread = t; 1667 + } else { 1668 + /* 1669 + * Make sure to keep the original task at 1670 + * the head of the list. 1671 + */ 1672 + t->next = info->thread->next; 1673 + info->thread->next = t; 1674 + } 1675 + } 1676 + while_each_thread(g, p); 1677 + rcu_read_unlock(); 1678 + 1679 + /* 1680 + * Now fill in each thread's information. 1681 + */ 1682 + for (t = info->thread; t != NULL; t = t->next) 1683 + if (!fill_thread_core_info(t, view, signr, &info->size)) 1684 + return 0; 1685 + 1686 + /* 1687 + * Fill in the two process-wide notes. 1688 + */ 1689 + fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); 1690 + info->size += notesize(&info->psinfo); 1691 + 1692 + fill_auxv_note(&info->auxv, current->mm); 1693 + info->size += notesize(&info->auxv); 1694 + 1695 + return 1; 1696 + } 1697 + 1698 + static size_t get_note_info_size(struct elf_note_info *info) 1699 + { 1700 + return info->size; 1701 + } 1702 + 1703 + /* 1704 + * Write all the notes for each thread. When writing the first thread, the 1705 + * process-wide notes are interleaved after the first thread-specific note. 1706 + */ 1707 + static int write_note_info(struct elf_note_info *info, 1708 + struct file *file, loff_t *foffset) 1709 + { 1710 + bool first = 1; 1711 + struct elf_thread_core_info *t = info->thread; 1712 + 1713 + do { 1714 + int i; 1715 + 1716 + if (!writenote(&t->notes[0], file, foffset)) 1717 + return 0; 1718 + 1719 + if (first && !writenote(&info->psinfo, file, foffset)) 1720 + return 0; 1721 + if (first && !writenote(&info->auxv, file, foffset)) 1722 + return 0; 1723 + 1724 + for (i = 1; i < info->thread_notes; ++i) 1725 + if (t->notes[i].data && 1726 + !writenote(&t->notes[i], file, foffset)) 1727 + return 0; 1728 + 1729 + first = 0; 1730 + t = t->next; 1731 + } while (t); 1732 + 1733 + return 1; 1734 + } 1735 + 1736 + static void free_note_info(struct elf_note_info *info) 1737 + { 1738 + struct elf_thread_core_info *threads = info->thread; 1739 + while (threads) { 1740 + unsigned int i; 1741 + struct elf_thread_core_info *t = threads; 1742 + threads = t->next; 1743 + WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus); 1744 + for (i = 1; i < info->thread_notes; ++i) 1745 + kfree(t->notes[i].data); 1746 + kfree(t); 1747 + } 1748 + kfree(info->psinfo.data); 1749 + } 1750 + 1751 + #else 1752 + 1531 1753 /* Here is the structure in which status of each thread is captured. */ 1532 1754 struct elf_thread_status 1533 1755 { ··· 1969 1747 kfree(info->xfpu); 1970 1748 #endif 1971 1749 } 1750 + 1751 + #endif 1972 1752 1973 1753 static struct vm_area_struct *first_vma(struct task_struct *tsk, 1974 1754 struct vm_area_struct *gate_vma)