const char * Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) { map_info_t *mp = Paddr2mptr(P, pltaddr); uintptr_t r_addr; file_info_t *fp; Elf32_Rela r; size_t i; if (mp == NULL || (fp = mp->map_file) == NULL || fp->file_plt_base == 0 || pltaddr < fp->file_plt_base || pltaddr >= fp->file_plt_base + fp->file_plt_size) { errno = EINVAL; return (NULL); } i = (pltaddr - fp->file_plt_base - M_PLT_XNumber * M32_PLT_ENTSIZE) / M32_PLT_ENTSIZE; r_addr = fp->file_jmp_rel + i * sizeof (Elf32_Rela); if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); } return (NULL); }
/* * Given a return address, determine the likely number of arguments * that were pushed on the stack prior to its execution. We do this by * expecting that a typical call sequence consists of pushing arguments on * the stack, executing a call instruction, and then performing an add * on %esp to restore it to the value prior to pushing the arguments for * the call. We attempt to detect such an add, and divide the addend * by the size of a word to determine the number of pushed arguments. * * If we do not find such an add, this does not necessarily imply that the * function took no arguments. It is not possible to reliably detect such a * void function because hand-coded assembler does not always perform an add * to %esp immediately after the "call" instruction (eg. _sys_call()). * Because of this, we default to returning MIN(sz, TR_ARG_MAX) instead of 0 * in the absence of an add to %esp. */ static ulong_t argcount(struct ps_prochandle *P, uint32_t pc, ssize_t sz) { uchar_t instr[6]; ulong_t count, max; max = MIN(sz / sizeof (uint32_t), TR_ARG_MAX); /* * Read the instruction at the return location. */ if (Pread(P, instr, sizeof (instr), (uintptr_t)pc) != sizeof (instr)) return (max); if (instr[1] != 0xc4) return (max); switch (instr[0]) { case 0x81: /* count is a longword */ count = instr[2]+(instr[3]<<8)+(instr[4]<<16)+(instr[5]<<24); break; case 0x83: /* count is a byte */ count = instr[2]; break; default: return (max); } count /= sizeof (uint32_t); return (MIN(count, max)); }
static int dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname) { struct ps_prochandle *P = data; GElf_Sym sym; prsyminfo_t sip; dof_helper_t dh; GElf_Half e_type; const char *mname; const char *syms[] = { "___SUNW_dof", "__SUNW_dof" }; int i, fd = -1; /* * The symbol ___SUNW_dof is for lazy-loaded DOF sections, and * __SUNW_dof is for actively-loaded DOF sections. We try to force * in both types of DOF section since the process may not yet have * run the code to instantiate these providers. */ for (i = 0; i < 2; i++) { if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym, &sip) != 0) { continue; } if ((mname = strrchr(oname, '/')) == NULL) mname = oname; else mname++; dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname); if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr + offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) { dt_dprintf("read of ELF header failed"); continue; } dh.dofhp_dof = sym.st_value; dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr; dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod), sip.prs_lmid, mname); if (fd == -1 && (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) { dt_dprintf("pr_open of helper device failed: %s\n", strerror(errno)); return (-1); /* errno is set for us */ } if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0) dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod); } if (fd != -1) (void) pr_close(P, fd); return (0); }
const char * Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) { map_info_t *mp = Paddr2mptr(P, pltaddr); file_info_t *fp; size_t i; uintptr_t r_addr; if (mp == NULL || (fp = mp->map_file) == NULL || fp->file_plt_base == 0 || pltaddr - fp->file_plt_base >= fp->file_plt_size) { errno = EINVAL; return (NULL); } i = (pltaddr - fp->file_plt_base) / M_PLT_ENTSIZE - M_PLT_XNumber; if (P->status.pr_dmodel == PR_MODEL_LP64) { Elf64_Rela r; r_addr = fp->file_jmp_rel + i * sizeof (r); if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF64_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf64_Sym *symp = &(((Elf64_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); } } else { Elf32_Rel r; r_addr = fp->file_jmp_rel + i * sizeof (r); if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { Elf_Data *data = fp->file_dynsym.sym_data_pri; Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]); return (fp->file_dynsym.sym_strs + symp->st_name); } } return (NULL); }
int main(int argc, const char *argv[]) { int ifd, ofd, perr, toread, ret; struct ps_prochandle *p; GElf_Sym sym; prsyminfo_t si; char buf[1024]; if (argc != 3) { fprintf(stderr, "pdump: <infile> <outfile>\n"); return (1); } ifd = open(argv[1], O_RDONLY); if (ifd < 0) { fprintf(stderr, "failed to open: %s: %s\n", argv[1], strerror(errno)); return (1); } ofd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC); if (ofd < 0) { fprintf(stderr, "failed to open: %s: %s\n", argv[1], strerror(errno)); return (1); } p = Pfgrab_core(ifd, NULL, &perr); if (p == NULL) { fprintf(stderr, "failed to grab core file\n"); return (1); } if (Pxlookup_by_name(p, NULL, "a.out", g_sym, &sym, &si) != 0) { fprintf(stderr, "failed to lookup symobl %s\n", g_sym); return (0); } while (sym.st_size > 0) { toread = MIN(sym.st_size, sizeof (buf)); ret = Pread(p, buf, toread, sym.st_value); if (ret < 0) { fprintf(stderr, "failed to Pread...\n"); return (1); } if (ret != 0) ret = write(ofd, buf, ret); if (ret < 0) { fprintf(stderr, "failed to write to output file %s\n", strerror(errno)); } sym.st_size -= ret; sym.st_value += ret; } return (0); }
void geFilePool::Reader::PreadCRC(void *buffer, size_t size, off64_t offset) { Pread(buffer, size, offset); size_t data_len = size - sizeof(uint32); uint32 computed_crc = Crc32(buffer, data_len); uint32 file_crc; FromLittleEndianBuffer(&file_crc, reinterpret_cast<char*>(buffer) + data_len); if (computed_crc != file_crc) { throw khSimpleException("geFilePool::Reader::PreadCRC: CRC mismatch"); } }
int Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp) { uintptr_t addr; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) { lwpstatus_t ls; if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0) return (-1); addr = ls.pr_ustack; } else { lwp_info_t *lwp; if ((lwp = getlwpcore(P, lwpid)) == NULL) return (-1); addr = lwp->lwp_status.pr_ustack; } if (P->status.pr_dmodel == PR_MODEL_NATIVE) { if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp)) return (-1); #ifdef _LP64 } else { stack32_t stk32; if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32)) return (-1); stack_32_to_n(&stk32, stkp); #endif } return (0); }
int Pissyscall(struct ps_prochandle *P, uintptr_t addr) { instr_t sysinstr; instr_t instr; sysinstr = SYSCALL32; if (Pread(P, &instr, sizeof (instr), addr) != sizeof (instr) || instr != sysinstr) return (0); else return (1); }
int Pissyscall(struct ps_prochandle *P, uintptr_t addr) { uchar_t instr[16]; if (P->status.pr_dmodel == PR_MODEL_LP64) { if (Pread(P, instr, sizeof (syscall_instr), addr) != sizeof (syscall_instr) || memcmp(instr, syscall_instr, sizeof (syscall_instr)) != 0) return (0); else return (1); } if (Pread(P, instr, sizeof (int_syscall_instr), addr) != sizeof (int_syscall_instr)) return (0); if (memcmp(instr, int_syscall_instr, sizeof (int_syscall_instr)) == 0) return (1); return (0); }
int dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) { uint32_t *text; int i; int srdepth = 0; dt_dprintf("%s: unimplemented\n", __func__); return (DT_PROC_ERR); if ((text = malloc(symp->st_size + 4)) == NULL) { dt_dprintf("mr sparkle: malloc() failed\n"); return (DT_PROC_ERR); } #ifdef DOODAD if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { dt_dprintf("mr sparkle: Pread() failed\n"); free(text); return (DT_PROC_ERR); } #endif /* * Leave a dummy instruction in the last slot to simplify edge * conditions. */ text[symp->st_size / 4] = 0; ftp->ftps_type = DTFTP_RETURN; ftp->ftps_pc = symp->st_value; ftp->ftps_size = symp->st_size; ftp->ftps_noffs = 0; free(text); if (ftp->ftps_noffs > 0) { if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { dt_dprintf("fasttrap probe creation ioctl failed: %s\n", strerror(errno)); return (dt_set_errno(dtp, errno)); } } return (ftp->ftps_noffs); }
void show_stat32(private_t *pri, long offset) { struct stat32 statb; timestruc_t ts; if (offset != NULL && Pread(Proc, &statb, sizeof (statb), offset) == sizeof (statb)) { (void) printf( "%s d=0x%.8X i=%-5u m=0%.6o l=%-2u u=%-5u g=%-5u", pri->pname, statb.st_dev, statb.st_ino, statb.st_mode, statb.st_nlink, statb.st_uid, statb.st_gid); switch (statb.st_mode & S_IFMT) { case S_IFCHR: case S_IFBLK: (void) printf(" rdev=0x%.8X\n", statb.st_rdev); break; default: (void) printf(" sz=%u\n", statb.st_size); break; } TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_atim); prtimestruc(pri, "at = ", &ts); TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_mtim); prtimestruc(pri, "mt = ", &ts); TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_ctim); prtimestruc(pri, "ct = ", &ts); (void) printf( "%s bsz=%-5d blks=%-5d fs=%.*s\n", pri->pname, statb.st_blksize, statb.st_blocks, _ST_FSTYPSZ, statb.st_fstype); } }
void show_o_stat(private_t *pri, long offset) { struct o_stat statb; timestruc_t ts; if (offset != NULL && Pread(Proc, &statb, sizeof (statb), offset) == sizeof (statb)) { (void) printf( "%s d=0x%.8X i=%-5u m=0%.6o l=%-2u u=%-5u g=%-5u", pri->pname, statb.st_dev & 0xffff, statb.st_ino, statb.st_mode, statb.st_nlink % 0xffff, statb.st_uid, statb.st_gid); switch (statb.st_mode & S_IFMT) { case S_IFCHR: case S_IFBLK: (void) printf(" rdev=0x%.4X\n", statb.st_rdev & 0xffff); break; default: (void) printf(" sz=%u\n", (uint32_t)statb.st_size); break; } ts.tv_nsec = 0; ts.tv_sec = statb.st_atim; prtimestruc(pri, "at = ", &ts); ts.tv_sec = statb.st_atim; prtimestruc(pri, "mt = ", &ts); ts.tv_sec = statb.st_atim; prtimestruc(pri, "ct = ", &ts); } }
int Plwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp) { uintptr_t addr; lwpstatus_t ls; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) { if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0) return (-1); } else { lwp_info_t *lwp; if ((lwp = getlwpcore(P, lwpid)) == NULL) return (-1); ls = lwp->lwp_status; } addr = ls.pr_ustack; /* * Read out the current stack; if the SS_ONSTACK flag is set then * this LWP is operating on the alternate signal stack. We can * recover the original stack from pr_oldcontext. */ if (P->status.pr_dmodel == PR_MODEL_NATIVE) { if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp)) return (-1); if (stkp->ss_flags & SS_ONSTACK) goto on_altstack; #ifdef _LP64 } else { stack32_t stk32; if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32)) return (-1); if (stk32.ss_flags & SS_ONSTACK) goto on_altstack; stack_32_to_n(&stk32, stkp); #endif } return (0); on_altstack: if (P->status.pr_dmodel == PR_MODEL_NATIVE) { ucontext_t *ctxp = (void *)ls.pr_oldcontext; if (Pread(P, stkp, sizeof (*stkp), (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp)) return (-1); #ifdef _LP64 } else { ucontext32_t *ctxp = (void *)ls.pr_oldcontext; stack32_t stk32; if (Pread(P, &stk32, sizeof (stk32), (uintptr_t)&ctxp->uc_stack) != sizeof (stk32)) return (-1); stack_32_to_n(&stk32, stkp); #endif } return (0); }
static int dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname) { struct ps_prochandle *P = data; GElf_Sym sym; #if defined(sun) prsyminfo_t sip; GElf_Half e_type; #endif dof_helper_t dh; const char *mname; const char *syms[] = { "___SUNW_dof", "__SUNW_dof" }; int i; #if defined(windows) HANDLE fd = NULL; DWORD ret, gen; #endif #if !defined(sun) dof_hdr_t hdr; #endif /* * The symbol ___SUNW_dof is for lazy-loaded DOF sections, and * __SUNW_dof is for actively-loaded DOF sections. We try to force * in both types of DOF section since the process may not yet have * run the code to instantiate these providers. */ for (i = 0; i < 2; i++) { if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym, NULL) != 0) { continue; } if ((mname = strrchr(oname, '/')) == NULL) mname = oname; else mname++; dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname); #if 0 if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr + offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) { dt_dprintf("read of ELF header failed"); continue; } dh.dofhp_dof = sym.st_value; dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr; #endif #if !defined(sun) dh.dofhp_addr = 0; dh.dofhp_dof = (uintptr_t) sym.st_value;; dh.dofhp_pid = Ppid(P); dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod), 0, mname); if (fd == NULL && (fd = CreateFile("\\\\.\\DtraceHelper", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == NULL) { dt_dprintf("open of helper device failed: %s\n", strerror(errno)); return (-1); /* errno is set for us */ } if ((DeviceIoControl(fd, DTRACEHIOC_ADDDOF, &dh, 0, &gen, 0, &ret, NULL)) == 0) dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod); else dt_dprintf("DOF was success for %s\n", dh.dofhp_mod); #else dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod), sip.prs_lmid, mname); if (fd == -1 && (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) { dt_dprintf("pr_open of helper device failed: %s\n", strerror(errno)); return (-1); /* errno is set for us */ } if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0) dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod); #endif } #if defined(sun) if (fd != -1) (void) pr_close(P, fd); #else if (fd != 0) CloseHandle(fd); #endif return (0); }
void geFilePool::Writer::Pread(std::string &buffer, size_t size, off64_t offset) { buffer.resize(size); Pread(&buffer[0], size, offset); }
static int Pstack_iter32(struct ps_prochandle *P, const prgregset_t regs, proc_stack_f *func, void *arg) { prgreg_t *prevfp = NULL; uint_t pfpsize = 0; int nfp = 0; struct { prgreg32_t fp; prgreg32_t pc; prgreg32_t args[32]; } frame; uint_t argc; ssize_t sz; prgregset_t gregs; uint32_t fp, pfp, pc; long args[32]; int rv; int i; /* * Type definition for a structure corresponding to an IA32 * signal frame. Refer to the comments in Pstack.c for more info */ typedef struct { prgreg32_t fp; prgreg32_t pc; int signo; caddr32_t ucp; caddr32_t sip; } sf_t; uclist_t ucl; ucontext32_t uc; uintptr_t uc_addr; init_uclist(&ucl, P); (void) memcpy(gregs, regs, sizeof (gregs)); fp = regs[R_FP]; pc = regs[R_PC]; while (fp != 0 || pc != 0) { if (stack_loop(fp, &prevfp, &nfp, &pfpsize)) break; if (fp != 0 && (sz = Pread(P, &frame, sizeof (frame), (uintptr_t)fp) >= (ssize_t)(2* sizeof (uint32_t)))) { /* * One more trick for signal frames: the kernel sets * the return pc of the signal frame to 0xffffffff on * Intel IA32, so argcount won't work. */ if (frame.pc != -1L) { sz -= 2* sizeof (uint32_t); argc = argcount(P, (uint32_t)frame.pc, sz); } else argc = 3; /* sighandler(signo, sip, ucp) */ } else { (void) memset(&frame, 0, sizeof (frame)); argc = 0; } gregs[R_FP] = fp; gregs[R_PC] = pc; for (i = 0; i < argc; i++) args[i] = (uint32_t)frame.args[i]; if ((rv = func(arg, gregs, argc, args)) != 0) break; /* * In order to allow iteration over java frames (which can have * their own frame pointers), we allow the iterator to change * the contents of gregs. If we detect a change, then we assume * that the new values point to the next frame. */ if (gregs[R_FP] != fp || gregs[R_PC] != pc) { fp = gregs[R_FP]; pc = gregs[R_PC]; continue; } pfp = fp; fp = frame.fp; pc = frame.pc; if (find_uclink(&ucl, pfp + sizeof (sf_t))) uc_addr = pfp + sizeof (sf_t); else uc_addr = NULL; if (uc_addr != NULL && Pread(P, &uc, sizeof (uc), uc_addr) == sizeof (uc)) { ucontext_32_to_prgregs(&uc, gregs); fp = gregs[R_FP]; pc = gregs[R_PC]; } } if (prevfp) free(prevfp); free_uclist(&ucl); return (rv); }
int main(int argc, char **argv) { bool walk = false, randsize = false, verbose = false, csum = false, rtest = false, wtest = false; int fd1, fd2 = 0, direct = 0, nbytes = 4096, j, o; unsigned long size, i, offset = 0, done = 0, unique = 0, benchmark = 0; void *buf1 = NULL, *buf2 = NULL; struct pagestuff *pages, *p; unsigned char c[16]; time_t last_printed = 0; extern char *optarg; RC4_KEY writedata; RC4_set_key(&writedata, 16, bcache_magic); while ((o = getopt(argc, argv, "dnwvscwlb:")) != EOF) switch (o) { case 'd': direct = O_DIRECT; break; case 'n': walk = true; break; case 'v': verbose = true; break; case 's': randsize = true; break; case 'c': csum = true; break; case 'w': wtest = true; break; case 'r': rtest = true; break; case 'l': klog = true; break; case 'b': benchmark = atol(optarg); break; default: usage(); } argv += optind; argc -= optind; if (!rtest && !wtest) rtest = true; if (argc < 1) { printf("Please enter a device to test\n"); exit(EXIT_FAILURE); } if (!csum && !benchmark && argc < 2) { printf("Please enter a device to compare against\n"); exit(EXIT_FAILURE); } fd1 = open(argv[0], (wtest ? O_RDWR : O_RDONLY)|direct); if (!csum && !benchmark) fd2 = open(argv[1], (wtest ? O_RDWR : O_RDONLY)|direct); if (fd1 == -1 || fd2 == -1) { perror("Error opening device"); exit(EXIT_FAILURE); } size = getblocks(fd1); if (!csum && !benchmark) size = MIN(size, getblocks(fd2)); size = size / 8 - 16; pages = calloc(size + 16, sizeof(*pages)); printf("size %li\n", size); if (posix_memalign(&buf1, 4096, 4096 * 16) || posix_memalign(&buf2, 4096, 4096 * 16)) { printf("Could not allocate buffers\n"); exit(EXIT_FAILURE); } //setvbuf(stdout, NULL, _IONBF, 0); for (i = 0; !benchmark || i < benchmark; i++) { bool writing = (wtest && (i & 1)) || !rtest; nbytes = randsize ? drand48() * 16 + 1 : 1; nbytes <<= 12; offset >>= 12; offset += walk ? normal() * 20 : random(); offset %= size; offset <<= 12; if (!(i % 200)) flushlog(); if (!verbose) { time_t now = time(NULL); if (now - last_printed >= 2) { last_printed = now; goto print; } } else print: printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n", i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11); done += nbytes >> 9; if (!writing) Pread(fd1, buf1, nbytes, offset); if (!writing && !csum && !benchmark) Pread(fd2, buf2, nbytes, offset); for (j = 0; j < nbytes; j += 4096) { p = &pages[(offset + j) / 4096]; if (writing) RC4(&writedata, 4096, zero, buf1 + j); if (csum) { MD4(buf1 + j, 4096, &c[0]); if (writing || (!p->readcount && !p->writecount)) { memcpy(&p->oldcsum[0], &p->csum[0], 16); memcpy(&p->csum[0], c, 16); } else if (memcmp(&p->csum[0], c, 16)) goto bad; } else if (!writing && !benchmark && memcmp(buf1 + j, buf2 + j, 4096)) goto bad; if (!p->writecount && !p->readcount) unique += 8; writing ? p->writecount++ : p->readcount++; } if (writing) Pwrite(fd1, buf1, nbytes, offset); if (writing && !csum && !benchmark) Pwrite(fd2, buf2, nbytes, offset); } printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n", i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11); exit(EXIT_SUCCESS); err: perror("IO error"); flushlog(); exit(EXIT_FAILURE); bad: printf("Bad read! loop %li offset %li readcount %i writecount %i\n", i, (offset + j) >> 9, p->readcount, p->writecount); if (!memcmp(&p->oldcsum[0], c, 16)) printf("Matches previous csum\n"); flushlog(); exit(EXIT_FAILURE); }
/* minix-without-mmap version of _rtld_map_object() */ Obj_Entry * _rtld_map_object_fallback(const char *path, int fd, const struct stat *sb) { Obj_Entry *obj; Elf_Ehdr *ehdr; Elf_Phdr *phdr; #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) Elf_Phdr *phtls; #endif size_t phsize; Elf_Phdr *phlimit; Elf_Phdr *segs[2]; int nsegs; caddr_t mapbase = MAP_FAILED; size_t mapsize = 0; int mapflags; Elf_Off base_offset; #ifdef MAP_ALIGNED Elf_Addr base_alignment; #endif Elf_Addr base_vaddr; Elf_Addr base_vlimit; Elf_Addr text_vlimit; int text_flags; caddr_t base_addr; Elf_Off data_offset; Elf_Addr data_vaddr; Elf_Addr data_vlimit; int data_flags; caddr_t data_addr; #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) Elf_Addr tls_vaddr = 0; /* Noise GCC */ #endif Elf_Addr phdr_vaddr; size_t phdr_memsz; #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) caddr_t gap_addr; size_t gap_size; #endif int i; #ifdef RTLD_LOADER Elf_Addr clear_vaddr; caddr_t clear_addr; size_t nclear; #endif if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) { _rtld_error("%s: not ELF file (too short)", path); return NULL; } obj = _rtld_obj_new(); obj->path = xstrdup(path); obj->pathlen = strlen(path); if (sb != NULL) { obj->dev = sb->st_dev; obj->ino = sb->st_ino; } #ifdef __minix ehdr = minix_mmap(NULL, _rtld_pagesz, PROT_READ|PROT_WRITE, MAP_PREALLOC|MAP_ANON, -1, (off_t)0); Pread(ehdr, _rtld_pagesz, fd, 0); #if MINIXVERBOSE fprintf(stderr, "minix mmap for header: 0x%lx\n", ehdr); #endif #else ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd, (off_t)0); #endif obj->ehdr = ehdr; if (ehdr == MAP_FAILED) { _rtld_error("%s: read error: %s", path, xstrerror(errno)); goto bad; } /* Make sure the file is valid */ if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0) { _rtld_error("%s: not ELF file (magic number bad)", path); goto bad; } if (ehdr->e_ident[EI_CLASS] != ELFCLASS) { _rtld_error("%s: invalid ELF class %x; expected %x", path, ehdr->e_ident[EI_CLASS], ELFCLASS); goto bad; } /* Elf_e_ident includes class */ if (ehdr->e_ident[EI_VERSION] != EV_CURRENT || ehdr->e_version != EV_CURRENT || ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) { _rtld_error("%s: unsupported file version", path); goto bad; } if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { _rtld_error("%s: unsupported file type", path); goto bad; } switch (ehdr->e_machine) { ELFDEFNNAME(MACHDEP_ID_CASES) default: _rtld_error("%s: unsupported machine", path); goto bad; } /* * We rely on the program header being in the first page. This is * not strictly required by the ABI specification, but it seems to * always true in practice. And, it simplifies things considerably. */ assert(ehdr->e_phentsize == sizeof(Elf_Phdr)); assert(ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf_Phdr) <= _rtld_pagesz); /* * Scan the program header entries, and save key information. * * We rely on there being exactly two load segments, text and data, * in that order. */ phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff); #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) phtls = NULL; #endif phsize = ehdr->e_phnum * sizeof(phdr[0]); obj->phdr = NULL; phdr_vaddr = EA_UNDEF; phdr_memsz = 0; phlimit = phdr + ehdr->e_phnum; nsegs = 0; while (phdr < phlimit) { switch (phdr->p_type) { case PT_INTERP: obj->interp = (void *)(uintptr_t)phdr->p_vaddr; dbg(("%s: PT_INTERP %p", obj->path, obj->interp)); break; case PT_LOAD: if (nsegs < 2) segs[nsegs] = phdr; ++nsegs; #if ELFSIZE == 64 #define PRImemsz PRIu64 #else #define PRImemsz PRIu32 #endif dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_LOAD", (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz)); break; case PT_PHDR: phdr_vaddr = phdr->p_vaddr; phdr_memsz = phdr->p_memsz; dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_PHDR", (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz)); break; case PT_DYNAMIC: obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr; dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_DYNAMIC", (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz)); break; #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) case PT_TLS: phtls = phdr; dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_TLS", (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz)); break; #endif } ++phdr; } phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff); obj->entry = (void *)(uintptr_t)ehdr->e_entry; if (!obj->dynamic) { _rtld_error("%s: not dynamically linked", path); goto bad; } if (nsegs != 2) { _rtld_error("%s: wrong number of segments (%d != 2)", path, nsegs); goto bad; } /* * Map the entire address space of the object as a file * region to stake out our contiguous region and establish a * base for relocation. We use a file mapping so that * the kernel will give us whatever alignment is appropriate * for the platform we're running on. * * We map it using the text protection, map the data segment * into the right place, then map an anon segment for the bss * and unmap the gaps left by padding to alignment. */ #ifdef MAP_ALIGNED base_alignment = segs[0]->p_align; #endif base_offset = round_down(segs[0]->p_offset); base_vaddr = round_down(segs[0]->p_vaddr); base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz); text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz); text_flags = protflags(segs[0]->p_flags); data_offset = round_down(segs[1]->p_offset); data_vaddr = round_down(segs[1]->p_vaddr); data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz); data_flags = protflags(segs[1]->p_flags); #ifdef RTLD_LOADER clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz; #endif obj->textsize = text_vlimit - base_vaddr; obj->vaddrbase = base_vaddr; obj->isdynamic = ehdr->e_type == ET_DYN; #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) if (phtls != NULL) { ++_rtld_tls_dtv_generation; obj->tlsindex = ++_rtld_tls_max_index; obj->tlssize = phtls->p_memsz; obj->tlsalign = phtls->p_align; obj->tlsinitsize = phtls->p_filesz; tls_vaddr = phtls->p_vaddr; } #endif obj->phdr_loaded = false; for (i = 0; i < nsegs; i++) { if (phdr_vaddr != EA_UNDEF && segs[i]->p_vaddr <= phdr_vaddr && segs[i]->p_memsz >= phdr_memsz) { obj->phdr_loaded = true; break; } if (segs[i]->p_offset <= ehdr->e_phoff && segs[i]->p_memsz >= phsize) { phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff; phdr_memsz = phsize; obj->phdr_loaded = true; break; } } if (obj->phdr_loaded) { obj->phdr = (void *)(uintptr_t)phdr_vaddr; obj->phsize = phdr_memsz; } else { Elf_Phdr *buf; buf = xmalloc(phsize); if (buf == NULL) { _rtld_error("%s: cannot allocate program header", path); goto bad; } memcpy(buf, phdr, phsize); obj->phdr = buf; obj->phsize = phsize; } dbg(("%s: phdr %p phsize %zu (%s)", obj->path, obj->phdr, obj->phsize, obj->phdr_loaded ? "loaded" : "allocated")); /* Unmap header if it overlaps the first load section. */ if (base_offset < _rtld_pagesz) { munmap(ehdr, _rtld_pagesz); obj->ehdr = MAP_FAILED; } /* * Calculate log2 of the base section alignment. */ mapflags = 0; #ifdef MAP_ALIGNED if (base_alignment > _rtld_pagesz) { unsigned int log2 = 0; for (; base_alignment > 1; base_alignment >>= 1) log2++; mapflags = MAP_ALIGNED(log2); }
int Pstack_iter(struct ps_prochandle *P, const prgregset_t regs, proc_stack_f *func, void *arg) { prgreg_t *prevfp = NULL; uint_t pfpsize = 0; int nfp = 0; prgregset_t gregs; long args[6]; prgreg_t fp; int i; int rv; uintptr_t sp; ssize_t n; uclist_t ucl; ucontext_t uc; init_uclist(&ucl, P); (void) memcpy(gregs, regs, sizeof (gregs)); for (;;) { fp = gregs[R_FP]; if (stack_loop(fp, &prevfp, &nfp, &pfpsize)) break; for (i = 0; i < 6; i++) args[i] = gregs[R_I0 + i]; if ((rv = func(arg, gregs, 6, args)) != 0) break; gregs[R_PC] = gregs[R_I7]; gregs[R_nPC] = gregs[R_PC] + 4; (void) memcpy(&gregs[R_O0], &gregs[R_I0], 8*sizeof (prgreg_t)); if ((sp = gregs[R_FP]) == 0) break; sp += STACK_BIAS; if (find_uclink(&ucl, sp + SA(sizeof (struct frame))) && Pread(P, &uc, sizeof (uc), sp + SA(sizeof (struct frame))) == sizeof (uc)) { ucontext_n_to_prgregs(&uc, gregs); sp = gregs[R_SP] + STACK_BIAS; } n = Pread(P, &gregs[R_L0], sizeof (struct rwindow), sp); if (n == sizeof (struct rwindow)) continue; /* * If we get here, then our Pread of the register window * failed. If this is because the address was not mapped, * then we attempt to read this window via any gwindows * information we have. If that too fails, abort our loop. */ if (n > 0) break; /* Failed for reason other than not mapped */ if (read_gwin(P, (struct rwindow *)&gregs[R_L0], sp) == -1) break; /* No gwindows match either */ } if (prevfp) free(prevfp); free_uclist(&ucl); return (rv); }
/*ARGSUSED*/ int dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) { uint8_t *text; ulong_t i, end; int size; pid_t pid = Pstatus(P)->pr_pid; char dmodel = Pstatus(P)->pr_dmodel; if ((text = malloc(symp->st_size)) == NULL) { dt_dprintf("mr sparkle: malloc() failed\n"); return (DT_PROC_ERR); } if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { dt_dprintf("mr sparkle: Pread() failed\n"); free(text); return (DT_PROC_ERR); } /* * We can't instrument offsets in functions with jump tables as * we might interpret a jump table offset as an instruction. */ if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { free(text); return (0); } ftp->ftps_probe_type = DTFTP_OFFSETS; ftp->ftps_pc = symp->st_value; ftp->ftps_size = (size_t)symp->st_size; ftp->ftps_noffs = 0; end = ftp->ftps_size; if (strcmp("*", pattern) == 0) { for (i = 0; i < end; i += size) { ftp->ftps_offs[ftp->ftps_noffs++] = i; size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); /* bail if we hit an invalid opcode */ if (size <= 0) break; } } else { char name[sizeof (i) * 2 + 1]; for (i = 0; i < end; i += size) { (void) snprintf(name, sizeof (name), "%lx", i); if (gmatch(name, pattern)) ftp->ftps_offs[ftp->ftps_noffs++] = i; size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); /* bail if we hit an invalid opcode */ if (size <= 0) break; } } free(text); if (ftp->ftps_noffs > 0) { if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { dt_dprintf("fasttrap probe creation ioctl failed: %s\n", strerror(errno)); return (dt_set_errno(dtp, errno)); } } return (ftp->ftps_noffs); }
Elf * fake_elf32(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr, Ehdr *ehdr, uint_t phnum, Phdr *phdr) #endif { enum { DI_PLTGOT, DI_JMPREL, DI_PLTRELSZ, DI_PLTREL, DI_SYMTAB, DI_HASH, DI_SYMENT, DI_STRTAB, DI_STRSZ, DI_SUNW_SYMTAB, DI_SUNW_SYMSZ, DI_NENT }; /* * Mask of dynamic options that must be present in a well * formed dynamic section. We need all of these in order to * put together a complete set of elf sections. They are * mandatory in both executables and shared objects so if one * of them is missing, we're in some trouble and should abort. * The PLT items are expected, but we will let them slide if * need be. The DI_SUNW_SYM* items are completely optional, so * we use them if they are present and ignore them otherwise. */ const int di_req_mask = (1 << DI_SYMTAB) | (1 << DI_SYMENT) | (1 << DI_STRTAB) | (1 << DI_STRSZ); int di_mask = 0; size_t size = 0; caddr_t elfdata = NULL; Elf *elf; size_t dynsym_size = 0, ldynsym_size; int dynstr_shndx; Ehdr *ep; Shdr *sp; Dyn *dp = NULL; Dyn *d[DI_NENT] = { 0 }; uint_t i; Off off; size_t pltsz = 0, pltentries = 0; uintptr_t hptr = NULL; Word hnchains = 0, hnbuckets = 0; if (ehdr->e_type == ET_DYN) phdr->p_vaddr += addr; if (P->rap != NULL) { if (rd_get_dyns(P->rap, addr, (void **)&dp, NULL) != RD_OK) goto bad; } else { if ((dp = malloc(phdr->p_filesz)) == NULL) goto bad; if (Pread(P, dp, phdr->p_filesz, phdr->p_vaddr) != phdr->p_filesz) goto bad; } /* * Iterate over the items in the dynamic section, grabbing * the address of items we want and saving them in dp[]. */ for (i = 0; i < phdr->p_filesz / sizeof (Dyn); i++) { switch (dp[i].d_tag) { /* For the .plt section */ case DT_PLTGOT: d[DI_PLTGOT] = &dp[i]; break; case DT_JMPREL: d[DI_JMPREL] = &dp[i]; break; case DT_PLTRELSZ: d[DI_PLTRELSZ] = &dp[i]; break; case DT_PLTREL: d[DI_PLTREL] = &dp[i]; break; /* For the .dynsym section */ case DT_SYMTAB: d[DI_SYMTAB] = &dp[i]; di_mask |= (1 << DI_SYMTAB); break; case DT_HASH: d[DI_HASH] = &dp[i]; di_mask |= (1 << DI_HASH); break; case DT_SYMENT: d[DI_SYMENT] = &dp[i]; di_mask |= (1 << DI_SYMENT); break; case DT_SUNW_SYMTAB: d[DI_SUNW_SYMTAB] = &dp[i]; break; case DT_SUNW_SYMSZ: d[DI_SUNW_SYMSZ] = &dp[i]; break; /* For the .dynstr section */ case DT_STRTAB: d[DI_STRTAB] = &dp[i]; di_mask |= (1 << DI_STRTAB); break; case DT_STRSZ: d[DI_STRSZ] = &dp[i]; di_mask |= (1 << DI_STRSZ); break; } } /* Ensure all required entries were collected */ if ((di_mask & di_req_mask) != di_req_mask) { dprintf("text section missing required dynamic entries: " "required 0x%x, found 0x%x\n", di_req_mask, di_mask); goto bad; } /* SUNW_ldynsym must be adjacent to dynsym. Ignore if not */ if ((d[DI_SUNW_SYMTAB] != NULL) && (d[DI_SUNW_SYMSZ] != NULL) && ((d[DI_SYMTAB]->d_un.d_ptr <= d[DI_SUNW_SYMTAB]->d_un.d_ptr) || (d[DI_SYMTAB]->d_un.d_ptr >= (d[DI_SUNW_SYMTAB]->d_un.d_ptr + d[DI_SUNW_SYMSZ]->d_un.d_val)))) { d[DI_SUNW_SYMTAB] = NULL; d[DI_SUNW_SYMSZ] = NULL; } /* elf header */ size = sizeof (Ehdr); /* program headers from in-core elf fragment */ size += phnum * ehdr->e_phentsize; /* unused shdr, and .shstrtab section */ size += sizeof (Shdr); size += sizeof (Shdr); size += roundup(sizeof (shstr), SH_ADDRALIGN); if (d[DI_HASH] != NULL) { Word hash[2]; hptr = d[DI_HASH]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) hptr += addr; if (Pread(P, hash, sizeof (hash), hptr) != sizeof (hash)) { dprintf("Pread of .hash at %lx failed\n", (long)(hptr)); goto bad; } hnbuckets = hash[0]; hnchains = hash[1]; } /* * .dynsym and .SUNW_ldynsym sections. * * The string table section used for the symbol table and * dynamic sections lies immediately after the dynsym, so the * presence of SUNW_ldynsym changes the dynstr section index. */ if (d[DI_SUNW_SYMTAB] != NULL) { size += sizeof (Shdr); /* SUNW_ldynsym shdr */ ldynsym_size = (size_t)d[DI_SUNW_SYMSZ]->d_un.d_val; dynsym_size = ldynsym_size - (d[DI_SYMTAB]->d_un.d_ptr - d[DI_SUNW_SYMTAB]->d_un.d_ptr); ldynsym_size -= dynsym_size; dynstr_shndx = 4; } else { dynsym_size = sizeof (Sym) * hnchains; ldynsym_size = 0; dynstr_shndx = 3; } size += sizeof (Shdr) + ldynsym_size + dynsym_size; /* .dynstr section */ size += sizeof (Shdr); size += roundup(d[DI_STRSZ]->d_un.d_val, SH_ADDRALIGN); /* .dynamic section */ size += sizeof (Shdr); size += roundup(phdr->p_filesz, SH_ADDRALIGN); /* .plt section */ if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL && d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) { size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val; if (d[DI_PLTREL]->d_un.d_val == DT_RELA) { pltentries = pltrelsz / sizeof (Rela); } else if (d[DI_PLTREL]->d_un.d_val == DT_REL) { pltentries = pltrelsz / sizeof (Rel); } else { /* fall back to the platform default */ #if ((defined(__i386) || defined(__amd64)) && !defined(_ELF64)) pltentries = pltrelsz / sizeof (Rel); dprintf("DI_PLTREL not found, defaulting to Rel"); #else /* (!(__i386 || __amd64)) || _ELF64 */ pltentries = pltrelsz / sizeof (Rela); dprintf("DI_PLTREL not found, defaulting to Rela"); #endif /* (!(__i386 || __amd64) || _ELF64 */ } if (pltentries < PLTREL_MIN_ENTRIES) { dprintf("too few PLT relocation entries " "(found %lu, expected at least %d)\n", (long)pltentries, PLTREL_MIN_ENTRIES); goto bad; } if (pltentries < PLTREL_MIN_ENTRIES + 2) goto done_with_plt; /* * Now that we know the number of plt relocation entries * we can calculate the size of the plt. */ pltsz = (pltentries + M_PLT_XNumber) * M_PLT_ENTSIZE; #if defined(__sparc) /* The sparc PLT always has a (delay slot) nop at the end */ pltsz += 4; #endif /* __sparc */ size += sizeof (Shdr); size += roundup(pltsz, SH_ADDRALIGN); } done_with_plt: if ((elfdata = calloc(1, size)) == NULL) { dprintf("failed to allocate size %ld\n", (long)size); goto bad; } /* LINTED - alignment */ ep = (Ehdr *)elfdata; (void) memcpy(ep, ehdr, offsetof(Ehdr, e_phoff)); ep->e_ehsize = sizeof (Ehdr); ep->e_phoff = sizeof (Ehdr); ep->e_phentsize = ehdr->e_phentsize; ep->e_phnum = phnum; ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize; ep->e_shentsize = sizeof (Shdr); /* * Plt and SUNW_ldynsym sections are optional. C logical * binary operators return a 0 or 1 value, so the following * adds 1 for each optional section present. */ ep->e_shnum = 5 + (pltsz != 0) + (d[DI_SUNW_SYMTAB] != NULL); ep->e_shstrndx = 1; /* LINTED - alignment */ sp = (Shdr *)(elfdata + ep->e_shoff); off = ep->e_shoff + ep->e_shentsize * ep->e_shnum; /* * Copying the program headers directly from the process's * address space is a little suspect, but since we only * use them for their address and size values, this is fine. */ if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize, addr + ehdr->e_phoff) != phnum * ep->e_phentsize) { dprintf("failed to read program headers\n"); goto bad; } /* * The first elf section is always skipped. */ sp++; /* * Section Header: .shstrtab */ sp->sh_name = SHSTR_NDX_shstrtab; sp->sh_type = SHT_STRTAB; sp->sh_flags = SHF_STRINGS; sp->sh_addr = 0; sp->sh_offset = off; sp->sh_size = sizeof (shstr); sp->sh_link = 0; sp->sh_info = 0; sp->sh_addralign = 1; sp->sh_entsize = 0; (void) memcpy(&elfdata[off], shstr, sizeof (shstr)); off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .SUNW_ldynsym */ if (d[DI_SUNW_SYMTAB] != NULL) { sp->sh_name = SHSTR_NDX_SUNW_ldynsym; sp->sh_type = SHT_SUNW_LDYNSYM; sp->sh_flags = SHF_ALLOC; sp->sh_addr = d[DI_SUNW_SYMTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = ldynsym_size; sp->sh_link = dynstr_shndx; /* Index of 1st global in table that has none == # items */ sp->sh_info = sp->sh_size / sizeof (Sym); sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = sizeof (Sym); if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .SUNW_ldynsym at %lx\n", (long)sp->sh_addr); goto bad; } off += sp->sh_size; /* No need to round up ldynsym data. Dynsym data is same type */ sp++; } /* * Section Header: .dynsym */ sp->sh_name = SHSTR_NDX_dynsym; sp->sh_type = SHT_DYNSYM; sp->sh_flags = SHF_ALLOC; sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = dynsym_size; sp->sh_link = dynstr_shndx; sp->sh_info = 1; /* Index of 1st global in table */ sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = sizeof (Sym); if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .dynsym at %lx\n", (long)sp->sh_addr); goto bad; } off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .dynstr */ sp->sh_name = SHSTR_NDX_dynstr; sp->sh_type = SHT_STRTAB; sp->sh_flags = SHF_ALLOC | SHF_STRINGS; sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = d[DI_STRSZ]->d_un.d_val; sp->sh_link = 0; sp->sh_info = 0; sp->sh_addralign = 1; sp->sh_entsize = 0; if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .dynstr\n"); goto bad; } off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .dynamic */ sp->sh_name = SHSTR_NDX_dynamic; sp->sh_type = SHT_DYNAMIC; sp->sh_flags = SHF_WRITE | SHF_ALLOC; sp->sh_addr = phdr->p_vaddr; if (ehdr->e_type == ET_DYN) sp->sh_addr -= addr; sp->sh_offset = off; sp->sh_size = phdr->p_filesz; sp->sh_link = dynstr_shndx; sp->sh_info = 0; sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = sizeof (Dyn); (void) memcpy(&elfdata[off], dp, sp->sh_size); off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; /* * Section Header: .plt */ if (pltsz != 0) { ulong_t plt_symhash; uint_t htmp, ndx; uintptr_t strtabptr, strtabname; Sym sym, *symtabptr; uint_t *hash; char strbuf[sizeof ("_PROCEDURE_LINKAGE_TABLE_")]; /* * Now we need to find the address of the plt by looking * up the "_PROCEDURE_LINKAGE_TABLE_" symbol. */ /* get the address of the symtab and strtab sections */ strtabptr = d[DI_STRTAB]->d_un.d_ptr; symtabptr = (Sym *)(uintptr_t)d[DI_SYMTAB]->d_un.d_ptr; if (ehdr->e_type == ET_DYN) { strtabptr += addr; symtabptr = (Sym*)((uintptr_t)symtabptr + addr); } if ((hptr == NULL) || (hnbuckets == 0) || (hnchains == 0)) { dprintf("empty or missing .hash\n"); goto badplt; } /* find the .hash bucket address for this symbol */ plt_symhash = elf_hash("_PROCEDURE_LINKAGE_TABLE_"); htmp = plt_symhash % hnbuckets; hash = &((uint_t *)hptr)[2 + htmp]; /* read the elf hash bucket index */ if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) != sizeof (ndx)) { dprintf("Pread of .hash at %lx failed\n", (long)hash); goto badplt; } while (ndx) { if (Pread(P, &sym, sizeof (sym), (uintptr_t)&symtabptr[ndx]) != sizeof (sym)) { dprintf("Pread of .symtab at %lx failed\n", (long)&symtabptr[ndx]); goto badplt; } strtabname = strtabptr + sym.st_name; if (Pread_string(P, strbuf, sizeof (strbuf), strtabname) < 0) { dprintf("Pread of .strtab at %lx failed\n", (long)strtabname); goto badplt; } if (strcmp("_PROCEDURE_LINKAGE_TABLE_", strbuf) == 0) break; hash = &((uint_t *)hptr)[2 + hnbuckets + ndx]; if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) != sizeof (ndx)) { dprintf("Pread of .hash at %lx failed\n", (long)hash); goto badplt; } } #if defined(__sparc) if (sym.st_value != d[DI_PLTGOT]->d_un.d_ptr) { dprintf("warning: DI_PLTGOT (%lx) doesn't match " ".plt symbol pointer (%lx)", (long)d[DI_PLTGOT]->d_un.d_ptr, (long)sym.st_value); } #endif /* __sparc */ if (ndx == 0) { dprintf( "Failed to find \"_PROCEDURE_LINKAGE_TABLE_\"\n"); goto badplt; } sp->sh_name = SHSTR_NDX_plt; sp->sh_type = SHT_PROGBITS; sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; sp->sh_addr = sym.st_value; if (ehdr->e_type == ET_DYN) sp->sh_addr += addr; sp->sh_offset = off; sp->sh_size = pltsz; sp->sh_link = 0; sp->sh_info = 0; sp->sh_addralign = SH_ADDRALIGN; sp->sh_entsize = M_PLT_ENTSIZE; if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) != sp->sh_size) { dprintf("failed to read .plt at %lx\n", (long)sp->sh_addr); goto badplt; } off += roundup(sp->sh_size, SH_ADDRALIGN); sp++; } badplt: /* make sure we didn't write past the end of allocated memory */ sp++; assert(((uintptr_t)(sp) - 1) < ((uintptr_t)elfdata + size)); free(dp); if ((elf = elf_memory(elfdata, size)) == NULL) { dprintf("failed to create ELF object " "in memory for size %ld\n", (long)size); free(elfdata); return (NULL); } fptr->file_elfmem = elfdata; return (elf); bad: if (dp != NULL) free(dp); if (elfdata != NULL) free(elfdata); return (NULL); }
/*ARGSUSED*/ int dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) { uint8_t *text; ulong_t i, end; int size; pid_t pid = Pstatus(P)->pr_pid; char dmodel = Pstatus(P)->pr_dmodel; /* * We allocate a few extra bytes at the end so we don't have to check * for overrunning the buffer. */ if ((text = calloc(1, symp->st_size + 4)) == NULL) { dt_dprintf("mr sparkle: malloc() failed\n"); return (DT_PROC_ERR); } if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { dt_dprintf("mr sparkle: Pread() failed\n"); free(text); return (DT_PROC_ERR); } ftp->ftps_probe_type = DTFTP_RETURN; ftp->ftps_pc = symp->st_value; ftp->ftps_size = (size_t)symp->st_size; ftp->ftps_noffs = 0; /* * If there's a jump table in the function we're only willing to * instrument these specific (and equivalent) instruction sequences: * leave * [rep] ret * and * movl %ebp,%esp * popl %ebp * [rep] ret * * We do this to avoid accidentally interpreting jump table * offsets as actual instructions. */ if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { for (i = 0, end = ftp->ftps_size; i < end; i += size) { size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); /* bail if we hit an invalid opcode */ if (size <= 0) break; if (text[i] == DT_LEAVE && text[i + 1] == DT_RET) { dt_dprintf("leave/ret at %lx\n", i + 1); ftp->ftps_offs[ftp->ftps_noffs++] = i + 1; size = 2; } else if (text[i] == DT_LEAVE && text[i + 1] == DT_REP && text[i + 2] == DT_RET) { dt_dprintf("leave/rep ret at %lx\n", i + 1); ftp->ftps_offs[ftp->ftps_noffs++] = i + 1; size = 3; } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP && text[i + 2] == DT_POPL_EBP && text[i + 3] == DT_RET) { dt_dprintf("movl/popl/ret at %lx\n", i + 3); ftp->ftps_offs[ftp->ftps_noffs++] = i + 3; size = 4; } else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP && text[i + 2] == DT_POPL_EBP && text[i + 3] == DT_REP && text[i + 4] == DT_RET) { dt_dprintf("movl/popl/rep ret at %lx\n", i + 3); ftp->ftps_offs[ftp->ftps_noffs++] = i + 3; size = 5; } } } else { for (i = 0, end = ftp->ftps_size; i < end; i += size) { size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); /* bail if we hit an invalid opcode */ if (size <= 0) break; /* ordinary ret */ if (size == 1 && text[i] == DT_RET) goto is_ret; /* two-byte ret */ if (size == 2 && text[i] == DT_REP && text[i + 1] == DT_RET) goto is_ret; /* ret <imm16> */ if (size == 3 && text[i] == DT_RET16) goto is_ret; /* two-byte ret <imm16> */ if (size == 4 && text[i] == DT_REP && text[i + 1] == DT_RET16) goto is_ret; /* 32-bit displacement jmp outside of the function */ if (size == 5 && text[i] == DT_JMP32 && symp->st_size <= (uintptr_t)(i + size + *(int32_t *)&text[i + 1])) goto is_ret; /* 8-bit displacement jmp outside of the function */ if (size == 2 && text[i] == DT_JMP8 && symp->st_size <= (uintptr_t)(i + size + *(int8_t *)&text[i + 1])) goto is_ret; /* 32-bit disp. conditional jmp outside of the func. */ if (size == 6 && DT_ISJ32(*(uint16_t *)&text[i]) && symp->st_size <= (uintptr_t)(i + size + *(int32_t *)&text[i + 2])) goto is_ret; /* 8-bit disp. conditional jmp outside of the func. */ if (size == 2 && DT_ISJ8(text[i]) && symp->st_size <= (uintptr_t)(i + size + *(int8_t *)&text[i + 1])) goto is_ret; continue; is_ret: dt_dprintf("return at offset %lx\n", i); ftp->ftps_offs[ftp->ftps_noffs++] = i; } } free(text); if (ftp->ftps_noffs > 0) { if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { dt_dprintf("fasttrap probe creation ioctl failed: %s\n", strerror(errno)); return (dt_set_errno(dtp, errno)); } } return (ftp->ftps_noffs); }
/*ARGSUSED*/ int dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) { ftp->ftps_probe_type = DTFTP_OFFSETS; ftp->ftps_pc = symp->st_value; ftp->ftps_size = (size_t)symp->st_size; ftp->ftps_noffs = 1; if (strcmp("-", ftp->ftps_func) == 0) { ftp->ftps_offs[0] = off; } else { uint8_t *text; ulong_t i; int size; pid_t pid = Pstatus(P)->pr_pid; char dmodel = Pstatus(P)->pr_dmodel; if ((text = malloc(symp->st_size)) == NULL) { dt_dprintf("mr sparkle: malloc() failed\n"); return (DT_PROC_ERR); } if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { dt_dprintf("mr sparkle: Pread() failed\n"); free(text); return (DT_PROC_ERR); } /* * We can't instrument offsets in functions with jump tables * as we might interpret a jump table offset as an * instruction. */ if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { free(text); return (0); } for (i = 0; i < symp->st_size; i += size) { if (i == off) { ftp->ftps_offs[0] = i; break; } /* * If we've passed the desired offset without a * match, then the given offset must not lie on a * instruction boundary. */ if (i > off) { free(text); return (DT_PROC_ALIGN); } size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); /* * If we hit an invalid instruction, bail as if we * couldn't find the offset. */ if (size <= 0) { free(text); return (DT_PROC_ALIGN); } } free(text); } if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { dt_dprintf("fasttrap probe creation ioctl failed: %s\n", strerror(errno)); return (dt_set_errno(dtp, errno)); } return (ftp->ftps_noffs); }
/* * 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); } }
static void read_dumphdr(void) { if (filemode) dumpfd = Open(dumpfile, O_RDONLY, 0644); else dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644); endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET; Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff); Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + sizeof (dumphdr)); pagesize = dumphdr.dump_pagesize; if (dumphdr.dump_magic != DUMP_MAGIC) logprint(SC_SL_NONE | SC_EXIT_PEND, "bad magic number %x", dumphdr.dump_magic); if ((dumphdr.dump_flags & DF_VALID) == 0 && !disregard_valid_flag) logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK, "dump already processed"); if (dumphdr.dump_version != DUMP_VERSION) logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND, "dump version (%d) != %s version (%d)", dumphdr.dump_version, progname, DUMP_VERSION); if (dumphdr.dump_wordsize != DUMP_WORDSIZE) logprint(SC_SL_NONE | SC_EXIT_PEND, "dump is from %u-bit kernel - cannot save on %u-bit kernel", dumphdr.dump_wordsize, DUMP_WORDSIZE); if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) { if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION) logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND, "dump data version (%d) != %s data version (%d)", datahdr.dump_datahdr_version, progname, DUMP_DATAHDR_VERSION); } else { (void) memset(&datahdr, 0, sizeof (datahdr)); datahdr.dump_maxcsize = pagesize; } /* * Read the initial header, clear the valid bits, and compare headers. * The main header may have been overwritten by swapping if we're * using a swap partition as the dump device, in which case we bail. */ Pread(dumpfd, &corehdr, sizeof (dumphdr_t), dumphdr.dump_start); corehdr.dump_flags &= ~DF_VALID; dumphdr.dump_flags &= ~DF_VALID; if (memcmp(&corehdr, &dumphdr, sizeof (dumphdr_t)) != 0) { /* * Clear valid bit so we don't complain on every invocation. */ if (!filemode) Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff); logprint(SC_SL_ERR | SC_EXIT_ERR, "initial dump header corrupt"); } }
/*ARGSUSED*/ static int dump_map(void *data, const prmap_t *pmp, const char *name) { pgcore_t *pgc = data; struct ps_prochandle *P = pgc->P; #ifdef _LP64 Elf64_Phdr phdr; #else Elf32_Phdr phdr; #endif size_t n; bzero(&phdr, sizeof (phdr)); phdr.p_type = PT_LOAD; phdr.p_vaddr = pmp->pr_vaddr; phdr.p_memsz = pmp->pr_size; if (pmp->pr_mflags & MA_READ) phdr.p_flags |= PF_R; if (pmp->pr_mflags & MA_WRITE) phdr.p_flags |= PF_W; if (pmp->pr_mflags & MA_EXEC) phdr.p_flags |= PF_X; if (pmp->pr_vaddr + pmp->pr_size > P->status.pr_stkbase && pmp->pr_vaddr < P->status.pr_stkbase + P->status.pr_stksize) { if (!(pgc->pgc_content & CC_CONTENT_STACK)) goto exclude; } else if ((pmp->pr_mflags & MA_ANON) && pmp->pr_vaddr + pmp->pr_size > P->status.pr_brkbase && pmp->pr_vaddr < P->status.pr_brkbase + P->status.pr_brksize) { if (!(pgc->pgc_content & CC_CONTENT_HEAP)) goto exclude; } else if (pmp->pr_mflags & MA_ISM) { if (pmp->pr_mflags & MA_NORESERVE) { if (!(pgc->pgc_content & CC_CONTENT_DISM)) goto exclude; } else { if (!(pgc->pgc_content & CC_CONTENT_ISM)) goto exclude; } } else if (pmp->pr_mflags & MA_SHM) { if (!(pgc->pgc_content & CC_CONTENT_SHM)) goto exclude; } else if (pmp->pr_mflags & MA_SHARED) { if (pmp->pr_mflags & MA_ANON) { if (!(pgc->pgc_content & CC_CONTENT_SHANON)) goto exclude; } else { if (!(pgc->pgc_content & CC_CONTENT_SHFILE)) goto exclude; } } else if (pmp->pr_mflags & MA_ANON) { if (!(pgc->pgc_content & CC_CONTENT_ANON)) goto exclude; } else if (phdr.p_flags == (PF_R | PF_X)) { if (!(pgc->pgc_content & CC_CONTENT_TEXT)) goto exclude; } else if (phdr.p_flags == PF_R) { if (!(pgc->pgc_content & CC_CONTENT_RODATA)) goto exclude; } else { if (!(pgc->pgc_content & CC_CONTENT_DATA)) goto exclude; } n = 0; while (n < pmp->pr_size) { size_t csz = MIN(pmp->pr_size - n, pgc->pgc_chunksz); /* * If we can't read out part of the victim's address * space for some reason ignore that failure and try to * emit a partial core file without that mapping's data. * As in the kernel, we mark these failures with the * PF_SUNW_FAILURE flag and store the errno where the * mapping would have been. */ if (Pread(P, pgc->pgc_chunk, csz, pmp->pr_vaddr + n) != csz || gc_pwrite64(pgc->pgc_fd, pgc->pgc_chunk, csz, *pgc->pgc_doff + n) != 0) { int err = errno; (void) gc_pwrite64(pgc->pgc_fd, &err, sizeof (err), *pgc->pgc_doff); *pgc->pgc_doff += roundup(sizeof (err), 8); phdr.p_flags |= PF_SUNW_FAILURE; (void) ftruncate64(pgc->pgc_fd, *pgc->pgc_doff); goto exclude; } n += csz; } phdr.p_offset = *pgc->pgc_doff; phdr.p_filesz = pmp->pr_size; *pgc->pgc_doff += roundup(phdr.p_filesz, 8); exclude: if (P->status.pr_dmodel == PR_MODEL_NATIVE) { if (gc_pwrite64(pgc->pgc_fd, &phdr, sizeof (phdr), *pgc->pgc_poff) != 0) return (1); *pgc->pgc_poff += sizeof (phdr); #ifdef _LP64 } else { Elf32_Phdr phdr32; bzero(&phdr32, sizeof (phdr32)); phdr32.p_type = phdr.p_type; phdr32.p_vaddr = (Elf32_Addr)phdr.p_vaddr; phdr32.p_memsz = (Elf32_Word)phdr.p_memsz; phdr32.p_flags = phdr.p_flags; phdr32.p_offset = (Elf32_Off)phdr.p_offset; phdr32.p_filesz = (Elf32_Word)phdr.p_filesz; if (gc_pwrite64(pgc->pgc_fd, &phdr32, sizeof (phdr32), *pgc->pgc_poff) != 0) return (1); *pgc->pgc_poff += sizeof (phdr32); #endif /* _LP64 */ } return (0); }
int Pstack_iter(struct ps_prochandle *P, const prgregset_t regs, proc_stack_f *func, void *arg) { struct { uintptr_t fp; uintptr_t pc; } frame; uint_t pfpsize = 0; prgreg_t *prevfp = NULL; prgreg_t fp, pfp; prgreg_t pc; prgregset_t gregs; int nfp = 0; uclist_t ucl; int rv = 0; int argc; uintptr_t uc_addr; ucontext_t uc; /* * Type definition for a structure corresponding to an IA32 * signal frame. Refer to the comments in Pstack.c for more info */ typedef struct { prgreg_t fp; prgreg_t pc; prgreg_t signo; siginfo_t *sip; } sigframe_t; prgreg_t args[32] = {0}; if (P->status.pr_dmodel != PR_MODEL_LP64) return (Pstack_iter32(P, regs, func, arg)); init_uclist(&ucl, P); (void) memcpy(gregs, regs, sizeof (gregs)); fp = gregs[R_FP]; pc = gregs[R_PC]; while (fp != 0 || pc != 0) { if (stack_loop(fp, &prevfp, &nfp, &pfpsize)) break; if (fp != 0 && Pread(P, &frame, sizeof (frame), (uintptr_t)fp) == sizeof (frame)) { if (frame.pc == -1) { argc = 3; args[2] = fp + sizeof (sigframe_t); if (Pread(P, &args, 2 * sizeof (prgreg_t), fp + 2 * sizeof (prgreg_t)) != 2 * sizeof (prgreg_t)) argc = 0; } else { argc = read_args(P, fp, pc, args, sizeof (args)); } } else { (void) memset(&frame, 0, sizeof (frame)); argc = 0; } gregs[R_FP] = fp; gregs[R_PC] = pc; if ((rv = func(arg, gregs, argc, args)) != 0) break; pfp = fp; fp = frame.fp; pc = frame.pc; if (pc == -1 && find_uclink(&ucl, pfp + sizeof (sigframe_t))) { uc_addr = pfp + sizeof (sigframe_t); if (Pread(P, &uc, sizeof (uc), uc_addr) == sizeof (uc)) { ucontext_n_to_prgregs(&uc, gregs); fp = gregs[R_FP]; pc = gregs[R_PC]; } } } if (prevfp) free(prevfp); free_uclist(&ucl); return (rv); }
int Psyscall_copyoutargs(struct ps_prochandle *P, int nargs, argdes_t *argp, uintptr_t ap) { if (P->status.pr_dmodel == PR_MODEL_ILP32) { uint32_t arglist[MAXARGS + 2]; int i; argdes_t *adp; if (Pread(P, &arglist[0], sizeof (int) * (nargs+1), (uintptr_t)ap) != sizeof (int) * (nargs+1)) return (-1); for (i = 0, adp = argp; i < nargs; i++, adp++) adp->arg_value = arglist[i]; } else { int pusharg = (nargs > 6) ? nargs - 6: 0; int64_t arglist[MAXARGS+2]; int i; argdes_t *adp; if (pusharg > 0 && Pread(P, &arglist[0], sizeof (int64_t) * (pusharg + 1), ap) != sizeof (int64_t) * (pusharg + 1)) return (-1); for (i = 0, adp = argp; i < nargs; i++, adp++) { switch (i) { case 0: adp->arg_value = P->status.pr_lwp.pr_reg[REG_RDI]; break; case 1: adp->arg_value = P->status.pr_lwp.pr_reg[REG_RSI]; break; case 2: adp->arg_value = P->status.pr_lwp.pr_reg[REG_RDX]; break; case 3: adp->arg_value = P->status.pr_lwp.pr_reg[REG_RCX]; break; case 4: adp->arg_value = P->status.pr_lwp.pr_reg[REG_R8]; break; case 5: adp->arg_value = P->status.pr_lwp.pr_reg[REG_R9]; break; default: adp->arg_value = arglist[i - 6]; break; } } return (0); } return (0); }