17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate#include <mdb/mdb_types.h>
307c478bdstevel@tonic-gate#include <mdb/mdb_argvec.h>
317c478bdstevel@tonic-gate#include <mdb/mdb_string.h>
327c478bdstevel@tonic-gate#include <mdb/mdb_err.h>
337c478bdstevel@tonic-gate#include <mdb/mdb_stdlib.h>
347c478bdstevel@tonic-gate#include <mdb/mdb_modapi.h>
357c478bdstevel@tonic-gate#include <mdb/mdb_frame.h>
367c478bdstevel@tonic-gate#include <mdb/mdb.h>
377c478bdstevel@tonic-gate
387c478bdstevel@tonic-gate#include <alloca.h>
397c478bdstevel@tonic-gate
407c478bdstevel@tonic-gate#define	AV_DEFSZ	16	/* Initial size of argument vector */
417c478bdstevel@tonic-gate#define	AV_GROW		2	/* Multiplier for growing argument vector */
427c478bdstevel@tonic-gate
437c478bdstevel@tonic-gatevoid
447c478bdstevel@tonic-gatemdb_argvec_create(mdb_argvec_t *vec)
457c478bdstevel@tonic-gate{
467c478bdstevel@tonic-gate	vec->a_data = NULL;
477c478bdstevel@tonic-gate	vec->a_nelems = 0;
487c478bdstevel@tonic-gate	vec->a_size = 0;
497c478bdstevel@tonic-gate}
507c478bdstevel@tonic-gate
517c478bdstevel@tonic-gatevoid
527c478bdstevel@tonic-gatemdb_argvec_destroy(mdb_argvec_t *vec)
537c478bdstevel@tonic-gate{
547c478bdstevel@tonic-gate	if (vec->a_data != NULL) {
557c478bdstevel@tonic-gate		mdb_argvec_reset(vec);
567c478bdstevel@tonic-gate		mdb_free(vec->a_data, sizeof (mdb_arg_t) * vec->a_size);
577c478bdstevel@tonic-gate	}
587c478bdstevel@tonic-gate}
597c478bdstevel@tonic-gate
607c478bdstevel@tonic-gatevoid
617c478bdstevel@tonic-gatemdb_argvec_append(mdb_argvec_t *vec, const mdb_arg_t *arg)
627c478bdstevel@tonic-gate{
637c478bdstevel@tonic-gate	if (vec->a_nelems >= vec->a_size) {
647c478bdstevel@tonic-gate		size_t size = vec->a_size ? vec->a_size * AV_GROW : AV_DEFSZ;
657c478bdstevel@tonic-gate		void *data = mdb_alloc(sizeof (mdb_arg_t) * size, UM_NOSLEEP);
667c478bdstevel@tonic-gate
677c478bdstevel@tonic-gate		if (data == NULL) {
687c478bdstevel@tonic-gate			warn("failed to grow argument vector");
697c478bdstevel@tonic-gate			longjmp(mdb.m_frame->f_pcb, MDB_ERR_NOMEM);
707c478bdstevel@tonic-gate		}
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate		bcopy(vec->a_data, data, sizeof (mdb_arg_t) * vec->a_size);
737c478bdstevel@tonic-gate		mdb_free(vec->a_data, sizeof (mdb_arg_t) * vec->a_size);
747c478bdstevel@tonic-gate
757c478bdstevel@tonic-gate		vec->a_data = data;
767c478bdstevel@tonic-gate		vec->a_size = size;
777c478bdstevel@tonic-gate	}
787c478bdstevel@tonic-gate
797c478bdstevel@tonic-gate	bcopy(arg, &vec->a_data[vec->a_nelems++], sizeof (mdb_arg_t));
807c478bdstevel@tonic-gate}
817c478bdstevel@tonic-gate
827c478bdstevel@tonic-gatevoid
837c478bdstevel@tonic-gatemdb_argvec_reset(mdb_argvec_t *vec)
847c478bdstevel@tonic-gate{
857c478bdstevel@tonic-gate	size_t nelems = vec->a_nelems;
867c478bdstevel@tonic-gate	mdb_arg_t *arg;
877c478bdstevel@tonic-gate
887c478bdstevel@tonic-gate	for (arg = vec->a_data; nelems != 0; nelems--, arg++) {
897c478bdstevel@tonic-gate		if (arg->a_type == MDB_TYPE_STRING && arg->a_un.a_str != NULL)
907c478bdstevel@tonic-gate			strfree((char *)arg->a_un.a_str);
917c478bdstevel@tonic-gate	}
927c478bdstevel@tonic-gate
937c478bdstevel@tonic-gate	vec->a_nelems = 0;
947c478bdstevel@tonic-gate}
957c478bdstevel@tonic-gate
967c478bdstevel@tonic-gatevoid
977c478bdstevel@tonic-gatemdb_argvec_zero(mdb_argvec_t *vec)
987c478bdstevel@tonic-gate{
997c478bdstevel@tonic-gate#ifdef DEBUG
1007c478bdstevel@tonic-gate	size_t i;
1017c478bdstevel@tonic-gate
1027c478bdstevel@tonic-gate	for (i = 0; i < vec->a_size; i++) {
1037c478bdstevel@tonic-gate		vec->a_data[i].a_type = UMEM_UNINITIALIZED_PATTERN;
1047c478bdstevel@tonic-gate		vec->a_data[i].a_un.a_val =
1057c478bdstevel@tonic-gate		    ((u_longlong_t)UMEM_UNINITIALIZED_PATTERN << 32) |
1067c478bdstevel@tonic-gate		    ((u_longlong_t)UMEM_UNINITIALIZED_PATTERN);
1077c478bdstevel@tonic-gate	}
1087c478bdstevel@tonic-gate#endif
1097c478bdstevel@tonic-gate	vec->a_nelems = 0;
1107c478bdstevel@tonic-gate}
1117c478bdstevel@tonic-gate
1127c478bdstevel@tonic-gatevoid
1137c478bdstevel@tonic-gatemdb_argvec_copy(mdb_argvec_t *dst, const mdb_argvec_t *src)
1147c478bdstevel@tonic-gate{
1157c478bdstevel@tonic-gate	if (src->a_nelems > dst->a_size) {
1167c478bdstevel@tonic-gate		mdb_arg_t *data =
1177c478bdstevel@tonic-gate		    mdb_alloc(sizeof (mdb_arg_t) * src->a_nelems, UM_NOSLEEP);
1187c478bdstevel@tonic-gate
1197c478bdstevel@tonic-gate		if (data == NULL) {
1207c478bdstevel@tonic-gate			warn("failed to grow argument vector");
1217c478bdstevel@tonic-gate			longjmp(mdb.m_frame->f_pcb, MDB_ERR_NOMEM);
1227c478bdstevel@tonic-gate		}
1237c478bdstevel@tonic-gate
1247c478bdstevel@tonic-gate		if (dst->a_data != NULL)
1257c478bdstevel@tonic-gate			mdb_free(dst->a_data, sizeof (mdb_arg_t) * dst->a_size);
1267c478bdstevel@tonic-gate
1277c478bdstevel@tonic-gate		dst->a_data = data;
1287c478bdstevel@tonic-gate		dst->a_size = src->a_nelems;
1297c478bdstevel@tonic-gate	}
1307c478bdstevel@tonic-gate
1317c478bdstevel@tonic-gate	bcopy(src->a_data, dst->a_data, sizeof (mdb_arg_t) * src->a_nelems);
1327c478bdstevel@tonic-gate	dst->a_nelems = src->a_nelems;
1337c478bdstevel@tonic-gate}
1347c478bdstevel@tonic-gate
1357c478bdstevel@tonic-gatestatic int
1367c478bdstevel@tonic-gateargvec_process_subopt(const mdb_opt_t *opt, const mdb_arg_t *arg)
1377c478bdstevel@tonic-gate{
1387c478bdstevel@tonic-gate	mdb_subopt_t *sop;
1397c478bdstevel@tonic-gate	const char *start;
1407c478bdstevel@tonic-gate	const char *next;
1417c478bdstevel@tonic-gate	char error[32];
1427c478bdstevel@tonic-gate	size_t len;
1437c478bdstevel@tonic-gate	uint_t value = 0;
1447c478bdstevel@tonic-gate	uint_t i;
1457c478bdstevel@tonic-gate
1467c478bdstevel@tonic-gate	start = arg->a_un.a_str;
1477c478bdstevel@tonic-gate
1487c478bdstevel@tonic-gate	for (i = 0; ; i++) {
1497c478bdstevel@tonic-gate		next = strchr(start, ',');
1507c478bdstevel@tonic-gate
1517c478bdstevel@tonic-gate		if (next == NULL)
1527c478bdstevel@tonic-gate			len = strlen(start);
1537c478bdstevel@tonic-gate		else
1547c478bdstevel@tonic-gate			len = next - start;
1557c478bdstevel@tonic-gate
1567c478bdstevel@tonic-gate		/*
1577c478bdstevel@tonic-gate		 * Record the index of the subopt if a match if found.
1587c478bdstevel@tonic-gate		 */
1597c478bdstevel@tonic-gate		for (sop = opt->opt_subopts; sop->sop_flag; sop++) {
1607c478bdstevel@tonic-gate			if (strlen(sop->sop_str) == len &&
1617c478bdstevel@tonic-gate			    strncmp(sop->sop_str, start, len) == 0) {
1627c478bdstevel@tonic-gate				value |= sop->sop_flag;
1637c478bdstevel@tonic-gate				sop->sop_index = i;
1647c478bdstevel@tonic-gate				goto found;
1657c478bdstevel@tonic-gate			}
1667c478bdstevel@tonic-gate		}
1677c478bdstevel@tonic-gate		(void) mdb_snprintf(error, len + 1, "%s", start);
1687c478bdstevel@tonic-gate		warn("invalid option for -%c: \"%s\"\n", opt->opt_char, error);
1697c478bdstevel@tonic-gate
1707c478bdstevel@tonic-gate		return (-1);
1717c478bdstevel@tonic-gate
1727c478bdstevel@tonic-gatefound:
1737c478bdstevel@tonic-gate		if (next == NULL)
1747c478bdstevel@tonic-gate			break;
1757c478bdstevel@tonic-gate		start = next + 1;
1767c478bdstevel@tonic-gate	}
1777c478bdstevel@tonic-gate
1787c478bdstevel@tonic-gate	*((uint_t *)opt->opt_valp) = value;
1797c478bdstevel@tonic-gate
1807c478bdstevel@tonic-gate	return (0);
1817c478bdstevel@tonic-gate}
1827c478bdstevel@tonic-gate
1837c478bdstevel@tonic-gate
1847c478bdstevel@tonic-gatestatic int
1857c478bdstevel@tonic-gateargvec_process_opt(const mdb_opt_t *opt, const mdb_arg_t *arg)
1867c478bdstevel@tonic-gate{
1877c478bdstevel@tonic-gate	uint64_t ui64;
1887c478bdstevel@tonic-gate	uintptr_t uip;
1897c478bdstevel@tonic-gate
1907c478bdstevel@tonic-gate	switch (opt->opt_type) {
1917c478bdstevel@tonic-gate	case MDB_OPT_SETBITS:
1927c478bdstevel@tonic-gate		*((uint_t *)opt->opt_valp) |= opt->opt_bits;
1937c478bdstevel@tonic-gate		break;
1947c478bdstevel@tonic-gate
1957c478bdstevel@tonic-gate	case MDB_OPT_CLRBITS:
1967c478bdstevel@tonic-gate		*((uint_t *)opt->opt_valp) &= ~opt->opt_bits;
1977c478bdstevel@tonic-gate		break;
1987c478bdstevel@tonic-gate
1997c478bdstevel@tonic-gate	case MDB_OPT_STR:
2007c478bdstevel@tonic-gate		if (arg->a_type != MDB_TYPE_STRING) {
2017c478bdstevel@tonic-gate			warn("string argument required for -%c\n",
2027c478bdstevel@tonic-gate			    opt->opt_char);
2037c478bdstevel@tonic-gate			return (-1);
2047c478bdstevel@tonic-gate		}
2057c478bdstevel@tonic-gate		*((const char **)opt->opt_valp) = arg->a_un.a_str;
2067c478bdstevel@tonic-gate		break;
2077c478bdstevel@tonic-gate
2087c478bdstevel@tonic-gate	case MDB_OPT_UINTPTR_SET:
2097c478bdstevel@tonic-gate		*opt->opt_flag = TRUE;
2107c478bdstevel@tonic-gate		/* FALLTHROUGH */
2117c478bdstevel@tonic-gate	case MDB_OPT_UINTPTR:
2127c478bdstevel@tonic-gate		if (arg->a_type == MDB_TYPE_STRING)
2137c478bdstevel@tonic-gate			uip = (uintptr_t)mdb_strtoull(arg->a_un.a_str);
2147c478bdstevel@tonic-gate		else
2157c478bdstevel@tonic-gate			uip = (uintptr_t)arg->a_un.a_val;
2167c478bdstevel@tonic-gate		*((uintptr_t *)opt->opt_valp) = uip;
2177c478bdstevel@tonic-gate		break;
2187c478bdstevel@tonic-gate
2197c478bdstevel@tonic-gate	case MDB_OPT_UINT64:
2207c478bdstevel@tonic-gate		if (arg->a_type == MDB_TYPE_STRING)
2217c478bdstevel@tonic-gate			ui64 = mdb_strtoull(arg->a_un.a_str);
2227c478bdstevel@tonic-gate		else
2237c478bdstevel@tonic-gate			ui64 = arg->a_un.a_val;
2247c478bdstevel@tonic-gate		*((uint64_t *)opt->opt_valp) = ui64;
2257c478bdstevel@tonic-gate		break;
2267c478bdstevel@tonic-gate
2277c478bdstevel@tonic-gate	case MDB_OPT_SUBOPTS:
2287c478bdstevel@tonic-gate		if (arg->a_type != MDB_TYPE_STRING) {
2297c478bdstevel@tonic-gate			warn("string argument required for -%c\n",
2307c478bdstevel@tonic-gate			    opt->opt_char);
2317c478bdstevel@tonic-gate			return (-1);
2327c478bdstevel@tonic-gate		}
2337c478bdstevel@tonic-gate		return (argvec_process_subopt(opt, arg));
2347c478bdstevel@tonic-gate
2357c478bdstevel@tonic-gate	default:
2367c478bdstevel@tonic-gate		warn("internal: bad opt=%p type=%hx\n",
2377c478bdstevel@tonic-gate		    (void *)opt, opt->opt_type);
2387c478bdstevel@tonic-gate		return (-1);
2397c478bdstevel@tonic-gate	}
2407c478bdstevel@tonic-gate
2417c478bdstevel@tonic-gate	return (0);
2427c478bdstevel@tonic-gate}
2437c478bdstevel@tonic-gate
2447c478bdstevel@tonic-gatestatic const mdb_opt_t *
2457c478bdstevel@tonic-gateargvec_findopt(const mdb_opt_t *opts, char c)
2467c478bdstevel@tonic-gate{
2477c478bdstevel@tonic-gate	const mdb_opt_t *optp;
2487c478bdstevel@tonic-gate
2497c478bdstevel@tonic-gate	for (optp = opts; optp->opt_char != 0; optp++) {
2507c478bdstevel@tonic-gate		if (optp->opt_char == c)
2517c478bdstevel@tonic-gate			return (optp);
2527c478bdstevel@tonic-gate	}
2537c478bdstevel@tonic-gate
2547c478bdstevel@tonic-gate	return (NULL);
2557c478bdstevel@tonic-gate}
2567c478bdstevel@tonic-gate
2577c478bdstevel@tonic-gatestatic int
2587c478bdstevel@tonic-gateargvec_getopts(const mdb_opt_t *opts, const mdb_arg_t *argv, int argc)
2597c478bdstevel@tonic-gate{
2607c478bdstevel@tonic-gate	const mdb_opt_t *optp;
2617c478bdstevel@tonic-gate	const mdb_arg_t *argp;
2627c478bdstevel@tonic-gate
2637c478bdstevel@tonic-gate	mdb_arg_t arg;
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gate	const char *p;
2667c478bdstevel@tonic-gate	int i;
2677c478bdstevel@tonic-gate	int nargs;	/* Number of arguments consumed in an iteration */
2687c478bdstevel@tonic-gate
2697c478bdstevel@tonic-gate	for (i = 0; i < argc; i++, argv++) {
2707c478bdstevel@tonic-gate		/*
2717c478bdstevel@tonic-gate		 * Each option must begin with a string argument whose first
2727c478bdstevel@tonic-gate		 * character is '-' and has additional characters afterward.
2737c478bdstevel@tonic-gate		 */
2747c478bdstevel@tonic-gate		if (argv->a_type != MDB_TYPE_STRING ||
2757c478bdstevel@tonic-gate		    argv->a_un.a_str[0] != '-' || argv->a_un.a_str[1] == '\0')
2767c478bdstevel@tonic-gate			return (i);
2777c478bdstevel@tonic-gate
2787c478bdstevel@tonic-gate		/*
2797c478bdstevel@tonic-gate		 * The special prefix '--' ends option processing.
2807c478bdstevel@tonic-gate		 */
2817c478bdstevel@tonic-gate		if (strncmp(argv->a_un.a_str, "--", 2) == 0)
2827c478bdstevel@tonic-gate			return (i);
2837c478bdstevel@tonic-gate
2847c478bdstevel@tonic-gate		for (p = &argv->a_un.a_str[1]; *p != '\0'; p++) {
2857c478bdstevel@tonic-gate			/*
2867c478bdstevel@tonic-gate			 * Locate an option struct whose opt_char field
2877c478bdstevel@tonic-gate			 * matches the current option letter.
2887c478bdstevel@tonic-gate			 */
2897c478bdstevel@tonic-gate			if ((optp = argvec_findopt(opts, *p)) == NULL) {
2907c478bdstevel@tonic-gate				warn("illegal option -- %c\n", *p);
2917c478bdstevel@tonic-gate				return (i);
2927c478bdstevel@tonic-gate			}
2937c478bdstevel@tonic-gate
2947c478bdstevel@tonic-gate			/*
2957c478bdstevel@tonic-gate			 * Require an argument for strings, immediate
2967c478bdstevel@tonic-gate			 * values, subopt-lists and callback functions
2977c478bdstevel@tonic-gate			 * which require arguments.
2987c478bdstevel@tonic-gate			 */
2997c478bdstevel@tonic-gate			if (optp->opt_type == MDB_OPT_STR ||
3007c478bdstevel@tonic-gate			    optp->opt_type == MDB_OPT_UINTPTR ||
3017c478bdstevel@tonic-gate			    optp->opt_type == MDB_OPT_UINTPTR_SET ||
3027c478bdstevel@tonic-gate			    optp->opt_type == MDB_OPT_SUBOPTS ||
3037c478bdstevel@tonic-gate			    optp->opt_type == MDB_OPT_UINT64) {
3047c478bdstevel@tonic-gate				/*
3057c478bdstevel@tonic-gate				 * More text after the option letter:
3067c478bdstevel@tonic-gate				 * forge a string argument from remainder.
3077c478bdstevel@tonic-gate				 */
3087c478bdstevel@tonic-gate				if (p[1] != '\0') {
3097c478bdstevel@tonic-gate					arg.a_type = MDB_TYPE_STRING;
3107c478bdstevel@tonic-gate					arg.a_un.a_str = ++p;
3117c478bdstevel@tonic-gate					argp = &arg;
3127c478bdstevel@tonic-gate					p += strlen(p) - 1;
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate					nargs = 0;
3157c478bdstevel@tonic-gate				/*
3167c478bdstevel@tonic-gate				 * Otherwise use the next argv element as
3177c478bdstevel@tonic-gate				 * the argument if there is one.
3187c478bdstevel@tonic-gate				 */
3197c478bdstevel@tonic-gate				} else if (++i == argc) {
3207c478bdstevel@tonic-gate					warn("option requires an "
3217c478bdstevel@tonic-gate					    "argument -- %c\n", *p);
3227c478bdstevel@tonic-gate					return (i - 1);
3237c478bdstevel@tonic-gate				} else {
3247c478bdstevel@tonic-gate					argp = ++argv;
3257c478bdstevel@tonic-gate					nargs = 1;
3267c478bdstevel@tonic-gate				}
3277c478bdstevel@tonic-gate			} else {
3287c478bdstevel@tonic-gate				argp = NULL;
3297c478bdstevel@tonic-gate				nargs = 0;
3307c478bdstevel@tonic-gate			}
3317c478bdstevel@tonic-gate
3327c478bdstevel@tonic-gate			/*
3337c478bdstevel@tonic-gate			 * Perform type-specific handling for this option.
3347c478bdstevel@tonic-gate			 */
3357c478bdstevel@tonic-gate			if (argvec_process_opt(optp, argp) == -1)
3367c478bdstevel@tonic-gate				return (i - nargs);
3377c478bdstevel@tonic-gate		}
3387c478bdstevel@tonic-gate	}
3397c478bdstevel@tonic-gate
3407c478bdstevel@tonic-gate	return (i);
3417c478bdstevel@tonic-gate}
3427c478bdstevel@tonic-gate
3437c478bdstevel@tonic-gateint
3447c478bdstevel@tonic-gatemdb_getopts(int argc, const mdb_arg_t *argv, ...)
3457c478bdstevel@tonic-gate{
3467c478bdstevel@tonic-gate	/*
3477c478bdstevel@tonic-gate	 * For simplicity just declare enough options on the stack to handle
3487c478bdstevel@tonic-gate	 * a-z and A-Z and an extra terminator.
3497c478bdstevel@tonic-gate	 */
3507c478bdstevel@tonic-gate	mdb_opt_t opts[53], *op = &opts[0];
3517c478bdstevel@tonic-gate	va_list alist;
3527c478bdstevel@tonic-gate	int c, i = 0;
3537c478bdstevel@tonic-gate	mdb_subopt_t *sop;
3547c478bdstevel@tonic-gate
3557c478bdstevel@tonic-gate	va_start(alist, argv);
3567c478bdstevel@tonic-gate
3577c478bdstevel@tonic-gate	for (i = 0; i < (sizeof (opts) / sizeof (opts[0]) - 1); i++, op++) {
3587c478bdstevel@tonic-gate		if ((c = va_arg(alist, int)) == 0)
3597c478bdstevel@tonic-gate			break; /* end of options */
3607c478bdstevel@tonic-gate
3617c478bdstevel@tonic-gate		op->opt_char = (char)c;
3627c478bdstevel@tonic-gate		op->opt_type = va_arg(alist, uint_t);
3637c478bdstevel@tonic-gate
3647c478bdstevel@tonic-gate		if (op->opt_type == MDB_OPT_SETBITS ||
3657c478bdstevel@tonic-gate		    op->opt_type == MDB_OPT_CLRBITS) {
3667c478bdstevel@tonic-gate			op->opt_bits = va_arg(alist, uint_t);
3677c478bdstevel@tonic-gate		} else if (op->opt_type == MDB_OPT_UINTPTR_SET) {
3687c478bdstevel@tonic-gate			op->opt_flag = va_arg(alist, boolean_t *);
3697c478bdstevel@tonic-gate		} else if (op->opt_type == MDB_OPT_SUBOPTS) {
3707c478bdstevel@tonic-gate			op->opt_subopts = va_arg(alist, mdb_subopt_t *);
3717c478bdstevel@tonic-gate
3727c478bdstevel@tonic-gate			for (sop = op->opt_subopts; sop->sop_flag; sop++)
3737c478bdstevel@tonic-gate				sop->sop_index = -1;
3747c478bdstevel@tonic-gate		}
3757c478bdstevel@tonic-gate
3767c478bdstevel@tonic-gate		op->opt_valp = va_arg(alist, void *);
3777c478bdstevel@tonic-gate	}
3787c478bdstevel@tonic-gate
3797c478bdstevel@tonic-gate	bzero(&opts[i], sizeof (mdb_opt_t));
3807c478bdstevel@tonic-gate	va_end(alist);
3817c478bdstevel@tonic-gate
3827c478bdstevel@tonic-gate	return (argvec_getopts(opts, argv, argc));
3837c478bdstevel@tonic-gate}
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate/*
3867c478bdstevel@tonic-gate * The old adb breakpoint and watchpoint routines did not accept any arguments;
3877c478bdstevel@tonic-gate * all characters after the verb were concatenated to form the string callback.
3887c478bdstevel@tonic-gate * This utility function concatenates all arguments in argv[] into a single
3897c478bdstevel@tonic-gate * string to simplify the implementation of these legacy routines.
3907c478bdstevel@tonic-gate */
3917c478bdstevel@tonic-gatechar *
3927c478bdstevel@tonic-gatemdb_argv_to_str(int argc, const mdb_arg_t *argv)
3937c478bdstevel@tonic-gate{
3947c478bdstevel@tonic-gate	char *s = NULL;
3957c478bdstevel@tonic-gate	size_t n = 0;
3967c478bdstevel@tonic-gate	int i;
3977c478bdstevel@tonic-gate
3987c478bdstevel@tonic-gate	for (i = 0; i < argc; i++) {
3997c478bdstevel@tonic-gate		if (argv[i].a_type == MDB_TYPE_STRING)
4007c478bdstevel@tonic-gate			n += strlen(argv[i].a_un.a_str);
4017c478bdstevel@tonic-gate	}
4027c478bdstevel@tonic-gate
4037c478bdstevel@tonic-gate	if (n != 0) {
4047c478bdstevel@tonic-gate		s = mdb_zalloc(n + argc, UM_SLEEP);
4057c478bdstevel@tonic-gate
4067c478bdstevel@tonic-gate		for (i = 0; i < argc - 1; i++, argv++) {
4077c478bdstevel@tonic-gate			(void) strcat(s, argv->a_un.a_str);
4087c478bdstevel@tonic-gate			(void) strcat(s, " ");
4097c478bdstevel@tonic-gate		}
4107c478bdstevel@tonic-gate
4117c478bdstevel@tonic-gate		(void) strcat(s, argv->a_un.a_str);
4127c478bdstevel@tonic-gate	}
4137c478bdstevel@tonic-gate
4147c478bdstevel@tonic-gate	return (s);
4157c478bdstevel@tonic-gate}
416