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