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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/stack.h> 30 #include <sys/regset.h> 31 #include <sys/frame.h> 32 #include <sys/sysmacros.h> 33 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <sys/types.h> 37 #include <errno.h> 38 #include <string.h> 39 40 #include "Pcontrol.h" 41 #include "Pstack.h" 42 #include "Pisadep.h" 43 44 #define M_PLT_NRSV 4 /* reserved PLT entries */ 45 #define M_PLT_ENTSIZE 12 /* size of each PLT entry */ 46 47 #define SYSCALL32 0x91d02008 /* 32-bit syscall (ta 8) instruction */ 48 49 #ifndef WINDOWSIZE32 50 #define WINDOWSIZE32 (16 * sizeof (int32_t)) 51 #endif 52 53 const char * 54 Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr) 55 { 56 map_info_t *mp = Paddr2mptr(P, pltaddr); 57 58 uintptr_t r_addr; 59 file_info_t *fp; 60 Elf32_Rela r; 61 size_t i; 62 63 if (mp == NULL || (fp = mp->map_file) == NULL || 64 fp->file_plt_base == 0 || pltaddr < fp->file_plt_base || 65 pltaddr >= fp->file_plt_base + fp->file_plt_size) { 66 errno = EINVAL; 67 return (NULL); 68 } 69 70 i = (pltaddr - fp->file_plt_base - 71 M_PLT_NRSV * M_PLT_ENTSIZE) / M_PLT_ENTSIZE; 72 73 r_addr = fp->file_jmp_rel + i * sizeof (Elf32_Rela); 74 75 if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) && 76 (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) { 77 78 Elf_Data *data = fp->file_dynsym.sym_data; 79 Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]); 80 81 return (fp->file_dynsym.sym_strs + symp->st_name); 82 } 83 84 return (NULL); 85 } 86 87 int 88 Pissyscall(struct ps_prochandle *P, uintptr_t addr) 89 { 90 instr_t sysinstr; 91 instr_t instr; 92 93 sysinstr = SYSCALL32; 94 95 if (Pread(P, &instr, sizeof (instr), addr) != sizeof (instr) || 96 instr != sysinstr) 97 return (0); 98 else 99 return (1); 100 } 101 102 int 103 Pissyscall_prev(struct ps_prochandle *P, uintptr_t addr, uintptr_t *dst) 104 { 105 uintptr_t prevaddr = addr - sizeof (instr_t); 106 107 if (Pissyscall(P, prevaddr)) { 108 if (dst) 109 *dst = prevaddr; 110 return (1); 111 } 112 113 return (0); 114 } 115 116 /* ARGSUSED */ 117 int 118 Pissyscall_text(struct ps_prochandle *P, const void *buf, size_t buflen) 119 { 120 instr_t sysinstr; 121 122 sysinstr = SYSCALL32; 123 124 if (buflen >= sizeof (instr_t) && 125 memcmp(buf, &sysinstr, sizeof (instr_t)) == 0) 126 return (1); 127 else 128 return (0); 129 } 130 131 /* 132 * For gwindows_t support, we define a structure to pass arguments to 133 * a Plwp_iter() callback routine. 134 */ 135 typedef struct { 136 struct ps_prochandle *gq_proc; /* libproc handle */ 137 struct rwindow *gq_rwin; /* rwindow destination buffer */ 138 uintptr_t gq_addr; /* stack address to match */ 139 } gwin_query_t; 140 141 static int 142 find_gwin(gwin_query_t *gqp, const lwpstatus_t *psp) 143 { 144 gwindows_t gwin; 145 struct stat64 st; 146 char path[64]; 147 ssize_t n; 148 int fd, i; 149 int rv = 0; /* Return value for skip to next lwp */ 150 151 (void) snprintf(path, sizeof (path), "/proc/%d/lwp/%d/gwindows", 152 (int)gqp->gq_proc->pid, (int)psp->pr_lwpid); 153 154 if (stat64(path, &st) == -1 || st.st_size == 0) 155 return (0); /* Nothing doing; skip to next lwp */ 156 157 if ((fd = open64(path, O_RDONLY)) >= 0) { 158 /* 159 * Zero out the gwindows_t because the gwindows file only has 160 * as much data as needed to represent the saved windows. 161 */ 162 (void) memset(&gwin, 0, sizeof (gwin)); 163 n = read(fd, &gwin, sizeof (gwin)); 164 165 if (n > 0) { 166 /* 167 * If we actually found a non-zero gwindows file and 168 * were able to read it, iterate through the buffers 169 * looking for a stack pointer match; if one is found, 170 * copy out the corresponding register window. 171 */ 172 for (i = 0; i < gwin.wbcnt; i++) { 173 if (gwin.spbuf[i] == (greg_t *)gqp->gq_addr) { 174 (void) memcpy(gqp->gq_rwin, 175 &gwin.wbuf[i], 176 sizeof (struct rwindow)); 177 178 rv = 1; /* We're done */ 179 break; 180 } 181 } 182 } 183 (void) close(fd); 184 } 185 186 return (rv); 187 } 188 189 static int 190 read_gwin(struct ps_prochandle *P, struct rwindow *rwp, uintptr_t sp) 191 { 192 gwin_query_t gq; 193 194 if (P->state == PS_DEAD) { 195 lwp_info_t *lwp = list_next(&P->core->core_lwp_head); 196 uint_t n; 197 int i; 198 199 for (n = 0; n < P->core->core_nlwp; n++, lwp = list_next(lwp)) { 200 gwindows_t *gwin = lwp->lwp_gwins; 201 202 if (gwin == NULL) 203 continue; /* No gwindows for this lwp */ 204 205 /* 206 * If this lwp has gwindows associated with it, iterate 207 * through the buffers looking for a stack pointer 208 * match; if one is found, copy out the register window. 209 */ 210 for (i = 0; i < gwin->wbcnt; i++) { 211 if (gwin->spbuf[i] == (greg_t *)sp) { 212 (void) memcpy(rwp, &gwin->wbuf[i], 213 sizeof (struct rwindow)); 214 return (0); /* We're done */ 215 } 216 } 217 } 218 219 return (-1); /* No gwindows match found */ 220 221 } 222 223 gq.gq_proc = P; 224 gq.gq_rwin = rwp; 225 gq.gq_addr = sp; 226 227 return (Plwp_iter(P, (proc_lwp_f *)find_gwin, &gq) ? 0 : -1); 228 } 229 230 static void 231 ucontext_n_to_prgregs(const ucontext_t *src, prgregset_t dst) 232 { 233 const greg_t *gregs = &src->uc_mcontext.gregs[0]; 234 235 dst[R_PSR] = gregs[REG_PSR]; 236 dst[R_PC] = gregs[REG_PC]; 237 dst[R_nPC] = gregs[REG_nPC]; 238 dst[R_Y] = gregs[REG_Y]; 239 240 dst[R_G1] = gregs[REG_G1]; 241 dst[R_G2] = gregs[REG_G2]; 242 dst[R_G3] = gregs[REG_G3]; 243 dst[R_G4] = gregs[REG_G4]; 244 dst[R_G5] = gregs[REG_G5]; 245 dst[R_G6] = gregs[REG_G6]; 246 dst[R_G7] = gregs[REG_G7]; 247 248 dst[R_O0] = gregs[REG_O0]; 249 dst[R_O1] = gregs[REG_O1]; 250 dst[R_O2] = gregs[REG_O2]; 251 dst[R_O3] = gregs[REG_O3]; 252 dst[R_O4] = gregs[REG_O4]; 253 dst[R_O5] = gregs[REG_O5]; 254 dst[R_O6] = gregs[REG_O6]; 255 dst[R_O7] = gregs[REG_O7]; 256 } 257 258 int 259 Pstack_iter(struct ps_prochandle *P, const prgregset_t regs, 260 proc_stack_f *func, void *arg) 261 { 262 prgreg_t *prevfp = NULL; 263 uint_t pfpsize = 0; 264 int nfp = 0; 265 prgregset_t gregs; 266 long args[6]; 267 prgreg_t fp; 268 int i; 269 int rv; 270 uintptr_t sp; 271 ssize_t n; 272 uclist_t ucl; 273 ucontext_t uc; 274 275 init_uclist(&ucl, P); 276 (void) memcpy(gregs, regs, sizeof (gregs)); 277 278 for (;;) { 279 fp = gregs[R_FP]; 280 if (stack_loop(fp, &prevfp, &nfp, &pfpsize)) 281 break; 282 283 for (i = 0; i < 6; i++) 284 args[i] = gregs[R_I0 + i]; 285 if ((rv = func(arg, gregs, 6, args)) != 0) 286 break; 287 288 gregs[R_PC] = gregs[R_I7]; 289 gregs[R_nPC] = gregs[R_PC] + 4; 290 (void) memcpy(&gregs[R_O0], &gregs[R_I0], 8*sizeof (prgreg_t)); 291 if ((sp = gregs[R_FP]) == 0) 292 break; 293 294 sp += STACK_BIAS; 295 296 if (find_uclink(&ucl, sp + SA(sizeof (struct frame))) && 297 Pread(P, &uc, sizeof (uc), sp + 298 SA(sizeof (struct frame))) == sizeof (uc)) { 299 ucontext_n_to_prgregs(&uc, gregs); 300 sp = gregs[R_SP] + STACK_BIAS; 301 } 302 303 n = Pread(P, &gregs[R_L0], sizeof (struct rwindow), sp); 304 305 if (n == sizeof (struct rwindow)) 306 continue; 307 308 /* 309 * If we get here, then our Pread of the register window 310 * failed. If this is because the address was not mapped, 311 * then we attempt to read this window via any gwindows 312 * information we have. If that too fails, abort our loop. 313 */ 314 if (n > 0) 315 break; /* Failed for reason other than not mapped */ 316 317 if (read_gwin(P, (struct rwindow *)&gregs[R_L0], sp) == -1) 318 break; /* No gwindows match either */ 319 } 320 321 if (prevfp) 322 free(prevfp); 323 324 free_uclist(&ucl); 325 return (rv); 326 } 327 328 uintptr_t 329 Psyscall_setup(struct ps_prochandle *P, int nargs, int sysindex, uintptr_t sp) 330 { 331 sp -= (nargs > 6)? 332 WINDOWSIZE32 + sizeof (int32_t) * (1 + nargs) : 333 WINDOWSIZE32 + sizeof (int32_t) * (1 + 6); 334 sp = PSTACK_ALIGN32(sp); 335 336 P->status.pr_lwp.pr_reg[R_G1] = sysindex; 337 P->status.pr_lwp.pr_reg[R_SP] = sp; 338 P->status.pr_lwp.pr_reg[R_PC] = P->sysaddr; 339 P->status.pr_lwp.pr_reg[R_nPC] = P->sysaddr + sizeof (instr_t); 340 341 return (sp + WINDOWSIZE32 + sizeof (int32_t)); 342 } 343 344 int 345 Psyscall_copyinargs(struct ps_prochandle *P, int nargs, argdes_t *argp, 346 uintptr_t ap) 347 { 348 uint32_t arglist[MAXARGS+2]; 349 int i; 350 argdes_t *adp; 351 352 for (i = 0, adp = argp; i < nargs; i++, adp++) { 353 arglist[i] = adp->arg_value; 354 355 if (i < 6) 356 (void) Pputareg(P, R_O0+i, adp->arg_value); 357 } 358 359 if (nargs > 6 && 360 Pwrite(P, &arglist[0], sizeof (int32_t) * nargs, 361 (uintptr_t)ap) != sizeof (int32_t) * nargs) 362 return (-1); 363 364 return (0); 365 } 366 367 /* ARGSUSED */ 368 int 369 Psyscall_copyoutargs(struct ps_prochandle *P, int nargs, argdes_t *argp, 370 uintptr_t ap) 371 { 372 /* Do nothing */ 373 return (0); 374 } 375