/* * Convert an address to a symbolic string or a numeric string. If nolocks * is set, we return an error code if this symbol appears to be a mutex- or * rwlock-related symbol in libc so the caller has a chance to find a more * helpful symbol. */ static int getsym(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size, int nolocks) { char name[256]; GElf_Sym sym; prsyminfo_t info; size_t len; if (P == NULL || Pxlookup_by_addr(P, addr, name, sizeof (name), &sym, &info) != 0) { (void) snprintf(buf, size, "%#lx", addr); return (0); } if (info.prs_object == NULL) info.prs_object = "<unknown>"; if (info.prs_lmid != LM_ID_BASE) { len = snprintf(buf, size, "LM%lu`", info.prs_lmid); buf += len; size -= len; } len = snprintf(buf, size, "%s`%s", info.prs_object, info.prs_name); buf += len; size -= len; if (sym.st_value != addr) len = snprintf(buf, size, "+%#lx", addr - sym.st_value); if (nolocks && strcmp("libc.so.1", info.prs_object) == 0 && (strstr("mutex", info.prs_name) == 0 || strstr("rw", info.prs_name) == 0)) return (-1); return (0); }
/* * 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); } }