| @@ -1,564 +1,579 @@ | | | @@ -1,564 +1,579 @@ |
1 | /* $NetBSD: core_elf32.c,v 1.58 2019/01/22 03:44:44 kamil Exp $ */ | | 1 | /* $NetBSD: core_elf32.c,v 1.58.4.1 2021/01/01 13:04:08 martin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software | | 17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: | | 18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by | | 19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. | | 20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | | 21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior | | 22 | * or promote products derived from this software without specific prior |
23 | * written permission. | | 23 | * written permission. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | | 25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | /* | | 38 | /* |
39 | * core_elf32.c/core_elf64.c: Support for the Elf32/Elf64 core file format. | | 39 | * core_elf32.c/core_elf64.c: Support for the Elf32/Elf64 core file format. |
40 | */ | | 40 | */ |
41 | | | 41 | |
42 | #include <sys/cdefs.h> | | 42 | #include <sys/cdefs.h> |
43 | __KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.58 2019/01/22 03:44:44 kamil Exp $"); | | 43 | __KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.58.4.1 2021/01/01 13:04:08 martin Exp $"); |
44 | | | 44 | |
45 | #ifdef _KERNEL_OPT | | 45 | #ifdef _KERNEL_OPT |
46 | #include "opt_coredump.h" | | 46 | #include "opt_coredump.h" |
47 | #include "opt_compat_netbsd32.h" | | 47 | #include "opt_compat_netbsd32.h" |
48 | #endif | | 48 | #endif |
49 | | | 49 | |
50 | #ifndef ELFSIZE | | 50 | #ifndef ELFSIZE |
51 | #define ELFSIZE 32 | | 51 | #define ELFSIZE 32 |
52 | #endif | | 52 | #endif |
53 | | | 53 | |
54 | #include <sys/param.h> | | 54 | #include <sys/param.h> |
55 | #include <sys/systm.h> | | 55 | #include <sys/systm.h> |
56 | #include <sys/proc.h> | | 56 | #include <sys/proc.h> |
57 | #include <sys/vnode.h> | | 57 | #include <sys/vnode.h> |
58 | #include <sys/exec.h> | | 58 | #include <sys/exec.h> |
59 | #include <sys/exec_elf.h> | | 59 | #include <sys/exec_elf.h> |
60 | #include <sys/ptrace.h> | | 60 | #include <sys/ptrace.h> |
61 | #include <sys/kmem.h> | | 61 | #include <sys/kmem.h> |
62 | #include <sys/kauth.h> | | 62 | #include <sys/kauth.h> |
63 | | | 63 | |
64 | #include <machine/reg.h> | | 64 | #include <machine/reg.h> |
65 | | | 65 | |
66 | #include <uvm/uvm_extern.h> | | 66 | #include <uvm/uvm_extern.h> |
67 | | | 67 | |
68 | #ifdef COREDUMP | | 68 | #ifdef COREDUMP |
69 | | | 69 | |
| | | 70 | #ifdef COMPAT_NETBSD32 |
| | | 71 | #include <machine/netbsd32_machdep.h> |
| | | 72 | #endif |
| | | 73 | |
70 | struct writesegs_state { | | 74 | struct writesegs_state { |
71 | Elf_Phdr *psections; | | 75 | Elf_Phdr *psections; |
72 | proc_t *p; | | 76 | proc_t *p; |
73 | off_t secoff; | | 77 | off_t secoff; |
74 | size_t npsections; | | 78 | size_t npsections; |
75 | }; | | 79 | }; |
76 | | | 80 | |
77 | /* | | 81 | /* |
78 | * We need to know how big the 'notes' are before we write the main header. | | 82 | * We need to know how big the 'notes' are before we write the main header. |
79 | * To avoid problems with double-processing we save the data. | | 83 | * To avoid problems with double-processing we save the data. |
80 | */ | | 84 | */ |
81 | struct note_buf { | | 85 | struct note_buf { |
82 | struct note_buf *nb_next; | | 86 | struct note_buf *nb_next; |
83 | unsigned char nb_data[4096 - sizeof (void *)]; | | 87 | unsigned char nb_data[4096 - sizeof (void *)]; |
84 | }; | | 88 | }; |
85 | | | 89 | |
86 | struct note_state { | | 90 | struct note_state { |
87 | struct note_buf *ns_first; | | 91 | struct note_buf *ns_first; |
88 | struct note_buf *ns_last; | | 92 | struct note_buf *ns_last; |
89 | unsigned int ns_count; /* Of full buffers */ | | 93 | unsigned int ns_count; /* Of full buffers */ |
90 | unsigned int ns_offset; /* Write point in last buffer */ | | 94 | unsigned int ns_offset; /* Write point in last buffer */ |
91 | }; | | 95 | }; |
92 | | | 96 | |
93 | static int ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *); | | 97 | static int ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *); |
94 | | | 98 | |
95 | static int ELFNAMEEND(coredump_notes)(struct lwp *, struct note_state *); | | 99 | static int ELFNAMEEND(coredump_notes)(struct lwp *, struct note_state *); |
96 | static int ELFNAMEEND(coredump_note)(struct lwp *, struct note_state *); | | 100 | static int ELFNAMEEND(coredump_note)(struct lwp *, struct note_state *); |
97 | | | 101 | |
98 | /* The 'note' section names and data are always 4-byte aligned. */ | | 102 | /* The 'note' section names and data are always 4-byte aligned. */ |
99 | #define ELFROUNDSIZE 4 /* XXX Should it be sizeof(Elf_Word)? */ | | 103 | #define ELFROUNDSIZE 4 /* XXX Should it be sizeof(Elf_Word)? */ |
100 | | | 104 | |
101 | #define elf_process_read_regs CONCAT(process_read_regs, ELFSIZE) | | 105 | #define elf_process_read_regs CONCAT(process_read_regs, ELFSIZE) |
102 | #define elf_process_read_fpregs CONCAT(process_read_fpregs, ELFSIZE) | | 106 | #define elf_process_read_fpregs CONCAT(process_read_fpregs, ELFSIZE) |
103 | #define elf_reg CONCAT(process_reg, ELFSIZE) | | 107 | #define elf_reg CONCAT(process_reg, ELFSIZE) |
104 | #define elf_fpreg CONCAT(process_fpreg, ELFSIZE) | | 108 | #define elf_fpreg CONCAT(process_fpreg, ELFSIZE) |
105 | | | 109 | |
106 | int | | 110 | int |
107 | ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) | | 111 | ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) |
108 | { | | 112 | { |
109 | Elf_Ehdr ehdr; | | 113 | Elf_Ehdr ehdr; |
110 | Elf_Shdr shdr; | | 114 | Elf_Shdr shdr; |
111 | Elf_Phdr *psections; | | 115 | Elf_Phdr *psections; |
112 | size_t psectionssize; | | 116 | size_t psectionssize; |
113 | int npsections; | | 117 | int npsections; |
114 | struct writesegs_state ws; | | 118 | struct writesegs_state ws; |
115 | off_t notestart; | | 119 | off_t notestart; |
116 | size_t notesize; | | 120 | size_t notesize; |
117 | int error, i; | | 121 | int error, i; |
118 | | | 122 | |
119 | struct note_state ns; | | 123 | struct note_state ns; |
120 | struct note_buf *nb; | | 124 | struct note_buf *nb; |
121 | | | 125 | |
122 | psections = NULL; | | 126 | psections = NULL; |
123 | | | 127 | |
124 | /* Get all of the notes (mostly all the registers). */ | | 128 | /* Get all of the notes (mostly all the registers). */ |
125 | ns.ns_first = kmem_alloc(sizeof *ns.ns_first, KM_SLEEP); | | 129 | ns.ns_first = kmem_alloc(sizeof *ns.ns_first, KM_SLEEP); |
126 | ns.ns_last = ns.ns_first; | | 130 | ns.ns_last = ns.ns_first; |
127 | ns.ns_count = 0; | | 131 | ns.ns_count = 0; |
128 | ns.ns_offset = 0; | | 132 | ns.ns_offset = 0; |
129 | error = ELFNAMEEND(coredump_notes)(l, &ns); | | 133 | error = ELFNAMEEND(coredump_notes)(l, &ns); |
130 | ns.ns_last->nb_next = NULL; | | 134 | ns.ns_last->nb_next = NULL; |
131 | if (error) | | 135 | if (error) |
132 | goto out; | | 136 | goto out; |
133 | notesize = ns.ns_count * sizeof nb->nb_data + ns.ns_offset; | | 137 | notesize = ns.ns_count * sizeof nb->nb_data + ns.ns_offset; |
134 | | | 138 | |
135 | /* | | 139 | /* |
136 | * We have to make a total of 3 passes across the map: | | 140 | * We have to make a total of 3 passes across the map: |
137 | * | | 141 | * |
138 | * 1. Count the number of map entries (the number of | | 142 | * 1. Count the number of map entries (the number of |
139 | * PT_LOAD sections in the dump). | | 143 | * PT_LOAD sections in the dump). |
140 | * | | 144 | * |
141 | * 2. Write the P-section headers. | | 145 | * 2. Write the P-section headers. |
142 | * | | 146 | * |
143 | * 3. Write the P-sections. | | 147 | * 3. Write the P-sections. |
144 | */ | | 148 | */ |
145 | | | 149 | |
146 | /* Pass 1: count the entries. */ | | 150 | /* Pass 1: count the entries. */ |
147 | npsections = uvm_coredump_count_segs(l->l_proc); | | 151 | npsections = uvm_coredump_count_segs(l->l_proc); |
148 | /* Allow for the PT_NOTE section. */ | | 152 | /* Allow for the PT_NOTE section. */ |
149 | npsections++; | | 153 | npsections++; |
150 | | | 154 | |
151 | /* Build the main elf header */ | | 155 | /* Build the main elf header */ |
152 | memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD); | | 156 | memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD); |
153 | memcpy(ehdr.e_ident, ELFMAG, SELFMAG); | | 157 | memcpy(ehdr.e_ident, ELFMAG, SELFMAG); |
154 | #if ELFSIZE == 32 | | 158 | #if ELFSIZE == 32 |
155 | ehdr.e_ident[EI_CLASS] = ELFCLASS32; | | 159 | ehdr.e_ident[EI_CLASS] = ELFCLASS32; |
156 | #elif ELFSIZE == 64 | | 160 | #elif ELFSIZE == 64 |
157 | ehdr.e_ident[EI_CLASS] = ELFCLASS64; | | 161 | ehdr.e_ident[EI_CLASS] = ELFCLASS64; |
158 | #endif | | 162 | #endif |
159 | ehdr.e_ident[EI_DATA] = ELFDEFNNAME(MACHDEP_ENDIANNESS); | | 163 | ehdr.e_ident[EI_DATA] = ELFDEFNNAME(MACHDEP_ENDIANNESS); |
160 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; | | 164 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; |
161 | /* | | 165 | /* |
162 | * NetBSD sets generic SYSV OSABI and ABI version 0 | | 166 | * NetBSD sets generic SYSV OSABI and ABI version 0 |
163 | * Native ELF files are distinguishable with NetBSD specific notes | | 167 | * Native ELF files are distinguishable with NetBSD specific notes |
164 | */ | | 168 | */ |
165 | ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; | | 169 | ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; |
166 | ehdr.e_ident[EI_ABIVERSION] = 0; | | 170 | ehdr.e_ident[EI_ABIVERSION] = 0; |
167 | | | 171 | |
168 | ehdr.e_type = ET_CORE; | | 172 | ehdr.e_type = ET_CORE; |
169 | /* XXX This should be the e_machine of the executable. */ | | 173 | /* XXX This should be the e_machine of the executable. */ |
170 | ehdr.e_machine = ELFDEFNNAME(MACHDEP_ID); | | 174 | ehdr.e_machine = ELFDEFNNAME(MACHDEP_ID); |
171 | ehdr.e_version = EV_CURRENT; | | 175 | ehdr.e_version = EV_CURRENT; |
172 | ehdr.e_entry = 0; | | 176 | ehdr.e_entry = 0; |
173 | ehdr.e_flags = 0; | | 177 | ehdr.e_flags = 0; |
174 | ehdr.e_ehsize = sizeof(ehdr); | | 178 | ehdr.e_ehsize = sizeof(ehdr); |
175 | ehdr.e_phentsize = sizeof(Elf_Phdr); | | 179 | ehdr.e_phentsize = sizeof(Elf_Phdr); |
176 | if (npsections < PN_XNUM) { | | 180 | if (npsections < PN_XNUM) { |
177 | ehdr.e_phnum = npsections; | | 181 | ehdr.e_phnum = npsections; |
178 | ehdr.e_shentsize = 0; | | 182 | ehdr.e_shentsize = 0; |
179 | ehdr.e_shnum = 0; | | 183 | ehdr.e_shnum = 0; |
180 | ehdr.e_shoff = 0; | | 184 | ehdr.e_shoff = 0; |
181 | ehdr.e_phoff = sizeof(ehdr); | | 185 | ehdr.e_phoff = sizeof(ehdr); |
182 | } else { | | 186 | } else { |
183 | ehdr.e_phnum = PN_XNUM; | | 187 | ehdr.e_phnum = PN_XNUM; |
184 | ehdr.e_shentsize = sizeof(Elf_Shdr); | | 188 | ehdr.e_shentsize = sizeof(Elf_Shdr); |
185 | ehdr.e_shnum = 1; | | 189 | ehdr.e_shnum = 1; |
186 | ehdr.e_shoff = sizeof(ehdr); | | 190 | ehdr.e_shoff = sizeof(ehdr); |
187 | ehdr.e_phoff = sizeof(ehdr) + sizeof(shdr); | | 191 | ehdr.e_phoff = sizeof(ehdr) + sizeof(shdr); |
188 | } | | 192 | } |
189 | ehdr.e_shstrndx = 0; | | 193 | ehdr.e_shstrndx = 0; |
190 | | | 194 | |
191 | #ifdef ELF_MD_COREDUMP_SETUP | | 195 | #ifdef ELF_MD_COREDUMP_SETUP |
192 | ELF_MD_COREDUMP_SETUP(l, &ehdr); | | 196 | ELF_MD_COREDUMP_SETUP(l, &ehdr); |
193 | #endif | | 197 | #endif |
194 | | | 198 | |
195 | /* Write out the ELF header. */ | | 199 | /* Write out the ELF header. */ |
196 | error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); | | 200 | error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); |
197 | if (error) | | 201 | if (error) |
198 | goto out; | | 202 | goto out; |
199 | | | 203 | |
200 | /* Write out sections, if needed */ | | 204 | /* Write out sections, if needed */ |
201 | if (npsections >= PN_XNUM) { | | 205 | if (npsections >= PN_XNUM) { |
202 | memset(&shdr, 0, sizeof(shdr)); | | 206 | memset(&shdr, 0, sizeof(shdr)); |
203 | shdr.sh_type = SHT_NULL; | | 207 | shdr.sh_type = SHT_NULL; |
204 | shdr.sh_info = npsections; | | 208 | shdr.sh_info = npsections; |
205 | error = coredump_write(cookie, UIO_SYSSPACE, &shdr, | | 209 | error = coredump_write(cookie, UIO_SYSSPACE, &shdr, |
206 | sizeof(shdr)); | | 210 | sizeof(shdr)); |
207 | if (error) | | 211 | if (error) |
208 | goto out; | | 212 | goto out; |
209 | } | | 213 | } |
210 | | | 214 | |
211 | psectionssize = npsections * sizeof(*psections); | | 215 | psectionssize = npsections * sizeof(*psections); |
212 | notestart = ehdr.e_phoff + psectionssize; | | 216 | notestart = ehdr.e_phoff + psectionssize; |
213 | | | 217 | |
214 | psections = kmem_zalloc(psectionssize, KM_SLEEP); | | 218 | psections = kmem_zalloc(psectionssize, KM_SLEEP); |
215 | | | 219 | |
216 | /* Pass 2: now find the P-section headers. */ | | 220 | /* Pass 2: now find the P-section headers. */ |
217 | ws.secoff = notestart + notesize; | | 221 | ws.secoff = notestart + notesize; |
218 | ws.psections = psections; | | 222 | ws.psections = psections; |
219 | ws.npsections = npsections - 1; | | 223 | ws.npsections = npsections - 1; |
220 | ws.p = l->l_proc; | | 224 | ws.p = l->l_proc; |
221 | error = uvm_coredump_walkmap(l->l_proc, ELFNAMEEND(coredump_getseghdrs), | | 225 | error = uvm_coredump_walkmap(l->l_proc, ELFNAMEEND(coredump_getseghdrs), |
222 | &ws); | | 226 | &ws); |
223 | if (error) | | 227 | if (error) |
224 | goto out; | | 228 | goto out; |
225 | if (ws.npsections != 0) { | | 229 | if (ws.npsections != 0) { |
226 | /* A section went away */ | | 230 | /* A section went away */ |
227 | error = ENOMEM; | | 231 | error = ENOMEM; |
228 | goto out; | | 232 | goto out; |
229 | } | | 233 | } |
230 | | | 234 | |
231 | /* Add the PT_NOTE header after the P-section headers. */ | | 235 | /* Add the PT_NOTE header after the P-section headers. */ |
232 | ws.psections->p_type = PT_NOTE; | | 236 | ws.psections->p_type = PT_NOTE; |
233 | ws.psections->p_offset = notestart; | | 237 | ws.psections->p_offset = notestart; |
234 | ws.psections->p_vaddr = 0; | | 238 | ws.psections->p_vaddr = 0; |
235 | ws.psections->p_paddr = 0; | | 239 | ws.psections->p_paddr = 0; |
236 | ws.psections->p_filesz = notesize; | | 240 | ws.psections->p_filesz = notesize; |
237 | ws.psections->p_memsz = 0; | | 241 | ws.psections->p_memsz = 0; |
238 | ws.psections->p_flags = PF_R; | | 242 | ws.psections->p_flags = PF_R; |
239 | ws.psections->p_align = ELFROUNDSIZE; | | 243 | ws.psections->p_align = ELFROUNDSIZE; |
240 | | | 244 | |
241 | /* Write the P-section headers followed by the PT_NOTE header */ | | 245 | /* Write the P-section headers followed by the PT_NOTE header */ |
242 | error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionssize); | | 246 | error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionssize); |
243 | if (error) | | 247 | if (error) |
244 | goto out; | | 248 | goto out; |
245 | | | 249 | |
246 | #ifdef DIAGNOSTIC | | 250 | #ifdef DIAGNOSTIC |
247 | if (coredump_offset(cookie) != notestart) | | 251 | if (coredump_offset(cookie) != notestart) |
248 | panic("coredump: offset %lld != notestart %lld", | | 252 | panic("coredump: offset %lld != notestart %lld", |
249 | (long long) coredump_offset(cookie), | | 253 | (long long) coredump_offset(cookie), |
250 | (long long) notestart); | | 254 | (long long) notestart); |
251 | #endif | | 255 | #endif |
252 | | | 256 | |
253 | /* Write out the notes. */ | | 257 | /* Write out the notes. */ |
254 | for (nb = ns.ns_first; nb != NULL; nb = nb->nb_next) { | | 258 | for (nb = ns.ns_first; nb != NULL; nb = nb->nb_next) { |
255 | error = coredump_write(cookie, UIO_SYSSPACE, nb->nb_data, | | 259 | error = coredump_write(cookie, UIO_SYSSPACE, nb->nb_data, |
256 | nb->nb_next == NULL ? ns.ns_offset : sizeof nb->nb_data); | | 260 | nb->nb_next == NULL ? ns.ns_offset : sizeof nb->nb_data); |
257 | if (error) | | 261 | if (error) |
258 | goto out; | | 262 | goto out; |
259 | } | | 263 | } |
260 | | | 264 | |
261 | /* Finally, write the sections themselves. */ | | 265 | /* Finally, write the sections themselves. */ |
262 | for (i = 0; i < npsections - 1; i++) { | | 266 | for (i = 0; i < npsections - 1; i++) { |
263 | if (psections[i].p_filesz == 0) | | 267 | if (psections[i].p_filesz == 0) |
264 | continue; | | 268 | continue; |
265 | | | 269 | |
266 | #ifdef DIAGNOSTIC | | 270 | #ifdef DIAGNOSTIC |
267 | if (coredump_offset(cookie) != psections[i].p_offset) | | 271 | if (coredump_offset(cookie) != psections[i].p_offset) |
268 | panic("coredump: offset %lld != p_offset[%d] %lld", | | 272 | panic("coredump: offset %lld != p_offset[%d] %lld", |
269 | (long long) coredump_offset(cookie), i, | | 273 | (long long) coredump_offset(cookie), i, |
270 | (long long) psections[i].p_filesz); | | 274 | (long long) psections[i].p_filesz); |
271 | #endif | | 275 | #endif |
272 | | | 276 | |
273 | error = coredump_write(cookie, UIO_USERSPACE, | | 277 | error = coredump_write(cookie, UIO_USERSPACE, |
274 | (void *)(vaddr_t)psections[i].p_vaddr, | | 278 | (void *)(vaddr_t)psections[i].p_vaddr, |
275 | psections[i].p_filesz); | | 279 | psections[i].p_filesz); |
276 | if (error) | | 280 | if (error) |
277 | goto out; | | 281 | goto out; |
278 | } | | 282 | } |
279 | | | 283 | |
280 | out: | | 284 | out: |
281 | if (psections) | | 285 | if (psections) |
282 | kmem_free(psections, psectionssize); | | 286 | kmem_free(psections, psectionssize); |
283 | while ((nb = ns.ns_first) != NULL) { | | 287 | while ((nb = ns.ns_first) != NULL) { |
284 | ns.ns_first = nb->nb_next; | | 288 | ns.ns_first = nb->nb_next; |
285 | kmem_free(nb, sizeof *nb); | | 289 | kmem_free(nb, sizeof *nb); |
286 | } | | 290 | } |
287 | return (error); | | 291 | return (error); |
288 | } | | 292 | } |
289 | | | 293 | |
290 | static int | | 294 | static int |
291 | ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *us) | | 295 | ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *us) |
292 | { | | 296 | { |
293 | struct writesegs_state *ws = us->cookie; | | 297 | struct writesegs_state *ws = us->cookie; |
294 | Elf_Phdr phdr; | | 298 | Elf_Phdr phdr; |
295 | vsize_t size, realsize; | | 299 | vsize_t size, realsize; |
296 | vaddr_t end; | | 300 | vaddr_t end; |
297 | int error; | | 301 | int error; |
298 | | | 302 | |
299 | /* Don't overrun if there are more sections */ | | 303 | /* Don't overrun if there are more sections */ |
300 | if (ws->npsections == 0) | | 304 | if (ws->npsections == 0) |
301 | return ENOMEM; | | 305 | return ENOMEM; |
302 | ws->npsections--; | | 306 | ws->npsections--; |
303 | | | 307 | |
304 | size = us->end - us->start; | | 308 | size = us->end - us->start; |
305 | realsize = us->realend - us->start; | | 309 | realsize = us->realend - us->start; |
306 | end = us->realend; | | 310 | end = us->realend; |
307 | | | 311 | |
308 | /* Don't bother writing out trailing zeros */ | | 312 | /* Don't bother writing out trailing zeros */ |
309 | while (realsize > 0) { | | 313 | while (realsize > 0) { |
310 | long buf[1024 / sizeof(long)]; | | 314 | long buf[1024 / sizeof(long)]; |
311 | size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize; | | 315 | size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize; |
312 | const long *ep; | | 316 | const long *ep; |
313 | int i; | | 317 | int i; |
314 | | | 318 | |
315 | end -= slen; | | 319 | end -= slen; |
316 | if ((error = copyin_proc(ws->p, (void *)end, buf, slen)) != 0) { | | 320 | if ((error = copyin_proc(ws->p, (void *)end, buf, slen)) != 0) { |
317 | /* | | 321 | /* |
318 | * In case of any errors of scanning the segments reset | | 322 | * In case of any errors of scanning the segments reset |
319 | * their content to a default value with zeros. This is | | 323 | * their content to a default value with zeros. This is |
320 | * achieved with shortening the p_filesz parameter. | | 324 | * achieved with shortening the p_filesz parameter. |
321 | * | | 325 | * |
322 | * This allows to emit core(5) files for a process | | 326 | * This allows to emit core(5) files for a process |
323 | * regardless of its state of mappings, such as mapping | | 327 | * regardless of its state of mappings, such as mapping |
324 | * pages after EOF in a file. | | 328 | * pages after EOF in a file. |
325 | */ | | 329 | */ |
326 | realsize -= slen; | | 330 | realsize -= slen; |
327 | continue; | | 331 | continue; |
328 | } | | 332 | } |
329 | | | 333 | |
330 | ep = (const long *) &buf[slen / sizeof(buf[0])]; | | 334 | ep = (const long *) &buf[slen / sizeof(buf[0])]; |
331 | for (i = 0, ep--; buf <= ep; ep--, i++) { | | 335 | for (i = 0, ep--; buf <= ep; ep--, i++) { |
332 | if (*ep) | | 336 | if (*ep) |
333 | break; | | 337 | break; |
334 | } | | 338 | } |
335 | realsize -= i * sizeof(buf[0]); | | 339 | realsize -= i * sizeof(buf[0]); |
336 | if (i * sizeof(buf[0]) < slen) | | 340 | if (i * sizeof(buf[0]) < slen) |
337 | break; | | 341 | break; |
338 | } | | 342 | } |
339 | | | 343 | |
340 | phdr.p_type = PT_LOAD; | | 344 | phdr.p_type = PT_LOAD; |
341 | phdr.p_offset = ws->secoff; | | 345 | phdr.p_offset = ws->secoff; |
342 | phdr.p_vaddr = us->start; | | 346 | phdr.p_vaddr = us->start; |
343 | phdr.p_paddr = 0; | | 347 | phdr.p_paddr = 0; |
344 | phdr.p_filesz = realsize; | | 348 | phdr.p_filesz = realsize; |
345 | phdr.p_memsz = size; | | 349 | phdr.p_memsz = size; |
346 | phdr.p_flags = 0; | | 350 | phdr.p_flags = 0; |
347 | if (us->prot & VM_PROT_READ) | | 351 | if (us->prot & VM_PROT_READ) |
348 | phdr.p_flags |= PF_R; | | 352 | phdr.p_flags |= PF_R; |
349 | if (us->prot & VM_PROT_WRITE) | | 353 | if (us->prot & VM_PROT_WRITE) |
350 | phdr.p_flags |= PF_W; | | 354 | phdr.p_flags |= PF_W; |
351 | if (us->prot & VM_PROT_EXECUTE) | | 355 | if (us->prot & VM_PROT_EXECUTE) |
352 | phdr.p_flags |= PF_X; | | 356 | phdr.p_flags |= PF_X; |
353 | phdr.p_align = PAGE_SIZE; | | 357 | phdr.p_align = PAGE_SIZE; |
354 | | | 358 | |
355 | ws->secoff += phdr.p_filesz; | | 359 | ws->secoff += phdr.p_filesz; |
356 | *ws->psections++ = phdr; | | 360 | *ws->psections++ = phdr; |
357 | | | 361 | |
358 | return (0); | | 362 | return (0); |
359 | } | | 363 | } |
360 | | | 364 | |
361 | static void | | 365 | static void |
362 | coredump_note_procinfo(struct lwp *l, struct note_state *ns) | | 366 | coredump_note_procinfo(struct lwp *l, struct note_state *ns) |
363 | { | | 367 | { |
364 | struct proc *p; | | 368 | struct proc *p; |
365 | struct netbsd_elfcore_procinfo cpi; | | 369 | struct netbsd_elfcore_procinfo cpi; |
366 | struct lwp *l0; | | 370 | struct lwp *l0; |
367 | sigset_t ss1, ss2; | | 371 | sigset_t ss1, ss2; |
368 | | | 372 | |
369 | p = l->l_proc; | | 373 | p = l->l_proc; |
370 | | | 374 | |
371 | /* First, write an elfcore_procinfo. */ | | 375 | /* First, write an elfcore_procinfo. */ |
372 | cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION; | | 376 | cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION; |
373 | cpi.cpi_cpisize = sizeof(cpi); | | 377 | cpi.cpi_cpisize = sizeof(cpi); |
374 | cpi.cpi_signo = p->p_sigctx.ps_info._signo; | | 378 | cpi.cpi_signo = p->p_sigctx.ps_info._signo; |
375 | cpi.cpi_sigcode = p->p_sigctx.ps_info._code; | | 379 | cpi.cpi_sigcode = p->p_sigctx.ps_info._code; |
376 | cpi.cpi_siglwp = p->p_sigctx.ps_lwp; | | 380 | cpi.cpi_siglwp = p->p_sigctx.ps_lwp; |
377 | | | 381 | |
378 | /* | | 382 | /* |
379 | * XXX This should be per-LWP. | | 383 | * XXX This should be per-LWP. |
380 | */ | | 384 | */ |
381 | ss1 = p->p_sigpend.sp_set; | | 385 | ss1 = p->p_sigpend.sp_set; |
382 | sigemptyset(&ss2); | | 386 | sigemptyset(&ss2); |
383 | LIST_FOREACH(l0, &p->p_lwps, l_sibling) { | | 387 | LIST_FOREACH(l0, &p->p_lwps, l_sibling) { |
384 | sigplusset(&l0->l_sigpend.sp_set, &ss1); | | 388 | sigplusset(&l0->l_sigpend.sp_set, &ss1); |
385 | sigplusset(&l0->l_sigmask, &ss2); | | 389 | sigplusset(&l0->l_sigmask, &ss2); |
386 | } | | 390 | } |
387 | memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend)); | | 391 | memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend)); |
388 | memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask)); | | 392 | memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask)); |
389 | memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore, | | 393 | memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore, |
390 | sizeof(cpi.cpi_sigignore)); | | 394 | sizeof(cpi.cpi_sigignore)); |
391 | memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch, | | 395 | memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch, |
392 | sizeof(cpi.cpi_sigcatch)); | | 396 | sizeof(cpi.cpi_sigcatch)); |
393 | | | 397 | |
394 | cpi.cpi_pid = p->p_pid; | | 398 | cpi.cpi_pid = p->p_pid; |
395 | mutex_enter(proc_lock); | | 399 | mutex_enter(proc_lock); |
396 | cpi.cpi_ppid = p->p_pptr->p_pid; | | 400 | cpi.cpi_ppid = p->p_pptr->p_pid; |
397 | cpi.cpi_pgrp = p->p_pgid; | | 401 | cpi.cpi_pgrp = p->p_pgid; |
398 | cpi.cpi_sid = p->p_session->s_sid; | | 402 | cpi.cpi_sid = p->p_session->s_sid; |
399 | mutex_exit(proc_lock); | | 403 | mutex_exit(proc_lock); |
400 | | | 404 | |
401 | cpi.cpi_ruid = kauth_cred_getuid(l->l_cred); | | 405 | cpi.cpi_ruid = kauth_cred_getuid(l->l_cred); |
402 | cpi.cpi_euid = kauth_cred_geteuid(l->l_cred); | | 406 | cpi.cpi_euid = kauth_cred_geteuid(l->l_cred); |
403 | cpi.cpi_svuid = kauth_cred_getsvuid(l->l_cred); | | 407 | cpi.cpi_svuid = kauth_cred_getsvuid(l->l_cred); |
404 | | | 408 | |
405 | cpi.cpi_rgid = kauth_cred_getgid(l->l_cred); | | 409 | cpi.cpi_rgid = kauth_cred_getgid(l->l_cred); |
406 | cpi.cpi_egid = kauth_cred_getegid(l->l_cred); | | 410 | cpi.cpi_egid = kauth_cred_getegid(l->l_cred); |
407 | cpi.cpi_svgid = kauth_cred_getsvgid(l->l_cred); | | 411 | cpi.cpi_svgid = kauth_cred_getsvgid(l->l_cred); |
408 | | | 412 | |
409 | cpi.cpi_nlwps = p->p_nlwps; | | 413 | cpi.cpi_nlwps = p->p_nlwps; |
410 | (void)strncpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); | | 414 | (void)strncpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); |
411 | cpi.cpi_name[sizeof(cpi.cpi_name) - 1] = '\0'; | | 415 | cpi.cpi_name[sizeof(cpi.cpi_name) - 1] = '\0'; |
412 | | | 416 | |
413 | ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_PROCINFO, | | 417 | ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_PROCINFO, |
414 | ELF_NOTE_NETBSD_CORE_NAME, &cpi, sizeof(cpi)); | | 418 | ELF_NOTE_NETBSD_CORE_NAME, &cpi, sizeof(cpi)); |
415 | } | | 419 | } |
416 | | | 420 | |
417 | static int | | 421 | static int |
418 | coredump_note_auxv(struct lwp *l, struct note_state *ns) | | 422 | coredump_note_auxv(struct lwp *l, struct note_state *ns) |
419 | { | | 423 | { |
420 | int error; | | 424 | int error; |
421 | size_t len; | | 425 | size_t len; |
422 | void *kauxv; | | 426 | void *kauxv; |
423 | | | 427 | |
424 | if ((error = proc_getauxv(l->l_proc, &kauxv, &len)) != 0) | | 428 | if ((error = proc_getauxv(l->l_proc, &kauxv, &len)) != 0) |
425 | return error; | | 429 | return error; |
426 | | | 430 | |
427 | ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_AUXV, | | 431 | ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_AUXV, |
428 | ELF_NOTE_NETBSD_CORE_NAME, kauxv, len); | | 432 | ELF_NOTE_NETBSD_CORE_NAME, kauxv, len); |
429 | | | 433 | |
430 | kmem_free(kauxv, len); | | 434 | kmem_free(kauxv, len); |
431 | return 0; | | 435 | return 0; |
432 | } | | 436 | } |
433 | | | 437 | |
434 | static int | | 438 | static int |
435 | ELFNAMEEND(coredump_notes)(struct lwp *l, struct note_state *ns) | | 439 | ELFNAMEEND(coredump_notes)(struct lwp *l, struct note_state *ns) |
436 | { | | 440 | { |
437 | int error; | | 441 | int error; |
438 | struct lwp *l0; | | 442 | struct lwp *l0; |
439 | struct proc *p = l->l_proc; | | 443 | struct proc *p = l->l_proc; |
440 | | | 444 | |
441 | coredump_note_procinfo(l, ns); | | 445 | coredump_note_procinfo(l, ns); |
442 | error = coredump_note_auxv(l, ns); | | 446 | error = coredump_note_auxv(l, ns); |
443 | if (error) | | 447 | if (error) |
444 | return error; | | 448 | return error; |
445 | | | 449 | |
446 | /* XXX Add hook for machdep per-proc notes. */ | | 450 | /* XXX Add hook for machdep per-proc notes. */ |
447 | | | 451 | |
448 | /* | | 452 | /* |
449 | * Now write the register info for the thread that caused the | | 453 | * Now write the register info for the thread that caused the |
450 | * coredump. | | 454 | * coredump. |
451 | */ | | 455 | */ |
452 | error = ELFNAMEEND(coredump_note)(l, ns); | | 456 | error = ELFNAMEEND(coredump_note)(l, ns); |
453 | if (error) | | 457 | if (error) |
454 | return error; | | 458 | return error; |
455 | | | 459 | |
456 | /* | | 460 | /* |
457 | * Now, for each LWP, write the register info and any other | | 461 | * Now, for each LWP, write the register info and any other |
458 | * per-LWP notes. | | 462 | * per-LWP notes. |
459 | * Lock in case this is a gcore requested dump. | | 463 | * Lock in case this is a gcore requested dump. |
460 | */ | | 464 | */ |
461 | mutex_enter(p->p_lock); | | 465 | mutex_enter(p->p_lock); |
462 | LIST_FOREACH(l0, &p->p_lwps, l_sibling) { | | 466 | LIST_FOREACH(l0, &p->p_lwps, l_sibling) { |
463 | if (l0 == l) /* we've taken care of this thread */ | | 467 | if (l0 == l) /* we've taken care of this thread */ |
464 | continue; | | 468 | continue; |
465 | error = ELFNAMEEND(coredump_note)(l0, ns); | | 469 | error = ELFNAMEEND(coredump_note)(l0, ns); |
466 | if (error) | | 470 | if (error) |
467 | break; | | 471 | break; |
468 | } | | 472 | } |
469 | mutex_exit(p->p_lock); | | 473 | mutex_exit(p->p_lock); |
470 | | | 474 | |
471 | return error; | | 475 | return error; |
472 | } | | 476 | } |
473 | | | 477 | |
474 | static int | | 478 | static int |
475 | ELFNAMEEND(coredump_note)(struct lwp *l, struct note_state *ns) | | 479 | ELFNAMEEND(coredump_note)(struct lwp *l, struct note_state *ns) |
476 | { | | 480 | { |
477 | int error; | | 481 | int error; |
478 | char name[64]; | | 482 | char name[64]; |
479 | elf_reg intreg; | | 483 | elf_reg intreg; |
480 | #ifdef PT_GETFPREGS | | 484 | #ifdef PT_GETFPREGS |
481 | elf_fpreg freg; | | 485 | elf_fpreg freg; |
482 | size_t freglen; | | 486 | size_t freglen; |
483 | #endif | | 487 | #endif |
484 | | | 488 | |
485 | snprintf(name, sizeof(name), "%s@%d", | | 489 | snprintf(name, sizeof(name), "%s@%d", |
486 | ELF_NOTE_NETBSD_CORE_NAME, l->l_lid); | | 490 | ELF_NOTE_NETBSD_CORE_NAME, l->l_lid); |
487 | | | 491 | |
488 | error = elf_process_read_regs(l, &intreg); | | 492 | error = elf_process_read_regs(l, &intreg); |
489 | if (error) | | 493 | if (error) |
490 | return (error); | | 494 | return (error); |
491 | | | 495 | |
492 | ELFNAMEEND(coredump_savenote)(ns, PT_GETREGS, name, &intreg, | | 496 | ELFNAMEEND(coredump_savenote)(ns, |
493 | sizeof(intreg)); | | 497 | #if ELFSIZE == 32 && defined(PT32_GETREGS) |
| | | 498 | PT32_GETREGS, |
| | | 499 | #else |
| | | 500 | PT_GETREGS, |
| | | 501 | #endif |
| | | 502 | name, &intreg, sizeof(intreg)); |
494 | | | 503 | |
495 | #ifdef PT_GETFPREGS | | 504 | #ifdef PT_GETFPREGS |
496 | freglen = sizeof(freg); | | 505 | freglen = sizeof(freg); |
497 | error = elf_process_read_fpregs(l, &freg, &freglen); | | 506 | error = elf_process_read_fpregs(l, &freg, &freglen); |
498 | if (error) | | 507 | if (error) |
499 | return (error); | | 508 | return (error); |
500 | | | 509 | |
501 | ELFNAMEEND(coredump_savenote)(ns, PT_GETFPREGS, name, &freg, freglen); | | 510 | ELFNAMEEND(coredump_savenote)(ns, |
| | | 511 | # if ELFSIZE == 32 && defined(PT32_GETFPREGS) |
| | | 512 | PT32_GETFPREGS, |
| | | 513 | # else |
| | | 514 | PT_GETFPREGS, |
| | | 515 | # endif |
| | | 516 | name, &freg, freglen); |
502 | #endif | | 517 | #endif |
503 | /* XXX Add hook for machdep per-LWP notes. */ | | 518 | /* XXX Add hook for machdep per-LWP notes. */ |
504 | return (0); | | 519 | return (0); |
505 | } | | 520 | } |
506 | | | 521 | |
507 | static void | | 522 | static void |
508 | save_note_bytes(struct note_state *ns, const void *data, size_t len) | | 523 | save_note_bytes(struct note_state *ns, const void *data, size_t len) |
509 | { | | 524 | { |
510 | struct note_buf *nb = ns->ns_last; | | 525 | struct note_buf *nb = ns->ns_last; |
511 | size_t copylen; | | 526 | size_t copylen; |
512 | unsigned char *wp; | | 527 | unsigned char *wp; |
513 | | | 528 | |
514 | /* | | 529 | /* |
515 | * Just copy the data into a buffer list. | | 530 | * Just copy the data into a buffer list. |
516 | * All but the last buffer is full. | | 531 | * All but the last buffer is full. |
517 | */ | | 532 | */ |
518 | for (;;) { | | 533 | for (;;) { |
519 | copylen = uimin(len, sizeof(nb->nb_data) - ns->ns_offset); | | 534 | copylen = uimin(len, sizeof(nb->nb_data) - ns->ns_offset); |
520 | wp = nb->nb_data + ns->ns_offset; | | 535 | wp = nb->nb_data + ns->ns_offset; |
521 | memcpy(wp, data, copylen); | | 536 | memcpy(wp, data, copylen); |
522 | if (copylen == len) | | 537 | if (copylen == len) |
523 | break; | | 538 | break; |
524 | nb->nb_next = kmem_alloc(sizeof(*nb->nb_next), KM_SLEEP); | | 539 | nb->nb_next = kmem_alloc(sizeof(*nb->nb_next), KM_SLEEP); |
525 | nb = nb->nb_next; | | 540 | nb = nb->nb_next; |
526 | ns->ns_last = nb; | | 541 | ns->ns_last = nb; |
527 | ns->ns_count++; | | 542 | ns->ns_count++; |
528 | ns->ns_offset = 0; | | 543 | ns->ns_offset = 0; |
529 | len -= copylen; | | 544 | len -= copylen; |
530 | data = (const unsigned char *)data + copylen; | | 545 | data = (const unsigned char *)data + copylen; |
531 | } | | 546 | } |
532 | | | 547 | |
533 | while ((copylen & (ELFROUNDSIZE - 1)) && | | 548 | while ((copylen & (ELFROUNDSIZE - 1)) && |
534 | wp + copylen < nb->nb_data + sizeof(nb->nb_data)) | | 549 | wp + copylen < nb->nb_data + sizeof(nb->nb_data)) |
535 | wp[copylen++] = 0; | | 550 | wp[copylen++] = 0; |
536 | | | 551 | |
537 | ns->ns_offset += copylen; | | 552 | ns->ns_offset += copylen; |
538 | } | | 553 | } |
539 | | | 554 | |
540 | void | | 555 | void |
541 | ELFNAMEEND(coredump_savenote)(struct note_state *ns, unsigned int type, | | 556 | ELFNAMEEND(coredump_savenote)(struct note_state *ns, unsigned int type, |
542 | const char *name, void *data, size_t data_len) | | 557 | const char *name, void *data, size_t data_len) |
543 | { | | 558 | { |
544 | Elf_Nhdr nhdr; | | 559 | Elf_Nhdr nhdr; |
545 | | | 560 | |
546 | nhdr.n_namesz = strlen(name) + 1; | | 561 | nhdr.n_namesz = strlen(name) + 1; |
547 | nhdr.n_descsz = data_len; | | 562 | nhdr.n_descsz = data_len; |
548 | nhdr.n_type = type; | | 563 | nhdr.n_type = type; |
549 | | | 564 | |
550 | save_note_bytes(ns, &nhdr, sizeof (nhdr)); | | 565 | save_note_bytes(ns, &nhdr, sizeof (nhdr)); |
551 | save_note_bytes(ns, name, nhdr.n_namesz); | | 566 | save_note_bytes(ns, name, nhdr.n_namesz); |
552 | save_note_bytes(ns, data, data_len); | | 567 | save_note_bytes(ns, data, data_len); |
553 | } | | 568 | } |
554 | | | 569 | |
555 | #else /* COREDUMP */ | | 570 | #else /* COREDUMP */ |
556 | | | 571 | |
557 | int | | 572 | int |
558 | ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) | | 573 | ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) |
559 | { | | 574 | { |
560 | | | 575 | |
561 | return ENOSYS; | | 576 | return ENOSYS; |
562 | } | | 577 | } |
563 | | | 578 | |
564 | #endif /* COREDUMP */ | | 579 | #endif /* COREDUMP */ |