Index: head/usr.bin/cmp/cmp.c =================================================================== --- head/usr.bin/cmp/cmp.c (revision 306812) +++ head/usr.bin/cmp/cmp.c (revision 306813) @@ -1,229 +1,218 @@ /* * Copyright (c) 1987, 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1987, 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)cmp.c 8.3 (Berkeley) 4/2/94"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include #include #include #include -#include #include #include "extern.h" int lflag, sflag, xflag, zflag; static void usage(void); int main(int argc, char *argv[]) { struct stat sb1, sb2; off_t skip1, skip2; int ch, fd1, fd2, oflag, special; const char *file1, *file2; cap_rights_t rights; - unsigned long cmd; uint32_t fcntls; oflag = O_RDONLY; while ((ch = getopt(argc, argv, "hlsxz")) != -1) switch (ch) { case 'h': /* Don't follow symlinks */ oflag |= O_NOFOLLOW; break; case 'l': /* print all differences */ lflag = 1; break; case 's': /* silent run */ sflag = 1; zflag = 1; break; case 'x': /* hex output */ lflag = 1; xflag = 1; break; case 'z': /* compare size first */ zflag = 1; break; case '?': default: usage(); } argv += optind; argc -= optind; if (lflag && sflag) errx(ERR_EXIT, "specifying -s with -l or -x is not permitted"); if (argc < 2 || argc > 4) usage(); /* Backward compatibility -- handle "-" meaning stdin. */ special = 0; if (strcmp(file1 = argv[0], "-") == 0) { special = 1; fd1 = 0; file1 = "stdin"; } else if ((fd1 = open(file1, oflag, 0)) < 0 && errno != EMLINK) { if (!sflag) err(ERR_EXIT, "%s", file1); else exit(ERR_EXIT); } if (strcmp(file2 = argv[1], "-") == 0) { if (special) errx(ERR_EXIT, "standard input may only be specified once"); special = 1; fd2 = 0; file2 = "stdin"; } else if ((fd2 = open(file2, oflag, 0)) < 0 && errno != EMLINK) { if (!sflag) err(ERR_EXIT, "%s", file2); else exit(ERR_EXIT); } skip1 = argc > 2 ? strtol(argv[2], NULL, 0) : 0; skip2 = argc == 4 ? strtol(argv[3], NULL, 0) : 0; if (fd1 == -1) { if (fd2 == -1) { c_link(file1, skip1, file2, skip2); exit(0); } else if (!sflag) errx(ERR_EXIT, "%s: Not a symbolic link", file2); else exit(ERR_EXIT); } else if (fd2 == -1) { if (!sflag) errx(ERR_EXIT, "%s: Not a symbolic link", file1); else exit(ERR_EXIT); } cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_MMAP_R); if (cap_rights_limit(fd1, &rights) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit rights for %s", file1); if (cap_rights_limit(fd2, &rights) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit rights for %s", file2); /* Required for fdopen(3). */ fcntls = CAP_FCNTL_GETFL; if (cap_fcntls_limit(fd1, fcntls) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit fcntls for %s", file1); if (cap_fcntls_limit(fd2, fcntls) < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to limit fcntls for %s", file2); - cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE, CAP_IOCTL); - if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) - err(ERR_EXIT, "unable to limit rights for stdout"); + if (caph_limit_stdout() == -1 || caph_limit_stderr() == -1) + err(ERR_EXIT, "unable to limit stdio"); - /* Required for printf(3) via isatty(3). */ - cmd = TIOCGETA; - if (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS) - err(ERR_EXIT, "unable to limit ioctls for stdout"); - - /* - * Cache NLS data, for strerror, for err(3), before entering capability - * mode. - */ - (void)catopen("libc", NL_CAT_LOCALE); + caph_cache_catpages(); if (cap_enter() < 0 && errno != ENOSYS) err(ERR_EXIT, "unable to enter capability mode"); if (!special) { if (fstat(fd1, &sb1)) { if (!sflag) err(ERR_EXIT, "%s", file1); else exit(ERR_EXIT); } if (!S_ISREG(sb1.st_mode)) special = 1; else { if (fstat(fd2, &sb2)) { if (!sflag) err(ERR_EXIT, "%s", file2); else exit(ERR_EXIT); } if (!S_ISREG(sb2.st_mode)) special = 1; } } if (special) c_special(fd1, file1, skip1, fd2, file2, skip2); else { if (zflag && sb1.st_size != sb2.st_size) { if (!sflag) (void) printf("%s %s differ: size\n", file1, file2); exit(DIFF_EXIT); } c_regular(fd1, file1, skip1, sb1.st_size, fd2, file2, skip2, sb2.st_size); } exit(0); } static void usage(void) { (void)fprintf(stderr, "usage: cmp [-l | -s | -x] [-hz] file1 file2 [skip1 [skip2]]\n"); exit(ERR_EXIT); } Index: head/usr.bin/col/col.c =================================================================== --- head/usr.bin/col/col.c (revision 306812) +++ head/usr.bin/col/col.c (revision 306813) @@ -1,599 +1,591 @@ /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Michael Rendell of the Memorial University of Newfoundland. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)col.c 8.5 (Berkeley) 5/4/95"; #endif #endif #include __FBSDID("$FreeBSD$"); #include +#include #include #include #include #include #include #include #include #include #include #include #define BS '\b' /* backspace */ #define TAB '\t' /* tab */ #define SPACE ' ' /* space */ #define NL '\n' /* newline */ #define CR '\r' /* carriage return */ #define ESC '\033' /* escape */ #define SI '\017' /* shift in to normal character set */ #define SO '\016' /* shift out to alternate character set */ #define VT '\013' /* vertical tab (aka reverse line feed) */ #define RLF '7' /* ESC-7 reverse line feed */ #define RHLF '8' /* ESC-8 reverse half-line feed */ #define FHLF '9' /* ESC-9 forward half-line feed */ /* build up at least this many lines before flushing them out */ #define BUFFER_MARGIN 32 typedef char CSET; typedef struct char_str { #define CS_NORMAL 1 #define CS_ALTERNATE 2 short c_column; /* column character is in */ CSET c_set; /* character set (currently only 2) */ wchar_t c_char; /* character in question */ int c_width; /* character width */ } CHAR; typedef struct line_str LINE; struct line_str { CHAR *l_line; /* characters on the line */ LINE *l_prev; /* previous line */ LINE *l_next; /* next line */ int l_lsize; /* allocated sizeof l_line */ int l_line_len; /* strlen(l_line) */ int l_needs_sort; /* set if chars went in out of order */ int l_max_col; /* max column in the line */ }; static void addto_lineno(int *, int); static LINE *alloc_line(void); static void dowarn(int); static void flush_line(LINE *); static void flush_lines(int); static void flush_blanks(void); static void free_line(LINE *); static void usage(void); static CSET last_set; /* char_set of last char printed */ static LINE *lines; static int compress_spaces; /* if doing space -> tab conversion */ static int fine; /* if `fine' resolution (half lines) */ static int max_bufd_lines; /* max # of half lines to keep in memory */ static int nblank_lines; /* # blanks after last flushed line */ static int no_backspaces; /* if not to output any backspaces */ static int pass_unknown_seqs; /* pass unknown control sequences */ #define PUTC(ch) \ do { \ if (putwchar(ch) == WEOF) \ errx(1, "write error"); \ } while (0) int main(int argc, char **argv) { wint_t ch; CHAR *c; CSET cur_set; /* current character set */ LINE *l; /* current line */ int extra_lines; /* # of lines above first line */ int cur_col; /* current column */ int cur_line; /* line number of current position */ int max_line; /* max value of cur_line */ int this_line; /* line l points to */ int nflushd_lines; /* number of lines that were flushed */ int adjust, opt, warned, width; const char *errstr; - cap_rights_t rights; - unsigned long cmd; (void)setlocale(LC_CTYPE, ""); - cap_rights_init(&rights, CAP_FSTAT, CAP_READ); - if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) - err(1, "unable to limit rights for stdin"); - cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE, CAP_IOCTL); - if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) - err(1, "unable to limit rights for stdout"); - cmd = TIOCGETA; /* required by isatty(3) in printf(3) */ - if (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS) - err(1, "unable to limit ioctls for stdout"); + if (caph_limit_stdio() == -1) + err(1, "unable to limit stdio"); if (cap_enter() < 0 && errno != ENOSYS) err(1, "unable to enter capability mode"); max_bufd_lines = 256; compress_spaces = 1; /* compress spaces into tabs */ while ((opt = getopt(argc, argv, "bfhl:px")) != -1) switch (opt) { case 'b': /* do not output backspaces */ no_backspaces = 1; break; case 'f': /* allow half forward line feeds */ fine = 1; break; case 'h': /* compress spaces into tabs */ compress_spaces = 1; break; case 'l': /* buffered line count */ max_bufd_lines = strtonum(optarg, 1, (INT_MAX - BUFFER_MARGIN) / 2, &errstr) * 2; if (errstr != NULL) errx(1, "bad -l argument, %s: %s", errstr, optarg); break; case 'p': /* pass unknown control sequences */ pass_unknown_seqs = 1; break; case 'x': /* do not compress spaces into tabs */ compress_spaces = 0; break; case '?': default: usage(); } if (optind != argc) usage(); adjust = cur_col = extra_lines = warned = 0; cur_line = max_line = nflushd_lines = this_line = 0; cur_set = last_set = CS_NORMAL; lines = l = alloc_line(); while ((ch = getwchar()) != WEOF) { if (!iswgraph(ch)) { switch (ch) { case BS: /* can't go back further */ if (cur_col == 0) continue; --cur_col; continue; case CR: cur_col = 0; continue; case ESC: /* just ignore EOF */ switch(getwchar()) { /* * In the input stream, accept both the * XPG5 sequences ESC-digit and the * traditional BSD sequences ESC-ctrl. */ case '\007': /* FALLTHROUGH */ case RLF: addto_lineno(&cur_line, -2); break; case '\010': /* FALLTHROUGH */ case RHLF: addto_lineno(&cur_line, -1); break; case '\011': /* FALLTHROUGH */ case FHLF: addto_lineno(&cur_line, 1); if (cur_line > max_line) max_line = cur_line; } continue; case NL: addto_lineno(&cur_line, 2); if (cur_line > max_line) max_line = cur_line; cur_col = 0; continue; case SPACE: ++cur_col; continue; case SI: cur_set = CS_NORMAL; continue; case SO: cur_set = CS_ALTERNATE; continue; case TAB: /* adjust column */ cur_col |= 7; ++cur_col; continue; case VT: addto_lineno(&cur_line, -2); continue; } if (iswspace(ch)) { if ((width = wcwidth(ch)) > 0) cur_col += width; continue; } if (!pass_unknown_seqs) continue; } /* Must stuff ch in a line - are we at the right one? */ if (cur_line + adjust != this_line) { LINE *lnew; /* round up to next line */ adjust = !fine && (cur_line & 1); if (cur_line + adjust < this_line) { while (cur_line + adjust < this_line && l->l_prev != NULL) { l = l->l_prev; this_line--; } if (cur_line + adjust < this_line) { if (nflushd_lines == 0) { /* * Allow backup past first * line if nothing has been * flushed yet. */ while (cur_line + adjust < this_line) { lnew = alloc_line(); l->l_prev = lnew; lnew->l_next = l; l = lines = lnew; extra_lines++; this_line--; } } else { if (!warned++) dowarn(cur_line); cur_line = this_line - adjust; } } } else { /* may need to allocate here */ while (cur_line + adjust > this_line) { if (l->l_next == NULL) { l->l_next = alloc_line(); l->l_next->l_prev = l; } l = l->l_next; this_line++; } } if (this_line > nflushd_lines && this_line - nflushd_lines >= max_bufd_lines + BUFFER_MARGIN) { if (extra_lines) { flush_lines(extra_lines); extra_lines = 0; } flush_lines(this_line - nflushd_lines - max_bufd_lines); nflushd_lines = this_line - max_bufd_lines; } } /* grow line's buffer? */ if (l->l_line_len + 1 >= l->l_lsize) { int need; need = l->l_lsize ? l->l_lsize * 2 : 90; if ((l->l_line = realloc(l->l_line, (unsigned)need * sizeof(CHAR))) == NULL) err(1, NULL); l->l_lsize = need; } c = &l->l_line[l->l_line_len++]; c->c_char = ch; c->c_set = cur_set; c->c_column = cur_col; c->c_width = wcwidth(ch); /* * If things are put in out of order, they will need sorting * when it is flushed. */ if (cur_col < l->l_max_col) l->l_needs_sort = 1; else l->l_max_col = cur_col; if (c->c_width > 0) cur_col += c->c_width; } if (ferror(stdin)) err(1, NULL); if (extra_lines) flush_lines(extra_lines); /* goto the last line that had a character on it */ for (; l->l_next; l = l->l_next) this_line++; flush_lines(this_line - nflushd_lines + 1); /* make sure we leave things in a sane state */ if (last_set != CS_NORMAL) PUTC(SI); /* flush out the last few blank lines */ if (max_line > this_line) nblank_lines = max_line - this_line; if (max_line & 1) nblank_lines++; flush_blanks(); exit(0); } static void flush_lines(int nflush) { LINE *l; while (--nflush >= 0) { l = lines; lines = l->l_next; if (l->l_line) { flush_blanks(); flush_line(l); } if (l->l_line || l->l_next) nblank_lines++; if (l->l_line) (void)free(l->l_line); free_line(l); } if (lines) lines->l_prev = NULL; } /* * Print a number of newline/half newlines. If fine flag is set, nblank_lines * is the number of half line feeds, otherwise it is the number of whole line * feeds. */ static void flush_blanks(void) { int half, i, nb; half = 0; nb = nblank_lines; if (nb & 1) { if (fine) half = 1; else nb++; } nb /= 2; for (i = nb; --i >= 0;) PUTC('\n'); if (half) { PUTC(ESC); PUTC(FHLF); if (!nb) PUTC('\r'); } nblank_lines = 0; } /* * Write a line to stdout taking care of space to tab conversion (-h flag) * and character set shifts. */ static void flush_line(LINE *l) { CHAR *c, *endc; int i, j, nchars, last_col, save, this_col, tot; last_col = 0; nchars = l->l_line_len; if (l->l_needs_sort) { static CHAR *sorted; static int count_size, *count, sorted_size; /* * Do an O(n) sort on l->l_line by column being careful to * preserve the order of characters in the same column. */ if (l->l_lsize > sorted_size) { sorted_size = l->l_lsize; if ((sorted = realloc(sorted, (unsigned)sizeof(CHAR) * sorted_size)) == NULL) err(1, NULL); } if (l->l_max_col >= count_size) { count_size = l->l_max_col + 1; if ((count = realloc(count, (unsigned)sizeof(int) * count_size)) == NULL) err(1, NULL); } memset(count, 0, sizeof(int) * l->l_max_col + 1); for (i = nchars, c = l->l_line; --i >= 0; c++) count[c->c_column]++; /* * calculate running total (shifted down by 1) to use as * indices into new line. */ for (tot = 0, i = 0; i <= l->l_max_col; i++) { save = count[i]; count[i] = tot; tot += save; } for (i = nchars, c = l->l_line; --i >= 0; c++) sorted[count[c->c_column]++] = *c; c = sorted; } else c = l->l_line; while (nchars > 0) { this_col = c->c_column; endc = c; do { ++endc; } while (--nchars > 0 && this_col == endc->c_column); /* if -b only print last character */ if (no_backspaces) { c = endc - 1; if (nchars > 0 && this_col + c->c_width > endc->c_column) continue; } if (this_col > last_col) { int nspace = this_col - last_col; if (compress_spaces && nspace > 1) { while (1) { int tab_col, tab_size; tab_col = (last_col + 8) & ~7; if (tab_col > this_col) break; tab_size = tab_col - last_col; if (tab_size == 1) PUTC(' '); else PUTC('\t'); nspace -= tab_size; last_col = tab_col; } } while (--nspace >= 0) PUTC(' '); last_col = this_col; } for (;;) { if (c->c_set != last_set) { switch (c->c_set) { case CS_NORMAL: PUTC(SI); break; case CS_ALTERNATE: PUTC(SO); } last_set = c->c_set; } PUTC(c->c_char); if ((c + 1) < endc) for (j = 0; j < c->c_width; j++) PUTC('\b'); if (++c >= endc) break; } last_col += (c - 1)->c_width; } } /* * Increment or decrement a line number, checking for overflow. * Stop one below INT_MAX such that the adjust variable is safe. */ void addto_lineno(int *lno, int offset) { if (offset > 0) { if (*lno >= INT_MAX - offset) errx(1, "too many lines"); } else { if (*lno < INT_MIN - offset) errx(1, "too many reverse line feeds"); } *lno += offset; } #define NALLOC 64 static LINE *line_freelist; static LINE * alloc_line(void) { LINE *l; int i; if (!line_freelist) { if ((l = realloc(NULL, sizeof(LINE) * NALLOC)) == NULL) err(1, NULL); line_freelist = l; for (i = 1; i < NALLOC; i++, l++) l->l_next = l + 1; l->l_next = NULL; } l = line_freelist; line_freelist = l->l_next; memset(l, 0, sizeof(LINE)); return (l); } static void free_line(LINE *l) { l->l_next = line_freelist; line_freelist = l; } static void usage(void) { (void)fprintf(stderr, "usage: col [-bfhpx] [-l nline]\n"); exit(1); } static void dowarn(int line) { warnx("warning: can't back up %s", line < 0 ? "past first line" : "-- line already flushed"); } Index: head/usr.bin/elfdump/elfdump.c =================================================================== --- head/usr.bin/elfdump/elfdump.c (revision 306812) +++ head/usr.bin/elfdump/elfdump.c (revision 306813) @@ -1,1261 +1,1257 @@ /*- * Copyright (c) 2003 David O'Brien. All rights reserved. * Copyright (c) 2001 Jake Burkholder * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include -#include #include #define ED_DYN (1<<0) #define ED_EHDR (1<<1) #define ED_GOT (1<<2) #define ED_HASH (1<<3) #define ED_INTERP (1<<4) #define ED_NOTE (1<<5) #define ED_PHDR (1<<6) #define ED_REL (1<<7) #define ED_SHDR (1<<8) #define ED_SYMTAB (1<<9) #define ED_ALL ((1<<10)-1) #define elf_get_addr elf_get_quad #define elf_get_off elf_get_quad #define elf_get_size elf_get_quad enum elf_member { D_TAG = 1, D_PTR, D_VAL, E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY, E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE, E_SHNUM, E_SHSTRNDX, N_NAMESZ, N_DESCSZ, N_TYPE, P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS, P_ALIGN, SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK, SH_INFO, SH_ADDRALIGN, SH_ENTSIZE, ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX, R_OFFSET, R_INFO, RA_OFFSET, RA_INFO, RA_ADDEND }; typedef enum elf_member elf_member_t; static int elf32_offsets[] = { 0, offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr), offsetof(Elf32_Dyn, d_un.d_val), offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), offsetof(Elf32_Ehdr, e_ident[EI_DATA]), offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine), offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry), offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff), offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize), offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum), offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum), offsetof(Elf32_Ehdr, e_shstrndx), offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), offsetof(Elf_Note, n_type), offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset), offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr), offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz), offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align), offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type), offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr), offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size), offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info), offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize), offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value), offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info), offsetof(Elf32_Sym, st_shndx), offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info), offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info), offsetof(Elf32_Rela, r_addend) }; static int elf64_offsets[] = { 0, offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr), offsetof(Elf64_Dyn, d_un.d_val), offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), offsetof(Elf32_Ehdr, e_ident[EI_DATA]), offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine), offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry), offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff), offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize), offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum), offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum), offsetof(Elf64_Ehdr, e_shstrndx), offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), offsetof(Elf_Note, n_type), offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset), offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr), offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz), offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align), offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type), offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr), offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size), offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info), offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize), offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value), offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info), offsetof(Elf64_Sym, st_shndx), offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info), offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info), offsetof(Elf64_Rela, r_addend) }; /* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */ static const char * d_tags(u_int64_t tag) { static char unknown_tag[48]; switch (tag) { case DT_NULL: return "DT_NULL"; case DT_NEEDED: return "DT_NEEDED"; case DT_PLTRELSZ: return "DT_PLTRELSZ"; case DT_PLTGOT: return "DT_PLTGOT"; case DT_HASH: return "DT_HASH"; case DT_STRTAB: return "DT_STRTAB"; case DT_SYMTAB: return "DT_SYMTAB"; case DT_RELA: return "DT_RELA"; case DT_RELASZ: return "DT_RELASZ"; case DT_RELAENT: return "DT_RELAENT"; case DT_STRSZ: return "DT_STRSZ"; case DT_SYMENT: return "DT_SYMENT"; case DT_INIT: return "DT_INIT"; case DT_FINI: return "DT_FINI"; case DT_SONAME: return "DT_SONAME"; case DT_RPATH: return "DT_RPATH"; case DT_SYMBOLIC: return "DT_SYMBOLIC"; case DT_REL: return "DT_REL"; case DT_RELSZ: return "DT_RELSZ"; case DT_RELENT: return "DT_RELENT"; case DT_PLTREL: return "DT_PLTREL"; case DT_DEBUG: return "DT_DEBUG"; case DT_TEXTREL: return "DT_TEXTREL"; case DT_JMPREL: return "DT_JMPREL"; case DT_BIND_NOW: return "DT_BIND_NOW"; case DT_INIT_ARRAY: return "DT_INIT_ARRAY"; case DT_FINI_ARRAY: return "DT_FINI_ARRAY"; case DT_INIT_ARRAYSZ: return "DT_INIT_ARRAYSZ"; case DT_FINI_ARRAYSZ: return "DT_FINI_ARRAYSZ"; case DT_RUNPATH: return "DT_RUNPATH"; case DT_FLAGS: return "DT_FLAGS"; case DT_PREINIT_ARRAY: return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */ case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ"; /* 0x6000000D - 0x6ffff000 operating system-specific semantics */ case 0x6ffffdf5: return "DT_GNU_PRELINKED"; case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ"; case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ"; case 0x6ffffdf8: return "DT_SUNW_CHECKSUM"; case DT_PLTPADSZ: return "DT_PLTPADSZ"; case DT_MOVEENT: return "DT_MOVEENT"; case DT_MOVESZ: return "DT_MOVESZ"; case DT_FEATURE: return "DT_FEATURE"; case DT_POSFLAG_1: return "DT_POSFLAG_1"; case DT_SYMINSZ: return "DT_SYMINSZ"; case DT_SYMINENT : return "DT_SYMINENT (DT_VALRNGHI)"; case DT_ADDRRNGLO: return "DT_ADDRRNGLO"; case DT_GNU_HASH: return "DT_GNU_HASH"; case 0x6ffffef8: return "DT_GNU_CONFLICT"; case 0x6ffffef9: return "DT_GNU_LIBLIST"; case DT_CONFIG: return "DT_CONFIG"; case DT_DEPAUDIT: return "DT_DEPAUDIT"; case DT_AUDIT: return "DT_AUDIT"; case DT_PLTPAD: return "DT_PLTPAD"; case DT_MOVETAB: return "DT_MOVETAB"; case DT_SYMINFO : return "DT_SYMINFO (DT_ADDRRNGHI)"; case DT_RELACOUNT: return "DT_RELACOUNT"; case DT_RELCOUNT: return "DT_RELCOUNT"; case DT_FLAGS_1: return "DT_FLAGS_1"; case DT_VERDEF: return "DT_VERDEF"; case DT_VERDEFNUM: return "DT_VERDEFNUM"; case DT_VERNEED: return "DT_VERNEED"; case DT_VERNEEDNUM: return "DT_VERNEEDNUM"; case 0x6ffffff0: return "DT_GNU_VERSYM"; /* 0x70000000 - 0x7fffffff processor-specific semantics */ case 0x70000000: return "DT_IA_64_PLT_RESERVE"; case 0x7ffffffd: return "DT_SUNW_AUXILIARY"; case 0x7ffffffe: return "DT_SUNW_USED"; case 0x7fffffff: return "DT_SUNW_FILTER"; } snprintf(unknown_tag, sizeof(unknown_tag), "ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag); return (unknown_tag); } static const char * e_machines(u_int mach) { static char machdesc[64]; switch (mach) { case EM_NONE: return "EM_NONE"; case EM_M32: return "EM_M32"; case EM_SPARC: return "EM_SPARC"; case EM_386: return "EM_386"; case EM_68K: return "EM_68K"; case EM_88K: return "EM_88K"; case EM_IAMCU: return "EM_IAMCU"; case EM_860: return "EM_860"; case EM_MIPS: return "EM_MIPS"; case EM_PPC: return "EM_PPC"; case EM_PPC64: return "EM_PPC64"; case EM_ARM: return "EM_ARM"; case EM_ALPHA: return "EM_ALPHA (legacy)"; case EM_SPARCV9:return "EM_SPARCV9"; case EM_IA_64: return "EM_IA_64"; case EM_X86_64: return "EM_X86_64"; case EM_AARCH64:return "EM_AARCH64"; case EM_RISCV: return "EM_RISCV"; } snprintf(machdesc, sizeof(machdesc), "(unknown machine) -- type 0x%x", mach); return (machdesc); } static const char *e_types[] = { "ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE" }; static const char *ei_versions[] = { "EV_NONE", "EV_CURRENT" }; static const char *ei_classes[] = { "ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64" }; static const char *ei_data[] = { "ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB" }; static const char *ei_abis[256] = { "ELFOSABI_NONE", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD", [255] = "ELFOSABI_STANDALONE" }; static const char *p_types[] = { "PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE", "PT_SHLIB", "PT_PHDR", "PT_TLS" }; static const char *p_flags[] = { "", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R", "PF_X|PF_W|PF_R" }; /* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */ static const char * sh_types(uint64_t machine, uint64_t sht) { static char unknown_buf[64]; if (sht < 0x60000000) { switch (sht) { case SHT_NULL: return "SHT_NULL"; case SHT_PROGBITS: return "SHT_PROGBITS"; case SHT_SYMTAB: return "SHT_SYMTAB"; case SHT_STRTAB: return "SHT_STRTAB"; case SHT_RELA: return "SHT_RELA"; case SHT_HASH: return "SHT_HASH"; case SHT_DYNAMIC: return "SHT_DYNAMIC"; case SHT_NOTE: return "SHT_NOTE"; case SHT_NOBITS: return "SHT_NOBITS"; case SHT_REL: return "SHT_REL"; case SHT_SHLIB: return "SHT_SHLIB"; case SHT_DYNSYM: return "SHT_DYNSYM"; case SHT_INIT_ARRAY: return "SHT_INIT_ARRAY"; case SHT_FINI_ARRAY: return "SHT_FINI_ARRAY"; case SHT_PREINIT_ARRAY: return "SHT_PREINIT_ARRAY"; case SHT_GROUP: return "SHT_GROUP"; case SHT_SYMTAB_SHNDX: return "SHT_SYMTAB_SHNDX"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: SHT %ju NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else if (sht < 0x70000000) { /* 0x60000000-0x6fffffff operating system-specific semantics */ switch (sht) { case 0x6ffffff0: return "XXX:VERSYM"; case SHT_SUNW_dof: return "SHT_SUNW_dof"; case SHT_GNU_HASH: return "SHT_GNU_HASH"; case 0x6ffffff7: return "SHT_GNU_LIBLIST"; case 0x6ffffffc: return "XXX:VERDEF"; case SHT_SUNW_verdef: return "SHT_SUNW(GNU)_verdef"; case SHT_SUNW_verneed: return "SHT_SUNW(GNU)_verneed"; case SHT_SUNW_versym: return "SHT_SUNW(GNU)_versym"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: OS-SPECIFIC SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else if (sht < 0x80000000) { /* 0x70000000-0x7fffffff processor-specific semantics */ switch (machine) { case EM_ARM: switch (sht) { case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX"; case SHT_ARM_PREEMPTMAP:return "SHT_ARM_PREEMPTMAP"; case SHT_ARM_ATTRIBUTES:return "SHT_ARM_ATTRIBUTES"; case SHT_ARM_DEBUGOVERLAY: return "SHT_ARM_DEBUGOVERLAY"; case SHT_ARM_OVERLAYSECTION: return "SHT_ARM_OVERLAYSECTION"; } break; case EM_IA_64: switch (sht) { case 0x70000000: return "SHT_IA_64_EXT"; case 0x70000001: return "SHT_IA_64_UNWIND"; } break; case EM_MIPS: switch (sht) { case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO"; case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS"; case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS"; } break; } switch (sht) { case 0x7ffffffd: return "XXX:AUXILIARY"; case 0x7fffffff: return "XXX:FILTER"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: PROCESSOR-SPECIFIC SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else { /* 0x80000000-0xffffffff application programs */ snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } } static const char *sh_flags[] = { "", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR", "SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR", "SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR" }; static const char * st_type(unsigned int mach, unsigned int type) { static char s_type[32]; switch (type) { case STT_NOTYPE: return "STT_NOTYPE"; case STT_OBJECT: return "STT_OBJECT"; case STT_FUNC: return "STT_FUNC"; case STT_SECTION: return "STT_SECTION"; case STT_FILE: return "STT_FILE"; case STT_COMMON: return "STT_COMMON"; case STT_TLS: return "STT_TLS"; case 13: if (mach == EM_SPARCV9) return "STT_SPARC_REGISTER"; break; } snprintf(s_type, sizeof(s_type), "", type); return (s_type); } static const char *st_bindings[] = { "STB_LOCAL", "STB_GLOBAL", "STB_WEAK" }; static char *dynstr; static char *shstrtab; static char *strtab; static FILE *out; static u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member); #if 0 static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member); #endif static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member); static void elf_print_ehdr(Elf32_Ehdr *e, void *sh); static void elf_print_phdr(Elf32_Ehdr *e, void *p); static void elf_print_shdr(Elf32_Ehdr *e, void *sh); static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str); static void elf_print_dynamic(Elf32_Ehdr *e, void *sh); static void elf_print_rel(Elf32_Ehdr *e, void *r); static void elf_print_rela(Elf32_Ehdr *e, void *ra); static void elf_print_interp(Elf32_Ehdr *e, void *p); static void elf_print_got(Elf32_Ehdr *e, void *sh); static void elf_print_hash(Elf32_Ehdr *e, void *sh); static void elf_print_note(Elf32_Ehdr *e, void *sh); static void usage(void); /* * Helpers for ELF files with shnum or shstrndx values that don't fit in the * ELF header. If the values are too large then an escape value is used to * indicate that the actual value is found in one of section 0's fields. */ static uint64_t elf_get_shnum(Elf32_Ehdr *e, void *sh) { uint64_t shnum; shnum = elf_get_quarter(e, e, E_SHNUM); if (shnum == 0) shnum = elf_get_word(e, (char *)sh, SH_SIZE); return shnum; } static uint64_t elf_get_shstrndx(Elf32_Ehdr *e, void *sh) { uint64_t shstrndx; shstrndx = elf_get_quarter(e, e, E_SHSTRNDX); if (shstrndx == SHN_XINDEX) shstrndx = elf_get_word(e, (char *)sh, SH_LINK); return shstrndx; } int main(int ac, char **av) { cap_rights_t rights; u_int64_t phoff; u_int64_t shoff; u_int64_t phentsize; u_int64_t phnum; u_int64_t shentsize; u_int64_t shnum; u_int64_t shstrndx; u_int64_t offset; u_int64_t name; u_int64_t type; struct stat sb; - unsigned long cmd; u_int flags; Elf32_Ehdr *e; void *p; void *sh; void *v; int fd; int ch; int i; out = stdout; flags = 0; while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1) switch (ch) { case 'a': flags = ED_ALL; break; case 'c': flags |= ED_SHDR; break; case 'd': flags |= ED_DYN; break; case 'e': flags |= ED_EHDR; break; case 'i': flags |= ED_INTERP; break; case 'G': flags |= ED_GOT; break; case 'h': flags |= ED_HASH; break; case 'n': flags |= ED_NOTE; break; case 'p': flags |= ED_PHDR; break; case 'r': flags |= ED_REL; break; case 's': flags |= ED_SYMTAB; break; case 'w': if ((out = fopen(optarg, "w")) == NULL) err(1, "%s", optarg); cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (cap_rights_limit(fileno(out), &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", optarg); break; case '?': default: usage(); } ac -= optind; av += optind; if (ac == 0 || flags == 0) usage(); if ((fd = open(*av, O_RDONLY)) < 0 || fstat(fd, &sb) < 0) err(1, "%s", *av); cap_rights_init(&rights, CAP_MMAP_R); if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", *av); - cap_rights_limit(STDIN_FILENO, cap_rights_init(&rights)); - cap_rights_init(&rights, CAP_FSTAT, CAP_IOCTL, CAP_WRITE); - cmd = TIOCGETA; /* required by isatty(3) in printf(3) */ - if ((cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) || - (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS) || - (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) || - (cap_ioctls_limit(STDERR_FILENO, &cmd, 1) < 0 && errno != ENOSYS)) - err(1, "unable to limit rights for stdout/stderr"); + cap_rights_init(&rights); + if ((cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) || + caph_limit_stdout() < 0 || caph_limit_stderr() < 0) { + err(1, "unable to limit rights for stdio"); + } if (cap_enter() < 0 && errno != ENOSYS) err(1, "unable to enter capability mode"); e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (e == MAP_FAILED) err(1, NULL); if (!IS_ELF(*(Elf32_Ehdr *)e)) errx(1, "not an elf file"); phoff = elf_get_off(e, e, E_PHOFF); shoff = elf_get_off(e, e, E_SHOFF); phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); p = (char *)e + phoff; if (shoff > 0) { sh = (char *)e + shoff; shnum = elf_get_shnum(e, sh); shstrndx = elf_get_shstrndx(e, sh); offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, SH_OFFSET); shstrtab = (char *)e + offset; } else { sh = NULL; shnum = 0; shstrndx = 0; shstrtab = NULL; } for (i = 0; (u_int64_t)i < shnum; i++) { name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME); offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET); if (strcmp(shstrtab + name, ".strtab") == 0) strtab = (char *)e + offset; if (strcmp(shstrtab + name, ".dynstr") == 0) dynstr = (char *)e + offset; } if (flags & ED_EHDR) elf_print_ehdr(e, sh); if (flags & ED_PHDR) elf_print_phdr(e, p); if (flags & ED_SHDR) elf_print_shdr(e, sh); for (i = 0; (u_int64_t)i < phnum; i++) { v = (char *)p + i * phentsize; type = elf_get_word(e, v, P_TYPE); switch (type) { case PT_INTERP: if (flags & ED_INTERP) elf_print_interp(e, v); break; case PT_NULL: case PT_LOAD: case PT_DYNAMIC: case PT_NOTE: case PT_SHLIB: case PT_PHDR: break; } } for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; type = elf_get_word(e, v, SH_TYPE); switch (type) { case SHT_SYMTAB: if (flags & ED_SYMTAB) elf_print_symtab(e, v, strtab); break; case SHT_DYNAMIC: if (flags & ED_DYN) elf_print_dynamic(e, v); break; case SHT_RELA: if (flags & ED_REL) elf_print_rela(e, v); break; case SHT_REL: if (flags & ED_REL) elf_print_rel(e, v); break; case SHT_NOTE: name = elf_get_word(e, v, SH_NAME); if (flags & ED_NOTE && strcmp(shstrtab + name, ".note.ABI-tag") == 0) elf_print_note(e, v); break; case SHT_DYNSYM: if (flags & ED_SYMTAB) elf_print_symtab(e, v, dynstr); break; case SHT_PROGBITS: name = elf_get_word(e, v, SH_NAME); if (flags & ED_GOT && strcmp(shstrtab + name, ".got") == 0) elf_print_got(e, v); break; case SHT_HASH: if (flags & ED_HASH) elf_print_hash(e, v); break; case SHT_NULL: case SHT_STRTAB: case SHT_NOBITS: case SHT_SHLIB: break; } } return 0; } static void elf_print_ehdr(Elf32_Ehdr *e, void *sh) { u_int64_t class; u_int64_t data; u_int64_t osabi; u_int64_t type; u_int64_t machine; u_int64_t version; u_int64_t entry; u_int64_t phoff; u_int64_t shoff; u_int64_t flags; u_int64_t ehsize; u_int64_t phentsize; u_int64_t phnum; u_int64_t shentsize; u_int64_t shnum; u_int64_t shstrndx; class = elf_get_byte(e, e, E_CLASS); data = elf_get_byte(e, e, E_DATA); osabi = elf_get_byte(e, e, E_OSABI); type = elf_get_quarter(e, e, E_TYPE); machine = elf_get_quarter(e, e, E_MACHINE); version = elf_get_word(e, e, E_VERSION); entry = elf_get_addr(e, e, E_ENTRY); phoff = elf_get_off(e, e, E_PHOFF); shoff = elf_get_off(e, e, E_SHOFF); flags = elf_get_word(e, e, E_FLAGS); ehsize = elf_get_quarter(e, e, E_EHSIZE); phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); fprintf(out, "\nelf header:\n"); fprintf(out, "\n"); fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data], ei_abis[osabi]); fprintf(out, "\te_type: %s\n", e_types[type]); fprintf(out, "\te_machine: %s\n", e_machines(machine)); fprintf(out, "\te_version: %s\n", ei_versions[version]); fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry); fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff); fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff); fprintf(out, "\te_flags: %jd\n", (intmax_t)flags); fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize); fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize); fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum); fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize); if (sh != NULL) { shnum = elf_get_shnum(e, sh); shstrndx = elf_get_shstrndx(e, sh); fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum); fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx); } } static void elf_print_phdr(Elf32_Ehdr *e, void *p) { u_int64_t phentsize; u_int64_t phnum; u_int64_t type; u_int64_t offset; u_int64_t vaddr; u_int64_t paddr; u_int64_t filesz; u_int64_t memsz; u_int64_t flags; u_int64_t align; void *v; int i; phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); fprintf(out, "\nprogram header:\n"); for (i = 0; (u_int64_t)i < phnum; i++) { v = (char *)p + i * phentsize; type = elf_get_word(e, v, P_TYPE); offset = elf_get_off(e, v, P_OFFSET); vaddr = elf_get_addr(e, v, P_VADDR); paddr = elf_get_addr(e, v, P_PADDR); filesz = elf_get_size(e, v, P_FILESZ); memsz = elf_get_size(e, v, P_MEMSZ); flags = elf_get_word(e, v, P_FLAGS); align = elf_get_size(e, v, P_ALIGN); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]); fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset); fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr); fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr); fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz); fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz); fprintf(out, "\tp_flags: %s\n", p_flags[flags]); fprintf(out, "\tp_align: %jd\n", (intmax_t)align); } } static void elf_print_shdr(Elf32_Ehdr *e, void *sh) { u_int64_t shentsize; u_int64_t shnum; u_int64_t name; u_int64_t type; u_int64_t flags; u_int64_t addr; u_int64_t offset; u_int64_t size; u_int64_t shlink; u_int64_t info; u_int64_t addralign; u_int64_t entsize; u_int64_t machine; void *v; int i; if (sh == NULL) { fprintf(out, "\nNo section headers\n"); return; } machine = elf_get_quarter(e, e, E_MACHINE); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); shnum = elf_get_shnum(e, sh); fprintf(out, "\nsection header:\n"); for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; name = elf_get_word(e, v, SH_NAME); type = elf_get_word(e, v, SH_TYPE); flags = elf_get_word(e, v, SH_FLAGS); addr = elf_get_addr(e, v, SH_ADDR); offset = elf_get_off(e, v, SH_OFFSET); size = elf_get_size(e, v, SH_SIZE); shlink = elf_get_word(e, v, SH_LINK); info = elf_get_word(e, v, SH_INFO); addralign = elf_get_size(e, v, SH_ADDRALIGN); entsize = elf_get_size(e, v, SH_ENTSIZE); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tsh_name: %s\n", shstrtab + name); fprintf(out, "\tsh_type: %s\n", sh_types(machine, type)); fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]); fprintf(out, "\tsh_addr: %#jx\n", addr); fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset); fprintf(out, "\tsh_size: %jd\n", (intmax_t)size); fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink); fprintf(out, "\tsh_info: %jd\n", (intmax_t)info); fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign); fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize); } } static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str) { u_int64_t machine; u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t value; u_int64_t info; u_int64_t shndx; void *st; int len; int i; machine = elf_get_quarter(e, e, E_MACHINE); offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); len = size / entsize; fprintf(out, "\nsymbol table (%s):\n", shstrtab + name); for (i = 0; i < len; i++) { st = (char *)e + offset + i * entsize; name = elf_get_word(e, st, ST_NAME); value = elf_get_addr(e, st, ST_VALUE); size = elf_get_size(e, st, ST_SIZE); info = elf_get_byte(e, st, ST_INFO); shndx = elf_get_quarter(e, st, ST_SHNDX); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tst_name: %s\n", str + name); fprintf(out, "\tst_value: %#jx\n", value); fprintf(out, "\tst_size: %jd\n", (intmax_t)size); fprintf(out, "\tst_info: %s %s\n", st_type(machine, ELF32_ST_TYPE(info)), st_bindings[ELF32_ST_BIND(info)]); fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx); } } static void elf_print_dynamic(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; int64_t tag; u_int64_t ptr; u_int64_t val; void *d; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); fprintf(out, "\ndynamic:\n"); for (i = 0; (u_int64_t)i < size / entsize; i++) { d = (char *)e + offset + i * entsize; tag = elf_get_size(e, d, D_TAG); ptr = elf_get_size(e, d, D_PTR); val = elf_get_addr(e, d, D_VAL); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\td_tag: %s\n", d_tags(tag)); switch (tag) { case DT_NEEDED: case DT_SONAME: case DT_RPATH: fprintf(out, "\td_val: %s\n", dynstr + val); break; case DT_PLTRELSZ: case DT_RELA: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: fprintf(out, "\td_val: %jd\n", (intmax_t)val); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_INIT: case DT_FINI: case DT_REL: case DT_JMPREL: fprintf(out, "\td_ptr: %#jx\n", ptr); break; case DT_NULL: case DT_SYMBOLIC: case DT_DEBUG: case DT_TEXTREL: break; } } } static void elf_print_rela(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t info; int64_t addend; void *ra; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); v = (char *)e + offset; fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name); for (i = 0; (u_int64_t)i < size / entsize; i++) { ra = (char *)v + i * entsize; offset = elf_get_addr(e, ra, RA_OFFSET); info = elf_get_word(e, ra, RA_INFO); addend = elf_get_off(e, ra, RA_ADDEND); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tr_offset: %#jx\n", offset); fprintf(out, "\tr_info: %jd\n", (intmax_t)info); fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend); } } static void elf_print_rel(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t info; void *r; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); v = (char *)e + offset; fprintf(out, "\nrelocation (%s):\n", shstrtab + name); for (i = 0; (u_int64_t)i < size / entsize; i++) { r = (char *)v + i * entsize; offset = elf_get_addr(e, r, R_OFFSET); info = elf_get_word(e, r, R_INFO); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tr_offset: %#jx\n", offset); fprintf(out, "\tr_info: %jd\n", (intmax_t)info); } } static void elf_print_interp(Elf32_Ehdr *e, void *p) { u_int64_t offset; char *s; offset = elf_get_off(e, p, P_OFFSET); s = (char *)e + offset; fprintf(out, "\ninterp:\n"); fprintf(out, "\t%s\n", s); } static void elf_print_got(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t addralign; u_int64_t size; u_int64_t addr; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); addralign = elf_get_size(e, sh, SH_ADDRALIGN); size = elf_get_size(e, sh, SH_SIZE); v = (char *)e + offset; fprintf(out, "\nglobal offset table:\n"); for (i = 0; (u_int64_t)i < size / addralign; i++) { addr = elf_get_addr(e, (char *)v + i * addralign, 0); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\t%#jx\n", addr); } } static void elf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused) { } static void elf_print_note(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t size; u_int64_t name; u_int32_t namesz; u_int32_t descsz; u_int32_t desc; char *n, *s; offset = elf_get_off(e, sh, SH_OFFSET); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); n = (char *)e + offset; fprintf(out, "\nnote (%s):\n", shstrtab + name); while (n < ((char *)e + offset + size)) { namesz = elf_get_word(e, n, N_NAMESZ); descsz = elf_get_word(e, n, N_DESCSZ); s = n + sizeof(Elf_Note); desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0); fprintf(out, "\t%s %d\n", s, desc); n += sizeof(Elf_Note) + namesz + descsz; } } static u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: val = ((uint8_t *)base)[elf32_offsets[member]]; break; case ELFCLASS64: val = ((uint8_t *)base)[elf64_offsets[member]]; break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } #if 0 static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } #endif static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be64dec(base); break; case ELFDATA2LSB: val = le64dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static void usage(void) { fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n"); exit(1); } Index: head/usr.bin/kdump/kdump.c =================================================================== --- head/usr.bin/kdump/kdump.c (revision 306812) +++ head/usr.bin/kdump/kdump.c (revision 306813) @@ -1,1894 +1,1858 @@ /*- * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #define _WANT_KERNEL_ERRNO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBCASPER #include #endif #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include "ktrace.h" #include "kdump_subr.h" #ifdef HAVE_LIBCASPER #include #include #include #endif u_int abidump(struct ktr_header *); int fetchprocinfo(struct ktr_header *, u_int *); int fread_tail(void *, int, int); void dumpheader(struct ktr_header *); void ktrsyscall(struct ktr_syscall *, u_int); void ktrsysret(struct ktr_sysret *, u_int); void ktrnamei(char *, int); void hexdump(char *, int, int); void visdump(char *, int, int); void ktrgenio(struct ktr_genio *, int); void ktrpsig(struct ktr_psig *); void ktrcsw(struct ktr_csw *); void ktrcsw_old(struct ktr_csw_old *); void ktruser(int, void *); void ktrcaprights(cap_rights_t *); void ktritimerval(struct itimerval *it); void ktrsockaddr(struct sockaddr *); void ktrstat(struct stat *); void ktrstruct(char *, size_t); void ktrcapfail(struct ktr_cap_fail *); void ktrfault(struct ktr_fault *); void ktrfaultend(struct ktr_faultend *); -void limitfd(int fd); void usage(void); #define TIMESTAMP_NONE 0x0 #define TIMESTAMP_ABSOLUTE 0x1 #define TIMESTAMP_ELAPSED 0x2 #define TIMESTAMP_RELATIVE 0x4 extern const char *signames[]; static int timestamp, decimal, fancy = 1, suppressdata, tail, threads, maxdata, resolv = 0, abiflag = 0, syscallno = 0; static const char *tracefile = DEF_TRACEFILE; static struct ktr_header ktr_header; #define TIME_FORMAT "%b %e %T %Y" #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) #define print_number64(first,i,n,c) do { \ uint64_t __v; \ \ if (quad_align && (((ptrdiff_t)((i) - (first))) & 1) == 1) { \ (i)++; \ (n)--; \ } \ if (quad_slots == 2) \ __v = (uint64_t)(uint32_t)(i)[0] | \ ((uint64_t)(uint32_t)(i)[1]) << 32; \ else \ __v = (uint64_t)*(i); \ if (decimal) \ printf("%c%jd", (c), (intmax_t)__v); \ else \ printf("%c%#jx", (c), (uintmax_t)__v); \ (i) += quad_slots; \ (n) -= quad_slots; \ (c) = ','; \ } while (0) #define print_number(i,n,c) do { \ if (decimal) \ printf("%c%jd", c, (intmax_t)*i); \ else \ printf("%c%#jx", c, (uintmax_t)(u_register_t)*i); \ i++; \ n--; \ c = ','; \ } while (0) struct proc_info { TAILQ_ENTRY(proc_info) info; u_int sv_flags; pid_t pid; }; static TAILQ_HEAD(trace_procs, proc_info) trace_procs; #ifdef HAVE_LIBCASPER static cap_channel_t *cappwd, *capgrp; #endif static void strerror_init(void) { /* * Cache NLS data before entering capability mode. * XXXPJD: There should be strerror_init() and strsignal_init() in libc. */ (void)catopen("libc", NL_CAT_LOCALE); } static void localtime_init(void) { time_t ltime; /* * Allow localtime(3) to cache /etc/localtime content before entering * capability mode. * XXXPJD: There should be localtime_init() in libc. */ (void)time(<ime); (void)localtime(<ime); } #ifdef HAVE_LIBCASPER static int cappwdgrp_setup(cap_channel_t **cappwdp, cap_channel_t **capgrpp) { cap_channel_t *capcas, *cappwdloc, *capgrploc; const char *cmds[1], *fields[1]; capcas = cap_init(); if (capcas == NULL) { err(1, "unable to create casper process"); exit(1); } cappwdloc = cap_service_open(capcas, "system.pwd"); capgrploc = cap_service_open(capcas, "system.grp"); /* Casper capability no longer needed. */ cap_close(capcas); if (cappwdloc == NULL || capgrploc == NULL) { if (cappwdloc == NULL) warn("unable to open system.pwd service"); if (capgrploc == NULL) warn("unable to open system.grp service"); exit(1); } /* Limit system.pwd to only getpwuid() function and pw_name field. */ cmds[0] = "getpwuid"; if (cap_pwd_limit_cmds(cappwdloc, cmds, 1) < 0) err(1, "unable to limit system.pwd service"); fields[0] = "pw_name"; if (cap_pwd_limit_fields(cappwdloc, fields, 1) < 0) err(1, "unable to limit system.pwd service"); /* Limit system.grp to only getgrgid() function and gr_name field. */ cmds[0] = "getgrgid"; if (cap_grp_limit_cmds(capgrploc, cmds, 1) < 0) err(1, "unable to limit system.grp service"); fields[0] = "gr_name"; if (cap_grp_limit_fields(capgrploc, fields, 1) < 0) err(1, "unable to limit system.grp service"); *cappwdp = cappwdloc; *capgrpp = capgrploc; return (0); } #endif /* HAVE_LIBCASPER */ int main(int argc, char *argv[]) { int ch, ktrlen, size; void *m; int trpoints = ALL_POINTS; int drop_logged; pid_t pid = 0; u_int sv_flags; setlocale(LC_CTYPE, ""); timestamp = TIMESTAMP_NONE; while ((ch = getopt(argc,argv,"f:dElm:np:AHRrSsTt:")) != -1) switch (ch) { case 'A': abiflag = 1; break; case 'f': tracefile = optarg; break; case 'd': decimal = 1; break; case 'l': tail = 1; break; case 'm': maxdata = atoi(optarg); break; case 'n': fancy = 0; break; case 'p': pid = atoi(optarg); break; case 'r': resolv = 1; break; case 'S': syscallno = 1; break; case 's': suppressdata = 1; break; case 'E': timestamp |= TIMESTAMP_ELAPSED; break; case 'H': threads = 1; break; case 'R': timestamp |= TIMESTAMP_RELATIVE; break; case 'T': timestamp |= TIMESTAMP_ABSOLUTE; break; case 't': trpoints = getpoints(optarg); if (trpoints < 0) errx(1, "unknown trace point in %s", optarg); break; default: usage(); } if (argc > optind) usage(); m = malloc(size = 1025); if (m == NULL) errx(1, "%s", strerror(ENOMEM)); if (strcmp(tracefile, "-") != 0) if (!freopen(tracefile, "r", stdin)) err(1, "%s", tracefile); strerror_init(); localtime_init(); #ifdef HAVE_LIBCASPER if (resolv != 0) { if (cappwdgrp_setup(&cappwd, &capgrp) < 0) { cappwd = NULL; capgrp = NULL; } } if (resolv == 0 || (cappwd != NULL && capgrp != NULL)) { if (cap_enter() < 0 && errno != ENOSYS) err(1, "unable to enter capability mode"); } #else if (resolv == 0) { if (cap_enter() < 0 && errno != ENOSYS) err(1, "unable to enter capability mode"); } #endif - limitfd(STDIN_FILENO); - limitfd(STDOUT_FILENO); - limitfd(STDERR_FILENO); + if (caph_limit_stdio() == -1) + err(1, "unable to limit stdio"); TAILQ_INIT(&trace_procs); drop_logged = 0; while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { if (ktr_header.ktr_type & KTR_DROP) { ktr_header.ktr_type &= ~KTR_DROP; if (!drop_logged && threads) { printf( "%6jd %6jd %-8.*s Events dropped.\n", (intmax_t)ktr_header.ktr_pid, ktr_header.ktr_tid > 0 ? (intmax_t)ktr_header.ktr_tid : 0, MAXCOMLEN, ktr_header.ktr_comm); drop_logged = 1; } else if (!drop_logged) { printf("%6jd %-8.*s Events dropped.\n", (intmax_t)ktr_header.ktr_pid, MAXCOMLEN, ktr_header.ktr_comm); drop_logged = 1; } } if (trpoints & (1< size) { m = realloc(m, ktrlen+1); if (m == NULL) errx(1, "%s", strerror(ENOMEM)); size = ktrlen; } if (ktrlen && fread_tail(m, ktrlen, 1) == 0) errx(1, "data too short"); if (fetchprocinfo(&ktr_header, (u_int *)m) != 0) continue; sv_flags = abidump(&ktr_header); if (pid && ktr_header.ktr_pid != pid && ktr_header.ktr_tid != pid) continue; if ((trpoints & (1<ktr_type) { case KTR_PROCCTOR: TAILQ_FOREACH(pi, &trace_procs, info) { if (pi->pid == kth->ktr_pid) { TAILQ_REMOVE(&trace_procs, pi, info); break; } } pi = malloc(sizeof(struct proc_info)); if (pi == NULL) errx(1, "%s", strerror(ENOMEM)); pi->sv_flags = *flags; pi->pid = kth->ktr_pid; TAILQ_INSERT_TAIL(&trace_procs, pi, info); return (1); case KTR_PROCDTOR: TAILQ_FOREACH(pi, &trace_procs, info) { if (pi->pid == kth->ktr_pid) { TAILQ_REMOVE(&trace_procs, pi, info); free(pi); break; } } return (1); } return (0); } u_int abidump(struct ktr_header *kth) { struct proc_info *pi; const char *abi; const char *arch; u_int flags = 0; TAILQ_FOREACH(pi, &trace_procs, info) { if (pi->pid == kth->ktr_pid) { flags = pi->sv_flags; break; } } if (abiflag == 0) return (flags); switch (flags & SV_ABI_MASK) { case SV_ABI_LINUX: abi = "L"; break; case SV_ABI_FREEBSD: abi = "F"; break; case SV_ABI_CLOUDABI: abi = "C"; break; default: abi = "U"; break; } if (flags & SV_LP64) arch = "64"; else if (flags & SV_ILP32) arch = "32"; else arch = "00"; printf("%s%s ", abi, arch); return (flags); } void dumpheader(struct ktr_header *kth) { static char unknown[64]; static struct timeval prevtime, prevtime_e; struct timeval temp; const char *type; const char *sign; switch (kth->ktr_type) { case KTR_SYSCALL: type = "CALL"; break; case KTR_SYSRET: type = "RET "; break; case KTR_NAMEI: type = "NAMI"; break; case KTR_GENIO: type = "GIO "; break; case KTR_PSIG: type = "PSIG"; break; case KTR_CSW: type = "CSW "; break; case KTR_USER: type = "USER"; break; case KTR_STRUCT: type = "STRU"; break; case KTR_SYSCTL: type = "SCTL"; break; case KTR_PROCCTOR: /* FALLTHROUGH */ case KTR_PROCDTOR: return; case KTR_CAPFAIL: type = "CAP "; break; case KTR_FAULT: type = "PFLT"; break; case KTR_FAULTEND: type = "PRET"; break; default: sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); type = unknown; } /* * The ktr_tid field was previously the ktr_buffer field, which held * the kernel pointer value for the buffer associated with data * following the record header. It now holds a threadid, but only * for trace files after the change. Older trace files still contain * kernel pointers. Detect this and suppress the results by printing * negative tid's as 0. */ if (threads) printf("%6jd %6jd %-8.*s ", (intmax_t)kth->ktr_pid, kth->ktr_tid > 0 ? (intmax_t)kth->ktr_tid : 0, MAXCOMLEN, kth->ktr_comm); else printf("%6jd %-8.*s ", (intmax_t)kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); if (timestamp) { if (timestamp & TIMESTAMP_ABSOLUTE) { printf("%jd.%06ld ", (intmax_t)kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); } if (timestamp & TIMESTAMP_ELAPSED) { if (prevtime_e.tv_sec == 0) prevtime_e = kth->ktr_time; timersub(&kth->ktr_time, &prevtime_e, &temp); printf("%jd.%06ld ", (intmax_t)temp.tv_sec, temp.tv_usec); } if (timestamp & TIMESTAMP_RELATIVE) { if (prevtime.tv_sec == 0) prevtime = kth->ktr_time; if (timercmp(&kth->ktr_time, &prevtime, <)) { timersub(&prevtime, &kth->ktr_time, &temp); sign = "-"; } else { timersub(&kth->ktr_time, &prevtime, &temp); sign = ""; } prevtime = kth->ktr_time; printf("%s%jd.%06ld ", sign, (intmax_t)temp.tv_sec, temp.tv_usec); } } printf("%s ", type); } #include static void ioctlname(unsigned long val) { const char *str; str = sysdecode_ioctlname(val); if (str != NULL) printf("%s", str); else if (decimal) printf("%lu", val); else printf("%#lx", val); } static enum sysdecode_abi syscallabi(u_int sv_flags) { if (sv_flags == 0) return (SYSDECODE_ABI_FREEBSD); switch (sv_flags & SV_ABI_MASK) { case SV_ABI_FREEBSD: return (SYSDECODE_ABI_FREEBSD); #if defined(__amd64__) || defined(__i386__) case SV_ABI_LINUX: #ifdef __amd64__ if (sv_flags & SV_ILP32) return (SYSDECODE_ABI_LINUX32); #endif return (SYSDECODE_ABI_LINUX); #endif #if defined(__aarch64__) || defined(__amd64__) case SV_ABI_CLOUDABI: return (SYSDECODE_ABI_CLOUDABI64); #endif default: return (SYSDECODE_ABI_UNKNOWN); } } static void syscallname(u_int code, u_int sv_flags) { const char *name; name = sysdecode_syscallname(syscallabi(sv_flags), code); if (name == NULL) printf("[%d]", code); else { printf("%s", name); if (syscallno) printf("[%d]", code); } } void ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) { int narg = ktr->ktr_narg; register_t *ip, *first; intmax_t arg; int quad_align, quad_slots; syscallname(ktr->ktr_code, sv_flags); ip = first = &ktr->ktr_args[0]; if (narg) { char c = '('; if (fancy && (sv_flags == 0 || (sv_flags & SV_ABI_MASK) == SV_ABI_FREEBSD)) { quad_align = 0; if (sv_flags & SV_ILP32) { #ifdef __powerpc__ quad_align = 1; #endif quad_slots = 2; } else quad_slots = 1; switch (ktr->ktr_code) { case SYS_bindat: case SYS_connectat: case SYS_faccessat: case SYS_fchmodat: case SYS_fchownat: case SYS_fstatat: case SYS_futimesat: case SYS_linkat: case SYS_mkdirat: case SYS_mkfifoat: case SYS_mknodat: case SYS_openat: case SYS_readlinkat: case SYS_renameat: case SYS_unlinkat: case SYS_utimensat: putchar('('); atfdname(*ip, decimal); c = ','; ip++; narg--; break; } switch (ktr->ktr_code) { case SYS_ioctl: { print_number(ip, narg, c); putchar(c); ioctlname(*ip); c = ','; ip++; narg--; break; } case SYS_ptrace: putchar('('); ptraceopname(*ip); c = ','; ip++; narg--; break; case SYS_access: case SYS_eaccess: case SYS_faccessat: print_number(ip, narg, c); putchar(','); accessmodename(*ip); ip++; narg--; break; case SYS_open: case SYS_openat: print_number(ip, narg, c); putchar(','); flagsandmodename(ip[0], ip[1], decimal); ip += 2; narg -= 2; break; case SYS_wait4: print_number(ip, narg, c); print_number(ip, narg, c); /* * A flags value of zero is valid for * wait4() but not for wait6(), so * handle zero special here. */ if (*ip == 0) { print_number(ip, narg, c); } else { putchar(','); wait6optname(*ip); ip++; narg--; } break; case SYS_wait6: putchar('('); idtypename(*ip, decimal); c = ','; ip++; narg--; print_number64(first, ip, narg, c); print_number(ip, narg, c); putchar(','); wait6optname(*ip); ip++; narg--; break; case SYS_chmod: case SYS_fchmod: case SYS_lchmod: case SYS_fchmodat: print_number(ip, narg, c); putchar(','); modename(*ip); ip++; narg--; break; case SYS_mknod: case SYS_mknodat: print_number(ip, narg, c); putchar(','); modename(*ip); ip++; narg--; break; case SYS_getfsstat: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); getfsstatflagsname(*ip); ip++; narg--; break; case SYS_mount: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); mountflagsname(*ip); ip++; narg--; break; case SYS_unmount: print_number(ip, narg, c); putchar(','); mountflagsname(*ip); ip++; narg--; break; case SYS_recvmsg: case SYS_sendmsg: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); sendrecvflagsname(*ip); ip++; narg--; break; case SYS_recvfrom: case SYS_sendto: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); sendrecvflagsname(*ip); ip++; narg--; break; case SYS_chflags: case SYS_fchflags: case SYS_lchflags: print_number(ip, narg, c); putchar(','); modename(*ip); ip++; narg--; break; case SYS_kill: print_number(ip, narg, c); putchar(','); signame(*ip); ip++; narg--; break; case SYS_reboot: putchar('('); rebootoptname(*ip); ip++; narg--; break; case SYS_umask: putchar('('); modename(*ip); ip++; narg--; break; case SYS_msync: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); msyncflagsname(*ip); ip++; narg--; break; #ifdef SYS_freebsd6_mmap case SYS_freebsd6_mmap: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); mmapprotname(*ip); putchar(','); ip++; narg--; mmapflagsname(*ip); ip++; narg--; break; #endif case SYS_mmap: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); mmapprotname(*ip); putchar(','); ip++; narg--; mmapflagsname(*ip); ip++; narg--; break; case SYS_mprotect: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); mmapprotname(*ip); ip++; narg--; break; case SYS_madvise: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); madvisebehavname(*ip); ip++; narg--; break; case SYS_setpriority: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); prioname(*ip); ip++; narg--; break; case SYS_fcntl: print_number(ip, narg, c); putchar(','); fcntlcmdname(ip[0], ip[1], decimal); ip += 2; narg -= 2; break; case SYS_socket: { int sockdomain; putchar('('); sockdomain = *ip; sockdomainname(sockdomain); ip++; narg--; putchar(','); socktypenamewithflags(*ip); ip++; narg--; if (sockdomain == PF_INET || sockdomain == PF_INET6) { putchar(','); sockipprotoname(*ip); ip++; narg--; } c = ','; break; } case SYS_setsockopt: case SYS_getsockopt: print_number(ip, narg, c); putchar(','); sockoptlevelname(*ip, decimal); if (*ip == SOL_SOCKET) { ip++; narg--; putchar(','); sockoptname(*ip); } ip++; narg--; break; #ifdef SYS_freebsd6_lseek case SYS_freebsd6_lseek: print_number(ip, narg, c); /* Hidden 'pad' argument, not in lseek(2) */ print_number(ip, narg, c); print_number64(first, ip, narg, c); putchar(','); whencename(*ip); ip++; narg--; break; #endif case SYS_lseek: print_number(ip, narg, c); print_number64(first, ip, narg, c); putchar(','); whencename(*ip); ip++; narg--; break; case SYS_flock: print_number(ip, narg, c); putchar(','); flockname(*ip); ip++; narg--; break; case SYS_mkfifo: case SYS_mkfifoat: case SYS_mkdir: case SYS_mkdirat: print_number(ip, narg, c); putchar(','); modename(*ip); ip++; narg--; break; case SYS_shutdown: print_number(ip, narg, c); putchar(','); shutdownhowname(*ip); ip++; narg--; break; case SYS_socketpair: putchar('('); sockdomainname(*ip); ip++; narg--; putchar(','); socktypenamewithflags(*ip); ip++; narg--; c = ','; break; case SYS_getrlimit: case SYS_setrlimit: putchar('('); rlimitname(*ip); ip++; narg--; c = ','; break; case SYS_quotactl: print_number(ip, narg, c); putchar(','); quotactlname(*ip); ip++; narg--; c = ','; break; case SYS_nfssvc: putchar('('); nfssvcname(*ip); ip++; narg--; c = ','; break; case SYS_rtprio: putchar('('); rtprioname(*ip); ip++; narg--; c = ','; break; case SYS___semctl: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); semctlname(*ip); ip++; narg--; break; case SYS_semget: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); semgetname(*ip); ip++; narg--; break; case SYS_msgctl: print_number(ip, narg, c); putchar(','); shmctlname(*ip); ip++; narg--; break; case SYS_shmat: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); shmatname(*ip); ip++; narg--; break; case SYS_shmctl: print_number(ip, narg, c); putchar(','); shmctlname(*ip); ip++; narg--; break; case SYS_shm_open: print_number(ip, narg, c); putchar(','); flagsname(ip[0]); printf(",0%o", (unsigned int)ip[1]); ip += 3; narg -= 3; break; case SYS_minherit: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); minheritname(*ip); ip++; narg--; break; case SYS_rfork: putchar('('); rforkname(*ip); ip++; narg--; c = ','; break; case SYS_lio_listio: putchar('('); lio_listioname(*ip); ip++; narg--; c = ','; break; case SYS_mlockall: putchar('('); mlockallname(*ip); ip++; narg--; break; case SYS_sched_setscheduler: print_number(ip, narg, c); putchar(','); schedpolicyname(*ip); ip++; narg--; break; case SYS_sched_get_priority_max: case SYS_sched_get_priority_min: putchar('('); schedpolicyname(*ip); ip++; narg--; break; case SYS_sendfile: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); sendfileflagsname(*(int *)ip); ip++; narg--; break; case SYS_kldsym: print_number(ip, narg, c); putchar(','); kldsymcmdname(*ip); ip++; narg--; break; case SYS_sigprocmask: putchar('('); sigprocmaskhowname(*ip); ip++; narg--; c = ','; break; case SYS___acl_get_file: case SYS___acl_set_file: case SYS___acl_get_fd: case SYS___acl_set_fd: case SYS___acl_delete_file: case SYS___acl_delete_fd: case SYS___acl_aclcheck_file: case SYS___acl_aclcheck_fd: case SYS___acl_get_link: case SYS___acl_set_link: case SYS___acl_delete_link: case SYS___acl_aclcheck_link: print_number(ip, narg, c); putchar(','); acltypename(*ip); ip++; narg--; break; case SYS_sigaction: putchar('('); signame(*ip); ip++; narg--; c = ','; break; case SYS_extattrctl: print_number(ip, narg, c); putchar(','); extattrctlname(*ip); ip++; narg--; break; case SYS_nmount: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); mountflagsname(*ip); ip++; narg--; break; case SYS_thr_create: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); thrcreateflagsname(*ip); ip++; narg--; break; case SYS_thr_kill: print_number(ip, narg, c); putchar(','); signame(*ip); ip++; narg--; break; case SYS_kldunloadf: print_number(ip, narg, c); putchar(','); kldunloadfflagsname(*ip); ip++; narg--; break; case SYS_linkat: case SYS_renameat: case SYS_symlinkat: print_number(ip, narg, c); putchar(','); atfdname(*ip, decimal); ip++; narg--; break; case SYS_cap_fcntls_limit: print_number(ip, narg, c); putchar(','); arg = *ip; ip++; narg--; capfcntlname(arg); break; case SYS_posix_fadvise: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); (void)putchar(','); fadvisebehavname((int)*ip); ip++; narg--; break; case SYS_procctl: putchar('('); idtypename(*ip, decimal); c = ','; ip++; narg--; print_number64(first, ip, narg, c); putchar(','); procctlcmdname(*ip); ip++; narg--; break; case SYS__umtx_op: print_number(ip, narg, c); putchar(','); umtxopname(*ip); switch (*ip) { case UMTX_OP_CV_WAIT: ip++; narg--; putchar(','); umtxcvwaitflags(*ip); break; case UMTX_OP_RW_RDLOCK: ip++; narg--; putchar(','); umtxrwlockflags(*ip); break; } ip++; narg--; break; case SYS_ftruncate: case SYS_truncate: print_number(ip, narg, c); print_number64(first, ip, narg, c); break; } } while (narg > 0) { print_number(ip, narg, c); } putchar(')'); } putchar('\n'); } void ktrsysret(struct ktr_sysret *ktr, u_int sv_flags) { register_t ret = ktr->ktr_retval; int error = ktr->ktr_error; syscallname(ktr->ktr_code, sv_flags); printf(" "); if (error == 0) { if (fancy) { printf("%ld", (long)ret); if (ret < 0 || ret > 9) printf("/%#lx", (unsigned long)ret); } else { if (decimal) printf("%ld", (long)ret); else printf("%#lx", (unsigned long)ret); } } else if (error == ERESTART) printf("RESTART"); else if (error == EJUSTRETURN) printf("JUSTRETURN"); else { printf("-1 errno %d", sysdecode_freebsd_to_abi_errno( syscallabi(sv_flags), error)); if (fancy) printf(" %s", strerror(ktr->ktr_error)); } putchar('\n'); } void ktrnamei(char *cp, int len) { printf("\"%.*s\"\n", len, cp); } void hexdump(char *p, int len, int screenwidth) { int n, i; int width; width = 0; do { width += 2; i = 13; /* base offset */ i += (width / 2) + 1; /* spaces every second byte */ i += (width * 2); /* width of bytes */ i += 3; /* " |" */ i += width; /* each byte */ i += 1; /* "|" */ } while (i < screenwidth); width -= 2; for (n = 0; n < len; n += width) { for (i = n; i < n + width; i++) { if ((i % width) == 0) { /* beginning of line */ printf(" 0x%04x", i); } if ((i % 2) == 0) { printf(" "); } if (i < len) printf("%02x", p[i] & 0xff); else printf(" "); } printf(" |"); for (i = n; i < n + width; i++) { if (i >= len) break; if (p[i] >= ' ' && p[i] <= '~') printf("%c", p[i]); else printf("."); } printf("|\n"); } if ((i % width) != 0) printf("\n"); } void visdump(char *dp, int datalen, int screenwidth) { int col = 0; char *cp; int width; char visbuf[5]; printf(" \""); col = 8; for (;datalen > 0; datalen--, dp++) { vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); cp = visbuf; /* * Keep track of printables and * space chars (like fold(1)). */ if (col == 0) { putchar('\t'); col = 8; } switch(*cp) { case '\n': col = 0; putchar('\n'); continue; case '\t': width = 8 - (col&07); break; default: width = strlen(cp); } if (col + width > (screenwidth-2)) { printf("\\\n\t"); col = 8; } col += width; do { putchar(*cp++); } while (*cp); } if (col == 0) printf(" "); printf("\"\n"); } void ktrgenio(struct ktr_genio *ktr, int len) { int datalen = len - sizeof (struct ktr_genio); char *dp = (char *)ktr + sizeof (struct ktr_genio); static int screenwidth = 0; int i, binary; printf("fd %d %s %d byte%s\n", ktr->ktr_fd, ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen, datalen == 1 ? "" : "s"); if (suppressdata) return; if (screenwidth == 0) { struct winsize ws; if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && ws.ws_col > 8) screenwidth = ws.ws_col; else screenwidth = 80; } if (maxdata && datalen > maxdata) datalen = maxdata; for (i = 0, binary = 0; i < datalen && binary == 0; i++) { if (dp[i] >= 32 && dp[i] < 127) continue; if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9) continue; binary = 1; } if (binary) hexdump(dp, datalen, screenwidth); else visdump(dp, datalen, screenwidth); } const char *signames[] = { "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ "USR2", NULL, /* 31 - 32 */ }; void ktrpsig(struct ktr_psig *psig) { if (psig->signo > 0 && psig->signo < NSIG) printf("SIG%s ", signames[psig->signo]); else printf("SIG %d ", psig->signo); if (psig->action == SIG_DFL) { printf("SIG_DFL code="); sigcodename(psig->signo, psig->code); putchar('\n'); } else { printf("caught handler=0x%lx mask=0x%x code=", (u_long)psig->action, psig->mask.__bits[0]); sigcodename(psig->signo, psig->code); putchar('\n'); } } void ktrcsw_old(struct ktr_csw_old *cs) { printf("%s %s\n", cs->out ? "stop" : "resume", cs->user ? "user" : "kernel"); } void ktrcsw(struct ktr_csw *cs) { printf("%s %s \"%s\"\n", cs->out ? "stop" : "resume", cs->user ? "user" : "kernel", cs->wmesg); } void ktruser(int len, void *p) { unsigned char *cp; if (sysdecode_utrace(stdout, p, len)) { printf("\n"); return; } printf("%d ", len); cp = p; while (len--) if (decimal) printf(" %d", *cp++); else printf(" %02x", *cp++); printf("\n"); } void ktrcaprights(cap_rights_t *rightsp) { printf("cap_rights_t "); capname(rightsp); printf("\n"); } static void ktrtimeval(struct timeval *tv) { printf("{%ld, %ld}", (long)tv->tv_sec, tv->tv_usec); } void ktritimerval(struct itimerval *it) { printf("itimerval { .interval = "); ktrtimeval(&it->it_interval); printf(", .value = "); ktrtimeval(&it->it_value); printf(" }\n"); } void ktrsockaddr(struct sockaddr *sa) { /* TODO: Support additional address families #include struct sockaddr_natm *natm; #include struct sockaddr_nb *nb; */ char addr[64]; /* * note: ktrstruct() has already verified that sa points to a * buffer at least sizeof(struct sockaddr) bytes long and exactly * sa->sa_len bytes long. */ printf("struct sockaddr { "); sockfamilyname(sa->sa_family); printf(", "); #define check_sockaddr_len(n) \ if (sa_##n.s##n##_len < sizeof(struct sockaddr_##n)) { \ printf("invalid"); \ break; \ } switch(sa->sa_family) { case AF_INET: { struct sockaddr_in sa_in; memset(&sa_in, 0, sizeof(sa_in)); memcpy(&sa_in, sa, sa->sa_len); check_sockaddr_len(in); inet_ntop(AF_INET, &sa_in.sin_addr, addr, sizeof addr); printf("%s:%u", addr, ntohs(sa_in.sin_port)); break; } case AF_INET6: { struct sockaddr_in6 sa_in6; memset(&sa_in6, 0, sizeof(sa_in6)); memcpy(&sa_in6, sa, sa->sa_len); check_sockaddr_len(in6); getnameinfo((struct sockaddr *)&sa_in6, sizeof(sa_in6), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST); printf("[%s]:%u", addr, htons(sa_in6.sin6_port)); break; } case AF_UNIX: { struct sockaddr_un sa_un; memset(&sa_un, 0, sizeof(sa_un)); memcpy(&sa_un, sa, sa->sa_len); printf("%.*s", (int)sizeof(sa_un.sun_path), sa_un.sun_path); break; } default: printf("unknown address family"); } printf(" }\n"); } void ktrstat(struct stat *statp) { char mode[12], timestr[PATH_MAX + 4]; struct passwd *pwd; struct group *grp; struct tm *tm; /* * note: ktrstruct() has already verified that statp points to a * buffer exactly sizeof(struct stat) bytes long. */ printf("struct stat {"); printf("dev=%ju, ino=%ju, ", (uintmax_t)statp->st_dev, (uintmax_t)statp->st_ino); if (resolv == 0) printf("mode=0%jo, ", (uintmax_t)statp->st_mode); else { strmode(statp->st_mode, mode); printf("mode=%s, ", mode); } printf("nlink=%ju, ", (uintmax_t)statp->st_nlink); if (resolv == 0) { pwd = NULL; } else { #ifdef HAVE_LIBCASPER if (cappwd != NULL) pwd = cap_getpwuid(cappwd, statp->st_uid); else #endif pwd = getpwuid(statp->st_uid); } if (pwd == NULL) printf("uid=%ju, ", (uintmax_t)statp->st_uid); else printf("uid=\"%s\", ", pwd->pw_name); if (resolv == 0) { grp = NULL; } else { #ifdef HAVE_LIBCASPER if (capgrp != NULL) grp = cap_getgrgid(capgrp, statp->st_gid); else #endif grp = getgrgid(statp->st_gid); } if (grp == NULL) printf("gid=%ju, ", (uintmax_t)statp->st_gid); else printf("gid=\"%s\", ", grp->gr_name); printf("rdev=%ju, ", (uintmax_t)statp->st_rdev); printf("atime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_atim.tv_sec); else { tm = localtime(&statp->st_atim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_atim.tv_nsec != 0) printf(".%09ld, ", statp->st_atim.tv_nsec); else printf(", "); printf("mtime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_mtim.tv_sec); else { tm = localtime(&statp->st_mtim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_mtim.tv_nsec != 0) printf(".%09ld, ", statp->st_mtim.tv_nsec); else printf(", "); printf("ctime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_ctim.tv_sec); else { tm = localtime(&statp->st_ctim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_ctim.tv_nsec != 0) printf(".%09ld, ", statp->st_ctim.tv_nsec); else printf(", "); printf("birthtime="); if (resolv == 0) printf("%jd", (intmax_t)statp->st_birthtim.tv_sec); else { tm = localtime(&statp->st_birthtim.tv_sec); strftime(timestr, sizeof(timestr), TIME_FORMAT, tm); printf("\"%s\"", timestr); } if (statp->st_birthtim.tv_nsec != 0) printf(".%09ld, ", statp->st_birthtim.tv_nsec); else printf(", "); printf("size=%jd, blksize=%ju, blocks=%jd, flags=0x%x", (uintmax_t)statp->st_size, (uintmax_t)statp->st_blksize, (intmax_t)statp->st_blocks, statp->st_flags); printf(" }\n"); } void ktrstruct(char *buf, size_t buflen) { char *name, *data; size_t namelen, datalen; int i; cap_rights_t rights; struct itimerval it; struct stat sb; struct sockaddr_storage ss; for (name = buf, namelen = 0; namelen < buflen && name[namelen] != '\0'; ++namelen) /* nothing */; if (namelen == buflen) goto invalid; if (name[namelen] != '\0') goto invalid; data = buf + namelen + 1; datalen = buflen - namelen - 1; if (datalen == 0) goto invalid; /* sanity check */ for (i = 0; i < (int)namelen; ++i) if (!isalpha(name[i])) goto invalid; if (strcmp(name, "caprights") == 0) { if (datalen != sizeof(cap_rights_t)) goto invalid; memcpy(&rights, data, datalen); ktrcaprights(&rights); } else if (strcmp(name, "itimerval") == 0) { if (datalen != sizeof(struct itimerval)) goto invalid; memcpy(&it, data, datalen); ktritimerval(&it); } else if (strcmp(name, "stat") == 0) { if (datalen != sizeof(struct stat)) goto invalid; memcpy(&sb, data, datalen); ktrstat(&sb); } else if (strcmp(name, "sockaddr") == 0) { if (datalen > sizeof(ss)) goto invalid; memcpy(&ss, data, datalen); if (datalen != ss.ss_len) goto invalid; ktrsockaddr((struct sockaddr *)&ss); } else { printf("unknown structure\n"); } return; invalid: printf("invalid record\n"); } void ktrcapfail(struct ktr_cap_fail *ktr) { switch (ktr->cap_type) { case CAPFAIL_NOTCAPABLE: /* operation on fd with insufficient capabilities */ printf("operation requires "); capname(&ktr->cap_needed); printf(", descriptor holds "); capname(&ktr->cap_held); break; case CAPFAIL_INCREASE: /* requested more capabilities than fd already has */ printf("attempt to increase capabilities from "); capname(&ktr->cap_held); printf(" to "); capname(&ktr->cap_needed); break; case CAPFAIL_SYSCALL: /* called restricted syscall */ printf("disallowed system call"); break; case CAPFAIL_LOOKUP: /* used ".." in strict-relative mode */ printf("restricted VFS lookup"); break; default: printf("unknown capability failure: "); capname(&ktr->cap_needed); printf(" "); capname(&ktr->cap_held); break; } printf("\n"); } void ktrfault(struct ktr_fault *ktr) { printf("0x%jx ", (uintmax_t)ktr->vaddr); vmprotname(ktr->type); printf("\n"); } void ktrfaultend(struct ktr_faultend *ktr) { vmresultname(ktr->result); printf("\n"); } void usage(void) { fprintf(stderr, "usage: kdump [-dEnlHRrSsTA] [-f trfile] " "[-m maxdata] [-p pid] [-t trstr]\n"); exit(1); } Index: head/usr.bin/tee/tee.c =================================================================== --- head/usr.bin/tee/tee.c (revision 306812) +++ head/usr.bin/tee/tee.c (revision 306813) @@ -1,172 +1,158 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)tee.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include +#include #include #include #include #include #include #include #include -#include #include typedef struct _list { struct _list *next; int fd; const char *name; } LIST; static LIST *head; static void add(int, const char *); static void usage(void); int main(int argc, char *argv[]) { LIST *p; int n, fd, rval, wval; char *bp; int append, ch, exitval; char *buf; - cap_rights_t rights; - unsigned long cmd; #define BSIZE (8 * 1024) append = 0; while ((ch = getopt(argc, argv, "ai")) != -1) switch((char)ch) { case 'a': append = 1; break; case 'i': (void)signal(SIGINT, SIG_IGN); break; case '?': default: usage(); } argv += optind; argc -= optind; if ((buf = malloc(BSIZE)) == NULL) err(1, "malloc"); - cap_rights_init(&rights, CAP_READ, CAP_FSTAT); - if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) - err(EXIT_FAILURE, "unable to limit rights for stdin"); - cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT, CAP_IOCTL); - if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) - err(EXIT_FAILURE, "unable to limit rights for stderr"); - cmd = TIOCGETA; - if (cap_ioctls_limit(STDERR_FILENO, &cmd, 1) < 0 && errno != ENOSYS) - err(EXIT_FAILURE, "unable to limit ioctls for stderr"); + if (caph_limit_stdin() == -1 || caph_limit_stderr() == -1) + err(EXIT_FAILURE, "unable to limit stdio"); add(STDOUT_FILENO, "stdout"); for (exitval = 0; *argv; ++argv) if ((fd = open(*argv, append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC, DEFFILEMODE)) < 0) { warn("%s", *argv); exitval = 1; } else add(fd, *argv); if (cap_enter() < 0 && errno != ENOSYS) err(EXIT_FAILURE, "unable to enter capability mode"); while ((rval = read(STDIN_FILENO, buf, BSIZE)) > 0) for (p = head; p; p = p->next) { n = rval; bp = buf; do { if ((wval = write(p->fd, bp, n)) == -1) { warn("%s", p->name); exitval = 1; break; } bp += wval; } while (n -= wval); } if (rval < 0) err(1, "read"); exit(exitval); } static void usage(void) { (void)fprintf(stderr, "usage: tee [-ai] [file ...]\n"); exit(1); } static void add(int fd, const char *name) { LIST *p; cap_rights_t rights; - unsigned long cmd; - if (fd == STDOUT_FILENO) - cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT, CAP_IOCTL); - else - cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT); - if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) - err(EXIT_FAILURE, "unable to limit rights"); - if (fd == STDOUT_FILENO) { - cmd = TIOCGETA; - if (cap_ioctls_limit(fd, &cmd, 1) < 0 && errno != ENOSYS) - err(EXIT_FAILURE, "unable to limit ioctls for stdout"); + if (caph_limit_stdout() == -1) + err(EXIT_FAILURE, "unable to limit stdout"); + } else { + cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT); + if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) + err(EXIT_FAILURE, "unable to limit rights"); } if ((p = malloc(sizeof(LIST))) == NULL) err(1, "malloc"); p->fd = fd; p->name = name; p->next = head; head = p; } Index: head/usr.bin/tr/tr.c =================================================================== --- head/usr.bin/tr/tr.c (revision 306812) +++ head/usr.bin/tr/tr.c (revision 306813) @@ -1,400 +1,382 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif #ifndef lint static const char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95"; #endif #include #include +#include #include #include -#include #include #include #include #include #include #include -#include #include #include #include #include "cmap.h" #include "cset.h" #include "extern.h" static STR s1 = { STRING1, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL }; static STR s2 = { STRING2, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL }; static struct cset *setup(char *, STR *, int, int); static void usage(void); int main(int argc, char **argv) { static int carray[NCHARS_SB]; - cap_rights_t rights; - unsigned long cmd; struct cmap *map; struct cset *delete, *squeeze; int n, *p; int Cflag, cflag, dflag, sflag, isstring2; wint_t ch, cnt, lastch; (void)setlocale(LC_ALL, ""); - cap_rights_init(&rights, CAP_FSTAT, CAP_IOCTL, CAP_READ); - if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) - err(1, "unable to limit rights for stdin"); - cap_rights_init(&rights, CAP_FSTAT, CAP_IOCTL, CAP_WRITE); - if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) - err(1, "unable to limit rights for stdout"); - if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) - err(1, "unable to limit rights for stderr"); - - /* Required for isatty(3). */ - cmd = TIOCGETA; - if (cap_ioctls_limit(STDIN_FILENO, &cmd, 1) < 0 && errno != ENOSYS) - err(1, "unable to limit ioctls for stdin"); - if (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS) - err(1, "unable to limit ioctls for stdout"); - if (cap_ioctls_limit(STDERR_FILENO, &cmd, 1) < 0 && errno != ENOSYS) - err(1, "unable to limit ioctls for stderr"); + if (caph_limit_stdio() == -1) + err(1, "unable to limit stdio"); if (cap_enter() < 0 && errno != ENOSYS) err(1, "unable to enter capability mode"); Cflag = cflag = dflag = sflag = 0; while ((ch = getopt(argc, argv, "Ccdsu")) != -1) switch((char)ch) { case 'C': Cflag = 1; cflag = 0; break; case 'c': cflag = 1; Cflag = 0; break; case 'd': dflag = 1; break; case 's': sflag = 1; break; case 'u': setbuf(stdout, (char *)NULL); break; case '?': default: usage(); } argc -= optind; argv += optind; switch(argc) { case 0: default: usage(); /* NOTREACHED */ case 1: isstring2 = 0; break; case 2: isstring2 = 1; break; } /* * tr -ds [-Cc] string1 string2 * Delete all characters (or complemented characters) in string1. * Squeeze all characters in string2. */ if (dflag && sflag) { if (!isstring2) usage(); delete = setup(argv[0], &s1, cflag, Cflag); squeeze = setup(argv[1], &s2, 0, 0); for (lastch = OOBCH; (ch = getwchar()) != WEOF;) if (!cset_in(delete, ch) && (lastch != ch || !cset_in(squeeze, ch))) { lastch = ch; (void)putwchar(ch); } if (ferror(stdin)) err(1, NULL); exit(0); } /* * tr -d [-Cc] string1 * Delete all characters (or complemented characters) in string1. */ if (dflag) { if (isstring2) usage(); delete = setup(argv[0], &s1, cflag, Cflag); while ((ch = getwchar()) != WEOF) if (!cset_in(delete, ch)) (void)putwchar(ch); if (ferror(stdin)) err(1, NULL); exit(0); } /* * tr -s [-Cc] string1 * Squeeze all characters (or complemented characters) in string1. */ if (sflag && !isstring2) { squeeze = setup(argv[0], &s1, cflag, Cflag); for (lastch = OOBCH; (ch = getwchar()) != WEOF;) if (lastch != ch || !cset_in(squeeze, ch)) { lastch = ch; (void)putwchar(ch); } if (ferror(stdin)) err(1, NULL); exit(0); } /* * tr [-Ccs] string1 string2 * Replace all characters (or complemented characters) in string1 with * the character in the same position in string2. If the -s option is * specified, squeeze all the characters in string2. */ if (!isstring2) usage(); map = cmap_alloc(); if (map == NULL) err(1, NULL); squeeze = cset_alloc(); if (squeeze == NULL) err(1, NULL); s1.str = argv[0]; if (Cflag || cflag) { cmap_default(map, OOBCH); if ((s2.str = strdup(argv[1])) == NULL) errx(1, "strdup(argv[1])"); } else s2.str = argv[1]; if (!next(&s2)) errx(1, "empty string2"); /* * For -s result will contain only those characters defined * as the second characters in each of the toupper or tolower * pairs. */ /* If string2 runs out of characters, use the last one specified. */ while (next(&s1)) { again: if (s1.state == CCLASS_LOWER && s2.state == CCLASS_UPPER && s1.cnt == 1 && s2.cnt == 1) { do { ch = towupper(s1.lastch); cmap_add(map, s1.lastch, ch); if (sflag && iswupper(ch)) cset_add(squeeze, ch); if (!next(&s1)) goto endloop; } while (s1.state == CCLASS_LOWER && s1.cnt > 1); /* skip upper set */ do { if (!next(&s2)) break; } while (s2.state == CCLASS_UPPER && s2.cnt > 1); goto again; } else if (s1.state == CCLASS_UPPER && s2.state == CCLASS_LOWER && s1.cnt == 1 && s2.cnt == 1) { do { ch = towlower(s1.lastch); cmap_add(map, s1.lastch, ch); if (sflag && iswlower(ch)) cset_add(squeeze, ch); if (!next(&s1)) goto endloop; } while (s1.state == CCLASS_UPPER && s1.cnt > 1); /* skip lower set */ do { if (!next(&s2)) break; } while (s2.state == CCLASS_LOWER && s2.cnt > 1); goto again; } else { cmap_add(map, s1.lastch, s2.lastch); if (sflag) cset_add(squeeze, s2.lastch); } (void)next(&s2); } endloop: if (cflag || (Cflag && MB_CUR_MAX > 1)) { /* * This is somewhat tricky: since the character set is * potentially huge, we need to avoid allocating a map * entry for every character. Our strategy is to set the * default mapping to the last character of string #2 * (= the one that gets automatically repeated), then to * add back identity mappings for characters that should * remain unchanged. We don't waste space on identity mappings * for non-characters with the -C option; those are simulated * in the I/O loop. */ s2.str = argv[1]; s2.state = NORMAL; for (cnt = 0; cnt < WINT_MAX; cnt++) { if (Cflag && !iswrune(cnt)) continue; if (cmap_lookup(map, cnt) == OOBCH) { if (next(&s2)) { cmap_add(map, cnt, s2.lastch); if (sflag) cset_add(squeeze, s2.lastch); } } else cmap_add(map, cnt, cnt); if ((s2.state == EOS || s2.state == INFINITE) && cnt >= cmap_max(map)) break; } cmap_default(map, s2.lastch); } else if (Cflag) { for (p = carray, cnt = 0; cnt < NCHARS_SB; cnt++) { if (cmap_lookup(map, cnt) == OOBCH && iswrune(cnt)) *p++ = cnt; else cmap_add(map, cnt, cnt); } n = p - carray; if (Cflag && n > 1) (void)mergesort(carray, n, sizeof(*carray), charcoll); s2.str = argv[1]; s2.state = NORMAL; for (cnt = 0; cnt < n; cnt++) { (void)next(&s2); cmap_add(map, carray[cnt], s2.lastch); /* * Chars taken from s2 can be different this time * due to lack of complex upper/lower processing, * so fill string2 again to not miss some. */ if (sflag) cset_add(squeeze, s2.lastch); } } cset_cache(squeeze); cmap_cache(map); if (sflag) for (lastch = OOBCH; (ch = getwchar()) != WEOF;) { if (!Cflag || iswrune(ch)) ch = cmap_lookup(map, ch); if (lastch != ch || !cset_in(squeeze, ch)) { lastch = ch; (void)putwchar(ch); } } else while ((ch = getwchar()) != WEOF) { if (!Cflag || iswrune(ch)) ch = cmap_lookup(map, ch); (void)putwchar(ch); } if (ferror(stdin)) err(1, NULL); exit (0); } static struct cset * setup(char *arg, STR *str, int cflag, int Cflag) { struct cset *cs; cs = cset_alloc(); if (cs == NULL) err(1, NULL); str->str = arg; while (next(str)) cset_add(cs, str->lastch); if (Cflag) cset_addclass(cs, wctype("rune"), true); if (cflag || Cflag) cset_invert(cs); cset_cache(cs); return (cs); } int charcoll(const void *a, const void *b) { static char sa[2], sb[2]; sa[0] = *(const int *)a; sb[0] = *(const int *)b; return (strcoll(sa, sb)); } static void usage(void) { (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", "usage: tr [-Ccsu] string1 string2", " tr [-Ccu] -d string1", " tr [-Ccu] -s string1", " tr [-Ccu] -ds string1 string2"); exit(1); }