1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_dump.h>
28*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
29*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_nv.h>
30*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
31*7c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
32*7c478bd9Sstevel@tonic-gate #include <limits.h>
33*7c478bd9Sstevel@tonic-gate
34*7c478bd9Sstevel@tonic-gate #define DUMP_PARAGRAPH 16
35*7c478bd9Sstevel@tonic-gate #define DUMP_WIDTH(x) (DUMP_PARAGRAPH * ((((x) >> 16) & 0xf) + 1))
36*7c478bd9Sstevel@tonic-gate #define DUMP_GROUP(x) ((((x) >> 20) & 0xff) + 1)
37*7c478bd9Sstevel@tonic-gate #define DUMP_MAXWIDTH DUMP_WIDTH(MDB_DUMP_WIDTH(0x10))
38*7c478bd9Sstevel@tonic-gate
39*7c478bd9Sstevel@tonic-gate /*
40*7c478bd9Sstevel@tonic-gate * This is the implementation of mdb's generic hexdump facility (though
41*7c478bd9Sstevel@tonic-gate * not named such in case we decide to add support for other radices).
42*7c478bd9Sstevel@tonic-gate * While it is possible to call mdb_dump_internal directly, it is
43*7c478bd9Sstevel@tonic-gate * recommended that you use mdb_dumpptr or mdb_dump64 instead.
44*7c478bd9Sstevel@tonic-gate */
45*7c478bd9Sstevel@tonic-gate
46*7c478bd9Sstevel@tonic-gate
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate * Output the header for the dump. pad is the width of the address
49*7c478bd9Sstevel@tonic-gate * field, and offset is the index of the byte that we want highlighted.
50*7c478bd9Sstevel@tonic-gate * If the output isn't MDB_DUMP_ALIGNed, we use offset to adjust the
51*7c478bd9Sstevel@tonic-gate * labels to reflect the true least significant address nibble.
52*7c478bd9Sstevel@tonic-gate */
53*7c478bd9Sstevel@tonic-gate
54*7c478bd9Sstevel@tonic-gate static void
mdb_dump_header(int flags,int pad,int offset)55*7c478bd9Sstevel@tonic-gate mdb_dump_header(int flags, int pad, int offset)
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate int nalign = !(flags & MDB_DUMP_ALIGN);
58*7c478bd9Sstevel@tonic-gate int group = DUMP_GROUP(flags);
59*7c478bd9Sstevel@tonic-gate int width = DUMP_WIDTH(flags);
60*7c478bd9Sstevel@tonic-gate int i;
61*7c478bd9Sstevel@tonic-gate
62*7c478bd9Sstevel@tonic-gate mdb_printf("%*s ", pad, "");
63*7c478bd9Sstevel@tonic-gate for (i = 0; i < width; i++) {
64*7c478bd9Sstevel@tonic-gate if (!(i % group))
65*7c478bd9Sstevel@tonic-gate mdb_printf((group == 1 && i && !(i % 8)) ? " " : " ");
66*7c478bd9Sstevel@tonic-gate if (i == offset && !nalign)
67*7c478bd9Sstevel@tonic-gate mdb_printf("\\/");
68*7c478bd9Sstevel@tonic-gate else
69*7c478bd9Sstevel@tonic-gate mdb_printf("%2x", (i + (nalign * offset)) & 0xf);
70*7c478bd9Sstevel@tonic-gate }
71*7c478bd9Sstevel@tonic-gate
72*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_ASCII) {
73*7c478bd9Sstevel@tonic-gate mdb_printf(" ");
74*7c478bd9Sstevel@tonic-gate for (i = 0; i < width; i++) {
75*7c478bd9Sstevel@tonic-gate if (i == offset && !nalign)
76*7c478bd9Sstevel@tonic-gate mdb_printf("v");
77*7c478bd9Sstevel@tonic-gate else
78*7c478bd9Sstevel@tonic-gate mdb_printf("%x", (i + (nalign * offset)) & 0xf);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate }
81*7c478bd9Sstevel@tonic-gate
82*7c478bd9Sstevel@tonic-gate mdb_printf("\n");
83*7c478bd9Sstevel@tonic-gate }
84*7c478bd9Sstevel@tonic-gate
85*7c478bd9Sstevel@tonic-gate
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate * Output a line of data. pad is as defined above. A non-zero lmargin
88*7c478bd9Sstevel@tonic-gate * and/or rmargin indicate a set of bytes that shouldn't be printed.
89*7c478bd9Sstevel@tonic-gate */
90*7c478bd9Sstevel@tonic-gate
91*7c478bd9Sstevel@tonic-gate static void
mdb_dump_data(uint64_t addr,uchar_t * buf,int flags,int pad,int lmargin,int rmargin)92*7c478bd9Sstevel@tonic-gate mdb_dump_data(uint64_t addr, uchar_t *buf, int flags, int pad,
93*7c478bd9Sstevel@tonic-gate int lmargin, int rmargin)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate uchar_t abuf[DUMP_MAXWIDTH + 1];
96*7c478bd9Sstevel@tonic-gate int group = DUMP_GROUP(flags);
97*7c478bd9Sstevel@tonic-gate int width = DUMP_WIDTH(flags);
98*7c478bd9Sstevel@tonic-gate int i;
99*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
100*7c478bd9Sstevel@tonic-gate int flip = FALSE;
101*7c478bd9Sstevel@tonic-gate
102*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_ENDIAN)
103*7c478bd9Sstevel@tonic-gate flip = TRUE;
104*7c478bd9Sstevel@tonic-gate #endif
105*7c478bd9Sstevel@tonic-gate
106*7c478bd9Sstevel@tonic-gate mdb_printf("%0*llx: ", pad, addr);
107*7c478bd9Sstevel@tonic-gate
108*7c478bd9Sstevel@tonic-gate for (i = 0; i < width; i++) {
109*7c478bd9Sstevel@tonic-gate if (!(i % group))
110*7c478bd9Sstevel@tonic-gate mdb_printf((group == 1 && i && !(i % 8)) ? " " : " ");
111*7c478bd9Sstevel@tonic-gate if (i < lmargin || (width - i) <= rmargin) {
112*7c478bd9Sstevel@tonic-gate mdb_printf(" ");
113*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
114*7c478bd9Sstevel@tonic-gate } else if (flip) {
115*7c478bd9Sstevel@tonic-gate int j = group * ((i / group) + 1) - (i % group) - 1;
116*7c478bd9Sstevel@tonic-gate mdb_printf("%02x", buf[j]);
117*7c478bd9Sstevel@tonic-gate #endif
118*7c478bd9Sstevel@tonic-gate } else {
119*7c478bd9Sstevel@tonic-gate mdb_printf("%02x", buf[i]);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate
123*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_ASCII) {
124*7c478bd9Sstevel@tonic-gate for (i = 0; i < width; i++)
125*7c478bd9Sstevel@tonic-gate if (i < lmargin || (width - i) <= rmargin)
126*7c478bd9Sstevel@tonic-gate abuf[i] = ' ';
127*7c478bd9Sstevel@tonic-gate else if (buf[i] < ' ' || buf[i] > '~')
128*7c478bd9Sstevel@tonic-gate abuf[i] = '.';
129*7c478bd9Sstevel@tonic-gate else
130*7c478bd9Sstevel@tonic-gate abuf[i] = buf[i];
131*7c478bd9Sstevel@tonic-gate abuf[width] = '\0';
132*7c478bd9Sstevel@tonic-gate mdb_printf(" %s", abuf);
133*7c478bd9Sstevel@tonic-gate }
134*7c478bd9Sstevel@tonic-gate
135*7c478bd9Sstevel@tonic-gate mdb_printf("\n");
136*7c478bd9Sstevel@tonic-gate }
137*7c478bd9Sstevel@tonic-gate
138*7c478bd9Sstevel@tonic-gate
139*7c478bd9Sstevel@tonic-gate /*
140*7c478bd9Sstevel@tonic-gate * Given an address and a length, compute the number of characters
141*7c478bd9Sstevel@tonic-gate * needed to display addresses within that range.
142*7c478bd9Sstevel@tonic-gate */
143*7c478bd9Sstevel@tonic-gate
144*7c478bd9Sstevel@tonic-gate static int
mdb_dump_pad(uint64_t addr,uint64_t len,int flags,int bytes)145*7c478bd9Sstevel@tonic-gate mdb_dump_pad(uint64_t addr, uint64_t len, int flags, int bytes)
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate uint64_t x;
148*7c478bd9Sstevel@tonic-gate int bits;
149*7c478bd9Sstevel@tonic-gate
150*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_PEDANT) {
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate * Assume full width pointers
153*7c478bd9Sstevel@tonic-gate */
154*7c478bd9Sstevel@tonic-gate bits = NBBY * bytes;
155*7c478bd9Sstevel@tonic-gate } else {
156*7c478bd9Sstevel@tonic-gate /*
157*7c478bd9Sstevel@tonic-gate * Vary width based on address and length, but first
158*7c478bd9Sstevel@tonic-gate * check to see if the address is relevant.
159*7c478bd9Sstevel@tonic-gate */
160*7c478bd9Sstevel@tonic-gate if (len > 1 || (addr && len == 1))
161*7c478bd9Sstevel@tonic-gate len--;
162*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_RELATIVE)
163*7c478bd9Sstevel@tonic-gate x = len;
164*7c478bd9Sstevel@tonic-gate else
165*7c478bd9Sstevel@tonic-gate x = len + addr;
166*7c478bd9Sstevel@tonic-gate
167*7c478bd9Sstevel@tonic-gate bits = 0;
168*7c478bd9Sstevel@tonic-gate while (x) {
169*7c478bd9Sstevel@tonic-gate bits++;
170*7c478bd9Sstevel@tonic-gate x >>= 1;
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate }
173*7c478bd9Sstevel@tonic-gate
174*7c478bd9Sstevel@tonic-gate return ((bits + 3) / 4);
175*7c478bd9Sstevel@tonic-gate }
176*7c478bd9Sstevel@tonic-gate
177*7c478bd9Sstevel@tonic-gate
178*7c478bd9Sstevel@tonic-gate /*
179*7c478bd9Sstevel@tonic-gate * The main dump routine, called by mdb_dump64 and (indirectly) by
180*7c478bd9Sstevel@tonic-gate * mdb_dumpptr. Arguments:
181*7c478bd9Sstevel@tonic-gate * addr - the address to start dumping at
182*7c478bd9Sstevel@tonic-gate * len - the amount of data to dump
183*7c478bd9Sstevel@tonic-gate * flags - to tune operation (see mdb_modapi.h)
184*7c478bd9Sstevel@tonic-gate * func - callback function used to obtain data
185*7c478bd9Sstevel@tonic-gate * arg - argument to pass to callback function
186*7c478bd9Sstevel@tonic-gate * bytes - size of pointer type
187*7c478bd9Sstevel@tonic-gate */
188*7c478bd9Sstevel@tonic-gate
189*7c478bd9Sstevel@tonic-gate int
mdb_dump_internal(uint64_t addr,uint64_t len,int flags,mdb_dump64_cb_t func,void * arg,int bytes)190*7c478bd9Sstevel@tonic-gate mdb_dump_internal(uint64_t addr, uint64_t len, int flags, mdb_dump64_cb_t func,
191*7c478bd9Sstevel@tonic-gate void *arg, int bytes)
192*7c478bd9Sstevel@tonic-gate {
193*7c478bd9Sstevel@tonic-gate uchar_t buffers[2][DUMP_MAXWIDTH];
194*7c478bd9Sstevel@tonic-gate uchar_t *buf, *pbuf;
195*7c478bd9Sstevel@tonic-gate uint64_t i;
196*7c478bd9Sstevel@tonic-gate ssize_t j;
197*7c478bd9Sstevel@tonic-gate uint64_t addrmax;
198*7c478bd9Sstevel@tonic-gate uint64_t offset; /* bytes between first position and addr */
199*7c478bd9Sstevel@tonic-gate uint64_t reqlen = len; /* requested length */
200*7c478bd9Sstevel@tonic-gate int l, r; /* left and right margins */
201*7c478bd9Sstevel@tonic-gate int pskip; /* previous line was skipped */
202*7c478bd9Sstevel@tonic-gate int pvalid; /* previous line was valid (we may skip) */
203*7c478bd9Sstevel@tonic-gate int bread, bwanted; /* used to handle partial reads */
204*7c478bd9Sstevel@tonic-gate int pad, n;
205*7c478bd9Sstevel@tonic-gate int group, width;
206*7c478bd9Sstevel@tonic-gate int err = 0;
207*7c478bd9Sstevel@tonic-gate
208*7c478bd9Sstevel@tonic-gate addrmax = (1LL << (bytes * NBBY - 1)) - 1 + (1LL << (bytes * NBBY - 1));
209*7c478bd9Sstevel@tonic-gate
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate * Ensure that len doesn't wrap around the end of addressable
212*7c478bd9Sstevel@tonic-gate * memory. Note that because we take an address and a length,
213*7c478bd9Sstevel@tonic-gate * it isn't possible to dump from 0 to UINT64_MAX if
214*7c478bd9Sstevel@tonic-gate * MDB_DUMP_TRIM is set.
215*7c478bd9Sstevel@tonic-gate */
216*7c478bd9Sstevel@tonic-gate if (len && (len - 1 > addrmax - addr)) {
217*7c478bd9Sstevel@tonic-gate len = addrmax - addr;
218*7c478bd9Sstevel@tonic-gate if (addr || (addrmax < UINT64_MAX))
219*7c478bd9Sstevel@tonic-gate len++;
220*7c478bd9Sstevel@tonic-gate }
221*7c478bd9Sstevel@tonic-gate
222*7c478bd9Sstevel@tonic-gate /*
223*7c478bd9Sstevel@tonic-gate * If a) the grouping isn't a power of two, or
224*7c478bd9Sstevel@tonic-gate * b) the display width is not evenly divisible by the grouping
225*7c478bd9Sstevel@tonic-gate * we ignore the specified grouping (and default to 4).
226*7c478bd9Sstevel@tonic-gate */
227*7c478bd9Sstevel@tonic-gate group = DUMP_GROUP(flags);
228*7c478bd9Sstevel@tonic-gate width = DUMP_WIDTH(flags);
229*7c478bd9Sstevel@tonic-gate if (((group - 1) & group) || (width % group)) {
230*7c478bd9Sstevel@tonic-gate group = 4;
231*7c478bd9Sstevel@tonic-gate flags = (flags & 0xfffff) | MDB_DUMP_GROUP(group);
232*7c478bd9Sstevel@tonic-gate }
233*7c478bd9Sstevel@tonic-gate
234*7c478bd9Sstevel@tonic-gate /*
235*7c478bd9Sstevel@tonic-gate * If we are reordering bytes to adjust for endianness, turn
236*7c478bd9Sstevel@tonic-gate * off text output, headers, and alignment to cut down on the
237*7c478bd9Sstevel@tonic-gate * number of special cases (and confusing output). For
238*7c478bd9Sstevel@tonic-gate * correctness, we will continue to observe MDB_DUMP_TRIM, but
239*7c478bd9Sstevel@tonic-gate * will truncate output if the specified length isn't a
240*7c478bd9Sstevel@tonic-gate * multiple of the grouping.
241*7c478bd9Sstevel@tonic-gate */
242*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_ENDIAN) {
243*7c478bd9Sstevel@tonic-gate flags &= ~(MDB_DUMP_ALIGN | MDB_DUMP_HEADER | MDB_DUMP_ASCII);
244*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_TRIM)
245*7c478bd9Sstevel@tonic-gate len -= len % group;
246*7c478bd9Sstevel@tonic-gate }
247*7c478bd9Sstevel@tonic-gate
248*7c478bd9Sstevel@tonic-gate /*
249*7c478bd9Sstevel@tonic-gate * If we are interested in seeing the data indexed relative to
250*7c478bd9Sstevel@tonic-gate * the starting location, paragraph alignment is irrelevant.
251*7c478bd9Sstevel@tonic-gate * The left margin will always be 0.
252*7c478bd9Sstevel@tonic-gate */
253*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_RELATIVE) {
254*7c478bd9Sstevel@tonic-gate flags &= ~MDB_DUMP_ALIGN;
255*7c478bd9Sstevel@tonic-gate l = 0;
256*7c478bd9Sstevel@tonic-gate } else {
257*7c478bd9Sstevel@tonic-gate l = addr % DUMP_PARAGRAPH;
258*7c478bd9Sstevel@tonic-gate }
259*7c478bd9Sstevel@tonic-gate
260*7c478bd9Sstevel@tonic-gate /*
261*7c478bd9Sstevel@tonic-gate * Compute the width of our addresses, and adjust our starting
262*7c478bd9Sstevel@tonic-gate * point based on the address and the state of the alignment
263*7c478bd9Sstevel@tonic-gate * flag.
264*7c478bd9Sstevel@tonic-gate */
265*7c478bd9Sstevel@tonic-gate pad = mdb_dump_pad(addr, len, flags, bytes);
266*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_ALIGN) {
267*7c478bd9Sstevel@tonic-gate len += l;
268*7c478bd9Sstevel@tonic-gate addr -= l;
269*7c478bd9Sstevel@tonic-gate offset = l;
270*7c478bd9Sstevel@tonic-gate } else {
271*7c478bd9Sstevel@tonic-gate offset = 0;
272*7c478bd9Sstevel@tonic-gate }
273*7c478bd9Sstevel@tonic-gate
274*7c478bd9Sstevel@tonic-gate /*
275*7c478bd9Sstevel@tonic-gate * Display the header (if appropriate), using the left margin
276*7c478bd9Sstevel@tonic-gate * to determine what our column header offset should be.
277*7c478bd9Sstevel@tonic-gate */
278*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_HEADER)
279*7c478bd9Sstevel@tonic-gate mdb_dump_header(flags, pad, l);
280*7c478bd9Sstevel@tonic-gate
281*7c478bd9Sstevel@tonic-gate /*
282*7c478bd9Sstevel@tonic-gate * If we aren't trimming and aligning the output, the left
283*7c478bd9Sstevel@tonic-gate * margin is now irrelevant and should be zeroed.
284*7c478bd9Sstevel@tonic-gate */
285*7c478bd9Sstevel@tonic-gate if (!(flags & MDB_DUMP_TRIM) || !(flags & MDB_DUMP_ALIGN))
286*7c478bd9Sstevel@tonic-gate l = 0;
287*7c478bd9Sstevel@tonic-gate
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate * We haven't skipped the previous line, it isn't valid to skip
290*7c478bd9Sstevel@tonic-gate * the current line, and we use buffer 0 first. lint doesn't
291*7c478bd9Sstevel@tonic-gate * realize that this implies pbuf won't be accessed until after
292*7c478bd9Sstevel@tonic-gate * it is set, so we explicitly initialize that here, too.
293*7c478bd9Sstevel@tonic-gate */
294*7c478bd9Sstevel@tonic-gate pskip = pvalid = FALSE;
295*7c478bd9Sstevel@tonic-gate pbuf = NULL;
296*7c478bd9Sstevel@tonic-gate n = 0;
297*7c478bd9Sstevel@tonic-gate r = 0;
298*7c478bd9Sstevel@tonic-gate
299*7c478bd9Sstevel@tonic-gate for (i = 0; i < len && r == 0; i += width) {
300*7c478bd9Sstevel@tonic-gate /*
301*7c478bd9Sstevel@tonic-gate * Select the current buffer.
302*7c478bd9Sstevel@tonic-gate */
303*7c478bd9Sstevel@tonic-gate buf = buffers[n];
304*7c478bd9Sstevel@tonic-gate
305*7c478bd9Sstevel@tonic-gate /*
306*7c478bd9Sstevel@tonic-gate * We have a right margin only if we are on the last
307*7c478bd9Sstevel@tonic-gate * line and either (1) MDB_DUMP_TRIM is set or (2) our
308*7c478bd9Sstevel@tonic-gate * untrimmed output would require reading past the end
309*7c478bd9Sstevel@tonic-gate * of addressable memory. In either case, we clear
310*7c478bd9Sstevel@tonic-gate * pvalid since we don't want to skip the last line.
311*7c478bd9Sstevel@tonic-gate */
312*7c478bd9Sstevel@tonic-gate if ((uint64_t)width >= len - i) {
313*7c478bd9Sstevel@tonic-gate pvalid = FALSE;
314*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_TRIM)
315*7c478bd9Sstevel@tonic-gate r = width - (len - i);
316*7c478bd9Sstevel@tonic-gate if ((uint64_t)width - 1 > addrmax - (addr + i)) {
317*7c478bd9Sstevel@tonic-gate int nr = width - (addrmax - (addr + i)) - 1;
318*7c478bd9Sstevel@tonic-gate r = MAX(r, nr);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate
322*7c478bd9Sstevel@tonic-gate /*
323*7c478bd9Sstevel@tonic-gate * Read data into the current buffer, obeying the left
324*7c478bd9Sstevel@tonic-gate * and right margins.
325*7c478bd9Sstevel@tonic-gate *
326*7c478bd9Sstevel@tonic-gate * We handle read(2)-style partial results by
327*7c478bd9Sstevel@tonic-gate * repeatedly calling the callback until we fill the
328*7c478bd9Sstevel@tonic-gate * buffer, we get a 0 (end of file), or we get a -1
329*7c478bd9Sstevel@tonic-gate * (error). We take care to never read the same data
330*7c478bd9Sstevel@tonic-gate * twice, though.
331*7c478bd9Sstevel@tonic-gate *
332*7c478bd9Sstevel@tonic-gate * mdb(1)-style partial results (i.e. EMDB_PARTIAL) are
333*7c478bd9Sstevel@tonic-gate * treated like any other error. If more exotic
334*7c478bd9Sstevel@tonic-gate * handling is desired, the caller is free to wrap
335*7c478bd9Sstevel@tonic-gate * their callback with an auxiliary function. See
336*7c478bd9Sstevel@tonic-gate * mdb_dumpptr and mdb_dump64 for examples of this.
337*7c478bd9Sstevel@tonic-gate */
338*7c478bd9Sstevel@tonic-gate bread = l;
339*7c478bd9Sstevel@tonic-gate bwanted = width - r;
340*7c478bd9Sstevel@tonic-gate while (bread < bwanted) {
341*7c478bd9Sstevel@tonic-gate j = func(buf + bread, bwanted - bread,
342*7c478bd9Sstevel@tonic-gate addr + i + bread, arg);
343*7c478bd9Sstevel@tonic-gate if (j <= 0) {
344*7c478bd9Sstevel@tonic-gate if (i + bread < offset) {
345*7c478bd9Sstevel@tonic-gate l++;
346*7c478bd9Sstevel@tonic-gate j = 1;
347*7c478bd9Sstevel@tonic-gate } else {
348*7c478bd9Sstevel@tonic-gate r += bwanted - bread;
349*7c478bd9Sstevel@tonic-gate pvalid = FALSE;
350*7c478bd9Sstevel@tonic-gate if (j == -1)
351*7c478bd9Sstevel@tonic-gate err = errno;
352*7c478bd9Sstevel@tonic-gate if (bread == l) {
353*7c478bd9Sstevel@tonic-gate i += width;
354*7c478bd9Sstevel@tonic-gate goto out;
355*7c478bd9Sstevel@tonic-gate }
356*7c478bd9Sstevel@tonic-gate break;
357*7c478bd9Sstevel@tonic-gate }
358*7c478bd9Sstevel@tonic-gate }
359*7c478bd9Sstevel@tonic-gate bread += j;
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate
362*7c478bd9Sstevel@tonic-gate /*
363*7c478bd9Sstevel@tonic-gate * If we are eliminating repeated lines, AND it is
364*7c478bd9Sstevel@tonic-gate * valid to eliminate this line, AND the current line
365*7c478bd9Sstevel@tonic-gate * is the same as the previous line, don't print the
366*7c478bd9Sstevel@tonic-gate * current line. If we didn't skip the previous line,
367*7c478bd9Sstevel@tonic-gate * print an asterisk and set the previous-line-skipped
368*7c478bd9Sstevel@tonic-gate * flag.
369*7c478bd9Sstevel@tonic-gate *
370*7c478bd9Sstevel@tonic-gate * Otherwise, print the line and clear the
371*7c478bd9Sstevel@tonic-gate * previous-line-skipped flag.
372*7c478bd9Sstevel@tonic-gate */
373*7c478bd9Sstevel@tonic-gate if ((flags & MDB_DUMP_SQUISH) && pvalid &&
374*7c478bd9Sstevel@tonic-gate (memcmp(buf, pbuf, width) == 0)) {
375*7c478bd9Sstevel@tonic-gate if (!pskip) {
376*7c478bd9Sstevel@tonic-gate mdb_printf("*\n");
377*7c478bd9Sstevel@tonic-gate pskip = TRUE;
378*7c478bd9Sstevel@tonic-gate }
379*7c478bd9Sstevel@tonic-gate } else {
380*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_RELATIVE)
381*7c478bd9Sstevel@tonic-gate mdb_dump_data(i, buf, flags, pad, l, r);
382*7c478bd9Sstevel@tonic-gate else
383*7c478bd9Sstevel@tonic-gate mdb_dump_data(addr + i, buf, flags, pad, l, r);
384*7c478bd9Sstevel@tonic-gate pskip = FALSE;
385*7c478bd9Sstevel@tonic-gate }
386*7c478bd9Sstevel@tonic-gate
387*7c478bd9Sstevel@tonic-gate /*
388*7c478bd9Sstevel@tonic-gate * If we have a non-zero left margin then we don't have
389*7c478bd9Sstevel@tonic-gate * a full buffer of data and we shouldn't try to skip
390*7c478bd9Sstevel@tonic-gate * the next line. It doesn't matter if the right
391*7c478bd9Sstevel@tonic-gate * margin is non-zero since we'll fall out of the loop.
392*7c478bd9Sstevel@tonic-gate */
393*7c478bd9Sstevel@tonic-gate if (!l)
394*7c478bd9Sstevel@tonic-gate pvalid = TRUE;
395*7c478bd9Sstevel@tonic-gate
396*7c478bd9Sstevel@tonic-gate /*
397*7c478bd9Sstevel@tonic-gate * Swap buffers, and zero the left margin.
398*7c478bd9Sstevel@tonic-gate */
399*7c478bd9Sstevel@tonic-gate n = (n + 1) % 2;
400*7c478bd9Sstevel@tonic-gate pbuf = buf;
401*7c478bd9Sstevel@tonic-gate l = 0;
402*7c478bd9Sstevel@tonic-gate }
403*7c478bd9Sstevel@tonic-gate
404*7c478bd9Sstevel@tonic-gate out:
405*7c478bd9Sstevel@tonic-gate /*
406*7c478bd9Sstevel@tonic-gate * If we successfully dumped everything, update . to be the
407*7c478bd9Sstevel@tonic-gate * address following that of the last byte requested.
408*7c478bd9Sstevel@tonic-gate */
409*7c478bd9Sstevel@tonic-gate if (i - r - offset >= reqlen) {
410*7c478bd9Sstevel@tonic-gate if (flags & MDB_DUMP_NEWDOT)
411*7c478bd9Sstevel@tonic-gate mdb_set_dot(addr + offset + reqlen);
412*7c478bd9Sstevel@tonic-gate } else if (err) {
413*7c478bd9Sstevel@tonic-gate errno = err;
414*7c478bd9Sstevel@tonic-gate mdb_warn("failed to read data at %#llx", addr + i - r);
415*7c478bd9Sstevel@tonic-gate return (-1);
416*7c478bd9Sstevel@tonic-gate }
417*7c478bd9Sstevel@tonic-gate
418*7c478bd9Sstevel@tonic-gate return (0);
419*7c478bd9Sstevel@tonic-gate }
420