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
gc_pwrite64(int fd,const void * buf,size_t len,off64_t off)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
Pgcore(struct ps_prochandle * P,const char * fname,core_content_t content)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
write_note(int fd,uint_t type,const void * desc,size_t descsz,off64_t * offp)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
per_lwp(void * data,const lwpstatus_t * lsp,const lwpsinfo_t * lip)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
iter_fd(void * data,const prfdinfo_t * fdinfo)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
is_debug_section(file_info_t * fptr,GElf_Shdr * shdr)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
count_debug(file_info_t * fptr)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
count_sections(pgcore_t * pgc)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
write_shdr(pgcore_t * pgc,const char * name,uint_t type,ulong_t flags,uintptr_t addr,ulong_t offset,size_t size,uint_t link,uint_t info,uintptr_t addralign,uintptr_t entsize)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
dump_symtab(pgcore_t * pgc,file_info_t * fptr,uint_t index,int dynsym)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
dump_debug(pgcore_t * pgc,file_info_t * fptr,uint_t * indexp)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
dump_sections(pgcore_t * pgc)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
dump_map(void * data,const prmap_t * pmp,const char * name)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
write_shstrtab(struct ps_prochandle * P,pgcore_t * pgc)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
Pfgcore(struct ps_prochandle * P,int fd,core_content_t content)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
proc_str2content(const char * str,core_content_t * cp)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
popc(core_content_t x)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
proc_content2str(core_content_t content,char * buf,size_t size)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