static char * nm_func_signature(ctf_file_t *fp, uint_t index, char *buf, size_t len) { int n; ctf_funcinfo_t f; ctf_id_t argv[32]; char arg[32]; char *start = buf; char *sep = ""; int i; if (ctf_func_info(fp, index, &f) == CTF_ERR) return (NULL); if (ctf_type_name(fp, f.ctc_return, arg, sizeof (arg)) != NULL) n = mdb_snprintf(buf, len, "%s (*)(", arg); else n = mdb_snprintf(buf, len, "<%ld> (*)(", f.ctc_return); if (len <= n) return (start); buf += n; len -= n; (void) ctf_func_args(fp, index, sizeof (argv) / sizeof (argv[0]), argv); for (i = 0; i < f.ctc_argc; i++) { if (ctf_type_name(fp, argv[i], arg, sizeof (arg)) != NULL) n = mdb_snprintf(buf, len, "%s%s", sep, arg); else n = mdb_snprintf(buf, len, "%s<%ld>", sep, argv[i]); if (len <= n) return (start); buf += n; len -= n; sep = ", "; } if (f.ctc_flags & CTF_FUNC_VARARG) { n = mdb_snprintf(buf, len, "%s...", sep); if (len <= n) return (start); buf += n; len -= n; } else if (f.ctc_argc == 0) { n = mdb_snprintf(buf, len, "void"); if (len <= n) return (start); buf += n; len -= n; } (void) mdb_snprintf(buf, len, ")"); return (start); }
/*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); }
/* * Given a symbol table index, return the arguments for the function described * by the corresponding entry in the symbol table. */ int ctf_func_args(ctf_file_t *fp, ulong_t symidx, uint_t argc, ctf_id_t *argv) { const ushort_t *dp; ctf_funcinfo_t f; if (ctf_func_info(fp, symidx, &f) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ /* * The argument data is two ushort_t's past the translation table * offset: one for the function info, and one for the return type. */ dp = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]) + 2; for (argc = MIN(argc, f.ctc_argc); argc != 0; argc--) *argv++ = *dp++; return (0); }
static void walk_symtab(Elf *elf, char *fname, ctf_file_t *fp, void (*callback)(ctf_file_t *, symtab_sym_t *)) { Elf_Scn *stab = NULL; Elf_Scn *text = NULL; Elf_Data *stabdata = NULL; Elf_Data *textdata = NULL; GElf_Ehdr ehdr; GElf_Shdr stabshdr; GElf_Shdr textshdr; int foundtext = 0, foundstab = 0; symtab_sym_t ss; if ((gelf_getehdr(elf, &ehdr)) == NULL) errx(1, "could not read ELF header from %s\n", fname); while ((stab = elf_nextscn(elf, stab)) != NULL) { (void) gelf_getshdr(stab, &stabshdr); if (stabshdr.sh_type == SHT_SYMTAB) { foundstab = 1; break; } } while ((text = elf_nextscn(elf, text)) != NULL) { (void) gelf_getshdr(text, &textshdr); if (strcmp(".text", elf_strptr(elf, ehdr.e_shstrndx, (size_t)textshdr.sh_name)) == 0) { foundtext = 1; break; } } if (!foundstab || !foundtext) return; stabdata = elf_getdata(stab, NULL); textdata = elf_rawdata(text, NULL); for (unsigned symdx = 0; symdx < (stabshdr.sh_size / stabshdr.sh_entsize); symdx++) { (void) gelf_getsym(stabdata, symdx, &ss.ss_sym); if ((GELF_ST_TYPE(ss.ss_sym.st_info) != STT_FUNC) || (ss.ss_sym.st_shndx == SHN_UNDEF)) continue; ss.ss_name = elf_strptr(elf, stabshdr.sh_link, ss.ss_sym.st_name); ss.ss_data = ((uint8_t *)(textdata->d_buf)) + (ss.ss_sym.st_value - textshdr.sh_addr); if (ctf_func_info(fp, symdx, &ss.ss_finfo) == CTF_ERR) { fprintf(stderr, "failed to get funcinfo for: %s\n", ss.ss_name); continue; } (void) callback(fp, &ss); } }
/*ARGSUSED*/ static void fbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) { fbt_probe_t *fbt = parg; struct modctl *ctl = fbt->fbtp_ctl; struct module *mp = ctl->mod_mp; ctf_file_t *fp = NULL, *pfp; ctf_funcinfo_t f; int error; ctf_id_t argv[32], type; int argc = sizeof (argv) / sizeof (ctf_id_t); const char *parent; if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) goto err; if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) { (void) strlcpy(desc->dtargd_native, "int", sizeof(desc->dtargd_native)); return; } if ((fp = ctf_modopen(mp, &error)) == NULL) { /* * We have no CTF information for this module -- and therefore * no args[] information. */ goto err; } /* * If we have a parent container, we must manually import it. */ if ((parent = ctf_parent_name(fp)) != NULL) { struct modctl *mp = &modules; struct modctl *mod = NULL; /* * We must iterate over all modules to find the module that * is our parent. */ do { if (strcmp(mp->mod_modname, parent) == 0) { mod = mp; break; } } while ((mp = mp->mod_next) != &modules); if (mod == NULL) goto err; if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) { goto err; } if (ctf_import(fp, pfp) != 0) { ctf_close(pfp); goto err; } ctf_close(pfp); } if (ctf_func_info(fp, fbt->fbtp_symndx, &f) == CTF_ERR) goto err; if (fbt->fbtp_roffset != 0) { if (desc->dtargd_ndx > 1) goto err; ASSERT(desc->dtargd_ndx == 1); type = f.ctc_return; } else { if (desc->dtargd_ndx + 1 > f.ctc_argc) goto err; if (ctf_func_args(fp, fbt->fbtp_symndx, argc, argv) == CTF_ERR) goto err; type = argv[desc->dtargd_ndx]; } if (ctf_type_name(fp, type, desc->dtargd_native, DTRACE_ARGTYPELEN) != NULL) { ctf_close(fp); return; } err: if (fp != NULL) ctf_close(fp); desc->dtargd_ndx = DTRACE_ARGNONE; }
uintptr_t la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, uintptr_t retval) #endif { #if !defined(_LP64) const char *sym_name = (const char *)symp->st_name; #endif sigset_t omask; char buf[256]; GElf_Sym sym; prsyminfo_t si; ctf_file_t *ctfp; ctf_funcinfo_t finfo; char *defname = (char *)(*defcookie); char *refname = (char *)(*refcookie); abilock(&omask); if (pidout) (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid()); if (retval == 0) { if (verbose_list == NULL) { (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()\n", refname, defname, sym_name); (void) fflush(ABISTREAM); } abiunlock(&omask); return (retval); } if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL) goto fail; if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname, sym_name, &sym, &si) != 0) goto fail; if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR) goto fail; if (verbose_list != NULL) { if (check_intlist(verbose_list, sym_name) != 0) { (void) type_name(ctfp, finfo.ctc_return, buf, sizeof (buf)); (void) fprintf(ABISTREAM, "\treturn = (%s) ", buf); print_value(ctfp, finfo.ctc_return, retval); (void) fprintf(ABISTREAM, "\n"); (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", refname, defname, sym_name); (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); } } else { (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", refname, defname, sym_name); (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); } (void) fflush(ABISTREAM); abiunlock(&omask); return (retval); fail: if (verbose_list != NULL) { if (check_intlist(verbose_list, sym_name) != 0) { (void) fprintf(ABISTREAM, "\treturn = 0x%p\n", (void *)retval); (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", refname, defname, sym_name); (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); } } else { (void) fprintf(ABISTREAM, "<- %-8s -> %8s:%s()", refname, defname, sym_name); (void) fprintf(ABISTREAM, " = 0x%p\n", (void *)retval); } (void) fflush(ABISTREAM); abiunlock(&omask); return (retval); }
uintptr_t la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, uintptr_t *defcookie, La_i86_regs *regset, uint_t *sb_flags) #endif { char *defname = (char *)(*defcookie); char *refname = (char *)(*refcookie); sigset_t omask; #if !defined(_LP64) char const *sym_name = (char const *)symp->st_name; #endif char buf[256]; GElf_Sym sym; prsyminfo_t si; ctf_file_t *ctfp; ctf_funcinfo_t finfo; int argc; ctf_id_t argt[NUM_ARGS]; ulong_t argv[NUM_ARGS]; int i; char *sep = ""; ctf_id_t type, rtype; int kind; abilock(&omask); if (pidout) (void) fprintf(ABISTREAM, "%7u:", (unsigned int)getpid()); if ((ctfp = Pname_to_ctf(proc_hdl, defname)) == NULL) goto fail; if (Pxlookup_by_name(proc_hdl, PR_LMID_EVERY, defname, sym_name, &sym, &si) != 0) goto fail; if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR) goto fail; (void) type_name(ctfp, finfo.ctc_return, buf, sizeof (buf)); (void) fprintf(ABISTREAM, "-> %-8s -> %8s:%s %s(", refname, defname, buf, sym_name); /* * According to bug in la_pltexit(), it can't return * if the type is just a struct/union. So, if the return * type is a struct/union, la_pltexit() should be off. */ rtype = ctf_type_resolve(ctfp, finfo.ctc_return); type = ctf_type_reference(ctfp, rtype); rtype = ctf_type_resolve(ctfp, type); kind = ctf_type_kind(ctfp, rtype); if ((kind == CTF_K_STRUCT || kind == CTF_K_UNION) && strpbrk(buf, "*") == NULL) *sb_flags |= LA_SYMB_NOPLTEXIT; argc = MIN(sizeof (argt) / sizeof (argt[0]), finfo.ctc_argc); (void) ctf_func_args(ctfp, si.prs_id, argc, argt); argv[0] = GETARG0(regset); if (argc > 1) argv[1] = GETARG1(regset); if (argc > 2) argv[2] = GETARG2(regset); if (argc > 3) argv[3] = GETARG3(regset); if (argc > 4) argv[4] = GETARG4(regset); if (argc > 5) argv[5] = GETARG5(regset); if (argc > 6) { for (i = 6; i < argc; i++) argv[i] = GETARG_6NUP(i, regset); } for (i = 0; i < argc; i++) { (void) type_name(ctfp, argt[i], buf, sizeof (buf)); (void) fprintf(ABISTREAM, "%s%s = ", sep, buf); rtype = ctf_type_resolve(ctfp, argt[i]); type = ctf_type_reference(ctfp, rtype); rtype = ctf_type_resolve(ctfp, type); kind = ctf_type_kind(ctfp, rtype); if (kind == CTF_K_STRUCT || kind == CTF_K_UNION) (void) fprintf(ABISTREAM, "0x%p", (void *)argv[i]); else print_value(ctfp, argt[i], argv[i]); sep = ", "; } if (finfo.ctc_flags & CTF_FUNC_VARARG) (void) fprintf(ABISTREAM, "%s...", sep); else if (argc == 0) (void) fprintf(ABISTREAM, "void"); if ((*sb_flags & LA_SYMB_NOPLTEXIT) != 0) (void) fprintf(ABISTREAM, ") ** ST\n"); else (void) fprintf(ABISTREAM, ")\n"); if (verbose_list != NULL && check_intlist(verbose_list, sym_name) != 0) { for (i = 0; i < argc; i++) { (void) type_name(ctfp, argt[i], buf, sizeof (buf)); (void) fprintf(ABISTREAM, "\targ%d = (%s) ", i, buf); print_value(ctfp, argt[i], argv[i]); (void) fprintf(ABISTREAM, "\n"); } if ((*sb_flags & LA_SYMB_NOPLTEXIT) != 0) { if (kind == CTF_K_STRUCT) (void) fprintf(ABISTREAM, "\treturn = (struct), apptrace " "will not trace the return\n"); else (void) fprintf(ABISTREAM, "\treturn = (union), apptrace " "will not trace the return\n"); } } (void) fflush(ABISTREAM); abiunlock(&omask); return (symp->st_value); fail: (void) fprintf(ABISTREAM, "-> %-8s -> %8s:%s(0x%lx, 0x%lx, 0x%lx) ** NR\n", refname, defname, sym_name, (ulong_t)GETARG0(regset), (ulong_t)GETARG1(regset), (ulong_t)GETARG2(regset)); *sb_flags |= LA_SYMB_NOPLTEXIT; (void) fflush(ABISTREAM); abiunlock(&omask); return (symp->st_value); }
/*ARGSUSED*/ static void instr_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) { instr_probe_t *fbt = parg; struct modctl *ctl = fbt->insp_ctl; struct module *mp = (struct module *) ctl; ctf_file_t *fp = NULL; ctf_funcinfo_t f; // int error; ctf_id_t argv[32], type; int argc = sizeof (argv) / sizeof (ctf_id_t); // const char *parent; if (mp->state != MODULE_STATE_LIVE || get_refcount(mp) != fbt->insp_loadcnt) return; if (fbt->insp_roffset != 0 && desc->dtargd_ndx == 0) { (void) strcpy(desc->dtargd_native, "int"); return; } # if 0 if ((fp = ctf_modopen(mp, &error)) == NULL) { /* * We have no CTF information for this module -- and therefore * no args[] information. */ goto err; } # endif //TODO(); if (fp == NULL) goto err; # if 0 /* * If we have a parent container, we must manually import it. */ if ((parent = ctf_parent_name(fp)) != NULL) { ctf_file_t *pfp; TODO(); struct modctl *mod; /* * We must iterate over all modules to find the module that * is our parent. */ for (mod = &modules; mod != NULL; mod = mod->mod_next) { if (strcmp(mod->mod_filename, parent) == 0) break; } if (mod == NULL) goto err; if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) goto err; if (ctf_import(fp, pfp) != 0) { ctf_close(pfp); goto err; } ctf_close(pfp); } # endif if (ctf_func_info(fp, fbt->insp_symndx, &f) == CTF_ERR) goto err; if (fbt->insp_roffset != 0) { if (desc->dtargd_ndx > 1) goto err; ASSERT(desc->dtargd_ndx == 1); type = f.ctc_return; } else { if (desc->dtargd_ndx + 1 > f.ctc_argc) goto err; if (ctf_func_args(fp, fbt->insp_symndx, argc, argv) == CTF_ERR) goto err; type = argv[desc->dtargd_ndx]; } if (ctf_type_name(fp, type, desc->dtargd_native, DTRACE_ARGTYPELEN) != NULL) { ctf_close(fp); return; } err: if (fp != NULL) ctf_close(fp); desc->dtargd_ndx = DTRACE_ARGNONE; }
/* * Read arguments from the frame indicated by regs into args, return the * number of arguments successfully read */ static int read_args(struct ps_prochandle *P, uintptr_t fp, uintptr_t pc, prgreg_t *args, size_t argsize) { GElf_Sym sym; ctf_file_t *ctfp = NULL; ctf_funcinfo_t finfo; prsyminfo_t si = {0}; uint8_t ins[SAVEARGS_INSN_SEQ_LEN]; size_t insnsize; int argc = 0; int rettype = 0; int start_index = 0; int args_style = 0; int i; ctf_id_t args_types[5]; if (Pxlookup_by_addr(P, pc, NULL, 0, &sym, &si) != 0) return (0); if ((ctfp = Paddr_to_ctf(P, pc)) == NULL) return (0); if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR) return (0); argc = finfo.ctc_argc; if (argc == 0) return (0); rettype = ctf_type_kind(ctfp, finfo.ctc_return); /* * If the function returns a structure or union greater than 16 bytes * in size %rdi contains the address in which to store the return * value rather than for an argument. */ if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) && ctf_type_size(ctfp, finfo.ctc_return) > 16) start_index = 1; else start_index = 0; /* * If any of the first 5 arguments are a structure less than 16 bytes * in size, it will be passed spread across two argument registers, * and we will not cope. */ if (ctf_func_args(ctfp, si.prs_id, 5, args_types) == CTF_ERR) return (0); for (i = 0; i < MIN(5, finfo.ctc_argc); i++) { int t = ctf_type_kind(ctfp, args_types[i]); if (((t == CTF_K_STRUCT) || (t == CTF_K_UNION)) && ctf_type_size(ctfp, args_types[i]) <= 16) return (0); } /* * The number of instructions to search for argument saving is limited * such that only instructions prior to %pc are considered and we * never read arguments from a function where the saving code has not * in fact yet executed. */ insnsize = MIN(MIN(sym.st_size, SAVEARGS_INSN_SEQ_LEN), pc - sym.st_value); if (Pread(P, ins, insnsize, sym.st_value) != insnsize) return (0); if ((argc != 0) && ((args_style = saveargs_has_args(ins, insnsize, argc, start_index)) != SAVEARGS_NO_ARGS)) { int regargs = MIN((6 - start_index), argc); size_t size = regargs * sizeof (long); int i; /* * If Studio pushed a structure return address as an argument, * we need to read one more argument than actually exists (the * addr) to make everything line up. */ if (args_style == SAVEARGS_STRUCT_ARGS) size += sizeof (long); if (Pread(P, args, size, (fp - size)) != size) return (0); for (i = 0; i < (regargs / 2); i++) { prgreg_t t = args[i]; args[i] = args[regargs - i - 1]; args[regargs - i - 1] = t; } if (argc > regargs) { size = MIN((argc - regargs) * sizeof (long), argsize - (regargs * sizeof (long))); if (Pread(P, &args[regargs], size, fp + (sizeof (uintptr_t) * 2)) != size) return (6); } return (argc); } else { return (0); } }