Print this page
12364 mdb trips assertion related to autowrap


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright (c) 2019, Joyent, Inc. All rights reserved.
  28  * Copyright (c) 2016 by Delphix. All rights reserved.
  29  */
  30 
  31 /*
  32  * MDB uses its own enhanced standard i/o mechanism for all input and output.
  33  * This file provides the underpinnings of this mechanism, including the
  34  * printf-style formatting code, the output pager, and APIs for raw input
  35  * and output.  This mechanism is used throughout the debugger for everything
  36  * from simple sprintf and printf-style formatting, to input to the lexer
  37  * and parser, to raw file i/o for reading ELF files.  In general, we divide
  38  * our i/o implementation into two parts:
  39  *
  40  * (1) An i/o buffer (mdb_iob_t) provides buffered read or write capabilities,
  41  * as well as access to formatting and the ability to invoke a pager.  The
  42  * buffer is constructed explicitly for use in either reading or writing; it
  43  * may not be used for both simultaneously.
  44  *
  45  * (2) Each i/o buffer is associated with an underlying i/o backend (mdb_io_t).
  46  * The backend provides, through an ops-vector, equivalents for the standard
  47  * read, write, lseek, ioctl, and close operations.  In addition, the backend


1760                 *spb.spb_buf = '\0';
1761         else if (buf != NULL && nbytes > 0)
1762                 *--spb.spb_buf = '\0';
1763 
1764         return (spb.spb_total);
1765 }
1766 
1767 /*PRINTFLIKE3*/
1768 size_t
1769 mdb_iob_snprintf(char *buf, size_t nbytes, const char *format, ...)
1770 {
1771         va_list alist;
1772 
1773         va_start(alist, format);
1774         nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist);
1775         va_end(alist);
1776 
1777         return (nbytes);
1778 }
1779 





















1780 void
1781 mdb_iob_nputs(mdb_iob_t *iob, const char *s, size_t nbytes)
1782 {
1783         size_t m, n, nleft = nbytes;
1784         const char *p, *q = s;
1785 
1786         ASSERT(iob->iob_flags & MDB_IOB_WRONLY);
1787 
1788         if (nbytes == 0)
1789                 return; /* Return immediately if there is no work to do */
1790 
1791         /*
1792          * If the string contains embedded newlines or tabs, invoke ourself
1793          * recursively for each string component, followed by a call to the
1794          * newline or tab routine.  This insures that strings with these
1795          * characters obey our wrapping and indenting rules, and that strings
1796          * with embedded newlines are flushed after each newline, allowing
1797          * the output pager to take over if it is enabled.
1798          */
1799         while ((p = strnpbrk(q, "\t\n", nleft)) != NULL) {
1800                 if (p > q)
1801                         mdb_iob_nputs(iob, q, (size_t)(p - q));
1802 
1803                 if (*p == '\t')
1804                         mdb_iob_tab(iob);
1805                 else
1806                         mdb_iob_nl(iob);
1807 
1808                 nleft -= (size_t)(p - q) + 1;   /* Update byte count */
1809                 q = p + 1;                      /* Advance past delimiter */
1810         }
1811 
1812         /*
1813          * For a given string component, we determine how many bytes (n) we can
1814          * copy into our buffer (limited by either cols or bufsiz depending
1815          * on whether AUTOWRAP is on), copy a chunk into the buffer, and
1816          * flush the buffer if we reach the end of a line.
1817          */
1818         while (nleft != 0) {
1819                 if (IOB_AUTOWRAP(iob)) {
1820                         ASSERT(iob->iob_cols >= iob->iob_nbytes);
1821                         n = iob->iob_cols - iob->iob_nbytes;
1822                 } else {
1823                         ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
1824                         n = iob->iob_bufsiz - iob->iob_nbytes;
1825                 }
1826 
1827                 m = MIN(nleft, n); /* copy at most n bytes in this pass */
1828 
1829                 bcopy(q, iob->iob_bufp, m);
1830                 nleft -= m;
1831                 q += m;
1832 
1833                 iob->iob_bufp += m;
1834                 iob->iob_nbytes += m;
1835 
1836                 if (m == n && nleft != 0) {
1837                         if (IOB_AUTOWRAP(iob)) {
1838                                 mdb_iob_nl(iob);
1839                         } else {
1840                                 mdb_iob_flush(iob);
1841                         }
1842                 }
1843         }
1844 }
1845 
1846 void


1867                  * insert sufficient whitespace to reach position n.
1868                  */
1869                 size_t n = (iob->iob_nbytes + iob->iob_tabstop) /
1870                     iob->iob_tabstop * iob->iob_tabstop;
1871 
1872                 if (n < iob->iob_cols)
1873                         mdb_iob_fill(iob, ' ', n - iob->iob_nbytes);
1874                 else
1875                         mdb_iob_nl(iob);
1876         }
1877 }
1878 
1879 void
1880 mdb_iob_fill(mdb_iob_t *iob, int c, size_t nfill)
1881 {
1882         size_t i, m, n;
1883 
1884         ASSERT(iob->iob_flags & MDB_IOB_WRONLY);
1885 
1886         while (nfill != 0) {
1887                 if (IOB_AUTOWRAP(iob)) {
1888                         ASSERT(iob->iob_cols >= iob->iob_nbytes);
1889                         n = iob->iob_cols - iob->iob_nbytes;
1890                 } else {
1891                         ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
1892                         n = iob->iob_bufsiz - iob->iob_nbytes;
1893                 }
1894 
1895                 m = MIN(nfill, n); /* fill at most n bytes in this pass */
1896 
1897                 for (i = 0; i < m; i++)
1898                         *iob->iob_bufp++ = (char)c;
1899 
1900                 iob->iob_nbytes += m;
1901                 nfill -= m;
1902 
1903                 if (m == n && nfill != 0) {
1904                         if (IOB_AUTOWRAP(iob)) {
1905                                 mdb_iob_nl(iob);
1906                         } else {
1907                                 mdb_iob_flush(iob);
1908                         }
1909                 }
1910         }
1911 }
1912 
1913 void
1914 mdb_iob_ws(mdb_iob_t *iob, size_t n)


2151 mdb_iob_t *
2152 mdb_iob_stack_pop(mdb_iob_stack_t *stk)
2153 {
2154         mdb_iob_t *top = stk->stk_top;
2155 
2156         ASSERT(top != NULL);
2157 
2158         stk->stk_top = top->iob_next;
2159         top->iob_next = NULL;
2160         stk->stk_size--;
2161 
2162         return (top);
2163 }
2164 
2165 size_t
2166 mdb_iob_stack_size(mdb_iob_stack_t *stk)
2167 {
2168         return (stk->stk_size);
2169 }
2170 




















2171 /*
2172  * Stub functions for i/o backend implementors: these stubs either act as
2173  * pass-through no-ops or return ENOTSUP as appropriate.
2174  */
2175 ssize_t
2176 no_io_read(mdb_io_t *io, void *buf, size_t nbytes)
2177 {
2178         if (io->io_next != NULL)
2179                 return (IOP_READ(io->io_next, buf, nbytes));
2180 
2181         return (set_errno(EMDB_IOWO));
2182 }
2183 
2184 ssize_t
2185 no_io_write(mdb_io_t *io, const void *buf, size_t nbytes)
2186 {
2187         if (io->io_next != NULL)
2188                 return (IOP_WRITE(io->io_next, buf, nbytes));
2189 
2190         return (set_errno(EMDB_IORO));




   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2020 Joyent, Inc.
  28  * Copyright (c) 2016 by Delphix. All rights reserved.
  29  */
  30 
  31 /*
  32  * MDB uses its own enhanced standard i/o mechanism for all input and output.
  33  * This file provides the underpinnings of this mechanism, including the
  34  * printf-style formatting code, the output pager, and APIs for raw input
  35  * and output.  This mechanism is used throughout the debugger for everything
  36  * from simple sprintf and printf-style formatting, to input to the lexer
  37  * and parser, to raw file i/o for reading ELF files.  In general, we divide
  38  * our i/o implementation into two parts:
  39  *
  40  * (1) An i/o buffer (mdb_iob_t) provides buffered read or write capabilities,
  41  * as well as access to formatting and the ability to invoke a pager.  The
  42  * buffer is constructed explicitly for use in either reading or writing; it
  43  * may not be used for both simultaneously.
  44  *
  45  * (2) Each i/o buffer is associated with an underlying i/o backend (mdb_io_t).
  46  * The backend provides, through an ops-vector, equivalents for the standard
  47  * read, write, lseek, ioctl, and close operations.  In addition, the backend


1760                 *spb.spb_buf = '\0';
1761         else if (buf != NULL && nbytes > 0)
1762                 *--spb.spb_buf = '\0';
1763 
1764         return (spb.spb_total);
1765 }
1766 
1767 /*PRINTFLIKE3*/
1768 size_t
1769 mdb_iob_snprintf(char *buf, size_t nbytes, const char *format, ...)
1770 {
1771         va_list alist;
1772 
1773         va_start(alist, format);
1774         nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist);
1775         va_end(alist);
1776 
1777         return (nbytes);
1778 }
1779 
1780 /*
1781  * Return how many bytes we can copy into our buffer, limited by either cols or
1782  * bufsiz depending on whether AUTOWRAP is on.  Note that typically,
1783  * mdb_iob_set_autowrap() will have already checked for an existing
1784  * "->iob_nbytes > ->iob_cols" situation, but we double check here anyway.
1785  */
1786 static size_t
1787 iob_bufleft(mdb_iob_t *iob)
1788 {
1789         if (IOB_AUTOWRAP(iob)) {
1790                 if (iob->iob_cols < iob->iob_nbytes) {
1791                         mdb_iob_nl(iob);
1792                         ASSERT(iob->iob_cols >= iob->iob_nbytes);
1793                 }
1794                 return (iob->iob_cols - iob->iob_nbytes);
1795         }
1796 
1797         ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
1798         return (iob->iob_bufsiz - iob->iob_nbytes);
1799 }
1800 
1801 void
1802 mdb_iob_nputs(mdb_iob_t *iob, const char *s, size_t nbytes)
1803 {
1804         size_t m, n, nleft = nbytes;
1805         const char *p, *q = s;
1806 
1807         ASSERT(iob->iob_flags & MDB_IOB_WRONLY);
1808 
1809         if (nbytes == 0)
1810                 return; /* Return immediately if there is no work to do */
1811 
1812         /*
1813          * If the string contains embedded newlines or tabs, invoke ourself
1814          * recursively for each string component, followed by a call to the
1815          * newline or tab routine.  This insures that strings with these
1816          * characters obey our wrapping and indenting rules, and that strings
1817          * with embedded newlines are flushed after each newline, allowing
1818          * the output pager to take over if it is enabled.
1819          */
1820         while ((p = strnpbrk(q, "\t\n", nleft)) != NULL) {
1821                 if (p > q)
1822                         mdb_iob_nputs(iob, q, (size_t)(p - q));
1823 
1824                 if (*p == '\t')
1825                         mdb_iob_tab(iob);
1826                 else
1827                         mdb_iob_nl(iob);
1828 
1829                 nleft -= (size_t)(p - q) + 1;   /* Update byte count */
1830                 q = p + 1;                      /* Advance past delimiter */
1831         }
1832 
1833         /*
1834          * For a given string component, we copy a chunk into the buffer, and


1835          * flush the buffer if we reach the end of a line.
1836          */
1837         while (nleft != 0) {
1838                 n = iob_bufleft(iob);







1839                 m = MIN(nleft, n); /* copy at most n bytes in this pass */
1840 
1841                 bcopy(q, iob->iob_bufp, m);
1842                 nleft -= m;
1843                 q += m;
1844 
1845                 iob->iob_bufp += m;
1846                 iob->iob_nbytes += m;
1847 
1848                 if (m == n && nleft != 0) {
1849                         if (IOB_AUTOWRAP(iob)) {
1850                                 mdb_iob_nl(iob);
1851                         } else {
1852                                 mdb_iob_flush(iob);
1853                         }
1854                 }
1855         }
1856 }
1857 
1858 void


1879                  * insert sufficient whitespace to reach position n.
1880                  */
1881                 size_t n = (iob->iob_nbytes + iob->iob_tabstop) /
1882                     iob->iob_tabstop * iob->iob_tabstop;
1883 
1884                 if (n < iob->iob_cols)
1885                         mdb_iob_fill(iob, ' ', n - iob->iob_nbytes);
1886                 else
1887                         mdb_iob_nl(iob);
1888         }
1889 }
1890 
1891 void
1892 mdb_iob_fill(mdb_iob_t *iob, int c, size_t nfill)
1893 {
1894         size_t i, m, n;
1895 
1896         ASSERT(iob->iob_flags & MDB_IOB_WRONLY);
1897 
1898         while (nfill != 0) {
1899                 n = iob_bufleft(iob);







1900                 m = MIN(nfill, n); /* fill at most n bytes in this pass */
1901 
1902                 for (i = 0; i < m; i++)
1903                         *iob->iob_bufp++ = (char)c;
1904 
1905                 iob->iob_nbytes += m;
1906                 nfill -= m;
1907 
1908                 if (m == n && nfill != 0) {
1909                         if (IOB_AUTOWRAP(iob)) {
1910                                 mdb_iob_nl(iob);
1911                         } else {
1912                                 mdb_iob_flush(iob);
1913                         }
1914                 }
1915         }
1916 }
1917 
1918 void
1919 mdb_iob_ws(mdb_iob_t *iob, size_t n)


2156 mdb_iob_t *
2157 mdb_iob_stack_pop(mdb_iob_stack_t *stk)
2158 {
2159         mdb_iob_t *top = stk->stk_top;
2160 
2161         ASSERT(top != NULL);
2162 
2163         stk->stk_top = top->iob_next;
2164         top->iob_next = NULL;
2165         stk->stk_size--;
2166 
2167         return (top);
2168 }
2169 
2170 size_t
2171 mdb_iob_stack_size(mdb_iob_stack_t *stk)
2172 {
2173         return (stk->stk_size);
2174 }
2175 
2176 /*
2177  * This only enables autowrap for iobs that are already autowrap themselves such
2178  * as mdb.m_out typically.
2179  *
2180  * Note that we might be the middle of the iob buffer at this point, and
2181  * specifically, iob->iob_nbytes could be more than iob->iob_cols.  As that's
2182  * not a valid situation, we may need to do an autowrap *now*.
2183  *
2184  * In theory, we would need to do this across all MDB_IOB_AUTOWRAP iob's;
2185  * instead, we have a failsafe in iob_bufleft().
2186  */
2187 void
2188 mdb_iob_set_autowrap(mdb_iob_t *iob)
2189 {
2190         mdb.m_flags |= MDB_FL_AUTOWRAP;
2191         if (IOB_WRAPNOW(iob, 0))
2192                 mdb_iob_nl(iob);
2193         ASSERT(iob->iob_cols >= iob->iob_nbytes);
2194 }
2195 
2196 /*
2197  * Stub functions for i/o backend implementors: these stubs either act as
2198  * pass-through no-ops or return ENOTSUP as appropriate.
2199  */
2200 ssize_t
2201 no_io_read(mdb_io_t *io, void *buf, size_t nbytes)
2202 {
2203         if (io->io_next != NULL)
2204                 return (IOP_READ(io->io_next, buf, nbytes));
2205 
2206         return (set_errno(EMDB_IOWO));
2207 }
2208 
2209 ssize_t
2210 no_io_write(mdb_io_t *io, const void *buf, size_t nbytes)
2211 {
2212         if (io->io_next != NULL)
2213                 return (IOP_WRITE(io->io_next, buf, nbytes));
2214 
2215         return (set_errno(EMDB_IORO));