xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_nm.c (revision 7c478bd9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/elf.h>
30 #include <sys/elf_SPARC.h>
31 
32 #include <libproc.h>
33 #include <libctf.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 
39 #include <mdb/mdb_string.h>
40 #include <mdb/mdb_argvec.h>
41 #include <mdb/mdb_nv.h>
42 #include <mdb/mdb_fmt.h>
43 #include <mdb/mdb_target.h>
44 #include <mdb/mdb_err.h>
45 #include <mdb/mdb_debug.h>
46 #include <mdb/mdb_conf.h>
47 #include <mdb/mdb_module.h>
48 #include <mdb/mdb_modapi.h>
49 #include <mdb/mdb_stdlib.h>
50 #include <mdb/mdb_lex.h>
51 #include <mdb/mdb_io_impl.h>
52 #include <mdb/mdb_help.h>
53 #include <mdb/mdb_disasm.h>
54 #include <mdb/mdb_frame.h>
55 #include <mdb/mdb_evset.h>
56 #include <mdb/mdb_print.h>
57 #include <mdb/mdb_nm.h>
58 #include <mdb/mdb_set.h>
59 #include <mdb/mdb_demangle.h>
60 #include <mdb/mdb.h>
61 
62 enum {
63 	NM_FMT_INDEX	= 0x0001,			/* -f ndx */
64 	NM_FMT_VALUE	= 0x0002,			/* -f val */
65 	NM_FMT_SIZE	= 0x0004,			/* -f size */
66 	NM_FMT_TYPE	= 0x0008,			/* -f type */
67 	NM_FMT_BIND	= 0x0010,			/* -f bind */
68 	NM_FMT_OTHER	= 0x0020,			/* -f oth */
69 	NM_FMT_SHNDX	= 0x0040,			/* -f shndx */
70 	NM_FMT_NAME	= 0x0080,			/* -f name */
71 	NM_FMT_CTYPE	= 0x0100,			/* -f ctype */
72 	NM_FMT_OBJECT	= 0x0200,			/* -f obj */
73 
74 	NM_FMT_CTFID	= 0x1000			/* -f ctfid */
75 };
76 
77 enum {
78 	NM_TYPE_NOTY	= 1 << STT_NOTYPE,		/* -t noty */
79 	NM_TYPE_OBJT	= 1 << STT_OBJECT,		/* -t objt */
80 	NM_TYPE_FUNC	= 1 << STT_FUNC,		/* -t func */
81 	NM_TYPE_SECT	= 1 << STT_SECTION,		/* -t sect */
82 	NM_TYPE_FILE	= 1 << STT_FILE,		/* -t file */
83 	NM_TYPE_COMM	= 1 << STT_COMMON,		/* -t comm */
84 	NM_TYPE_TLS	= 1 << STT_TLS,			/* -t tls */
85 	NM_TYPE_REGI	= 1 << STT_SPARC_REGISTER	/* -t regi */
86 };
87 
88 typedef struct {
89 	GElf_Sym nm_sym;
90 	const char *nm_name;
91 	mdb_syminfo_t nm_si;
92 	const char *nm_object;
93 	ctf_file_t *nm_fp;
94 } nm_sym_t;
95 
96 typedef struct {
97 	ctf_file_t *nii_fp;
98 
99 	uint_t nii_flags;
100 	uint_t nii_types;
101 	ulong_t nii_id;
102 	const char *nii_pfmt;
103 	const char *nii_ofmt;
104 
105 	const GElf_Sym *nii_symp;
106 
107 	nm_sym_t **nii_sympp;
108 } nm_iter_info_t;
109 
110 typedef struct {
111 	mdb_tgt_sym_f *ngs_cb;
112 	void *ngs_arg;
113 	mdb_syminfo_t ngs_si;
114 	const char *ngs_object;
115 } nm_gelf_symtab_t;
116 
117 typedef struct {
118 	uint_t noi_which;
119 	uint_t noi_type;
120 	mdb_tgt_sym_f *noi_cb;
121 	nm_iter_info_t *noi_niip;
122 } nm_object_iter_t;
123 
124 static const char *
125 nm_type2str(uchar_t info)
126 {
127 	switch (GELF_ST_TYPE(info)) {
128 	case STT_NOTYPE:
129 		return ("NOTY");
130 	case STT_OBJECT:
131 		return ("OBJT");
132 	case STT_FUNC:
133 		return ("FUNC");
134 	case STT_SECTION:
135 		return ("SECT");
136 	case STT_FILE:
137 		return ("FILE");
138 	case STT_COMMON:
139 		return ("COMM");
140 	case STT_TLS:
141 		return ("TLS");
142 	case STT_SPARC_REGISTER:
143 		return ("REGI");
144 	default:
145 		return ("?");
146 	}
147 }
148 
149 static const char *
150 nm_bind2str(uchar_t info)
151 {
152 	switch (GELF_ST_BIND(info)) {
153 	case STB_LOCAL:
154 		return ("LOCL");
155 	case STB_GLOBAL:
156 		return ("GLOB");
157 	case STB_WEAK:
158 		return ("WEAK");
159 	default:
160 		return ("?");
161 	}
162 }
163 
164 static const char *
165 nm_sect2str(GElf_Half shndx)
166 {
167 	static char buf[16];
168 
169 	switch (shndx) {
170 	case SHN_UNDEF:
171 		return ("UNDEF");
172 	case SHN_ABS:
173 		return ("ABS");
174 	case SHN_COMMON:
175 		return ("COMMON");
176 	default:
177 		(void) mdb_iob_snprintf(buf, sizeof (buf), "%hu", shndx);
178 		return (buf);
179 	}
180 }
181 
182 static char *
183 nm_func_signature(ctf_file_t *fp, uint_t index, char *buf, size_t len)
184 {
185 	int n;
186 	ctf_funcinfo_t f;
187 	ctf_id_t argv[32];
188 	char arg[32];
189 	char *start = buf;
190 	char *sep = "";
191 	int i;
192 
193 	if (ctf_func_info(fp, index, &f) == CTF_ERR)
194 		return (NULL);
195 
196 	if (ctf_type_name(fp, f.ctc_return, arg, sizeof (arg)) != NULL)
197 		n = mdb_snprintf(buf, len, "%s (*)(", arg);
198 	else
199 		n = mdb_snprintf(buf, len, "<%ld> (*)(", f.ctc_return);
200 
201 	if (len <= n)
202 		return (start);
203 
204 	buf += n;
205 	len -= n;
206 
207 	(void) ctf_func_args(fp, index, sizeof (argv) / sizeof (argv[0]), argv);
208 
209 	for (i = 0; i < f.ctc_argc; i++) {
210 		if (ctf_type_name(fp, argv[i], arg, sizeof (arg)) != NULL)
211 			n = mdb_snprintf(buf, len, "%s%s", sep, arg);
212 		else
213 			n = mdb_snprintf(buf, len, "%s<%ld>", sep, argv[i]);
214 
215 		if (len <= n)
216 			return (start);
217 
218 		buf += n;
219 		len -= n;
220 
221 		sep = ", ";
222 	}
223 
224 	if (f.ctc_flags & CTF_FUNC_VARARG) {
225 		n = mdb_snprintf(buf, len, "%s...", sep);
226 		if (len <= n)
227 			return (start);
228 		buf += n;
229 		len -= n;
230 	} else if (f.ctc_argc == 0) {
231 		n = mdb_snprintf(buf, len, "void");
232 		if (len <= n)
233 			return (start);
234 		buf += n;
235 		len -= n;
236 	}
237 
238 	(void) mdb_snprintf(buf, len, ")");
239 
240 	return (start);
241 }
242 
243 static void
244 nm_print_ctype(void *data)
245 {
246 	nm_iter_info_t *niip = data;
247 	char buf[256];
248 	ctf_id_t id;
249 	char *str = NULL;
250 	uint_t index = niip->nii_id;
251 	ctf_file_t *fp = niip->nii_fp;
252 
253 	if (fp != NULL) {
254 		if (GELF_ST_TYPE(niip->nii_symp->st_info) == STT_FUNC)
255 			str = nm_func_signature(fp, index, buf, sizeof (buf));
256 		else if ((id = ctf_lookup_by_symbol(fp, index)) != CTF_ERR)
257 			str = ctf_type_name(fp, id, buf, sizeof (buf));
258 	}
259 
260 	if (str == NULL)
261 		str = "<unknown type>";
262 
263 	mdb_printf("%-50s", str);
264 }
265 
266 static void
267 nm_print_ctfid(void *data)
268 {
269 	nm_iter_info_t *niip = data;
270 	ctf_id_t id;
271 	uint_t index = niip->nii_id;
272 	ctf_file_t *fp = niip->nii_fp;
273 
274 	if (fp != NULL && (id = ctf_lookup_by_symbol(fp, index)) != CTF_ERR) {
275 		mdb_printf("%-9ld", id);
276 	} else {
277 		mdb_printf("%9s", "");
278 	}
279 }
280 
281 static void
282 nm_print_obj(void *data)
283 {
284 	const char *obj = (const char *)data;
285 
286 	if (obj == MDB_TGT_OBJ_EXEC)
287 		obj = "exec";
288 	else if (obj == MDB_TGT_OBJ_RTLD)
289 		obj = "rtld";
290 	else if (obj == MDB_TGT_OBJ_EVERY)
291 		obj = "";
292 
293 	mdb_printf("%-15s", obj);
294 }
295 
296 /*ARGSUSED*/
297 static int
298 nm_print(void *data, const GElf_Sym *sym, const char *name,
299     const mdb_syminfo_t *sip, const char *obj)
300 {
301 	nm_iter_info_t *niip = data;
302 
303 	if (!((1 << GELF_ST_TYPE(sym->st_info)) & niip->nii_types))
304 		return (0);
305 
306 	niip->nii_id = sip->sym_id;
307 	niip->nii_symp = sym;
308 
309 	mdb_table_print(niip->nii_flags, "|",
310 	    MDB_TBL_PRNT, NM_FMT_INDEX, "%5u", sip->sym_id,
311 	    MDB_TBL_FUNC, NM_FMT_OBJECT, nm_print_obj, obj,
312 	    MDB_TBL_PRNT, NM_FMT_VALUE, niip->nii_pfmt, sym->st_value,
313 	    MDB_TBL_PRNT, NM_FMT_SIZE, niip->nii_pfmt, sym->st_size,
314 	    MDB_TBL_PRNT, NM_FMT_TYPE, "%-5s", nm_type2str(sym->st_info),
315 	    MDB_TBL_PRNT, NM_FMT_BIND, "%-5s", nm_bind2str(sym->st_info),
316 	    MDB_TBL_PRNT, NM_FMT_OTHER, niip->nii_ofmt, sym->st_other,
317 	    MDB_TBL_PRNT, NM_FMT_SHNDX, "%-8s", nm_sect2str(sym->st_shndx),
318 	    MDB_TBL_FUNC, NM_FMT_CTFID, nm_print_ctfid, niip,
319 	    MDB_TBL_FUNC, NM_FMT_CTYPE, nm_print_ctype, niip,
320 	    MDB_TBL_PRNT, NM_FMT_NAME, "%s", name,
321 	    MDB_TBL_DONE);
322 
323 	mdb_printf("\n");
324 
325 	return (0);
326 }
327 
328 /*ARGSUSED*/
329 static int
330 nm_any(void *data, const GElf_Sym *sym, const char *name,
331     const mdb_syminfo_t *sip, const char *obj)
332 {
333 	return (nm_print(data, sym, name, sip, obj));
334 }
335 
336 /*ARGSUSED*/
337 static int
338 nm_undef(void *data, const GElf_Sym *sym, const char *name,
339     const mdb_syminfo_t *sip, const char *obj)
340 {
341 	if (sym->st_shndx == SHN_UNDEF)
342 		return (nm_print(data, sym, name, sip, obj));
343 
344 	return (0);
345 }
346 
347 /*ARGSUSED*/
348 static int
349 nm_asgn(void *data, const GElf_Sym *sym, const char *name,
350     const mdb_syminfo_t *sip, const char *obj)
351 {
352 	const char *opts;
353 
354 	switch (GELF_ST_TYPE(sym->st_info)) {
355 	case STT_FUNC:
356 		opts = "-f";
357 		break;
358 	case STT_OBJECT:
359 		opts = "-o";
360 		break;
361 	default:
362 		opts = "";
363 	}
364 
365 	mdb_printf("%#llr::nmadd %s -s %#llr %s\n",
366 	    sym->st_value, opts, sym->st_size, name);
367 
368 	return (0);
369 }
370 
371 /*ARGSUSED*/
372 static int
373 nm_cnt_any(void *data, const GElf_Sym *sym, const char *name,
374     const mdb_syminfo_t *sip, const char *obj)
375 {
376 	size_t *cntp = (size_t *)data;
377 	(*cntp)++;
378 	return (0);
379 }
380 
381 /*ARGSUSED*/
382 static int
383 nm_cnt_undef(void *data, const GElf_Sym *sym, const char *name,
384     const mdb_syminfo_t *sip, const char *obj)
385 {
386 	if (sym->st_shndx == SHN_UNDEF)
387 		return (nm_cnt_any(data, sym, name, sip, obj));
388 
389 	return (0);
390 }
391 
392 /*ARGSUSED*/
393 static int
394 nm_get_any(void *data, const GElf_Sym *sym, const char *name,
395     const mdb_syminfo_t *sip, const char *obj)
396 {
397 	nm_iter_info_t *niip = data;
398 	nm_sym_t **sympp = niip->nii_sympp;
399 
400 	(*sympp)->nm_sym = *sym;
401 	(*sympp)->nm_name = name;
402 	(*sympp)->nm_si = *sip;
403 	(*sympp)->nm_object = obj;
404 	(*sympp)->nm_fp = niip->nii_fp;
405 	(*sympp)++;
406 
407 	return (0);
408 }
409 
410 /*ARGSUSED*/
411 static int
412 nm_get_undef(void *data, const GElf_Sym *sym, const char *name,
413     const mdb_syminfo_t *sip, const char *obj)
414 {
415 	if (sym->st_shndx == SHN_UNDEF)
416 		return (nm_get_any(data, sym, name, sip, obj));
417 
418 	return (0);
419 }
420 
421 static int
422 nm_compare_name(const void *lp, const void *rp)
423 {
424 	const nm_sym_t *lhs = (nm_sym_t *)lp;
425 	const nm_sym_t *rhs = (nm_sym_t *)rp;
426 
427 	return (strcmp(lhs->nm_name, rhs->nm_name));
428 }
429 
430 static int
431 nm_compare_val(const void *lp, const void *rp)
432 {
433 	const nm_sym_t *lhs = (nm_sym_t *)lp;
434 	const nm_sym_t *rhs = (nm_sym_t *)rp;
435 
436 	return (lhs->nm_sym.st_value < rhs->nm_sym.st_value ? -1 :
437 	    (lhs->nm_sym.st_value > rhs->nm_sym.st_value ? 1 : 0));
438 }
439 
440 static int
441 nm_gelf_symtab_cb(void *data, const GElf_Sym *symp, const char *name, uint_t id)
442 {
443 	nm_gelf_symtab_t *ngsp = data;
444 
445 	ngsp->ngs_si.sym_id = id;
446 
447 	return (ngsp->ngs_cb(ngsp->ngs_arg, symp, name, &ngsp->ngs_si,
448 	    ngsp->ngs_object));
449 }
450 
451 static void
452 nm_gelf_symtab_iter(mdb_gelf_symtab_t *gst, const char *object, uint_t table,
453     mdb_tgt_sym_f *cb, void *arg)
454 {
455 	nm_gelf_symtab_t ngs;
456 
457 	ngs.ngs_cb = cb;
458 	ngs.ngs_arg = arg;
459 
460 	ngs.ngs_si.sym_table = table;
461 	ngs.ngs_object = object;
462 
463 	mdb_gelf_symtab_iter(gst, nm_gelf_symtab_cb, &ngs);
464 }
465 
466 static int nm_symbol_iter(const char *, uint_t, uint_t, mdb_tgt_sym_f *,
467     nm_iter_info_t *);
468 
469 /*ARGSUSED*/
470 static int
471 nm_object_iter_cb(void *data, const mdb_map_t *mp, const char *name)
472 {
473 	nm_object_iter_t *noip = data;
474 
475 	return (nm_symbol_iter(name, noip->noi_which, noip->noi_type,
476 	    noip->noi_cb, noip->noi_niip));
477 }
478 
479 int
480 nm_symbol_iter(const char *object, uint_t which, uint_t type,
481     mdb_tgt_sym_f *cb, nm_iter_info_t *niip)
482 {
483 	mdb_tgt_t *t = mdb.m_target;
484 
485 	if (object == MDB_TGT_OBJ_EVERY) {
486 		nm_object_iter_t noi;
487 
488 		noi.noi_which = which;
489 		noi.noi_type = type;
490 		noi.noi_cb = cb;
491 		noi.noi_niip = niip;
492 
493 		return (mdb_tgt_object_iter(t, nm_object_iter_cb, &noi));
494 	}
495 
496 	niip->nii_fp = mdb_tgt_name_to_ctf(t, object);
497 
498 	return (mdb_tgt_symbol_iter(t, object, which, type, cb, niip));
499 }
500 
501 /*ARGSUSED*/
502 int
503 cmd_nm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
504 {
505 	enum {
506 		NM_DYNSYM	= 0x0001,	/* -D (use dynsym) */
507 		NM_DEC		= 0x0002,	/* -d (decimal output) */
508 		NM_GLOBAL	= 0x0004,	/* -g (globals only) */
509 		NM_NOHDRS	= 0x0008,	/* -h (suppress header) */
510 		NM_OCT		= 0x0010,	/* -o (octal output) */
511 		NM_UNDEF	= 0x0020,	/* -u (undefs only) */
512 		NM_HEX		= 0x0040,	/* -x (hex output) */
513 		NM_SORT_NAME	= 0x0080,	/* -n (sort by name) */
514 		NM_SORT_VALUE	= 0x0100,	/* -v (sort by value) */
515 		NM_PRVSYM	= 0x0200,	/* -P (use private symtab) */
516 		NM_PRTASGN	= 0x0400	/* -p (print in asgn syntax) */
517 	};
518 
519 	mdb_subopt_t opt_fmt_opts[] = {
520 		{ NM_FMT_INDEX, "ndx" },
521 		{ NM_FMT_VALUE, "val" },
522 		{ NM_FMT_SIZE, "sz" },
523 		{ NM_FMT_TYPE, "type" },
524 		{ NM_FMT_BIND, "bind" },
525 		{ NM_FMT_OTHER, "oth" },
526 		{ NM_FMT_SHNDX, "shndx" },
527 		{ NM_FMT_NAME, "name" },
528 		{ NM_FMT_CTYPE, "ctype" },
529 		{ NM_FMT_OBJECT, "obj" },
530 		{ NM_FMT_CTFID, "ctfid" },
531 		{ 0, NULL }
532 	};
533 
534 	mdb_subopt_t opt_type_opts[] = {
535 		{ NM_TYPE_NOTY, "noty" },
536 		{ NM_TYPE_OBJT, "objt" },
537 		{ NM_TYPE_FUNC, "func" },
538 		{ NM_TYPE_SECT, "sect" },
539 		{ NM_TYPE_FILE, "file" },
540 		{ NM_TYPE_COMM, "comm" },
541 		{ NM_TYPE_TLS, "tls" },
542 		{ NM_TYPE_REGI, "regi" },
543 		{ 0, NULL }
544 	};
545 
546 	uint_t optf = 0;
547 	uint_t opt_fmt;
548 	uint_t opt_types;
549 	int i;
550 
551 	mdb_tgt_sym_f *callback;
552 	uint_t which, type;
553 
554 	char *object = (char *)MDB_TGT_OBJ_EVERY;
555 	int hwidth;
556 	size_t nsyms = 0;
557 
558 	nm_sym_t *syms, *symp;
559 
560 	nm_iter_info_t nii;
561 
562 	/* default output columns */
563 	opt_fmt = NM_FMT_VALUE | NM_FMT_SIZE | NM_FMT_TYPE | NM_FMT_BIND |
564 	    NM_FMT_OTHER | NM_FMT_SHNDX | NM_FMT_NAME;
565 
566 	/* default output types */
567 	opt_types = NM_TYPE_NOTY | NM_TYPE_OBJT | NM_TYPE_FUNC | NM_TYPE_SECT |
568 	    NM_TYPE_FILE | NM_TYPE_COMM | NM_TYPE_TLS | NM_TYPE_REGI;
569 
570 	i = mdb_getopts(argc, argv,
571 	    'D', MDB_OPT_SETBITS, NM_DYNSYM, &optf,
572 	    'P', MDB_OPT_SETBITS, NM_PRVSYM, &optf,
573 	    'd', MDB_OPT_SETBITS, NM_DEC, &optf,
574 	    'g', MDB_OPT_SETBITS, NM_GLOBAL, &optf,
575 	    'h', MDB_OPT_SETBITS, NM_NOHDRS, &optf,
576 	    'n', MDB_OPT_SETBITS, NM_SORT_NAME, &optf,
577 	    'o', MDB_OPT_SETBITS, NM_OCT, &optf,
578 	    'p', MDB_OPT_SETBITS, NM_PRTASGN | NM_NOHDRS, &optf,
579 	    'u', MDB_OPT_SETBITS, NM_UNDEF, &optf,
580 	    'v', MDB_OPT_SETBITS, NM_SORT_VALUE, &optf,
581 	    'x', MDB_OPT_SETBITS, NM_HEX, &optf,
582 	    'f', MDB_OPT_SUBOPTS, opt_fmt_opts, &opt_fmt,
583 	    't', MDB_OPT_SUBOPTS, opt_type_opts, &opt_types,
584 	    NULL);
585 
586 	if (i != argc) {
587 		if (flags & DCMD_ADDRSPEC)
588 			return (DCMD_USAGE);
589 
590 		if (argc != 0 && (argc - i) == 1) {
591 			if (argv[i].a_type != MDB_TYPE_STRING ||
592 			    argv[i].a_un.a_str[0] == '-')
593 				return (DCMD_USAGE);
594 			else
595 				object = (char *)argv[i].a_un.a_str;
596 		} else
597 			return (DCMD_USAGE);
598 	}
599 
600 	if ((optf & (NM_DEC | NM_HEX | NM_OCT)) == 0) {
601 		switch (mdb.m_radix) {
602 		case 8:
603 			optf |= NM_OCT;
604 			break;
605 		case 10:
606 			optf |= NM_DEC;
607 			break;
608 		default:
609 			optf |= NM_HEX;
610 		}
611 	}
612 
613 	switch (optf & (NM_DEC | NM_HEX | NM_OCT)) {
614 	case NM_DEC:
615 #ifdef _LP64
616 		nii.nii_pfmt = "%-20llu";
617 		nii.nii_ofmt = "%-5u";
618 		hwidth = 20;
619 #else
620 		nii.nii_pfmt = "%-10llu";
621 		nii.nii_ofmt = "%-5u";
622 		hwidth = 10;
623 #endif
624 		break;
625 	case NM_HEX:
626 #ifdef _LP64
627 		nii.nii_pfmt = "0x%016llx";
628 		nii.nii_ofmt = "0x%-3x";
629 		hwidth = 18;
630 #else
631 		nii.nii_pfmt = "0x%08llx";
632 		nii.nii_ofmt = "0x%-3x";
633 		hwidth = 10;
634 #endif
635 		break;
636 	case NM_OCT:
637 #ifdef _LP64
638 		nii.nii_pfmt = "%-22llo";
639 		nii.nii_ofmt = "%-5o";
640 		hwidth = 22;
641 #else
642 		nii.nii_pfmt = "%-11llo";
643 		nii.nii_ofmt = "%-5o";
644 		hwidth = 11;
645 #endif
646 		break;
647 	default:
648 		mdb_warn("-d/-o/-x options are mutually exclusive\n");
649 		return (DCMD_USAGE);
650 	}
651 
652 	if (object != MDB_TGT_OBJ_EVERY && (optf & NM_PRVSYM)) {
653 		mdb_warn("-P/object options are mutually exclusive\n");
654 		return (DCMD_USAGE);
655 	}
656 
657 	if ((flags & DCMD_ADDRSPEC) && (optf & NM_PRVSYM)) {
658 		mdb_warn("-P/address options are mutually exclusive\n");
659 		return (DCMD_USAGE);
660 	}
661 
662 	if (!(optf & NM_NOHDRS)) {
663 		mdb_printf("%<u>");
664 		mdb_table_print(opt_fmt, " ",
665 		    MDB_TBL_PRNT, NM_FMT_INDEX, "Index",
666 		    MDB_TBL_PRNT, NM_FMT_OBJECT, "%-15s", "Object",
667 		    MDB_TBL_PRNT, NM_FMT_VALUE, "%-*s", hwidth, "Value",
668 		    MDB_TBL_PRNT, NM_FMT_SIZE, "%-*s", hwidth, "Size",
669 		    MDB_TBL_PRNT, NM_FMT_TYPE, "%-5s", "Type",
670 		    MDB_TBL_PRNT, NM_FMT_BIND, "%-5s", "Bind",
671 		    MDB_TBL_PRNT, NM_FMT_OTHER, "%-5s", "Other",
672 		    MDB_TBL_PRNT, NM_FMT_SHNDX, "%-8s", "Shndx",
673 		    MDB_TBL_PRNT, NM_FMT_CTFID, "%-9s", "CTF ID",
674 		    MDB_TBL_PRNT, NM_FMT_CTYPE, "%-50s", "C Type",
675 		    MDB_TBL_PRNT, NM_FMT_NAME, "%s", "Name",
676 		    MDB_TBL_DONE);
677 
678 		mdb_printf("%</u>\n");
679 	}
680 
681 	nii.nii_flags = opt_fmt;
682 	nii.nii_types = opt_types;
683 
684 	if (optf & NM_DYNSYM)
685 		which = MDB_TGT_DYNSYM;
686 	else
687 		which = MDB_TGT_SYMTAB;
688 
689 	if (optf & NM_GLOBAL)
690 		type = MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_ANY;
691 	else
692 		type = MDB_TGT_BIND_ANY | MDB_TGT_TYPE_ANY;
693 
694 	if (flags & DCMD_ADDRSPEC)
695 		optf |= NM_SORT_NAME; /* use sorting path if only one symbol */
696 
697 	if (optf & (NM_SORT_NAME | NM_SORT_VALUE)) {
698 		char name[MDB_SYM_NAMLEN];
699 		GElf_Sym sym;
700 		mdb_syminfo_t si;
701 
702 		if (optf & NM_UNDEF)
703 			callback = nm_cnt_undef;
704 		else
705 			callback = nm_cnt_any;
706 
707 		if (flags & DCMD_ADDRSPEC) {
708 			const mdb_map_t *mp;
709 			/* gather relevant data for the specified addr */
710 
711 			nii.nii_fp = mdb_tgt_addr_to_ctf(mdb.m_target, addr);
712 
713 			if (mdb_tgt_lookup_by_addr(mdb.m_target, addr,
714 			    MDB_SYM_FUZZY, name, sizeof (name), &sym,
715 			    &si) == -1) {
716 				mdb_warn("%lr", addr);
717 				return (DCMD_ERR);
718 			}
719 
720 			if ((mp = mdb_tgt_addr_to_map(mdb.m_target, addr))
721 			    != NULL) {
722 				object = mdb_alloc(strlen(mp->map_name) + 1,
723 				    UM_SLEEP | UM_GC);
724 
725 				(void) strcpy(object, mp->map_name);
726 
727 				/*
728 				 * Try to find a better match for the syminfo.
729 				 */
730 				(void) mdb_tgt_lookup_by_name(mdb.m_target,
731 				    object, name, &sym, &si);
732 			}
733 
734 			(void) callback(&nsyms, &sym, name, &si, object);
735 
736 		} else if (optf & NM_PRVSYM) {
737 			nsyms = mdb_gelf_symtab_size(mdb.m_prsym);
738 		} else {
739 			(void) mdb_tgt_symbol_iter(mdb.m_target, object,
740 			    which, type, callback, &nsyms);
741 		}
742 
743 		if (nsyms == 0)
744 			return (DCMD_OK);
745 
746 		syms = symp = mdb_alloc(sizeof (nm_sym_t) * nsyms,
747 		    UM_SLEEP | UM_GC);
748 
749 		nii.nii_sympp = &symp;
750 
751 		if (optf & NM_UNDEF)
752 			callback = nm_get_undef;
753 		else
754 			callback = nm_get_any;
755 
756 		if (flags & DCMD_ADDRSPEC) {
757 			(void) callback(&nii, &sym, name, &si, object);
758 		} else if (optf & NM_PRVSYM) {
759 			nm_gelf_symtab_iter(mdb.m_prsym, object, MDB_TGT_PRVSYM,
760 			    callback, &nii);
761 		} else if (nm_symbol_iter(object, which, type, callback,
762 		    &nii) == -1) {
763 			mdb_warn("failed to iterate over symbols");
764 			return (DCMD_ERR);
765 		}
766 
767 		if (optf & NM_SORT_NAME)
768 			qsort(syms, nsyms, sizeof (nm_sym_t), nm_compare_name);
769 		else
770 			qsort(syms, nsyms, sizeof (nm_sym_t), nm_compare_val);
771 	}
772 
773 	if ((optf & (NM_PRVSYM | NM_PRTASGN)) == (NM_PRVSYM | NM_PRTASGN))
774 		callback = nm_asgn;
775 	else if (optf & NM_UNDEF)
776 		callback = nm_undef;
777 	else
778 		callback = nm_any;
779 
780 	if (optf & (NM_SORT_NAME | NM_SORT_VALUE)) {
781 		for (symp = syms; nsyms-- != 0; symp++) {
782 			nii.nii_fp = symp->nm_fp;
783 
784 			callback(&nii, &symp->nm_sym, symp->nm_name,
785 			    &symp->nm_si, symp->nm_object);
786 		}
787 
788 	} else {
789 		if (optf & NM_PRVSYM) {
790 			nm_gelf_symtab_iter(mdb.m_prsym, object, MDB_TGT_PRVSYM,
791 			    callback, &nii);
792 
793 		} else if (nm_symbol_iter(object, which, type, callback, &nii)
794 		    == -1) {
795 			mdb_warn("failed to iterate over symbols");
796 			return (DCMD_ERR);
797 		}
798 	}
799 
800 	return (DCMD_OK);
801 }
802 
803 int
804 cmd_nmadd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
805 {
806 	uintptr_t opt_e = 0, opt_s = 0;
807 	uint_t opt_f = FALSE, opt_o = FALSE;
808 
809 	GElf_Sym sym;
810 	int i;
811 
812 	if (!(flags & DCMD_ADDRSPEC))
813 		return (DCMD_USAGE);
814 
815 	i = mdb_getopts(argc, argv,
816 	    'f', MDB_OPT_SETBITS, TRUE, &opt_f,
817 	    'o', MDB_OPT_SETBITS, TRUE, &opt_o,
818 	    'e', MDB_OPT_UINTPTR, &opt_e,
819 	    's', MDB_OPT_UINTPTR, &opt_s, NULL);
820 
821 	if (i != (argc - 1) || argv[i].a_type != MDB_TYPE_STRING ||
822 	    argv[i].a_un.a_str[0] == '-' || argv[i].a_un.a_str[0] == '+')
823 		return (DCMD_USAGE);
824 
825 	if (opt_e && opt_e < addr) {
826 		mdb_warn("end (%p) is less than start address (%p)\n",
827 		    (void *)opt_e, (void *)addr);
828 		return (DCMD_USAGE);
829 	}
830 
831 	if (mdb_gelf_symtab_lookup_by_name(mdb.m_prsym,
832 	    argv[i].a_un.a_str, &sym, NULL) == -1) {
833 		bzero(&sym, sizeof (sym));
834 		sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
835 	}
836 
837 	if (opt_f)
838 		sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
839 	if (opt_o)
840 		sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
841 	if (opt_e)
842 		sym.st_size = (GElf_Xword)(opt_e - addr);
843 	if (opt_s)
844 		sym.st_size = (GElf_Xword)(opt_s);
845 	sym.st_value = (GElf_Addr)addr;
846 
847 	mdb_gelf_symtab_insert(mdb.m_prsym, argv[i].a_un.a_str, &sym);
848 
849 	mdb_iob_printf(mdb.m_out, "added %s, value=%llr size=%llr\n",
850 	    argv[i].a_un.a_str, sym.st_value, sym.st_size);
851 
852 	return (DCMD_OK);
853 }
854 
855 /*ARGSUSED*/
856 int
857 cmd_nmdel(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
858 {
859 	const char *name;
860 	GElf_Sym sym;
861 	uint_t id;
862 
863 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING ||
864 	    argv->a_un.a_str[0] == '-' || (flags & DCMD_ADDRSPEC))
865 		return (DCMD_USAGE);
866 
867 	name = argv->a_un.a_str;
868 
869 	if (mdb_gelf_symtab_lookup_by_name(mdb.m_prsym, name, &sym, &id) == 0) {
870 		mdb_gelf_symtab_delete(mdb.m_prsym, name, &sym);
871 		mdb_printf("deleted %s, value=%llr size=%llr\n",
872 		    name, sym.st_value, sym.st_size);
873 		return (DCMD_OK);
874 	}
875 
876 	mdb_warn("symbol '%s' not found in private symbol table\n", name);
877 	return (DCMD_ERR);
878 }
879 
880 void
881 nm_help(void)
882 {
883 	mdb_printf("-D         print .dynsym instead of .symtab\n"
884 	    "-P         print private symbol table instead of .symtab\n"
885 	    "-d         print value and size in decimal\n"
886 	    "-g         only print global symbols\n"
887 	    "-h         suppress header line\n"
888 	    "-n         sort symbols by name\n"
889 	    "-o         print value and size in octal\n"
890 	    "-p         print symbols as a series of ::nmadd commands\n"
891 	    "-u         only print undefined symbols\n"
892 	    "-v         sort symbols by value\n"
893 	    "-x         print value and size in hexadecimal\n"
894 	    "-f format  use specified format\n"
895 	    "           ndx, val, sz, type, bind, oth, shndx, "
896 	    "name, ctype, obj\n"
897 	    "-t types   display symbols with the specified types\n"
898 	    "           noty, objt, func, sect, file, regi\n"
899 	    "obj        specify object whose symbol table should be used\n");
900 }
901 
902 void
903 nmadd_help(void)
904 {
905 	mdb_printf("-f       set type of symbol to STT_FUNC\n"
906 	    "-o       set type of symbol to STT_OBJECT\n"
907 	    "-e end   set size of symbol to end - start address\n"
908 	    "-s size  set size of symbol to explicit value\n"
909 	    "name     specify symbol name to add\n");
910 }
911