int mdb_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf, size_t nbytes, GElf_Sym *sym) { return (mdb_tgt_lookup_by_addr(mdb.m_target, addr, flags, buf, nbytes, sym, NULL)); }
/* * Determine the return address for the current frame. Typically this is the * fr_savpc value from the current frame, but we also perform some special * handling to see if we are stopped on one of the first two instructions of a * typical function prologue, in which case %ebp will not be set up yet. */ int mdb_ia32_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp, mdb_instr_t curinstr) { struct frame fr; GElf_Sym s; char buf[1]; enum { M_PUSHL_EBP = 0x55, /* pushl %ebp */ M_MOVL_EBP = 0x8b /* movl %esp, %ebp */ }; if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY, buf, 0, &s, NULL) == 0) { if (pc == s.st_value && curinstr == M_PUSHL_EBP) fp = sp - 4; else if (pc == s.st_value + 1 && curinstr == M_MOVL_EBP) fp = sp; } if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) { *p = fr.fr_savpc; return (0); } return (-1); /* errno is set for us */ }
/*ARGSUSED*/ int mdb_ctf_func_info(const GElf_Sym *symp, const mdb_syminfo_t *sip, mdb_ctf_funcinfo_t *mfp) { ctf_file_t *fp = NULL; ctf_funcinfo_t f; mdb_tgt_t *t = mdb.m_target; char name[MDB_SYM_NAMLEN]; const mdb_map_t *mp; mdb_syminfo_t si; int err; if (symp == NULL || mfp == NULL) return (set_errno(EINVAL)); /* * In case the input symbol came from a merged or private symbol table, * re-lookup the address as a symbol, and then perform a fully scoped * lookup of that symbol name to get the mdb_syminfo_t for its CTF. */ if ((fp = mdb_tgt_addr_to_ctf(t, symp->st_value)) == NULL || (mp = mdb_tgt_addr_to_map(t, symp->st_value)) == NULL || mdb_tgt_lookup_by_addr(t, symp->st_value, MDB_TGT_SYM_FUZZY, name, sizeof (name), NULL, NULL) != 0) return (-1); /* errno is set for us */ if (strchr(name, '`') != NULL) err = mdb_tgt_lookup_by_scope(t, name, NULL, &si); else err = mdb_tgt_lookup_by_name(t, mp->map_name, name, NULL, &si); if (err != 0) return (-1); /* errno is set for us */ if (ctf_func_info(fp, si.sym_id, &f) == CTF_ERR) return (set_errno(ctf_to_errno(ctf_errno(fp)))); set_ctf_id(&mfp->mtf_return, fp, f.ctc_return); mfp->mtf_argc = f.ctc_argc; mfp->mtf_flags = f.ctc_flags; mfp->mtf_symidx = si.sym_id; return (0); }
int mdb_ctf_lookup_by_addr(uintptr_t addr, mdb_ctf_id_t *p) { GElf_Sym sym; mdb_syminfo_t si; char name[MDB_SYM_NAMLEN]; const mdb_map_t *mp; mdb_tgt_t *t = mdb.m_target; const char *obj, *c; if (p == NULL) return (set_errno(EINVAL)); if (mdb_tgt_lookup_by_addr(t, addr, MDB_TGT_SYM_EXACT, name, sizeof (name), NULL, NULL) == -1) { mdb_ctf_type_invalidate(p); return (-1); /* errno is set for us */ } if ((c = strrsplit(name, '`')) != NULL) { obj = name; } else { if ((mp = mdb_tgt_addr_to_map(t, addr)) == NULL) { mdb_ctf_type_invalidate(p); return (-1); /* errno is set for us */ } obj = mp->map_name; c = name; } if (mdb_tgt_lookup_by_name(t, obj, c, &sym, &si) == -1) { mdb_ctf_type_invalidate(p); return (-1); /* errno is set for us */ } return (mdb_ctf_lookup_by_symbol(&sym, &si, p)); }
/*ARGSUSED*/ int cmd_nm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { enum { NM_DYNSYM = 0x0001, /* -D (use dynsym) */ NM_DEC = 0x0002, /* -d (decimal output) */ NM_GLOBAL = 0x0004, /* -g (globals only) */ NM_NOHDRS = 0x0008, /* -h (suppress header) */ NM_OCT = 0x0010, /* -o (octal output) */ NM_UNDEF = 0x0020, /* -u (undefs only) */ NM_HEX = 0x0040, /* -x (hex output) */ NM_SORT_NAME = 0x0080, /* -n (sort by name) */ NM_SORT_VALUE = 0x0100, /* -v (sort by value) */ NM_PRVSYM = 0x0200, /* -P (use private symtab) */ NM_PRTASGN = 0x0400 /* -p (print in asgn syntax) */ }; mdb_subopt_t opt_fmt_opts[] = { { NM_FMT_INDEX, "ndx" }, { NM_FMT_VALUE, "val" }, { NM_FMT_SIZE, "sz" }, { NM_FMT_TYPE, "type" }, { NM_FMT_BIND, "bind" }, { NM_FMT_OTHER, "oth" }, { NM_FMT_SHNDX, "shndx" }, { NM_FMT_NAME, "name" }, { NM_FMT_CTYPE, "ctype" }, { NM_FMT_OBJECT, "obj" }, { NM_FMT_CTFID, "ctfid" }, { 0, NULL } }; mdb_subopt_t opt_type_opts[] = { { NM_TYPE_NOTY, "noty" }, { NM_TYPE_OBJT, "objt" }, { NM_TYPE_FUNC, "func" }, { NM_TYPE_SECT, "sect" }, { NM_TYPE_FILE, "file" }, { NM_TYPE_COMM, "comm" }, { NM_TYPE_TLS, "tls" }, { NM_TYPE_REGI, "regi" }, { 0, NULL } }; uint_t optf = 0; uint_t opt_fmt; uint_t opt_types; int i; mdb_tgt_sym_f *callback; uint_t which, type; char *object = (char *)MDB_TGT_OBJ_EVERY; int hwidth; size_t nsyms = 0; nm_sym_t *syms, *symp; nm_iter_info_t nii; /* default output columns */ opt_fmt = NM_FMT_VALUE | NM_FMT_SIZE | NM_FMT_TYPE | NM_FMT_BIND | NM_FMT_OTHER | NM_FMT_SHNDX | NM_FMT_NAME; /* default output types */ opt_types = NM_TYPE_NOTY | NM_TYPE_OBJT | NM_TYPE_FUNC | NM_TYPE_SECT | NM_TYPE_FILE | NM_TYPE_COMM | NM_TYPE_TLS | NM_TYPE_REGI; i = mdb_getopts(argc, argv, 'D', MDB_OPT_SETBITS, NM_DYNSYM, &optf, 'P', MDB_OPT_SETBITS, NM_PRVSYM, &optf, 'd', MDB_OPT_SETBITS, NM_DEC, &optf, 'g', MDB_OPT_SETBITS, NM_GLOBAL, &optf, 'h', MDB_OPT_SETBITS, NM_NOHDRS, &optf, 'n', MDB_OPT_SETBITS, NM_SORT_NAME, &optf, 'o', MDB_OPT_SETBITS, NM_OCT, &optf, 'p', MDB_OPT_SETBITS, NM_PRTASGN | NM_NOHDRS, &optf, 'u', MDB_OPT_SETBITS, NM_UNDEF, &optf, 'v', MDB_OPT_SETBITS, NM_SORT_VALUE, &optf, 'x', MDB_OPT_SETBITS, NM_HEX, &optf, 'f', MDB_OPT_SUBOPTS, opt_fmt_opts, &opt_fmt, 't', MDB_OPT_SUBOPTS, opt_type_opts, &opt_types, NULL); if (i != argc) { if (flags & DCMD_ADDRSPEC) return (DCMD_USAGE); if (argc != 0 && (argc - i) == 1) { if (argv[i].a_type != MDB_TYPE_STRING || argv[i].a_un.a_str[0] == '-') return (DCMD_USAGE); else object = (char *)argv[i].a_un.a_str; } else return (DCMD_USAGE); } if ((optf & (NM_DEC | NM_HEX | NM_OCT)) == 0) { switch (mdb.m_radix) { case 8: optf |= NM_OCT; break; case 10: optf |= NM_DEC; break; default: optf |= NM_HEX; } } switch (optf & (NM_DEC | NM_HEX | NM_OCT)) { case NM_DEC: #ifdef _LP64 nii.nii_pfmt = "%-20llu"; nii.nii_ofmt = "%-5u"; hwidth = 20; #else nii.nii_pfmt = "%-10llu"; nii.nii_ofmt = "%-5u"; hwidth = 10; #endif break; case NM_HEX: #ifdef _LP64 nii.nii_pfmt = "0x%016llx"; nii.nii_ofmt = "0x%-3x"; hwidth = 18; #else nii.nii_pfmt = "0x%08llx"; nii.nii_ofmt = "0x%-3x"; hwidth = 10; #endif break; case NM_OCT: #ifdef _LP64 nii.nii_pfmt = "%-22llo"; nii.nii_ofmt = "%-5o"; hwidth = 22; #else nii.nii_pfmt = "%-11llo"; nii.nii_ofmt = "%-5o"; hwidth = 11; #endif break; default: mdb_warn("-d/-o/-x options are mutually exclusive\n"); return (DCMD_USAGE); } if (object != MDB_TGT_OBJ_EVERY && (optf & NM_PRVSYM)) { mdb_warn("-P/object options are mutually exclusive\n"); return (DCMD_USAGE); } if ((flags & DCMD_ADDRSPEC) && (optf & NM_PRVSYM)) { mdb_warn("-P/address options are mutually exclusive\n"); return (DCMD_USAGE); } if (!(optf & NM_NOHDRS)) { mdb_printf("%<u>"); mdb_table_print(opt_fmt, " ", MDB_TBL_PRNT, NM_FMT_INDEX, "Index", MDB_TBL_PRNT, NM_FMT_OBJECT, "%-15s", "Object", MDB_TBL_PRNT, NM_FMT_VALUE, "%-*s", hwidth, "Value", MDB_TBL_PRNT, NM_FMT_SIZE, "%-*s", hwidth, "Size", MDB_TBL_PRNT, NM_FMT_TYPE, "%-5s", "Type", MDB_TBL_PRNT, NM_FMT_BIND, "%-5s", "Bind", MDB_TBL_PRNT, NM_FMT_OTHER, "%-5s", "Other", MDB_TBL_PRNT, NM_FMT_SHNDX, "%-8s", "Shndx", MDB_TBL_PRNT, NM_FMT_CTFID, "%-9s", "CTF ID", MDB_TBL_PRNT, NM_FMT_CTYPE, "%-50s", "C Type", MDB_TBL_PRNT, NM_FMT_NAME, "%s", "Name", MDB_TBL_DONE); mdb_printf("%</u>\n"); } nii.nii_flags = opt_fmt; nii.nii_types = opt_types; if (optf & NM_DYNSYM) which = MDB_TGT_DYNSYM; else which = MDB_TGT_SYMTAB; if (optf & NM_GLOBAL) type = MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_ANY; else type = MDB_TGT_BIND_ANY | MDB_TGT_TYPE_ANY; if (flags & DCMD_ADDRSPEC) optf |= NM_SORT_NAME; /* use sorting path if only one symbol */ if (optf & (NM_SORT_NAME | NM_SORT_VALUE)) { char name[MDB_SYM_NAMLEN]; GElf_Sym sym; mdb_syminfo_t si; if (optf & NM_UNDEF) callback = nm_cnt_undef; else callback = nm_cnt_any; if (flags & DCMD_ADDRSPEC) { const mdb_map_t *mp; /* gather relevant data for the specified addr */ nii.nii_fp = mdb_tgt_addr_to_ctf(mdb.m_target, addr); if (mdb_tgt_lookup_by_addr(mdb.m_target, addr, MDB_SYM_FUZZY, name, sizeof (name), &sym, &si) == -1) { mdb_warn("%lr", addr); return (DCMD_ERR); } if ((mp = mdb_tgt_addr_to_map(mdb.m_target, addr)) != NULL) { object = mdb_alloc(strlen(mp->map_name) + 1, UM_SLEEP | UM_GC); (void) strcpy(object, mp->map_name); /* * Try to find a better match for the syminfo. */ (void) mdb_tgt_lookup_by_name(mdb.m_target, object, name, &sym, &si); } (void) callback(&nsyms, &sym, name, &si, object); } else if (optf & NM_PRVSYM) { nsyms = mdb_gelf_symtab_size(mdb.m_prsym); } else { (void) mdb_tgt_symbol_iter(mdb.m_target, object, which, type, callback, &nsyms); } if (nsyms == 0) return (DCMD_OK); syms = symp = mdb_alloc(sizeof (nm_sym_t) * nsyms, UM_SLEEP | UM_GC); nii.nii_sympp = &symp; if (optf & NM_UNDEF) callback = nm_get_undef; else callback = nm_get_any; if (flags & DCMD_ADDRSPEC) { (void) callback(&nii, &sym, name, &si, object); } else if (optf & NM_PRVSYM) { nm_gelf_symtab_iter(mdb.m_prsym, object, MDB_TGT_PRVSYM, callback, &nii); } else if (nm_symbol_iter(object, which, type, callback, &nii) == -1) { mdb_warn("failed to iterate over symbols"); return (DCMD_ERR); } if (optf & NM_SORT_NAME) qsort(syms, nsyms, sizeof (nm_sym_t), nm_compare_name); else qsort(syms, nsyms, sizeof (nm_sym_t), nm_compare_val); } if ((optf & (NM_PRVSYM | NM_PRTASGN)) == (NM_PRVSYM | NM_PRTASGN)) callback = nm_asgn; else if (optf & NM_UNDEF) callback = nm_undef; else callback = nm_any; if (optf & (NM_SORT_NAME | NM_SORT_VALUE)) { for (symp = syms; nsyms-- != 0; symp++) { nii.nii_fp = symp->nm_fp; callback(&nii, &symp->nm_sym, symp->nm_name, &symp->nm_si, symp->nm_object); } } else { if (optf & NM_PRVSYM) { nm_gelf_symtab_iter(mdb.m_prsym, object, MDB_TGT_PRVSYM, callback, &nii); } else if (nm_symbol_iter(object, which, type, callback, &nii) == -1) { mdb_warn("failed to iterate over symbols"); return (DCMD_ERR); } } return (DCMD_OK); }