Date: Thu, 8 Jun 2006 23:50:38 GMT From: John Birrell <jb@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 98841 for review Message-ID: <200606082350.k58NocoM088132@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=98841 Change 98841 by jb@jb_freebsd2 on 2006/06/08 23:50:34 Integrate OpenSolaris ON (OS/Net) Consolidation - 20060605 Affected files ... .. //depot/projects/dtrace/src/contrib/opensolaris/cmd/sgs/include/debug.h#3 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/cmd/sgs/include/sgs.h#2 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/ctf.c#6 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c#4 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/ctftools.h#3 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/dwarf.c#4 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/input.c#4 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/merge.c#3 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/output.c#4 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/stabs.c#3 integrate .. //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/util.c#4 integrate .. //depot/projects/dtrace/src/sys/contrib/opensolaris/common/avl/avl.c#5 integrate .. //depot/projects/dtrace/src/sys/contrib/opensolaris/uts/common/sys/dtrace_impl.h#9 integrate Differences ... ==== //depot/projects/dtrace/src/contrib/opensolaris/cmd/sgs/include/debug.h#3 (text) ==== @@ -27,7 +27,7 @@ #ifndef _DEBUG_H #define _DEBUG_H -#pragma ident "@(#)debug.h 1.136 06/04/14 SMI" +#pragma ident "@(#)debug.h 1.137 06/05/09 SMI" /* * Global include file for lddbg debugging. @@ -67,6 +67,7 @@ #define DBG_CONF_VERSION 2 #define DBG_CONF_PRCFAIL 3 #define DBG_CONF_CORRUPT 4 +#define DBG_CONF_ABIMISMATCH 5 #define DBG_ORDER_INFO_RANGE 1 /* sh_link out of range */ #define DBG_ORDER_INFO_ORDER 2 /* sh_info also ordered */ ==== //depot/projects/dtrace/src/contrib/opensolaris/cmd/sgs/include/sgs.h#2 (text) ==== @@ -33,7 +33,7 @@ #ifndef _SGS_H #define _SGS_H -#pragma ident "@(#)sgs.h 1.52 06/03/07 SMI" +#pragma ident "@(#)sgs.h 1.53 06/05/09 SMI" #ifdef __cplusplus @@ -93,6 +93,21 @@ #define SGSOFFSETOF(s, m) ((size_t)(&(((s *)0)->m))) /* + * When casting between integer and pointer types, gcc will complain + * if the integer type used is not large enough to hold the pointer + * value without loss. Although a dubious practice in general, this + * is sometimes done by design. In those cases, the general solution + * is to introduce an intermediate cast to widen the integer value. The + * CAST_PTRINT macro does this, and its use documents the fact that + * the programmer is doing that sort of cast. + */ +#ifdef __GNUC__ +#define CAST_PTRINT(cast, value) ((cast)(uintptr_t)value) +#else +#define CAST_PTRINT(cast, value) ((cast)value) +#endif + +/* * General typedefs. */ typedef enum { ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/ctf.c#6 (text) ==== @@ -23,7 +23,7 @@ * Use is subject to license terms. */ -#pragma ident "@(#)ctf.c 1.13 06/04/20 SMI" +#pragma ident "@(#)ctf.c 1.14 06/05/03 SMI" /* * Create and parse buffers containing CTF data. @@ -546,9 +546,7 @@ (void) bcopy_data(h, sizeof (ctf_header_t), &bufpos); (void) bcopy_data(buf->ctb_base, buf->ctb_ptr - buf->ctb_base, &bufpos); - if (strtab_write(&buf->ctb_strtab, bcopy_data, - (void *) &bufpos) < 0) - terminate("strtab_write failed\n"); + (void) strtab_write(&buf->ctb_strtab, bcopy_data, &bufpos); *resszp = bufpos - outbuf; return (outbuf); } @@ -572,9 +570,7 @@ (void) compress_buffer(buf->ctb_base, buf->ctb_ptr - buf->ctb_base, &resbuf); compress_flush(&resbuf, Z_FULL_FLUSH); - if (strtab_write(&buf->ctb_strtab, compress_buffer, - (void *) &resbuf) < 0) - terminate("strtab_write failed\n"); + (void) strtab_write(&buf->ctb_strtab, compress_buffer, &resbuf); compress_end(&resbuf); *resszp = (resbuf.rb_ptr - resbuf.rb_base); ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c#4 (text) ==== @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,11 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)ctfconvert.c 1.11 05/06/08 SMI" +#pragma ident "@(#)ctfconvert.c 1.12 06/05/03 SMI" /* * Given a file containing sections with stabs data, convert the stabs data to @@ -101,7 +100,7 @@ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { close(fd); terminate("failed to read %s: %s\n", filename, - elf_errmsg(elf_errno())); + elf_errmsg(-1)); } source_types = built_source_types(elf, filename); @@ -124,8 +123,10 @@ * None of the readers found compatible type data. */ - if (findelfsecidx(elf, ".debug") >= 0) - terminate("DWARF version 1 is not supported\n"); + if (findelfsecidx(elf, filename, ".debug") >= 0) { + terminate("%s: DWARF version 1 is not supported\n", + filename); + } if (!(source_types & SOURCE_C) && ignore_non_c) { debug(1, "Ignoring file %s not built from C sources\n", ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/ctftools.h#3 (text) ==== @@ -26,7 +26,7 @@ #ifndef _CTFTOOLS_H #define _CTFTOOLS_H -#pragma ident "@(#)ctftools.h 1.14 06/04/20 SMI" +#pragma ident "@(#)ctftools.h 1.15 06/05/03 SMI" /* * Functions and data structures used in the manipulation of stabs and CTF data @@ -428,11 +428,11 @@ /* util.c */ int streq(char *, char *); -int findelfsecidx(Elf *, char *); +int findelfsecidx(Elf *, const char *, const char *); char *mktmpname(const char *, const char *); void terminate(char *, ...); +void aborterr(char *, ...); void set_terminate_cleanup(void (*)()); -void vaterminate(char *, va_list); void elfterminate(const char *, const char *, ...); void warning(char *, ...); void vadebug(int, char *, va_list); ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/dwarf.c#4 (text) ==== @@ -23,7 +23,7 @@ * Use is subject to license terms. */ -#pragma ident "@(#)dwarf.c 1.5 06/04/20 SMI" +#pragma ident "@(#)dwarf.c 1.6 06/05/03 SMI" /* * DWARF to tdata conversion @@ -1784,7 +1784,7 @@ if (gelf_getehdr(elf, &ehdr) == NULL) { terminate("failed to read ELF header: %s\n", - elf_errmsg(elf_errno())); + elf_errmsg(-1)); } if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/input.c#4 (text) ==== @@ -23,7 +23,7 @@ * Use is subject to license terms. */ -#pragma ident "@(#)input.c 1.8 06/04/21 SMI" +#pragma ident "@(#)input.c 1.9 06/05/03 SMI" /* * Routines for retrieving CTF data from a .SUNW_ctf ELF section @@ -93,7 +93,7 @@ int ctfscnidx; tdata_t *td; - if ((ctfscnidx = findelfsecidx(elf, ".SUNW_ctf")) < 0) { + if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { if (require_ctf && (built_source_types(elf, file) & SOURCE_C)) { terminate("Input file %s was partially built from " @@ -295,7 +295,7 @@ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warning("Can't open input file %s: %s\n", file, - elf_errmsg(elf_errno())); + elf_errmsg(-1)); err++; (void) close(fd); continue; @@ -346,7 +346,7 @@ Elf_Scn *scn; int symtabidx; - if ((symtabidx = findelfsecidx(elf, ".symtab")) < 0) + if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0) return (NULL); si = xcalloc(sizeof (symit_data_t)); ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/merge.c#3 (text) ==== @@ -23,7 +23,7 @@ * Use is subject to license terms. */ -#pragma ident "@(#)merge.c 1.12 06/04/20 SMI" +#pragma ident "@(#)merge.c 1.13 06/05/03 SMI" /* * This file contains routines that merge one tdata_t tree, called the child, @@ -476,7 +476,7 @@ * exhaustive search through the entire graph. This usually * means that the "name" hash function is broken. */ - terminate("Second pass for %d (%s) == %d\n", ctdp->t_id, + aborterr("Second pass for %d (%s) == %d\n", ctdp->t_id, tdesc_name(ctdp), ed.ed_tgt->t_id); } else { int id = mcd->md_tgt->td_nextid++; @@ -518,7 +518,7 @@ * through the entire hash. This usually means that the hash * function is broken. */ - terminate("Self-unique second pass for %d (%s) == %d\n", + aborterr("Self-unique second pass for %d (%s) == %d\n", ctdp->t_id, tdesc_name(ctdp), ed.ed_tgt->t_id); } else { int id = mcd->md_tgt->td_nextid++; @@ -696,7 +696,7 @@ } if ((template.t_id = get_mapping(mcd->md_ta, oldid)) == 0) - terminate("failed to get mapping for tid %d\n", oldid); + aborterr("failed to get mapping for tid %d\n", oldid); if (!hash_find(mcd->md_parent->td_idhash, (void *)&template, (void *)&tgt) && (!(mcd->md_flags & MCD_F_REFMERGE) || @@ -917,7 +917,7 @@ if (!hash_find(rmd->rmd_tgt->td_idhash, (void *)&template, (void *)&defn)) { - terminate("Couldn't unforward %d (%s)\n", defnid, + aborterr("Couldn't unforward %d (%s)\n", defnid, tdesc_name(defn)); } @@ -1062,7 +1062,7 @@ debug(3, "add_tdtbr_cb added %d items\n", tdrc); if (list_count(*mcd->md_tdtbr) != 0) - terminate("Couldn't remap all nodes\n"); + aborterr("Couldn't remap all nodes\n"); /* * We now have an alist of master forwards and the ids of the new master ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/output.c#4 (text) ==== @@ -23,7 +23,7 @@ * Use is subject to license terms. */ -#pragma ident "@(#)output.c 1.14 06/04/20 SMI" +#pragma ident "@(#)output.c 1.15 06/05/03 SMI" /* * Routines for preparing tdata trees for conversion into CTF data, and @@ -344,7 +344,8 @@ match.iim_fuzzy = fuzzymatch; match.iim_file = NULL; - if ((stidx = findelfsecidx(elf, dynsym ? ".dynsym" : ".symtab")) < 0) + if ((stidx = findelfsecidx(elf, file, + dynsym ? ".dynsym" : ".symtab")) < 0) terminate("%s: Can't open symbol table\n", file); scn = elf_getscn(elf, stidx); data = elf_getdata(scn, NULL); @@ -626,7 +627,7 @@ } if (symtab_idx == -1) { - terminate("Cannot find %s section\n", + terminate("%s: Cannot find %s section\n", srcname, dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB"); } ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/stabs.c#3 (text) ==== @@ -23,7 +23,7 @@ * Use is subject to license terms. */ -#pragma ident "@(#)stabs.c 1.10 06/04/20 SMI" +#pragma ident "@(#)stabs.c 1.11 06/05/03 SMI" /* * Routines used to read stabs data from a file, and to build a tdata structure @@ -174,7 +174,7 @@ * assembled under an iidesc list. */ int -stabs_read(tdata_t *td, Elf *elf, const char *filename) +stabs_read(tdata_t *td, Elf *elf, const char *file) { Elf_Scn *scn; Elf_Data *data; @@ -190,18 +190,18 @@ int nstabs, rc, i; int scope = 0; - if (!((stabidx = findelfsecidx(elf, ".stab.excl")) >= 0 && - (stabstridx = findelfsecidx(elf, ".stab.exclstr")) >= 0) && - !((stabidx = findelfsecidx(elf, ".stab")) >= 0 && - (stabstridx = findelfsecidx(elf, ".stabstr")) >= 0)) { + if (!((stabidx = findelfsecidx(elf, file, ".stab.excl")) >= 0 && + (stabstridx = findelfsecidx(elf, file, ".stab.exclstr")) >= 0) && + !((stabidx = findelfsecidx(elf, file, ".stab")) >= 0 && + (stabstridx = findelfsecidx(elf, file, ".stabstr")) >= 0)) { errno = ENOENT; return (-1); } file_stack = stack_new(free); - stack_push(file_stack, (void *)filename); - curhdr = filename; + stack_push(file_stack, (void *)file); + curhdr = file; debug(3, "Found stabs in %d, strings in %d\n", stabidx, stabstridx); @@ -249,8 +249,8 @@ if ((str = elf_strptr(elf, stabstridx, (size_t)stab->n_strx)) == NULL) { - terminate("Can't find string at %u for stab %d\n", - stab->n_strx, i); + terminate("%s: Can't find string at %u for stab %d\n", + file, stab->n_strx, i); } if (stab->n_type == N_BINCL) { @@ -265,8 +265,8 @@ continue; } else if (stab->n_type == N_OPT) { if (strcmp(str, "gcc2_compiled.") == 0) { - terminate("GCC-generated stabs are " - "unsupported. Use DWARF instead.\n"); + terminate("%s: GCC-generated stabs are " + "unsupported. Use DWARF instead.\n", file); } continue; } @@ -312,9 +312,12 @@ ofstr = fstr; iidescp = NULL; - if ((rc = parse_stab(stab, fstr, &iidescp)) < 0) - terminate("Couldn't parse stab \"%s\" (file %s)\n", - str, curhdr); + + if ((rc = parse_stab(stab, fstr, &iidescp)) < 0) { + terminate("%s: Couldn't parse stab \"%s\" " + "(source file %s)\n", file, str, curhdr); + } + if (rc == 0) goto parse_loop_end; @@ -356,7 +359,8 @@ iidesc_free(iidescp, NULL); break; default: - terminate("Unknown iidesc type %d\n", iidescp->ii_type); + aborterr("invalid ii_type %d for stab type %d", + iidescp->ii_type, stab->n_type); } parse_loop_end: ==== //depot/projects/dtrace/src/contrib/opensolaris/tools/ctf/cvt/util.c#4 (text) ==== @@ -23,7 +23,7 @@ * Use is subject to license terms. */ -#pragma ident "@(#)util.c 1.9 06/04/20 SMI" +#pragma ident "@(#)util.c 1.10 06/05/03 SMI" /* * Utility functions @@ -61,24 +61,29 @@ } int -findelfsecidx(Elf *elf, char *tofind) +findelfsecidx(Elf *elf, const char *file, const char *tofind) { Elf_Scn *scn = NULL; GElf_Ehdr ehdr; GElf_Shdr shdr; - if (gelf_getehdr(elf, &ehdr) == NULL) { - terminate("gelf_getehdr: %s\n", elf_errmsg(elf_errno())); - } + if (gelf_getehdr(elf, &ehdr) == NULL) + elfterminate(file, "Couldn't read ehdr"); while ((scn = elf_nextscn(elf, scn)) != NULL) { char *name; - if (gelf_getshdr(scn, &shdr) == NULL || - (name = elf_strptr(elf, ehdr.e_shstrndx, + if (gelf_getshdr(scn, &shdr) == NULL) { + elfterminate(file, + "Couldn't read header for section %d", + elf_ndxscn(scn)); + } + + if ((name = elf_strptr(elf, ehdr.e_shstrndx, (size_t)shdr.sh_name)) == NULL) { - terminate("gelf_getehdr: %s\n", - elf_errmsg(elf_errno())); + elfterminate(file, + "Couldn't get name for section %d", + elf_ndxscn(scn)); } if (strcmp(name, tofind) == 0) @@ -102,12 +107,6 @@ } void -vaterminate(char *format, va_list ap) -{ - whine("ERROR", format, ap); -} - -void set_terminate_cleanup(void (*cleanup)()) { terminate_cleanup = cleanup; @@ -117,17 +116,17 @@ void terminate(char *format, ...) { - if (format) { - va_list ap; + va_list ap; - va_start(ap, format); - whine("ERROR", format, ap); - va_end(ap); - } + va_start(ap, format); + whine("ERROR", format, ap); + va_end(ap); if (terminate_cleanup) terminate_cleanup(); + if (getenv("CTF_ABORT_ON_TERMINATE") != NULL) + abort(); #if defined(__FreeBSD__) /* * For the time being just output the termination message, but don't @@ -143,6 +142,19 @@ /*PRINTFLIKE1*/ void +aborterr(char *format, ...) +{ + va_list ap; + + va_start(ap, format); + whine("ERROR", format, ap); + va_end(ap); + + abort(); +} + +/*PRINTFLIKE1*/ +void warning(char *format, ...) { va_list ap; @@ -203,7 +215,7 @@ vsnprintf(msgbuf, sizeof (msgbuf), fmt, ap); va_end(ap); - terminate("%s: %s: %s\n", file, msgbuf, elf_errmsg(elf_errno())); + terminate("%s: %s: %s\n", file, msgbuf, elf_errmsg(-1)); } const char * ==== //depot/projects/dtrace/src/sys/contrib/opensolaris/common/avl/avl.c#5 (text) ==== @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,11 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)avl.c 1.12 05/10/30 SMI" +#pragma ident "@(#)avl.c 1.13 06/05/05 SMI" /* @@ -573,6 +572,9 @@ { avl_node_t *node; int child = direction; /* rely on AVL_BEFORE == 0, AVL_AFTER == 1 */ +#ifdef DEBUG + int diff; +#endif ASSERT(tree != NULL); ASSERT(new_data != NULL); @@ -584,20 +586,34 @@ * node and reverse the insertion direction. */ node = AVL_DATA2NODE(here, tree->avl_offset); - ASSERT(tree->avl_compar(new_data, here) > 0 ? child == 1 : child == 0); + +#ifdef DEBUG + diff = tree->avl_compar(new_data, here); + ASSERT(-1 <= diff && diff <= 1); + ASSERT(diff != 0); + ASSERT(diff > 0 ? child == 1 : child == 0); +#endif if (node->avl_child[child] != NULL) { node = node->avl_child[child]; child = 1 - child; while (node->avl_child[child] != NULL) { - ASSERT(tree->avl_compar(new_data, - AVL_NODE2DATA(node, tree->avl_offset)) > 0 ? - child == 1 : child == 0); +#ifdef DEBUG + diff = tree->avl_compar(new_data, + AVL_NODE2DATA(node, tree->avl_offset)); + ASSERT(-1 <= diff && diff <= 1); + ASSERT(diff != 0); + ASSERT(diff > 0 ? child == 1 : child == 0); +#endif node = node->avl_child[child]; } - ASSERT(tree->avl_compar(new_data, - AVL_NODE2DATA(node, tree->avl_offset)) > 0 ? - child == 1 : child == 0); +#ifdef DEBUG + diff = tree->avl_compar(new_data, + AVL_NODE2DATA(node, tree->avl_offset)); + ASSERT(-1 <= diff && diff <= 1); + ASSERT(diff != 0); + ASSERT(diff > 0 ? child == 1 : child == 0); +#endif } ASSERT(node->avl_child[child] == NULL); @@ -731,6 +747,7 @@ * Here we know "delete" is at least partially a leaf node. It can * be easily removed from the tree. */ + ASSERT(tree->avl_numnodes > 0); --tree->avl_numnodes; parent = AVL_XPARENT(delete); which_child = AVL_XCHILD(delete); ==== //depot/projects/dtrace/src/sys/contrib/opensolaris/uts/common/sys/dtrace_impl.h#9 (text) ==== @@ -18,6 +18,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -27,7 +28,7 @@ #define _SYS_DTRACE_IMPL_H #if defined(sun) -#pragma ident "@(#)dtrace_impl.h 1.20 06/04/03 SMI" +#pragma ident "@(#)dtrace_impl.h 1.21 06/05/19 SMI" #endif #ifdef __cplusplus @@ -997,16 +998,17 @@ #define DTRACE_NHELPER_ACTIONS 1 typedef struct dtrace_helper_action { - dtrace_difo_t *dthp_predicate; /* helper action predicate */ - int dthp_nactions; /* number of actions */ - dtrace_difo_t **dthp_actions; /* array of actions */ - int dthp_generation; /* helper action generation */ - struct dtrace_helper_action *dthp_next; /* next helper action */ + int dtha_generation; /* helper action generation */ + int dtha_nactions; /* number of actions */ + dtrace_difo_t *dtha_predicate; /* helper action predicate */ + dtrace_difo_t **dtha_actions; /* array of actions */ + struct dtrace_helper_action *dtha_next; /* next helper action */ } dtrace_helper_action_t; typedef struct dtrace_helper_provider { + int dthp_generation; /* helper provider generation */ + uint32_t dthp_ref; /* reference count */ dof_helper_t dthp_prov; /* DOF w/ provider and probes */ - uint32_t dthp_ref; /* reference count */ } dtrace_helper_provider_t; typedef struct dtrace_helpers { @@ -1014,6 +1016,7 @@ dtrace_vstate_t dthps_vstate; /* helper action var. state */ dtrace_helper_provider_t **dthps_provs; /* array of providers */ uint_t dthps_nprovs; /* count of providers */ + uint_t dthps_maxprovs; /* provider array size */ int dthps_generation; /* current generation */ pid_t dthps_pid; /* pid of associated proc */ int dthps_deferred; /* helper in deferred list */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200606082350.k58NocoM088132>