mdb_dump.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <mdb/mdb_dump.h>
#include <mdb/mdb_modapi.h>
#include <limits.h>
#define DUMP_PARAGRAPH 16
/*
* This is the implementation of mdb's generic hexdump facility (though
* not named such in case we decide to add support for other radices).
* While it is possible to call mdb_dump_internal directly, it is
* recommended that you use mdb_dumpptr or mdb_dump64 instead.
*/
/*
* Output the header for the dump. pad is the width of the address
* field, and offset is the index of the byte that we want highlighted.
* If the output isn't MDB_DUMP_ALIGNed, we use offset to adjust the
* labels to reflect the true least significant address nibble.
*/
static void
{
int i;
for (i = 0; i < width; i++) {
if (!(i % group))
mdb_printf("\\/");
else
}
if (flags & MDB_DUMP_ASCII) {
mdb_printf(" ");
for (i = 0; i < width; i++) {
mdb_printf("v");
else
}
}
mdb_printf("\n");
}
/*
* Output a line of data. pad is as defined above. A non-zero lmargin
*/
static void
{
int i;
#ifdef _LITTLE_ENDIAN
if (flags & MDB_DUMP_ENDIAN)
#endif
for (i = 0; i < width; i++) {
if (!(i % group))
mdb_printf(" ");
#ifdef _LITTLE_ENDIAN
} else if (flip) {
#endif
} else {
}
}
if (flags & MDB_DUMP_ASCII) {
for (i = 0; i < width; i++)
abuf[i] = ' ';
abuf[i] = '.';
else
}
mdb_printf("\n");
}
/*
* Given an address and a length, compute the number of characters
* needed to display addresses within that range.
*/
static int
{
uint64_t x;
int bits;
if (flags & MDB_DUMP_PEDANT) {
/*
* Assume full width pointers
*/
} else {
/*
* Vary width based on address and length, but first
* check to see if the address is relevant.
*/
len--;
if (flags & MDB_DUMP_RELATIVE)
x = len;
else
bits = 0;
while (x) {
bits++;
x >>= 1;
}
}
}
/*
* The main dump routine, called by mdb_dump64 and (indirectly) by
* mdb_dumpptr. Arguments:
* addr - the address to start dumping at
* len - the amount of data to dump
* flags - to tune operation (see mdb_modapi.h)
* func - callback function used to obtain data
* arg - argument to pass to callback function
* bytes - size of pointer type
*/
int
{
uint64_t i;
ssize_t j;
int l, r; /* left and right margins */
int pskip; /* previous line was skipped */
int pvalid; /* previous line was valid (we may skip) */
int pad, n;
int err = 0;
/*
* Ensure that len doesn't wrap around the end of addressable
* memory. Note that because we take an address and a length,
* it isn't possible to dump from 0 to UINT64_MAX if
* MDB_DUMP_TRIM is set.
*/
len++;
}
/*
* If a) the grouping isn't a power of two, or
* b) the display width is not evenly divisible by the grouping
* we ignore the specified grouping (and default to 4).
*/
group = 4;
}
/*
* If we are reordering bytes to adjust for endianness, turn
* off text output, headers, and alignment to cut down on the
* number of special cases (and confusing output). For
* correctness, we will continue to observe MDB_DUMP_TRIM, but
* will truncate output if the specified length isn't a
* multiple of the grouping.
*/
if (flags & MDB_DUMP_ENDIAN) {
if (flags & MDB_DUMP_TRIM)
}
/*
* If we are interested in seeing the data indexed relative to
* the starting location, paragraph alignment is irrelevant.
* The left margin will always be 0.
*/
if (flags & MDB_DUMP_RELATIVE) {
flags &= ~MDB_DUMP_ALIGN;
l = 0;
} else {
l = addr % DUMP_PARAGRAPH;
}
/*
* Compute the width of our addresses, and adjust our starting
* point based on the address and the state of the alignment
* flag.
*/
if (flags & MDB_DUMP_ALIGN) {
len += l;
addr -= l;
offset = l;
} else {
offset = 0;
}
/*
* Display the header (if appropriate), using the left margin
* to determine what our column header offset should be.
*/
if (flags & MDB_DUMP_HEADER)
/*
* If we aren't trimming and aligning the output, the left
* margin is now irrelevant and should be zeroed.
*/
l = 0;
/*
* We haven't skipped the previous line, it isn't valid to skip
* the current line, and we use buffer 0 first. lint doesn't
* realize that this implies pbuf won't be accessed until after
* it is set, so we explicitly initialize that here, too.
*/
n = 0;
r = 0;
/*
* Select the current buffer.
*/
/*
* We have a right margin only if we are on the last
* line and either (1) MDB_DUMP_TRIM is set or (2) our
* untrimmed output would require reading past the end
* of addressable memory. In either case, we clear
* pvalid since we don't want to skip the last line.
*/
if (flags & MDB_DUMP_TRIM)
}
}
/*
* Read data into the current buffer, obeying the left
* and right margins.
*
* We handle read(2)-style partial results by
* repeatedly calling the callback until we fill the
* buffer, we get a 0 (end of file), or we get a -1
* (error). We take care to never read the same data
* twice, though.
*
* mdb(1)-style partial results (i.e. EMDB_PARTIAL) are
* treated like any other error. If more exotic
* handling is desired, the caller is free to wrap
* their callback with an auxiliary function. See
* mdb_dumpptr and mdb_dump64 for examples of this.
*/
bread = l;
if (j <= 0) {
l++;
j = 1;
} else {
if (j == -1)
if (bread == l) {
i += width;
goto out;
}
break;
}
}
bread += j;
}
/*
* If we are eliminating repeated lines, AND it is
* valid to eliminate this line, AND the current line
* is the same as the previous line, don't print the
* current line. If we didn't skip the previous line,
* print an asterisk and set the previous-line-skipped
* flag.
*
* Otherwise, print the line and clear the
* previous-line-skipped flag.
*/
if (!pskip) {
mdb_printf("*\n");
}
} else {
if (flags & MDB_DUMP_RELATIVE)
else
}
/*
* If we have a non-zero left margin then we don't have
* a full buffer of data and we shouldn't try to skip
* the next line. It doesn't matter if the right
* margin is non-zero since we'll fall out of the loop.
*/
if (!l)
/*
* Swap buffers, and zero the left margin.
*/
n = (n + 1) % 2;
l = 0;
}
out:
/*
* If we successfully dumped everything, update . to be the
* address following that of the last byte requested.
*/
if (flags & MDB_DUMP_NEWDOT)
} else if (err) {
return (-1);
}
return (0);
}