/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* 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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2016 Joyent, Inc.
*/
/*
* Format String Decoder
*
* This file provides the core engine for converting strings of format
* characters into formatted output. The various format dcmds invoke the
* mdb_fmt_print() function below with a target, address space identifier,
* address, count, and format character, and it reads the required data from
* the target and prints the formatted output to stdout. Since nearly two
* thirds of the format characters can be expressed as simple printf format
* strings, we implement the engine using the lookup table below. Each entry
* provides either a pointer to a printf format string or a pointer to a
* function to perform special processing. For the printf case, the
* corresponding data size in bytes is also supplied. The printf processing
* code handles 1, 2, 4, and 8-byte reads into an unsigned integer container
* of the given size, and then simply calls mdb_iob_printf with the integer
* and format string. This handles all printf cases, except when unsigned
* promotion of an integer type in the varargs list does not perform the
* conversion we require to get the proper result. With the current set of
* format characters, this case only occurs twice: we need a 4-byte float
* to get promoted to 8-byte double for the 'f' format so it can be
* correctly formatted by %f, and we need a 1-byte int8_t to get promoted
* with sign extension to a 4-byte int32_t for the 'v' format so it can be
* correctly formatted by %d. We provide explicit functions to handle these
* cases, as well as to handle special format characters such as 'i', etc.
* We also provide a cmd_formats() dcmd function below which prints a table
* of the output formats and their sizes. Format characters that provide
* custom functions provide their help description string explicitly. All
* the printf formats have their help strings generated automatically by
* our printf "unparser" mdb_iob_format2str().
*/
#include <mdb/mdb_types.h>
#include <mdb/mdb_target.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_modapi.h>
/*
* There are several 'special' characters that are handled outside of
* mdb_fmt_print(). These are characters that write (vwWZ) and characters that
* match (lLM). We include them here so that ::formats can display an
* appropriate message, but they are handled specially by write_arglist() and
* match_arglist() in mdb_cmds.c.
*/
typedef struct mdb_fmt_desc {
#ifndef _KMDB
#endif
/*ARGSUSED*/
static mdb_tgt_addr_t
{
while (cnt-- != 0)
} else {
while (cnt-- != 0)
}
return (addr);
}
#ifndef _KMDB
static mdb_tgt_addr_t
{
float f;
/*
* We need to handle float as a special case because we need it to be
* promoted to a double by virtue of appearing as a parameter, and all
* our generic format handling below is based on integer types.
*/
while (cnt-- != 0) {
warn("failed to read data from target");
break;
}
addr += sizeof (f);
}
return (addr);
}
#endif
/*ARGSUSED*/
static mdb_tgt_addr_t
{
}
/*ARGSUSED*/
static mdb_tgt_addr_t
{
}
/*ARGSUSED*/
static mdb_tgt_addr_t
{
}
/*ARGSUSED*/
static mdb_tgt_addr_t
{
while (cnt-- != 0)
return (addr);
}
/*ARGSUSED*/
static mdb_tgt_addr_t
{
return (addr);
}
/*ARGSUSED*/
static mdb_tgt_addr_t
{
return (addr);
}
static mdb_tgt_addr_t
{
do {
if (nbytes > 0) {
} else if (nbytes < 0) {
warn("failed to read data from target");
goto out;
}
if (cnt != 0)
}
out:
return (addr);
}
static mdb_tgt_addr_t
{
char *s;
do {
if (nbytes > 0) {
strfree(s);
} else if (nbytes < 0) {
warn("failed to read data from target");
goto out;
}
if (cnt != 0)
}
out:
return (addr);
}
static mdb_tgt_addr_t
{
char *buf, *s;
convert = &strchr2adb;
else
convert = &strchr2esc;
strfree(s);
}
return (addr);
}
static mdb_tgt_addr_t
{
ushort_t x;
while (cnt-- != 0) {
x = (x << 8) | (x >> 8);
addr += sizeof (x);
} else {
warn("failed to read data from target");
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
uint_t x;
while (cnt-- != 0) {
x = ((x << 24) | ((x << 8) & 0xff0000) |
((x >> 8) & 0xff00) | ((x >> 24) & 0xff));
addr += sizeof (x);
} else {
warn("failed to read data from target");
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
int32_t x;
while (cnt-- != 0) {
addr += sizeof (x);
} else {
warn("failed to read data from target");
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
int64_t x;
while (cnt-- != 0) {
if ((time_t)x == x)
else
addr += sizeof (x);
} else {
warn("failed to read data from target");
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
int8_t x;
while (cnt-- != 0) {
addr += sizeof (x);
} else {
warn("failed to read data from target");
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
while (cnt-- != 0) {
return (addr); /* If we didn't move, we failed */
}
return (addr);
}
static mdb_tgt_addr_t
{
uint32_t i;
warn("failed to read data from target");
break; /* Fail if we can't read instruction */
}
break; /* Fail if we didn't advance */
}
return (addr);
}
static mdb_tgt_addr_t
{
uint64_t x;
while (cnt-- != 0) {
addr += sizeof (x);
} else {
warn("failed to read data from target");
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
uint64_t x;
while (cnt-- != 0) {
addr += sizeof (x);
} else {
warn("failed to read data from target");
break;
}
}
return (addr);
}
#ifdef _KMDB
#else
#endif
#ifdef _LP64
#else
#endif
#ifdef _KMDB
#else
B_TRUE }, /* 102 = f */
#endif
};
{
void *buf;
union {
double d;
} u;
return (addr);
}
case FMT_FUNC:
break;
case FMT_PRINTF:
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
default:
}
fail("format %c is using illegal fp size\n",
fmt);
}
buf = &u.d;
}
while (cnt-- != 0) {
warn("failed to read data from target");
return (addr);
}
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
u.d);
} else {
u.i8);
}
break;
}
}
break;
default:
}
return (addr);
}
/*ARGSUSED*/
int
{
int i;
const char *write;
return (DCMD_USAGE);
continue;
else
case SZ_NONE:
mdb_printf("\n");
break;
case 0:
mdb_printf(" (variable size)\n");
break;
case 1:
mdb_printf(" (1 byte)\n");
break;
default:
}
}
return (DCMD_OK);
}