mdb_cmds.c revision 63360950109af2ce85a962ca61f40b8782f11100
/*
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/elf_SPARC.h>
#include <libproc.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <alloca.h>
#include <libctf.h>
#include <ctype.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_argvec.h>
#include <mdb/mdb_target.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_conf.h>
#include <mdb/mdb_module.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_stdlib.h>
#include <mdb/mdb_io_impl.h>
#include <mdb/mdb_help.h>
#include <mdb/mdb_disasm.h>
#include <mdb/mdb_frame.h>
#include <mdb/mdb_evset.h>
#include <mdb/mdb_print.h>
#include <mdb/mdb_demangle.h>
#include <mdb/mdb_macalias.h>
#ifdef _KMDB
#include <kmdb/kmdb_kdi.h>
#endif
#ifdef __sparc
#define SETHI_MASK 0xc1c00000
#define SETHI_VALUE 0x01000000
#define OP_ARITH_MEM_MASK 0x2
#define OP_ARITH 0x2
#define OP_MEM 0x3
#define OP3_CC_MASK 0x10
#define OP3_COMPLEX_MASK 0x20
#define OP3_ADD 0x00
#define OP3_OR 0x02
#define OP3_XOR 0x03
#ifndef R_O7
#define R_O7 0xf
#endif
#endif /* __sparc */
static mdb_tgt_addr_t
{
addr) == -1)
return (addr);
return (addr);
if (rdback) {
return (addr);
}
return (addr + sizeof (n));
}
static mdb_tgt_addr_t
{
addr) == -1)
return (addr);
return (addr);
if (rdback) {
return (addr);
}
return (addr + sizeof (n));
}
static mdb_tgt_addr_t
{
addr) == -1)
return (addr);
return (addr);
if (rdback) {
return (addr);
}
return (addr + sizeof (n));
}
static mdb_tgt_addr_t
{
uint64_t o;
addr) == -1)
return (addr);
return (addr);
if (rdback) {
return (addr);
}
return (addr + sizeof (n));
}
static int
{
size_t i;
if (argc == 1) {
mdb_warn("expected value to write following %c\n",
return (DCMD_ERR);
}
case 'v':
break;
case 'w':
break;
case 'W':
break;
case 'Z':
break;
}
mdb_warn("expected immediate value instead of '%c'\n",
return (DCMD_ERR);
}
mdb_warn("failed to write \"%s\"",
return (DCMD_ERR);
}
} else
mdb_warn("failed to write %llr at address 0x%llx",
break;
}
}
return (DCMD_OK);
}
static mdb_tgt_addr_t
{
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
break;
}
}
return (addr);
}
static mdb_tgt_addr_t
{
uint64_t x;
break;
}
}
return (addr);
}
static int
{
size_t i;
if (argc < 2) {
return (DCMD_ERR);
}
if (argc > 3) {
mdb_warn("only value and mask may follow %c\n",
return (DCMD_ERR);
}
case 'l':
break;
case 'L':
break;
case 'M':
break;
}
mdb_warn("expected immediate value instead of '%c'\n",
return (DCMD_ERR);
}
mdb_warn("failed to evaluate \"%s\"",
return (DCMD_ERR);
}
} else
}
/*
* In adb(1), the match operators ignore any repeat count that has
* been applied to them. We emulate this undocumented property
* by returning DCMD_ABORT if our input is not a pipeline.
*/
}
static int
{
return (FALSE);
return (FALSE);
}
return (TRUE);
}
static int
{
char buf[MDB_TGT_SYM_NAMLEN];
size_t i, n;
const char *fmt;
int is_dis;
/*
* This is nasty, but necessary for precise adb compatibility.
* Detect disassembly format by looking for "ai" or "ia":
*/
fmt = "%-#*lla\n";
fmt = "%-#*lla";
} else {
fmt = "%-#*lla%16T";
}
/*
* If symbolic decoding is on, disassembly is off, and the
* address exactly matches a symbol, print the symbol name:
*/
/*
* If this is a virtual address, cast it so that it reflects
* only the valid component of the address.
*/
if (as == MDB_TGT_AS_VIRT)
}
if (argc == 0) {
/*
* Yes, for you trivia buffs: if you use a format verb and give
* no format string, you get: X^"= "i ... note that in adb the
* the '=' verb once had 'z' as its default, but then 'z' was
* deleted (it was once an alias for 'i') and so =\n now calls
* scanform("z") and produces a 'bad modifier' message.
*/
};
}
case MDB_TYPE_CHAR:
n = 1;
break;
case MDB_TYPE_IMMEDIATE:
break;
case MDB_TYPE_STRING:
n = 1;
break;
}
}
return (DCMD_OK);
}
static int
{
}
}
/*ARGSUSED*/
static int
{
}
#ifndef _KMDB
/*ARGSUSED*/
static int
{
}
#endif
/*ARGSUSED*/
static int
{
}
/*ARGSUSED*/
static int
{
const char *tgt_argv[1];
mdb_tgt_t *t;
size_t i, n;
if (argc == 0) {
mdb_warn("expected one or more format characters "
"following '='\n");
return (DCMD_ERR);
}
case MDB_TYPE_CHAR:
n = 1;
break;
case MDB_TYPE_IMMEDIATE:
break;
case MDB_TYPE_STRING:
n = 1;
break;
}
}
mdb_tgt_destroy(t);
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
const char *p;
mdb_var_t *v;
if (argc == 2) {
mdb_warn("improper arguments following '>' operator\n");
return (DCMD_ERR);
}
case 'c':
break;
case 's':
break;
case 'i':
break;
case 'l':
break;
default:
mdb_warn("%c is not a valid // modifier\n",
return (DCMD_ERR);
}
argv++;
argc--;
}
mdb_warn("expected single variable name following '>'\n");
return (DCMD_ERR);
}
mdb_warn("variable names may not exceed %d characters\n",
MDB_NV_NAMELEN - 1);
return (DCMD_ERR);
}
mdb_warn("'%c' may not be used in a variable name\n", *p);
return (DCMD_ERR);
}
else
mdb_nv_set_value(v, dot);
return (DCMD_OK);
}
static int
{
int i;
for (i = 0; i < 2; i++) {
mdb_arg_t v;
int rv;
v.a_type = MDB_TYPE_STRING;
return (rv);
}
}
return (DCMD_ERR);
}
static int
{
char *sname;
int rv;
if (!(flags & DCMD_ADDRSPEC)) {
addr = mdb_get_dot();
flags |= DCMD_ADDRSPEC;
}
return (rv);
mdb_arg_t v;
int rv;
v.a_type = MDB_TYPE_STRING;
return (rv);
}
return (rv);
}
static int
{
const char *alias;
int rv;
return (DCMD_ERR);
if (flags & DCMD_ADDRSPEC) {
} else {
}
}
/*ARGSUSED*/
static int
{
const char *fname;
int rv;
return (DCMD_USAGE);
if (flags & DCMD_PIPE_OUT) {
mdb_warn("macro files cannot be used as input to a pipeline\n");
return (DCMD_ABORT);
}
int err;
return (DCMD_OK);
}
return (rv);
return (DCMD_ABORT);
}
static int
{
const char *fname;
int rv;
/*
* The syntax [expr[,count]]$< with no trailing macro file name is
* magic in that if count is zero, this command won't be called and
* the expression is thus a no-op. If count is non-zero, we get
* invoked with argc == 0, and this means abort the current macro.
* If our debugger stack depth is greater than one, we may be using
* $< from within a previous $<<, so in that case we set m_in to
* NULL to force this entire frame to be popped.
*/
if (argc == 0) {
} else
mdb_warn("input stack is empty\n");
return (DCMD_OK);
}
return (DCMD_USAGE);
return (DCMD_OK);
}
return (rv);
return (DCMD_ABORT);
}
#ifndef _KMDB
/*ARGSUSED*/
static int
{
if (flags & DCMD_ADDRSPEC)
return (DCMD_USAGE);
mdb_warn("expected string argument\n");
continue;
}
continue;
}
if (len > 0) {
mdb_warn("write failed");
break;
}
}
}
if (mdb_iob_err(iob))
}
return (status);
}
#endif
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
return (DCMD_ABORT);
if (mdb_get_dot() != 0)
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
return (DCMD_ABORT);
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
mdb_warn("command is not supported by current target\n");
return (DCMD_ERR);
}
/*ARGSUSED*/
static int
{
#ifdef _KMDB
return (DCMD_USAGE);
if (opt_u) {
return (DCMD_ERR);
}
}
#endif
/*NOTREACHED*/
return (DCMD_ERR);
}
#ifdef _KMDB
static void
quit_help(void)
{
"-u unload the debugger (if not loaded at boot)\n");
}
#endif
/*ARGSUSED*/
static int
{
mdb_var_t *v;
return (DCMD_USAGE);
if (opt_prt) {
mdb_printf("%#llr>%s\n",
mdb_nv_get_value(v), mdb_nv_get_name(v));
} else {
mdb_printf("%s = %llr\n",
mdb_nv_get_name(v), mdb_nv_get_value(v));
}
}
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
mdb_var_t *v;
if (argc != 0)
return (DCMD_USAGE);
if ((value = mdb_nv_get_value(v)) != 0)
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
if (argc != 0)
return (DCMD_USAGE);
if (flags & DCMD_ADDRSPEC) {
mdb_warn("expected radix from 2 to 16\n");
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
if (argc != 0)
return (DCMD_USAGE);
if (flags & DCMD_ADDRSPEC)
mdb_printf("symbol matching distance = %lr (%s)\n",
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
if (argc != 0)
return (DCMD_USAGE);
if (flags & DCMD_ADDRSPEC)
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
if (argc != 0)
return (DCMD_USAGE);
mdb_warn("failed to re-open target for writing");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
mdb_var_t *v;
size_t i;
for (i = 0; i < argc; i++) {
mdb_warn("bad option: arg %lu is not a string\n",
(ulong_t)i + 1);
return (DCMD_USAGE);
}
}
mdb_warn("variable '%s' not defined\n",
else
}
return (DCMD_OK);
}
#ifndef _KMDB
/*ARGSUSED*/
static int
{
int i;
return (DCMD_USAGE);
mdb_warn("log may not be manipulated in this context\n");
return (DCMD_ABORT);
}
if (i != argc)
/*
* If no arguments were specified, print the log file name (if any)
* and report whether the log is enabled or disabled.
*/
if (argc == 0) {
mdb_printf("%s: logging to \"%s\" is currently %s\n",
} else
return (DCMD_OK);
}
/*
* If the -d option was specified, pop the log i/o object off the
* i/o stack of stdin, stdout, and stderr.
*/
if (opt_d) {
} else
mdb_warn("logging is already disabled\n");
return (DCMD_OK);
}
/*
* The -e option is the default: (re-)enable logging by pushing
* the log i/o object on to stdin, stdout, and stderr. If we have
* a previous log file, we need to pop it and close it. If we have
* no new log file, push the previous one back on.
*/
}
}
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
mdb_warn("no log file has been selected\n");
return (DCMD_ERR);
}
static int
{
if (argc == 0) {
}
}
#endif
/*ARGSUSED*/
static int
{
int i, mode = MDB_MOD_LOCAL;
#ifdef _KMDB
#endif
NULL);
argc -= i;
argv += i;
return (DCMD_USAGE);
return (DCMD_ERR);
return (DCMD_OK);
}
static void
load_help(void)
{
#ifdef _KMDB
"-d defer load until next continue\n"
#endif
"-s load module silently\n");
}
/*ARGSUSED*/
static int
{
int mode = 0;
int i;
#ifdef _KMDB
#endif
NULL);
argc -= i;
argv += i;
return (DCMD_USAGE);
return (DCMD_ERR);
}
return (DCMD_OK);
}
#ifdef _KMDB
static void
unload_help(void)
{
"-d defer unload until next continue\n");
}
#endif
static int
{
return (DCMD_USAGE);
if (argc != 0) {
return (DCMD_USAGE);
} else if (flags & DCMD_ADDRSPEC)
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
#ifdef DEBUG
#else
#endif
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
mdb_printf("No algol 68 here\n");
else
mdb_printf("No adb here\n");
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
mdb_printf("CHAPTER 1\n");
else
mdb_printf("No Language H here\n");
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
else
return (0);
}
/*ARGSUSED*/
static int
{
if (argc != 0)
return (DCMD_USAGE);
return (0);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
return (DCMD_ABORT);
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
int i = *((int *)data);
*((int *)data) = i;
return (0);
}
/*ARGSUSED*/
static int
{
int i = 1;
const char *obj = MDB_TGT_OBJ_EVERY;
return (DCMD_USAGE);
if (argc == 1) {
return (DCMD_USAGE);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
name = "[ shmem ]";
name = "[ stack ]";
name = "[ heap ]";
name = "[ anon ]";
}
return (0);
}
static int
{
const mdb_map_t *m;
return (DCMD_USAGE);
mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
"BASE", "LIMIT", "SIZE", "NAME");
if (flags & DCMD_ADDRSPEC) {
mdb_warn("failed to obtain mapping");
else
} else if (argc != 0) {
else
if (m == NULL)
mdb_warn("failed to obtain mapping");
else
mdb_warn("failed to iterate over mappings");
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
const char *version;
version = "Unknown";
return (0);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
if (opt_v) {
} else {
mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
"BASE", "LIMIT", "SIZE", "NAME");
}
mdb_warn("failed to iterate over objects");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
char *objname;
/*
* Not all objects have CTF and label data, so set version to "Unknown".
*/
version = "Unknown";
/*
* The hash table implementation in OVERLOAD mode limits the version
* name to 31 characters because we cannot specify an external name.
* The full version name is available via the ::objects dcmd if needed.
*/
return (0);
}
static int
showrev_ispatch(const char *s)
{
if (s == NULL)
return (0);
if (*s == 'T')
s++; /* skip T for T-patch */
for (; *s != '\0'; s++) {
if ((*s < '0' || *s > '9') && *s != '-')
return (0);
}
return (1);
}
/*ARGSUSED*/
static int
{
return (0);
}
static int
{
const char *version = mdb_nv_get_name(v);
int patch;
mdb_printf("%s: %s Objects: ",
(void) mdb_inc_indent(2);
(void) mdb_dec_indent(2);
mdb_printf("\n");
}
return (0);
}
/*
* Display version information for each object in the system.
* Print information about patches only, unless showall is TRUE.
*/
static int
{
&vers_nv) == -1) {
mdb_warn("failed to iterate over objects");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*
* Display information similar to what showrev(1M) displays when invoked
* with no arguments.
*/
static int
showrev_sysinfo(void)
{
const char *s;
int rc;
struct utsname u;
}
/*
* Match the order of the showrev(1M) output and put "Application
* architecture" before "Kernel version"
*/
mdb_printf("Application architecture: %s\n", s);
if (rc != -1)
mdb_printf("Kernel version: %s %s %s %s\n",
mdb_printf("Platform: %s\n", s);
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
return (showrev_objectversions(opt_v));
else
return (showrev_sysinfo());
}
#ifdef __sparc
static void
{
}
/*ARGSUSED*/
static int
{
int len;
int i;
int j;
/*
* if the size of the symbol is 0, then this symbol must be for an
* alternate entry point or just some global label. We will,
* therefore, get back to the text that follows this symbol in
* some other symbol
*/
if (size == 0)
return (0);
return (0);
return (0);
}
for (i = 0; i < len; i++) {
continue;
/*
* see if we already have a match with just the sethi
*/
/*
* search from the sethi on until we hit a relevant instr
*/
for (j = i + 1; j < len; j++) {
goto instr_end;
/*
* This is a simple tool; we only deal
* with operations which take immediates
*/
if (I(text[j]) == 0)
goto instr_end;
/*
* sign extend the immediate value
*/
imm13 <<= 19;
imm13 >>= 19;
/* arithmetic operations */
if (op3 & OP3_COMPLEX_MASK)
goto instr_end;
switch (op3 & ~OP3_CC_MASK) {
case OP3_OR:
break;
case OP3_ADD:
break;
case OP3_XOR:
break;
default:
goto instr_end;
}
} else {
/* loads and stores */
/* op3 == OP_MEM */
}
/*
* if we're clobbering rd, break
*/
break;
break;
/*
* see if a call clobbers an %o or %g
*/
break;
}
}
}
return (0);
}
static int
{
int len, i;
argc -= i;
argv += i;
if (len <= 1)
return (DCMD_USAGE);
/*
* Set up a NULL-terminated symbol list, and then iterate over the
* symbol table, scanning each function for references to these symbols.
*/
len = 0;
return (DCMD_USAGE);
return (DCMD_USAGE);
} else
} else
}
if (flags & DCMD_ADDRSPEC)
if (optg)
else
mdb_warn("failed to iterate over symbol table");
return (DCMD_ERR);
}
return (DCMD_OK);
}
#endif /* __sparc */
static int
{
if (s[0] >= '0' && s[0] <= '9') {
return (0);
}
mdb_warn("symbol '%s' not found\n", s);
return (-1);
}
return (0);
}
static int
{
int i;
/*
* Disgusting argument post-processing ... basically the idea is to get
* the target address into addr, which we do by using the specified
* expression value, looking up a string as a symbol name, or by
* using the address specified as dot.
*/
if (i != argc) {
return (DCMD_USAGE);
return (DCMD_ERR);
} else
} else
return (DCMD_USAGE);
}
/*
* If we're not in window mode yet, and some type of arguments were
* specified, see if the address corresponds nicely to a function.
* If not, turn on window mode; otherwise disassemble the function.
*/
/*
* If the symbol has a size then set our end address to
* be the end of the function symbol we just located.
*/
} else
}
/*
* Window-mode doesn't make sense in a loop.
*/
/*
* If -n was explicit, limit output to n instructions;
* otherwise set n to some reasonable default
*/
if (n != -1UL)
eaddr = 0;
else
n = 10;
/*
* If the state is IDLE (i.e. no address space), turn on -f.
*/
if (opt_f)
else
n++;
return (DCMD_ERR);
if (opt_a)
else
}
} else {
#ifdef __sparc
if (addr & 0x3) {
mdb_warn("address is not properly aligned\n");
return (DCMD_ERR);
}
#endif
return (DCMD_ERR);
if (opt_a)
else
}
return (DCMD_ERR);
mdb_printf("%<b>");
mdb_flush();
if (opt_a)
else
mdb_printf("%</b>\n");
return (DCMD_ERR);
if (opt_a)
else
}
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
}
static int
{
int status;
return (DCMD_USAGE);
if (argc > 1) {
const char *p;
return (DCMD_ABORT);
}
mdb_warn("'%c' may not be used in a variable "
"name\n", *p);
return (DCMD_ABORT);
}
return (DCMD_ERR);
/*
* If there already exists a vcb for this variable, we may be
* calling ::walk in a loop. We only create a vcb for this
* variable on the first invocation.
*/
}
if (flags & DCMD_ADDRSPEC)
else
if (status == -1) {
mdb_warn("failed to perform walk");
return (DCMD_ERR);
}
return (DCMD_OK);
}
static ssize_t
{
}
/* ARGSUSED3 */
static ssize_t
{
}
static int
{
int error;
return (DCMD_USAGE);
return (DCMD_USAGE);
/*
* If neither -f nor -p were specified and the state is IDLE (i.e. no
* address space), turn on -p. This is so we can read large files.
*/
if (phys)
else if (file)
mdb_partial_xread, (void *)mdb_tgt_fread);
else
mdb_partial_xread, (void *)mdb_tgt_vread);
}
/*ARGSUSED*/
static int
{
if (flags & DCMD_ADDRSPEC)
return (DCMD_USAGE);
else
}
mdb_printf("\n");
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
const char *c;
mdb_pipe_t p;
return (DCMD_USAGE);
const char *num;
if (argc == 1) {
return (DCMD_USAGE);
} else {
return (DCMD_USAGE);
}
if (*c != '\0')
return (DCMD_USAGE);
} else if (argc != 0) {
return (DCMD_USAGE);
}
mdb_get_pipe(&p);
return (DCMD_OK);
if (flags & DCMD_PIPE_OUT) {
mdb_set_pipe(&p);
} else {
while (p.pipe_len-- > 0)
}
return (DCMD_OK);
}
static void
head_help(void)
{
"-n num\n or\n"
"-num pass only the first `num' elements in the pipe.\n"
"\n%<b>Note:%</b> `num' is a decimal number.\n");
}
static int
{
const char *p;
mdb_var_t *v;
if (argc == 0)
return (DCMD_USAGE);
add_tag++;
else
del_tag++;
argc--;
argv++;
}
if (!(flags & DCMD_ADDRSPEC))
addr = 0; /* set variables to zero unless explicit addr given */
continue;
mdb_warn("ignored bad option -- %s\n",
continue;
}
mdb_warn("'%c' may not be used in a variable "
"name\n", *p);
return (DCMD_ERR);
}
} else if (flags & DCMD_ADDRSPEC)
mdb_nv_set_value(v, addr);
if (v != NULL) {
if (add_tag)
v->v_flags |= MDB_NV_TAGGED;
if (del_tag)
v->v_flags &= ~MDB_NV_TAGGED;
}
}
return (DCMD_OK);
}
#ifndef _KMDB
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
return (DCMD_OK);
return (DCMD_ERR);
}
#endif
/*ARGSUSED*/
static int
{
const char *p = "";
if (argc != 0) {
return (DCMD_USAGE);
}
(void) mdb_set_prompt(p);
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
mdb_warn("failed to get physical mapping");
return (DCMD_ERR);
}
if (flags & DCMD_PIPE_OUT)
else
return (DCMD_OK);
}
static const char *
{
return ("-");
}
static void
print_evsep(void)
{
static const char dash20[] = "--------------------";
}
/*ARGSUSED*/
static int
{
const char *s2str;
int visible;
if (opts & EVENTS_OPT_V) {
else
s2str = "-";
} else
else
mdb_printf(" %c %c%c %2u %2u %-40s %-21s\n",
if (opts & EVENTS_OPT_V) {
print_evsep();
}
}
return (0);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
if (opts & EVENTS_OPT_V) {
mdb_printf(" ID S TA HT LM %-40s %-21s\n%-17s%s\n",
"Description", "Status", "", "Action");
} else {
mdb_printf(" ID S TA HT LM %-40s %-21s\n",
"Description", "Action");
}
print_evsep();
}
static int
{
const char *format;
return (DCMD_OK);
format = "target stopped at:\n%-#16a%8T%s\n";
else
format = "target stopped at %a:\n";
}
case MDB_TGT_IDLE:
mdb_warn("target is idle\n");
break;
case MDB_TGT_RUNNING:
mdb_warn("target is running, stop directive pending\n");
else
mdb_warn("target is running\n");
break;
case MDB_TGT_STOPPED:
mdb_warn("target is stopped\n");
break;
case MDB_TGT_UNDEAD:
mdb_warn("target has terminated\n");
break;
case MDB_TGT_DEAD:
mdb_warn("target is a core dump\n");
break;
case MDB_TGT_LOST:
mdb_warn("target is no longer under debugger control\n");
break;
}
return (DCMD_OK);
}
/*
* corresponding kmdb versions don't.
*/
#ifdef _KMDB
#define CONT_MAXARGS 0 /* no optional SIG argument */
#else
#define CONT_MAXARGS 1
#endif
/*ARGSUSED*/
static int
{
int sig = 0;
return (DCMD_USAGE);
if (argc > 0) {
mdb_warn("invalid signal name -- %s\n",
return (DCMD_USAGE);
}
} else
}
(void) mdb_tgt_status(t, &st);
mdb_warn("failed to create new target");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
(void) mdb_tgt_status(t, &st);
return (tgt_status(&st));
}
return (DCMD_ERR);
}
return (tgt_status(&st));
}
static int
{
const char *name = "single-step";
func = &mdb_tgt_step_out;
name = "step (out)";
argv++;
argc--;
name = "step (branch)";
argv++;
argc--;
func = &mdb_tgt_next;
name = "step (over)";
argv++;
argc--;
}
}
}
static int
{
&mdb_tgt_step_out, "step (out)"));
}
static int
{
&mdb_tgt_next, "step (over)"));
}
static int
{
&mdb_tgt_continue, "continue"));
}
#ifndef _KMDB
/*ARGSUSED*/
static int
{
if (flags & DCMD_ADDRSPEC)
return (DCMD_USAGE);
mdb_warn("failed to create new target");
return (DCMD_ERR);
}
}
#endif
/*
* To simplify the implementation of :d, :z, and ::delete, we use the sp
* parameter to store the criteria for what to delete. If spec_base is set,
* we delete vespecs with a matching address. If spec_id is set, we delete
* vespecs with a matching id. Otherwise, we delete all vespecs. We bump
* sp->spec_size so the caller can tell how many vespecs were deleted.
*/
static int
{
int status = -1;
if (vid < 0)
return (0); /* skip over target implementation events */
if (status == 0) {
}
return (0);
}
static int
{
mdb_warn("no traced events matched description\n");
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
return (ve_delete_spec(&spec));
}
static int
{
return (DCMD_USAGE);
if (flags & DCMD_ADDRSPEC)
else if (argc == 0)
return (ve_delete_spec(&spec));
}
static void
srcexec_file_help(void)
{
"The library of macros delivered with previous versions of Solaris have been\n"
"superseded by the dcmds and walkers provided by MDB. See ::help for\n"
"commands that can be used to list the available dcmds and walkers.\n"
"\n"
"Aliases have been created for several of the more popular macros. To see\n"
"the list of aliased macros, as well as their native MDB equivalents,\n"
"type $M.\n");
#ifdef _KMDB
"When invoked, the $< and $<< dcmds will consult the macro alias list. If an\n"
"alias cannot be found, an attempt will be made to locate a data type whose\n"
"name corresponds to the requested macro. If such a type can be found, it\n"
"will be displayed using the ::print dcmd.\n");
#else
"When invoked, the $< and $<< dcmds will first attempt to locate a macro with\n"
"the indicated name. If no macro can be found, and if no alias exists for\n"
"this macro, an attempt will be made to locate a data type whose name\n"
"corresponds to the requested macro. If such a type can be found, it will be\n"
"displayed using the ::print dcmd.\n");
#endif
}
static void
events_help(void)
{
mdb_printf("Options:\n"
"-a show all events, including internal debugger events\n"
"-v show verbose display, including inactivity reason\n"
"\nOutput Columns:\n"
"ID decimal event specifier id number:\n"
" [ ] event tracing is enabled\n"
" ( ) event tracing is disabled\n"
" < > target is currently stopped on this type of event\n\n"
"S event specifier state:\n"
" - event specifier is idle (not applicable yet)\n"
" + event specifier is active\n"
" * event specifier is armed (target program running)\n"
" ! error occurred while attempting to arm event\n\n"
"TA event specifier flags:\n"
" t event specifier is temporary (delete at next stop)\n"
" T event specifier is sticky (::delete all has no effect)\n"
" d event specifier will be disabled when HT = LM\n"
" D event specifier will be deleted when HT = LM\n"
" s target will automatically stop when HT = LM\n\n"
"HT hit count (number of times event has occurred)\n"
"LM hit limit (limit for autostop, disable, delete)\n");
}
static void
dump_help(void)
{
"-e adjust for endianness\n"
" (assumes 4-byte words; use -g to change word size)\n"
#ifdef _KMDB
"-f no effect\n"
#else
"-f dump from object file\n"
#endif
"-g n display bytes in groups of n\n"
" (default is 4; n must be a power of 2, divide line width)\n"
"-p dump from physical memory\n"
"-q don't print ASCII\n"
"-r use relative numbering (automatically sets -u)\n"
"-s elide repeated lines\n"
"-t only read from and display contents of specified addresses\n"
" (default is to read and print entire lines)\n"
"-u un-align output\n"
" (default is to align output at paragraph boundary)\n"
"-w n display n 16-byte paragraphs per line\n"
" (default is 1, maximum is 16)\n");
}
/*
* Table of built-in dcmds associated with the root 'mdb' module. Future
* expansion of this program should be done here, or through the external
* loadable module interface.
*/
const mdb_dcmd_t mdb_dcmd_builtins[] = {
/*
* dcmds common to both mdb and kmdb
*/
{ "$<", "macro-name", "replace input with macro",
{ "$<<", "macro-name", "source macro",
{ "$b", "[-av]", "list traced software events",
{ "array", ":[type count] [variable]", "print each array element's "
"address", cmd_array },
{ "bp", "?[+/-dDestT] [-c cmd] [-n count] sym ...", "breakpoint at the "
{ "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-w paragraphs]",
{ "events", "[-av]", "list traced software events",
{ "evset", "?[+/-dDestT] [-c cmd] [-n count] id ...",
#ifdef __sparc
{ "findsym", "?[-g] [symbol|addr ...]", "search for symbol references "
#endif
head_help },
{ "list", "?type member [variable]",
"walk list using member as link pointer", cmd_list },
{ "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]",
{ "nmadd", ":[-fo] [-e end] [-s size] name",
{ "offsetof", "type member", "print the offset of a given struct "
"or union member", cmd_offsetof },
{ "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]",
{ "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]",
{ "stackregs", "?", "print stack backtrace and registers",
cmd_notsup },
{ "vtop", ":[-a as]", "print physical mapping of virtual address",
cmd_vtop },
#ifdef _KMDB
/*
* dcmds specific to kmdb, or which have kmdb-specific arguments
*/
{ "step", "[ over | out ]",
"single-step target to next instruction", cmd_step },
unload_help },
{ "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]",
#else
/*
* dcmds specific to mdb, or which have mdb-specific arguments
*/
{ ":t", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on delivery "
{ "attach", "?[core|pid]",
"attach to process or core file", cmd_notsup },
{ "fltbp", "?[+/-dDestT] [-c cmd] [-n count] fault ...",
{ "release", NULL,
"release the previously attached process", cmd_notsup },
{ "sigbp", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on "
{ "step", "[ over | out ] [SIG]",
"single-step target to next instruction", cmd_step },
{ "sysbp", "?[+/-dDestT] [-io] [-c cmd] [-n count] syscall ...",
{ "wp", ":[+/-dDelstT] [-rwx] [-c cmd] [-n count] [-L size]",
#endif
{ NULL }
};