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