xref: /illumos-gate/usr/src/lib/libproc/common/Pgcore.c (revision 438283cf397cce47d80cc67b04bbfdfe73b0d142)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
28  * Copyright 2018 Joyent, Inc.
29  * Copyright (c) 2013 by Delphix. All rights reserved.
30  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
31  * Copyright 2026 Oxide Computer Company
32  * Copyright 2026 Carsten Grzemba
33  */
34 
35 #define	_STRUCTURED_PROC	1
36 
37 #include <assert.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <errno.h>
43 #include <procfs.h>
44 #include <priv.h>
45 #include <sys/elf.h>
46 #include <sys/machelf.h>
47 #include <sys/sysmacros.h>
48 #include <sys/systeminfo.h>
49 #include <sys/proc.h>
50 #include <sys/utsname.h>
51 #include <core_shstrtab.h>
52 
53 #include "Pcontrol.h"
54 #include "P32ton.h"
55 #include "proc_fd.h"
56 
57 typedef struct {
58 	struct ps_prochandle *P;
59 	int		pgc_fd;
60 	off64_t		*pgc_poff;
61 	off64_t		*pgc_soff;
62 	off64_t		*pgc_doff;
63 	core_content_t	pgc_content;
64 	void		*pgc_chunk;
65 	size_t		pgc_chunksz;
66 
67 	shstrtab_t	pgc_shstrtab;
68 } pgcore_t;
69 
70 typedef struct {
71 	int		fd_fd;
72 	off64_t		*fd_doff;
73 } fditer_t;
74 
75 static int
76 gc_pwrite64(int fd, const void *buf, size_t len, off64_t off)
77 {
78 	int err;
79 
80 	err = pwrite64(fd, buf, len, off);
81 
82 	if (err < 0)
83 		return (err);
84 
85 	/*
86 	 * We will take a page from ZFS's book here and use the otherwise
87 	 * unused EBADE to mean a short write.  Typically this will actually
88 	 * result from ENOSPC or EDQUOT, but we can't be sure.
89 	 */
90 	if (err < len) {
91 		errno = EBADE;
92 		return (-1);
93 	}
94 
95 	return (0);
96 }
97 
98 int
99 Pgcore(struct ps_prochandle *P, const char *fname, core_content_t content)
100 {
101 	int fd;
102 	int err;
103 	int saved_errno;
104 
105 	if ((fd = creat64(fname, 0666)) < 0)
106 		return (-1);
107 
108 	if ((err = Pfgcore(P, fd, content)) != 0) {
109 		saved_errno = errno;
110 		(void) close(fd);
111 		(void) unlink(fname);
112 		errno = saved_errno;
113 		return (err);
114 	}
115 
116 	return (close(fd));
117 }
118 
119 static int
120 write_note(int fd, uint_t type, const void *desc, size_t descsz, off64_t *offp)
121 {
122 	/*
123 	 * Note headers are the same regardless of the data model of the
124 	 * ELF file; we arbitrarily use Elf64_Nhdr here.
125 	 */
126 	struct {
127 		Elf64_Nhdr nhdr;
128 		char name[8];
129 	} n;
130 
131 	bzero(&n, sizeof (n));
132 	bcopy("CORE", n.name, 4);
133 	n.nhdr.n_type = type;
134 	n.nhdr.n_namesz = 5;
135 	n.nhdr.n_descsz = roundup(descsz, 4);
136 
137 	if (gc_pwrite64(fd, &n, sizeof (n), *offp) != 0)
138 		return (-1);
139 
140 	*offp += sizeof (n);
141 
142 	if (gc_pwrite64(fd, desc, n.nhdr.n_descsz, *offp) != 0)
143 		return (-1);
144 
145 	*offp += n.nhdr.n_descsz;
146 
147 	return (0);
148 }
149 
150 static int
151 per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
152 {
153 	pgcore_t *pgc = data;
154 	struct ps_prochandle *P = pgc->P;
155 	prlwpname_t name = { 0, "" };
156 	psinfo_t ps;
157 	prxregset_t *xregs;
158 	size_t size;
159 
160 	/*
161 	 * If lsp is NULL this indicates that this is a zombie LWP in
162 	 * which case we dump only the lwpsinfo_t structure and none of
163 	 * the other ancillary LWP state data.
164 	 */
165 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
166 		if (write_note(pgc->pgc_fd, NT_LWPSINFO, lip,
167 		    sizeof (lwpsinfo_t), pgc->pgc_doff) != 0)
168 			return (1);
169 		if (lsp == NULL)
170 			return (0);
171 		if (write_note(pgc->pgc_fd, NT_LWPSTATUS, lsp,
172 		    sizeof (lwpstatus_t), pgc->pgc_doff) != 0)
173 			return (1);
174 #ifdef _LP64
175 	} else {
176 		lwpsinfo32_t li32;
177 		lwpstatus32_t ls32;
178 		lwpsinfo_n_to_32(lip, &li32);
179 		if (write_note(pgc->pgc_fd, NT_LWPSINFO, &li32,
180 		    sizeof (lwpsinfo32_t), pgc->pgc_doff) != 0)
181 			return (1);
182 		if (lsp == NULL)
183 			return (0);
184 		lwpstatus_n_to_32(lsp, &ls32);
185 		if (write_note(pgc->pgc_fd, NT_LWPSTATUS, &ls32,
186 		    sizeof (lwpstatus32_t), pgc->pgc_doff) != 0)
187 			return (1);
188 #endif	/* _LP64 */
189 	}
190 
191 	if (Plwp_getxregs(P, lsp->pr_lwpid, &xregs, &size) == 0) {
192 		if (write_note(pgc->pgc_fd, NT_PRXREG, xregs, size,
193 		    pgc->pgc_doff) != 0)
194 			return (1);
195 
196 		Plwp_freexregs(P, xregs, size);
197 	}
198 
199 	if (Plwp_getname(P, lsp->pr_lwpid, name.pr_lwpname,
200 	    sizeof (name.pr_lwpname)) == 0) {
201 		name.pr_lwpid = lsp->pr_lwpid;
202 		if (write_note(pgc->pgc_fd, NT_LWPNAME, &name,
203 		    sizeof (name), pgc->pgc_doff) != 0)
204 			return (1);
205 	}
206 
207 	if (!(lsp->pr_flags & PR_AGENT))
208 		return (0);
209 
210 	if (Plwp_getspymaster(P, lsp->pr_lwpid, &ps) != 0)
211 		return (0);
212 
213 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
214 		if (write_note(pgc->pgc_fd, NT_SPYMASTER, &ps,
215 		    sizeof (psinfo_t), pgc->pgc_doff) != 0)
216 			return (1);
217 #ifdef _LP64
218 	} else {
219 		psinfo32_t ps32;
220 		psinfo_n_to_32(&ps, &ps32);
221 		if (write_note(pgc->pgc_fd, NT_SPYMASTER, &ps32,
222 		    sizeof (psinfo32_t), pgc->pgc_doff) != 0)
223 			return (1);
224 #endif	/* _LP64 */
225 	}
226 
227 
228 	return (0);
229 }
230 
231 static int
232 iter_fd(void *data, const prfdinfo_t *fdinfo)
233 {
234 	fditer_t *iter = data;
235 	prfdinfo_core_t core;
236 	int ret = 0;
237 
238 	if (proc_fdinfo_to_core(fdinfo, &core) != 0)
239 		return (1);
240 
241 	ret = write_note(iter->fd_fd, NT_FDINFO, &core,
242 	    sizeof (core), iter->fd_doff);
243 
244 	if (ret != 0)
245 		return (1);
246 	return (0);
247 }
248 
249 /*
250  * Look for sections that begin with the string '.debug_'. In particular, this
251  * will catch all DWARF related sections and it will catch those that different
252  * folks use that are not related to DWARF, but still begin with this prefix
253  * (e.g. .debug_gdb_scripts). Notably though, this does not catch something like
254  * stabs (though it could). This really is filtering based on the section name,
255  * less so intent.
256  */
257 static boolean_t
258 is_debug_section(file_info_t *fptr, GElf_Shdr *shdr)
259 {
260 	if (shdr->sh_name == 0 || shdr->sh_name > fptr->file_shstrsz)
261 		return (B_FALSE);
262 
263 	if (strncmp(fptr->file_shstrs + shdr->sh_name, ".debug_",
264 	    strlen(".debug_")) != 0) {
265 		return (B_FALSE);
266 	}
267 
268 	return (B_TRUE);
269 }
270 
271 static uint_t
272 count_debug(file_info_t *fptr)
273 {
274 	uint_t count = 0;
275 	Elf_Scn *scn = NULL;
276 
277 	if (fptr->file_elf == NULL || fptr->file_shstrsz <= 1) {
278 		return (0);
279 	}
280 
281 	while ((scn = elf_nextscn(fptr->file_elf, scn)) != NULL) {
282 		GElf_Shdr shdr;
283 
284 		if (gelf_getshdr(scn, &shdr) == NULL)
285 			continue;
286 
287 		if (is_debug_section(fptr, &shdr))
288 			count++;
289 	}
290 
291 	return (count);
292 }
293 
294 static uint_t
295 count_sections(pgcore_t *pgc)
296 {
297 	struct ps_prochandle *P = pgc->P;
298 	file_info_t *fptr;
299 	uint_t nshdrs = 0;
300 
301 	if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB |
302 	    CC_CONTENT_DEBUG))) {
303 		return (0);
304 	}
305 
306 	for (fptr = list_head(&P->file_head); fptr != NULL;
307 	    fptr = list_next(&P->file_head, fptr)) {
308 		int hit_symtab = 0;
309 
310 		Pbuild_file_symtab(P, fptr);
311 
312 		if ((pgc->pgc_content & CC_CONTENT_CTF) &&
313 		    Pbuild_file_ctf(P, fptr) != NULL) {
314 			sym_tbl_t *sym;
315 
316 			nshdrs++;
317 
318 			if (fptr->file_ctf_dyn) {
319 				sym = &fptr->file_dynsym;
320 			} else {
321 				sym = &fptr->file_symtab;
322 				hit_symtab = 1;
323 			}
324 
325 			if (sym->sym_data_pri != NULL && sym->sym_symn != 0 &&
326 			    sym->sym_strs != NULL)
327 				nshdrs += 2;
328 		}
329 
330 		if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
331 		    fptr->file_symtab.sym_data_pri != NULL &&
332 		    fptr->file_symtab.sym_symn != 0 &&
333 		    fptr->file_symtab.sym_strs != NULL) {
334 			nshdrs += 2;
335 		}
336 
337 		if ((pgc->pgc_content & CC_CONTENT_DEBUG) != 0)
338 			nshdrs += count_debug(fptr);
339 	}
340 
341 	return (nshdrs == 0 ? 0 : nshdrs + 2);
342 }
343 
344 static int
345 write_shdr(pgcore_t *pgc, const char *name, uint_t type, ulong_t flags,
346     uintptr_t addr, ulong_t offset, size_t size, uint_t link, uint_t info,
347     uintptr_t addralign, uintptr_t entsize)
348 {
349 	if (pgc->P->status.pr_dmodel == PR_MODEL_ILP32) {
350 		Elf32_Shdr shdr;
351 
352 		bzero(&shdr, sizeof (shdr));
353 		if (!shstrtab_ndx(&pgc->pgc_shstrtab, name, &shdr.sh_name)) {
354 			return (-1);
355 		}
356 		shdr.sh_type = type;
357 		shdr.sh_flags = flags;
358 		shdr.sh_addr = (Elf32_Addr)addr;
359 		shdr.sh_offset = offset;
360 		shdr.sh_size = size;
361 		shdr.sh_link = link;
362 		shdr.sh_info = info;
363 		shdr.sh_addralign = addralign;
364 		shdr.sh_entsize = entsize;
365 
366 		if (gc_pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
367 		    *pgc->pgc_soff) != 0)
368 			return (-1);
369 
370 		*pgc->pgc_soff += sizeof (shdr);
371 #ifdef _LP64
372 	} else {
373 		Elf64_Shdr shdr;
374 
375 		bzero(&shdr, sizeof (shdr));
376 		if (!shstrtab_ndx(&pgc->pgc_shstrtab, name, &shdr.sh_name)) {
377 			return (-1);
378 		}
379 		shdr.sh_type = type;
380 		shdr.sh_flags = flags;
381 		shdr.sh_addr = addr;
382 		shdr.sh_offset = offset;
383 		shdr.sh_size = size;
384 		shdr.sh_link = link;
385 		shdr.sh_info = info;
386 		shdr.sh_addralign = addralign;
387 		shdr.sh_entsize = entsize;
388 
389 		if (gc_pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
390 		    *pgc->pgc_soff) != 0)
391 			return (-1);
392 
393 		*pgc->pgc_soff += sizeof (shdr);
394 #endif	/* _LP64 */
395 	}
396 
397 	return (0);
398 }
399 
400 static int
401 dump_symtab(pgcore_t *pgc, file_info_t *fptr, uint_t index, int dynsym)
402 {
403 	sym_tbl_t *sym = dynsym ? &fptr->file_dynsym : &fptr->file_symtab;
404 	shstrtype_t symname = dynsym ? STR_DYNSYM : STR_SYMTAB;
405 	shstrtype_t strname = dynsym ? STR_DYNSTR : STR_STRTAB;
406 	uint_t symtype = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
407 	size_t size;
408 	uintptr_t addr = fptr->file_map->map_pmap.pr_vaddr;
409 
410 	if (sym->sym_data_pri == NULL || sym->sym_symn == 0 ||
411 	    sym->sym_strs == NULL)
412 		return (0);
413 
414 	size = sym->sym_hdr_pri.sh_size;
415 	if (gc_pwrite64(pgc->pgc_fd, sym->sym_data_pri->d_buf, size,
416 	    *pgc->pgc_doff) != 0)
417 		return (-1);
418 
419 	if (write_shdr(pgc, shstrtab_data[symname], symtype, 0, addr,
420 	    *pgc->pgc_doff, size, index + 1, sym->sym_hdr_pri.sh_info,
421 	    sym->sym_hdr_pri.sh_addralign, sym->sym_hdr_pri.sh_entsize) != 0)
422 		return (-1);
423 
424 	*pgc->pgc_doff += roundup(size, 8);
425 
426 	size = sym->sym_strhdr.sh_size;
427 	if (gc_pwrite64(pgc->pgc_fd, sym->sym_strs, size, *pgc->pgc_doff) != 0)
428 		return (-1);
429 
430 	if (write_shdr(pgc, shstrtab_data[strname], SHT_STRTAB, SHF_STRINGS,
431 	    addr, *pgc->pgc_doff, size, 0, 0, 1, 0) != 0)
432 		return (-1);
433 
434 	*pgc->pgc_doff += roundup(size, 8);
435 
436 	return (0);
437 }
438 
439 static int
440 dump_debug(pgcore_t *pgc, file_info_t *fptr, uint_t *indexp)
441 {
442 	Elf_Scn *scn = NULL;
443 
444 	if (fptr->file_elf == NULL || fptr->file_shstrsz <= 1) {
445 		return (0);
446 	}
447 
448 	while ((scn = elf_nextscn(fptr->file_elf, scn)) != NULL) {
449 		GElf_Shdr shdr;
450 		Elf_Data *data;
451 
452 		if (gelf_getshdr(scn, &shdr) == NULL)
453 			continue;
454 
455 		if (!is_debug_section(fptr, &shdr))
456 			continue;
457 
458 		if ((data = elf_getdata(scn, NULL)) == NULL) {
459 			return (-1);
460 		}
461 
462 		if (gc_pwrite64(pgc->pgc_fd, data->d_buf, data->d_size,
463 		    *pgc->pgc_doff) != 0)
464 			return (-1);
465 
466 		if (write_shdr(pgc, fptr->file_shstrs + shdr.sh_name,
467 		    shdr.sh_type, shdr.sh_flags,
468 		    fptr->file_map->map_pmap.pr_vaddr, *pgc->pgc_doff,
469 		    data->d_size, 0, shdr.sh_info, shdr.sh_addralign,
470 		    shdr.sh_entsize) != 0) {
471 			return (-1);
472 		}
473 
474 		*indexp = *indexp + 1;
475 		*pgc->pgc_doff += roundup(data->d_size, 8);
476 	}
477 
478 	return (0);
479 }
480 
481 static int
482 dump_sections(pgcore_t *pgc)
483 {
484 	struct ps_prochandle *P = pgc->P;
485 	file_info_t *fptr;
486 	uint_t index = 1;
487 
488 	if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB |
489 	    CC_CONTENT_DEBUG))) {
490 		return (0);
491 	}
492 
493 	for (fptr = list_head(&P->file_head); fptr != NULL;
494 	    fptr = list_next(&P->file_head, fptr)) {
495 		int hit_symtab = 0;
496 
497 		Pbuild_file_symtab(P, fptr);
498 
499 		if ((pgc->pgc_content & CC_CONTENT_CTF) &&
500 		    Pbuild_file_ctf(P, fptr) != NULL) {
501 			sym_tbl_t *sym;
502 			uint_t dynsym;
503 			uint_t symindex = 0;
504 
505 			/*
506 			 * Write the symtab out first so we can correctly
507 			 * set the sh_link field in the CTF section header.
508 			 * symindex will be 0 if there is no corresponding
509 			 * symbol table section.
510 			 */
511 			if (fptr->file_ctf_dyn) {
512 				sym = &fptr->file_dynsym;
513 				dynsym = 1;
514 			} else {
515 				sym = &fptr->file_symtab;
516 				dynsym = 0;
517 				hit_symtab = 1;
518 			}
519 
520 			if (sym->sym_data_pri != NULL && sym->sym_symn != 0 &&
521 			    sym->sym_strs != NULL) {
522 				symindex = index;
523 				if (dump_symtab(pgc, fptr, index, dynsym) != 0)
524 					return (-1);
525 				index += 2;
526 			}
527 
528 			/*
529 			 * Write the CTF data that we've read out of the
530 			 * file itself into the core file.
531 			 */
532 			if (gc_pwrite64(pgc->pgc_fd, fptr->file_ctf_buf,
533 			    fptr->file_ctf_size, *pgc->pgc_doff) != 0)
534 				return (-1);
535 
536 			if (write_shdr(pgc, shstrtab_data[STR_CTF],
537 			    SHT_PROGBITS, 0, fptr->file_map->map_pmap.pr_vaddr,
538 			    *pgc->pgc_doff, fptr->file_ctf_size, symindex, 0,
539 			    4, 0) != 0)
540 				return (-1);
541 
542 			index++;
543 			*pgc->pgc_doff += roundup(fptr->file_ctf_size, 8);
544 		}
545 
546 		if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
547 		    fptr->file_symtab.sym_data_pri != NULL &&
548 		    fptr->file_symtab.sym_symn != 0 &&
549 		    fptr->file_symtab.sym_strs != NULL) {
550 			if (dump_symtab(pgc, fptr, index, 0) != 0)
551 				return (-1);
552 			index += 2;
553 		}
554 
555 		if ((pgc->pgc_content & CC_CONTENT_DEBUG) != 0 &&
556 		    dump_debug(pgc, fptr, &index) != 0) {
557 			return (-1);
558 		}
559 	}
560 
561 	return (0);
562 }
563 
564 /*ARGSUSED*/
565 static int
566 dump_map(void *data, const prmap_t *pmp, const char *name)
567 {
568 	pgcore_t *pgc = data;
569 	struct ps_prochandle *P = pgc->P;
570 #ifdef _LP64
571 	Elf64_Phdr phdr;
572 #else
573 	Elf32_Phdr phdr;
574 #endif
575 	size_t n;
576 
577 	bzero(&phdr, sizeof (phdr));
578 	phdr.p_type = PT_LOAD;
579 	phdr.p_vaddr = pmp->pr_vaddr;
580 	phdr.p_memsz = pmp->pr_size;
581 	if (pmp->pr_mflags & MA_READ)
582 		phdr.p_flags |= PF_R;
583 	if (pmp->pr_mflags & MA_WRITE)
584 		phdr.p_flags |= PF_W;
585 	if (pmp->pr_mflags & MA_EXEC)
586 		phdr.p_flags |= PF_X;
587 
588 	if (pmp->pr_vaddr + pmp->pr_size > P->status.pr_stkbase &&
589 	    pmp->pr_vaddr < P->status.pr_stkbase + P->status.pr_stksize) {
590 		if (!(pgc->pgc_content & CC_CONTENT_STACK))
591 			goto exclude;
592 
593 	} else if ((pmp->pr_mflags & MA_ANON) &&
594 	    pmp->pr_vaddr + pmp->pr_size > P->status.pr_brkbase &&
595 	    pmp->pr_vaddr < P->status.pr_brkbase + P->status.pr_brksize) {
596 		if (!(pgc->pgc_content & CC_CONTENT_HEAP))
597 			goto exclude;
598 
599 	} else if (pmp->pr_mflags & MA_ISM) {
600 		if (pmp->pr_mflags & MA_NORESERVE) {
601 			if (!(pgc->pgc_content & CC_CONTENT_DISM))
602 				goto exclude;
603 		} else {
604 			if (!(pgc->pgc_content & CC_CONTENT_ISM))
605 				goto exclude;
606 		}
607 
608 	} else if (pmp->pr_mflags & MA_SHM) {
609 		if (!(pgc->pgc_content & CC_CONTENT_SHM))
610 			goto exclude;
611 
612 	} else if (pmp->pr_mflags & MA_SHARED) {
613 		if (pmp->pr_mflags & MA_ANON) {
614 			if (!(pgc->pgc_content & CC_CONTENT_SHANON))
615 				goto exclude;
616 		} else {
617 			if (!(pgc->pgc_content & CC_CONTENT_SHFILE))
618 				goto exclude;
619 		}
620 
621 	} else if (pmp->pr_mflags & MA_ANON) {
622 		if (!(pgc->pgc_content & CC_CONTENT_ANON))
623 			goto exclude;
624 
625 	} else if (phdr.p_flags == (PF_R | PF_X)) {
626 		if (!(pgc->pgc_content & CC_CONTENT_TEXT))
627 			goto exclude;
628 
629 	} else if (phdr.p_flags == PF_R) {
630 		if (!(pgc->pgc_content & CC_CONTENT_RODATA))
631 			goto exclude;
632 
633 	} else {
634 		if (!(pgc->pgc_content & CC_CONTENT_DATA))
635 			goto exclude;
636 	}
637 
638 	n = 0;
639 	while (n < pmp->pr_size) {
640 		size_t csz = MIN(pmp->pr_size - n, pgc->pgc_chunksz);
641 		ssize_t ret;
642 
643 		/*
644 		 * If we happen to have a PROT_NONE mapping, don't try to read
645 		 * from the address space.
646 		 */
647 		if ((pmp->pr_mflags & (MA_READ | MA_WRITE | MA_EXEC)) == 0) {
648 			bzero(pgc->pgc_chunk, csz);
649 			ret = csz;
650 		} else {
651 			ret = Pread(P, pgc->pgc_chunk, csz, pmp->pr_vaddr + n);
652 		}
653 
654 		/*
655 		 * If we can't read out part of the victim's address
656 		 * space for some reason ignore that failure and try to
657 		 * emit a partial core file without that mapping's data.
658 		 * As in the kernel, we mark these failures with the
659 		 * PF_SUNW_FAILURE flag and store the errno where the
660 		 * mapping would have been.
661 		 */
662 		if (ret != csz || gc_pwrite64(pgc->pgc_fd, pgc->pgc_chunk, csz,
663 		    *pgc->pgc_doff + n) != 0) {
664 			int err = errno;
665 			(void) gc_pwrite64(pgc->pgc_fd, &err, sizeof (err),
666 			    *pgc->pgc_doff);
667 			*pgc->pgc_doff += roundup(sizeof (err), 8);
668 
669 			phdr.p_flags |= PF_SUNW_FAILURE;
670 			(void) ftruncate64(pgc->pgc_fd, *pgc->pgc_doff);
671 			goto exclude;
672 		}
673 
674 		n += csz;
675 	}
676 
677 	phdr.p_offset = *pgc->pgc_doff;
678 	phdr.p_filesz = pmp->pr_size;
679 	*pgc->pgc_doff += roundup(phdr.p_filesz, 8);
680 
681 exclude:
682 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
683 		if (gc_pwrite64(pgc->pgc_fd, &phdr, sizeof (phdr),
684 		    *pgc->pgc_poff) != 0)
685 			return (1);
686 
687 		*pgc->pgc_poff += sizeof (phdr);
688 #ifdef _LP64
689 	} else {
690 		Elf32_Phdr phdr32;
691 
692 		bzero(&phdr32, sizeof (phdr32));
693 		phdr32.p_type = phdr.p_type;
694 		phdr32.p_vaddr = (Elf32_Addr)phdr.p_vaddr;
695 		phdr32.p_memsz = (Elf32_Word)phdr.p_memsz;
696 		phdr32.p_flags = phdr.p_flags;
697 		phdr32.p_offset = (Elf32_Off)phdr.p_offset;
698 		phdr32.p_filesz = (Elf32_Word)phdr.p_filesz;
699 
700 		if (gc_pwrite64(pgc->pgc_fd, &phdr32, sizeof (phdr32),
701 		    *pgc->pgc_poff) != 0)
702 			return (1);
703 
704 		*pgc->pgc_poff += sizeof (phdr32);
705 #endif	/* _LP64 */
706 	}
707 
708 	return (0);
709 }
710 
711 int
712 write_shstrtab(struct ps_prochandle *P, pgcore_t *pgc)
713 {
714 	off64_t off = *pgc->pgc_doff;
715 	size_t size = 0;
716 	shstrtab_t *s = &pgc->pgc_shstrtab;
717 
718 	if (shstrtab_size(s) == 1)
719 		return (0);
720 
721 	/*
722 	 * Preemptively stick the name of the shstrtab in the string table.
723 	 */
724 	if (!shstrtab_ndx(&pgc->pgc_shstrtab,
725 	    shstrtab_data[STR_SHSTRTAB], NULL)) {
726 		return (1);
727 	}
728 	size = shstrtab_size(s);
729 
730 	/*
731 	 * Dump all the strings that we used being sure we include the
732 	 * terminating null character.
733 	 */
734 	for (shstrtab_ent_t *ent = list_head(&s->sst_names); ent != NULL;
735 	    ent = list_next(&s->sst_names, ent)) {
736 		if (gc_pwrite64(pgc->pgc_fd, ent->sste_name, ent->sste_len,
737 		    off + ent->sste_offset) != 0) {
738 			return (1);
739 		}
740 	}
741 
742 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
743 		Elf32_Shdr shdr;
744 
745 		bzero(&shdr, sizeof (shdr));
746 		if (!shstrtab_ndx(&pgc->pgc_shstrtab,
747 		    shstrtab_data[STR_SHSTRTAB], &shdr.sh_name)) {
748 			return (1);
749 		}
750 		shdr.sh_size = size;
751 		shdr.sh_offset = *pgc->pgc_doff;
752 		shdr.sh_addralign = 1;
753 		shdr.sh_flags = SHF_STRINGS;
754 		shdr.sh_type = SHT_STRTAB;
755 
756 		if (gc_pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
757 		    *pgc->pgc_soff) != 0)
758 			return (1);
759 
760 		*pgc->pgc_soff += sizeof (shdr);
761 #ifdef _LP64
762 	} else {
763 		Elf64_Shdr shdr;
764 
765 		bzero(&shdr, sizeof (shdr));
766 		if (!shstrtab_ndx(&pgc->pgc_shstrtab,
767 		    shstrtab_data[STR_SHSTRTAB], &shdr.sh_name)) {
768 			return (1);
769 		}
770 		shdr.sh_size = size;
771 		shdr.sh_offset = *pgc->pgc_doff;
772 		shdr.sh_addralign = 1;
773 		shdr.sh_flags = SHF_STRINGS;
774 		shdr.sh_type = SHT_STRTAB;
775 
776 		if (gc_pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
777 		    *pgc->pgc_soff) != 0)
778 			return (1);
779 
780 		*pgc->pgc_soff += sizeof (shdr);
781 #endif	/* _LP64 */
782 	}
783 
784 	*pgc->pgc_doff += roundup(size, 8);
785 
786 	return (0);
787 }
788 
789 /*
790  * Don't explicity stop the process; that's up to the consumer.
791  */
792 #define	NOTES_SECTIONS 1
793 int
794 Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
795 {
796 	char plat[SYS_NMLN];
797 	char zonename[ZONENAME_MAX];
798 	int platlen = -1;
799 	pgcore_t pgc;
800 	off64_t poff, soff, doff, boff;
801 	struct utsname uts;
802 	uint_t nphdrs, nshdrs;
803 
804 	if (ftruncate64(fd, 0) != 0)
805 		return (-1);
806 
807 	if (content == CC_CONTENT_INVALID) {
808 		errno = EINVAL;
809 		return (-1);
810 	}
811 
812 	/*
813 	 * Cache the mappings and other useful data.
814 	 */
815 	(void) Prd_agent(P);
816 	(void) Ppsinfo(P);
817 
818 	(void) memset(&pgc, 0, sizeof (pgc));
819 	pgc.P = P;
820 	pgc.pgc_fd = fd;
821 	pgc.pgc_poff = &poff;
822 	pgc.pgc_soff = &soff;
823 	pgc.pgc_doff = &doff;
824 	pgc.pgc_content = content;
825 	pgc.pgc_chunksz = PAGESIZE;
826 	if ((pgc.pgc_chunk = malloc(pgc.pgc_chunksz)) == NULL)
827 		return (-1);
828 
829 	if (!shstrtab_init(&pgc.pgc_shstrtab)) {
830 		goto err;
831 	}
832 
833 	/*
834 	 * There is one PT_NOTE program header for ancillary data, and one
835 	 * program header for each mapping.
836 	 */
837 	nphdrs = NOTES_SECTIONS + P->map_count;
838 	nshdrs = count_sections(&pgc);
839 
840 	(void) Pplatform(P, plat, sizeof (plat));
841 	platlen = strlen(plat) + 1;
842 	Preadauxvec(P);
843 	(void) Puname(P, &uts);
844 	if (Pzonename(P, zonename, sizeof (zonename)) == NULL)
845 		zonename[0] = '\0';
846 
847 	/*
848 	 * The core file contents may required zero section headers, but if we
849 	 * overflow the 16 bits allotted to the program header count in the ELF
850 	 * header, we'll need that program header at index zero.
851 	 */
852 	if (nshdrs == 0 && nphdrs >= PN_XNUM)
853 		nshdrs = 1;
854 
855 	/*
856 	 * Set up the ELF header.
857 	 */
858 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
859 		Elf32_Ehdr ehdr;
860 
861 		bzero(&ehdr, sizeof (ehdr));
862 		ehdr.e_ident[EI_MAG0] = ELFMAG0;
863 		ehdr.e_ident[EI_MAG1] = ELFMAG1;
864 		ehdr.e_ident[EI_MAG2] = ELFMAG2;
865 		ehdr.e_ident[EI_MAG3] = ELFMAG3;
866 		ehdr.e_type = ET_CORE;
867 
868 		ehdr.e_ident[EI_CLASS] = ELFCLASS32;
869 #if defined(__sparc)
870 		ehdr.e_machine = EM_SPARC;
871 		ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
872 #elif defined(__i386) || defined(__amd64)
873 		ehdr.e_machine = EM_386;
874 		ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
875 #else
876 #error "unknown machine type"
877 #endif
878 		ehdr.e_ident[EI_VERSION] = EV_CURRENT;
879 
880 		ehdr.e_version = EV_CURRENT;
881 		ehdr.e_ehsize = sizeof (ehdr);
882 
883 		if (nphdrs >= PN_XNUM)
884 			ehdr.e_phnum = PN_XNUM;
885 		else
886 			ehdr.e_phnum = (unsigned short)nphdrs;
887 
888 		ehdr.e_phentsize = sizeof (Elf32_Phdr);
889 		ehdr.e_phoff = ehdr.e_ehsize;
890 
891 		if (nshdrs > 0) {
892 			if (nshdrs >= SHN_LORESERVE)
893 				ehdr.e_shnum = 0;
894 			else
895 				ehdr.e_shnum = (unsigned short)nshdrs;
896 
897 			if (nshdrs - 1 >= SHN_LORESERVE)
898 				ehdr.e_shstrndx = SHN_XINDEX;
899 			else
900 				ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
901 
902 			ehdr.e_shentsize = sizeof (Elf32_Shdr);
903 			ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
904 		}
905 
906 		if (gc_pwrite64(fd, &ehdr, sizeof (ehdr), 0) != 0)
907 			goto err;
908 
909 		poff = ehdr.e_phoff;
910 		soff = ehdr.e_shoff;
911 		doff = boff = ehdr.e_ehsize +
912 		    ehdr.e_phentsize * nphdrs +
913 		    ehdr.e_shentsize * nshdrs;
914 
915 #ifdef _LP64
916 	} else {
917 		Elf64_Ehdr ehdr;
918 
919 		bzero(&ehdr, sizeof (ehdr));
920 		ehdr.e_ident[EI_MAG0] = ELFMAG0;
921 		ehdr.e_ident[EI_MAG1] = ELFMAG1;
922 		ehdr.e_ident[EI_MAG2] = ELFMAG2;
923 		ehdr.e_ident[EI_MAG3] = ELFMAG3;
924 		ehdr.e_type = ET_CORE;
925 
926 		ehdr.e_ident[EI_CLASS] = ELFCLASS64;
927 #if defined(__sparc)
928 		ehdr.e_machine = EM_SPARCV9;
929 		ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
930 #elif defined(__i386) || defined(__amd64)
931 		ehdr.e_machine = EM_AMD64;
932 		ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
933 #else
934 #error "unknown machine type"
935 #endif
936 		ehdr.e_ident[EI_VERSION] = EV_CURRENT;
937 
938 		ehdr.e_version = EV_CURRENT;
939 		ehdr.e_ehsize = sizeof (ehdr);
940 
941 		if (nphdrs >= PN_XNUM)
942 			ehdr.e_phnum = PN_XNUM;
943 		else
944 			ehdr.e_phnum = (unsigned short)nphdrs;
945 
946 		ehdr.e_phentsize = sizeof (Elf64_Phdr);
947 		ehdr.e_phoff = ehdr.e_ehsize;
948 
949 		if (nshdrs > 0) {
950 			if (nshdrs >= SHN_LORESERVE)
951 				ehdr.e_shnum = 0;
952 			else
953 				ehdr.e_shnum = (unsigned short)nshdrs;
954 
955 			if (nshdrs - 1 >= SHN_LORESERVE)
956 				ehdr.e_shstrndx = SHN_XINDEX;
957 			else
958 				ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
959 
960 			ehdr.e_shentsize = sizeof (Elf64_Shdr);
961 			ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
962 		}
963 
964 		if (gc_pwrite64(fd, &ehdr, sizeof (ehdr), 0) != 0)
965 			goto err;
966 
967 		poff = ehdr.e_phoff;
968 		soff = ehdr.e_shoff;
969 		doff = boff = ehdr.e_ehsize +
970 		    ehdr.e_phentsize * nphdrs +
971 		    ehdr.e_shentsize * nshdrs;
972 
973 #endif	/* _LP64 */
974 	}
975 
976 	/*
977 	 * Write the zero indexed section if it exists.
978 	 */
979 	if (nshdrs > 0 && write_shdr(&pgc, shstrtab_data[STR_NONE], 0, 0, 0, 0,
980 	    nshdrs >= SHN_LORESERVE ? nshdrs : 0,
981 	    nshdrs - 1 >= SHN_LORESERVE ? nshdrs - 1 : 0,
982 	    nphdrs >= PN_XNUM ? nphdrs : 0, 0, 0) != 0)
983 		goto err;
984 
985 	/*
986 	 * Construct the note header and section.
987 	 */
988 
989 	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
990 		if (write_note(fd, NT_PSINFO, &P->psinfo, sizeof (psinfo_t),
991 		    &doff) != 0) {
992 			goto err;
993 		}
994 		if (write_note(fd, NT_PSTATUS, &P->status, sizeof (pstatus_t),
995 		    &doff) != 0) {
996 			goto err;
997 		}
998 		if (write_note(fd, NT_AUXV, P->auxv,
999 		    P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
1000 			goto err;
1001 		}
1002 #ifdef _LP64
1003 	} else {
1004 		psinfo32_t pi32;
1005 		pstatus32_t ps32;
1006 		auxv32_t *av32;
1007 		size_t size = sizeof (auxv32_t) * P->nauxv;
1008 		int i;
1009 
1010 		psinfo_n_to_32(&P->psinfo, &pi32);
1011 		if (write_note(fd, NT_PSINFO, &pi32, sizeof (psinfo32_t),
1012 		    &doff) != 0) {
1013 			goto err;
1014 		}
1015 		pstatus_n_to_32(&P->status, &ps32);
1016 		if (write_note(fd, NT_PSTATUS, &ps32, sizeof (pstatus32_t),
1017 		    &doff) != 0) {
1018 			goto err;
1019 		}
1020 		if ((av32 = malloc(size)) == NULL)
1021 			goto err;
1022 
1023 		for (i = 0; i < P->nauxv; i++) {
1024 			auxv_n_to_32(&P->auxv[i], &av32[i]);
1025 		}
1026 
1027 		if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
1028 			free(av32);
1029 			goto err;
1030 		}
1031 
1032 		free(av32);
1033 #endif	/* _LP64 */
1034 	}
1035 
1036 	if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0 ||
1037 	    write_note(fd, NT_UTSNAME, &uts, sizeof (uts), &doff) != 0 ||
1038 	    write_note(fd, NT_CONTENT, &content, sizeof (content), &doff) != 0)
1039 		goto err;
1040 
1041 	{
1042 		prcred_t cred, *cp;
1043 		size_t size = sizeof (prcred_t);
1044 
1045 		if (Pcred(P, &cred, 0) != 0)
1046 			goto err;
1047 
1048 		if (cred.pr_ngroups > 0)
1049 			size += sizeof (gid_t) * (cred.pr_ngroups - 1);
1050 		if ((cp = malloc(size)) == NULL)
1051 			goto err;
1052 
1053 		if (Pcred(P, cp, cred.pr_ngroups) != 0 ||
1054 		    write_note(fd, NT_PRCRED, cp, size, &doff) != 0) {
1055 			free(cp);
1056 			goto err;
1057 		}
1058 
1059 		free(cp);
1060 	}
1061 
1062 	{
1063 		prpriv_t *ppriv = NULL;
1064 		const priv_impl_info_t *pinfo;
1065 		size_t pprivsz, pinfosz;
1066 
1067 		if (Ppriv(P, &ppriv) == -1)
1068 			goto err;
1069 		pprivsz = PRIV_PRPRIV_SIZE(ppriv);
1070 
1071 		if (write_note(fd, NT_PRPRIV, ppriv, pprivsz, &doff) != 0) {
1072 			Ppriv_free(P, ppriv);
1073 			goto err;
1074 		}
1075 		Ppriv_free(P, ppriv);
1076 
1077 		if ((pinfo = getprivimplinfo()) == NULL)
1078 			goto err;
1079 		pinfosz = PRIV_IMPL_INFO_SIZE(pinfo);
1080 
1081 		if (write_note(fd, NT_PRPRIVINFO, pinfo, pinfosz, &doff) != 0)
1082 			goto err;
1083 	}
1084 
1085 	if (write_note(fd, NT_ZONENAME, zonename, strlen(zonename) + 1,
1086 	    &doff) != 0)
1087 		goto err;
1088 
1089 	{
1090 		fditer_t iter;
1091 		iter.fd_fd = fd;
1092 		iter.fd_doff = &doff;
1093 
1094 		if (Pfdinfo_iter(P, iter_fd, &iter) != 0)
1095 			goto err;
1096 	}
1097 
1098 
1099 	{
1100 		prsecflags_t *psf = NULL;
1101 
1102 		if (Psecflags(P, &psf) != 0)
1103 			goto err;
1104 
1105 		if (write_note(fd, NT_SECFLAGS, psf,
1106 		    sizeof (prsecflags_t), &doff) != 0) {
1107 			Psecflags_free(psf);
1108 			goto err;
1109 		}
1110 
1111 		Psecflags_free(psf);
1112 	}
1113 
1114 	{
1115 		prcwd_t *cwd = NULL;
1116 
1117 		if (Pcwd(P, &cwd) != 0)
1118 			goto err;
1119 
1120 		if (write_note(fd, NT_CWD, cwd,
1121 		    sizeof (prcwd_t), &doff) != 0) {
1122 			Pcwd_free(cwd);
1123 			goto err;
1124 		}
1125 
1126 		Pcwd_free(cwd);
1127 	}
1128 
1129 #if defined(__i386) || defined(__amd64)
1130 	/* CSTYLED */
1131 	{
1132 		struct ssd *ldtp;
1133 		size_t size;
1134 		int nldt;
1135 
1136 		/*
1137 		 * Only dump out non-zero sized LDT notes.
1138 		 */
1139 		if ((nldt = Pldt(P, NULL, 0)) != 0) {
1140 			size = sizeof (struct ssd) * nldt;
1141 			if ((ldtp = malloc(size)) == NULL)
1142 				goto err;
1143 
1144 			if (Pldt(P, ldtp, nldt) == -1 ||
1145 			    write_note(fd, NT_LDT, ldtp, size, &doff) != 0) {
1146 				free(ldtp);
1147 				goto err;
1148 			}
1149 
1150 			free(ldtp);
1151 		}
1152 	}
1153 #endif	/* __i386 || __amd64 */
1154 
1155 	if (Plwp_iter_all(P, per_lwp, &pgc) != 0)
1156 		goto err;
1157 
1158 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
1159 		Elf32_Phdr phdr;
1160 
1161 		bzero(&phdr, sizeof (phdr));
1162 		phdr.p_type = PT_NOTE;
1163 		phdr.p_flags = PF_R;
1164 		phdr.p_offset = (Elf32_Off)boff;
1165 		phdr.p_filesz = doff - boff;
1166 		boff = doff;
1167 
1168 		if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0)
1169 			goto err;
1170 		poff += sizeof (phdr);
1171 #ifdef _LP64
1172 	} else {
1173 		Elf64_Phdr phdr;
1174 
1175 		bzero(&phdr, sizeof (phdr));
1176 		phdr.p_type = PT_NOTE;
1177 		phdr.p_flags = PF_R;
1178 		phdr.p_offset = boff;
1179 		phdr.p_filesz = doff - boff;
1180 		boff = doff;
1181 
1182 		if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0)
1183 			goto err;
1184 		poff += sizeof (phdr);
1185 #endif	/* _LP64 */
1186 	}
1187 
1188 	/*
1189 	 * Construct the headers for each mapping and write out its data
1190 	 * if the content parameter indicates that it should be present
1191 	 * in the core file.
1192 	 */
1193 	if (Pmapping_iter(P, dump_map, &pgc) != 0)
1194 		goto err;
1195 
1196 	if (dump_sections(&pgc) != 0)
1197 		goto err;
1198 
1199 	if (write_shstrtab(P, &pgc) != 0)
1200 		goto err;
1201 
1202 	free(pgc.pgc_chunk);
1203 	shstrtab_fini(&pgc.pgc_shstrtab);
1204 
1205 	return (0);
1206 
1207 err:
1208 	/*
1209 	 * Wipe out anything we may have written if there was an error.
1210 	 */
1211 	(void) ftruncate64(fd, 0);
1212 	free(pgc.pgc_chunk);
1213 	shstrtab_fini(&pgc.pgc_shstrtab);
1214 
1215 	return (-1);
1216 }
1217 
1218 static const char *content_str[] = {
1219 	"stack",	/* CC_CONTENT_STACK */
1220 	"heap",		/* CC_CONTENT_HEAP */
1221 	"shfile",	/* CC_CONTENT_SHFILE */
1222 	"shanon",	/* CC_CONTENT_SHANON */
1223 	"text",		/* CC_CONTENT_TEXT */
1224 	"data",		/* CC_CONTENT_DATA */
1225 	"rodata",	/* CC_CONTENT_RODATA */
1226 	"anon",		/* CC_CONTENT_ANON */
1227 	"shm",		/* CC_CONTENT_SHM */
1228 	"ism",		/* CC_CONTENT_ISM */
1229 	"dism",		/* CC_CONTENT_DISM */
1230 	"ctf",		/* CC_CONTENT_CTF */
1231 	"symtab",	/* CC_CONTENT_SYMTAB */
1232 	"debug"		/* CC_CONTENT_DEBUG */
1233 };
1234 
1235 static uint_t ncontent_str = sizeof (content_str) / sizeof (content_str[0]);
1236 
1237 #define	STREQ(a, b, n)	(strlen(b) == (n) && strncmp(a, b, n) == 0)
1238 
1239 int
1240 proc_str2content(const char *str, core_content_t *cp)
1241 {
1242 	const char *cur = str;
1243 	int add = 1;
1244 	core_content_t mask, content = 0;
1245 
1246 	for (;;) {
1247 		for (cur = str; isalpha(*cur); cur++)
1248 			continue;
1249 
1250 		if (STREQ(str, "default", cur - str)) {
1251 			mask = CC_CONTENT_DEFAULT;
1252 		} else if (STREQ(str, "all", cur - str)) {
1253 			mask = CC_CONTENT_ALL;
1254 		} else if (STREQ(str, "none", cur - str)) {
1255 			mask = 0;
1256 		} else {
1257 			int i = 0;
1258 
1259 			while (!STREQ(str, content_str[i], cur - str)) {
1260 				i++;
1261 
1262 				if (i >= ncontent_str)
1263 					return (-1);
1264 			}
1265 
1266 			mask = (core_content_t)1 << i;
1267 		}
1268 
1269 		if (add)
1270 			content |= mask;
1271 		else
1272 			content &= ~mask;
1273 
1274 		switch (*cur) {
1275 		case '\0':
1276 			*cp = content;
1277 			return (0);
1278 		case '+':
1279 			add = 1;
1280 			break;
1281 		case '-':
1282 			add = 0;
1283 			break;
1284 		default:
1285 			return (-1);
1286 		}
1287 
1288 		str = cur + 1;
1289 	}
1290 }
1291 
1292 static int
1293 popc(core_content_t x)
1294 {
1295 	int i;
1296 
1297 	for (i = 0; x != 0; i++)
1298 		x &= x - 1;
1299 
1300 	return (i);
1301 }
1302 
1303 int
1304 proc_content2str(core_content_t content, char *buf, size_t size)
1305 {
1306 	int nonecnt, defcnt, allcnt;
1307 	core_content_t mask, bit;
1308 	int first;
1309 	uint_t index;
1310 	size_t n, tot = 0;
1311 
1312 	if (content == 0)
1313 		return ((int)strlcpy(buf, "none", size));
1314 
1315 	if (content & ~CC_CONTENT_ALL)
1316 		return ((int)strlcpy(buf, "<invalid>", size));
1317 
1318 	nonecnt = popc(content);
1319 	defcnt = 1 + popc(content ^ CC_CONTENT_DEFAULT);
1320 	allcnt = 1 + popc(content ^ CC_CONTENT_ALL);
1321 
1322 	if (defcnt <= nonecnt && defcnt <= allcnt) {
1323 		mask = content ^ CC_CONTENT_DEFAULT;
1324 		first = 0;
1325 		tot += (n = strlcpy(buf, "default", size));
1326 		if (n > size)
1327 			n = size;
1328 		buf += n;
1329 		size -= n;
1330 	} else if (allcnt < nonecnt) {
1331 		mask = content ^ CC_CONTENT_ALL;
1332 		first = 0;
1333 		tot += (n = strlcpy(buf, "all", size));
1334 		if (n > size)
1335 			n = size;
1336 		buf += n;
1337 		size -= n;
1338 	} else {
1339 		mask = content;
1340 		first = 1;
1341 	}
1342 
1343 	while (mask != 0) {
1344 		bit = mask ^ (mask & (mask - 1));
1345 
1346 		if (!first) {
1347 			if (size > 1) {
1348 				*buf = (bit & content) ? '+' : '-';
1349 				buf++;
1350 				size--;
1351 			}
1352 
1353 			tot++;
1354 		}
1355 		index = popc(bit - 1);
1356 		tot += (n = strlcpy(buf, content_str[index], size));
1357 		if (n > size)
1358 			n = size;
1359 		buf += n;
1360 		size -= n;
1361 
1362 		mask ^= bit;
1363 		first = 0;
1364 	}
1365 
1366 	return ((int)tot);
1367 }
1368