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