dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libproc / i386 / Pisadep.c
blob65892c99eadfa462e812022274a5a71b5c67b89f
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/stack.h>
27 #include <sys/regset.h>
28 #include <sys/frame.h>
29 #include <sys/sysmacros.h>
30 #include <sys/trap.h>
31 #include <sys/machelf.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <errno.h>
37 #include <string.h>
39 #include "Pcontrol.h"
40 #include "Pstack.h"
42 static uchar_t int_syscall_instr[] = { 0xCD, T_SYSCALLINT };
44 const char *
45 Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr)
47 map_info_t *mp = Paddr2mptr(P, pltaddr);
49 uintptr_t r_addr;
50 file_info_t *fp;
51 Elf32_Rel r;
52 size_t i;
54 if (mp == NULL || (fp = mp->map_file) == NULL ||
55 fp->file_plt_base == 0 ||
56 pltaddr - fp->file_plt_base >= fp->file_plt_size) {
57 errno = EINVAL;
58 return (NULL);
61 i = (pltaddr - fp->file_plt_base) / M_PLT_ENTSIZE - M_PLT_XNumber;
63 r_addr = fp->file_jmp_rel + i * sizeof (r);
65 if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) &&
66 (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) {
68 Elf_Data *data = fp->file_dynsym.sym_data_pri;
69 Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]);
71 return (fp->file_dynsym.sym_strs + symp->st_name);
74 return (NULL);
77 int
78 Pissyscall(struct ps_prochandle *P, uintptr_t addr)
80 uchar_t instr[16];
82 if (Pread(P, instr, sizeof (int_syscall_instr), addr) !=
83 sizeof (int_syscall_instr))
84 return (0);
86 if (memcmp(instr, int_syscall_instr, sizeof (int_syscall_instr)) == 0)
87 return (1);
89 return (0);
92 int
93 Pissyscall_prev(struct ps_prochandle *P, uintptr_t addr, uintptr_t *dst)
95 int ret;
97 if (ret = Pissyscall(P, addr - sizeof (int_syscall_instr))) {
98 if (dst)
99 *dst = addr - sizeof (int_syscall_instr);
100 return (ret);
103 return (0);
106 /* ARGSUSED */
108 Pissyscall_text(struct ps_prochandle *P, const void *buf, size_t buflen)
110 if (buflen < sizeof (int_syscall_instr))
111 return (0);
113 if (memcmp(buf, int_syscall_instr, sizeof (int_syscall_instr)) == 0)
114 return (1);
116 return (0);
119 #define TR_ARG_MAX 6 /* Max args to print, same as SPARC */
122 * Given a return address, determine the likely number of arguments
123 * that were pushed on the stack prior to its execution. We do this by
124 * expecting that a typical call sequence consists of pushing arguments on
125 * the stack, executing a call instruction, and then performing an add
126 * on %esp to restore it to the value prior to pushing the arguments for
127 * the call. We attempt to detect such an add, and divide the addend
128 * by the size of a word to determine the number of pushed arguments.
130 * If we do not find such an add, this does not necessarily imply that the
131 * function took no arguments. It is not possible to reliably detect such a
132 * void function because hand-coded assembler does not always perform an add
133 * to %esp immediately after the "call" instruction (eg. _sys_call()).
134 * Because of this, we default to returning MIN(sz, TR_ARG_MAX) instead of 0
135 * in the absence of an add to %esp.
137 static ulong_t
138 argcount(struct ps_prochandle *P, long pc, ssize_t sz)
140 uchar_t instr[6];
141 ulong_t count, max;
143 max = MIN(sz / sizeof (long), TR_ARG_MAX);
146 * Read the instruction at the return location.
148 if (Pread(P, instr, sizeof (instr), pc) != sizeof (instr) ||
149 instr[1] != 0xc4)
150 return (max);
152 switch (instr[0]) {
153 case 0x81: /* count is a longword */
154 count = instr[2]+(instr[3]<<8)+(instr[4]<<16)+(instr[5]<<24);
155 break;
156 case 0x83: /* count is a byte */
157 count = instr[2];
158 break;
159 default:
160 return (max);
163 count /= sizeof (long);
164 return (MIN(count, max));
167 static void
168 ucontext_n_to_prgregs(const ucontext_t *src, prgregset_t dst)
170 (void) memcpy(dst, src->uc_mcontext.gregs, sizeof (gregset_t));
174 Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
175 proc_stack_f *func, void *arg)
177 prgreg_t *prevfp = NULL;
178 uint_t pfpsize = 0;
179 int nfp = 0;
180 struct {
181 long fp;
182 long pc;
183 long args[32];
184 } frame;
185 uint_t argc;
186 ssize_t sz;
187 prgregset_t gregs;
188 prgreg_t fp, pfp;
189 prgreg_t pc;
190 int rv;
193 * Type definition for a structure corresponding to an IA32
194 * signal frame. Refer to the comments in Pstack.c for more info
196 typedef struct {
197 long fp;
198 long pc;
199 int signo;
200 ucontext_t *ucp;
201 siginfo_t *sip;
202 } sf_t;
204 uclist_t ucl;
205 ucontext_t uc;
206 uintptr_t uc_addr;
208 init_uclist(&ucl, P);
209 (void) memcpy(gregs, regs, sizeof (gregs));
211 fp = regs[R_FP];
212 pc = regs[R_PC];
214 while (fp != 0 || pc != 0) {
215 if (stack_loop(fp, &prevfp, &nfp, &pfpsize))
216 break;
218 if (fp != 0 &&
219 (sz = Pread(P, &frame, sizeof (frame), (uintptr_t)fp)
220 >= (ssize_t)(2* sizeof (long)))) {
222 * One more trick for signal frames: the kernel sets
223 * the return pc of the signal frame to 0xffffffff on
224 * Intel IA32, so argcount won't work.
226 if (frame.pc != -1L) {
227 sz -= 2* sizeof (long);
228 argc = argcount(P, (long)frame.pc, sz);
229 } else
230 argc = 3; /* sighandler(signo, sip, ucp) */
231 } else {
232 (void) memset(&frame, 0, sizeof (frame));
233 argc = 0;
236 gregs[R_FP] = fp;
237 gregs[R_PC] = pc;
239 if ((rv = func(arg, gregs, argc, frame.args)) != 0)
240 break;
243 * In order to allow iteration over java frames (which can have
244 * their own frame pointers), we allow the iterator to change
245 * the contents of gregs. If we detect a change, then we assume
246 * that the new values point to the next frame.
248 if (gregs[R_FP] != fp || gregs[R_PC] != pc) {
249 fp = gregs[R_FP];
250 pc = gregs[R_PC];
251 continue;
254 pfp = fp;
255 fp = frame.fp;
256 pc = frame.pc;
258 if (find_uclink(&ucl, pfp + sizeof (sf_t)))
259 uc_addr = pfp + sizeof (sf_t);
260 else
261 uc_addr = (uintptr_t)NULL;
263 if (uc_addr != (uintptr_t)NULL &&
264 Pread(P, &uc, sizeof (uc), uc_addr) == sizeof (uc)) {
266 ucontext_n_to_prgregs(&uc, gregs);
267 fp = gregs[R_FP];
268 pc = gregs[R_PC];
272 free(prevfp);
274 free_uclist(&ucl);
275 return (rv);
278 uintptr_t
279 Psyscall_setup(struct ps_prochandle *P, int nargs, int sysindex, uintptr_t sp)
281 sp -= sizeof (int) * (nargs+2); /* space for arg list + CALL parms */
283 P->status.pr_lwp.pr_reg[EAX] = sysindex;
284 P->status.pr_lwp.pr_reg[R_SP] = sp;
285 P->status.pr_lwp.pr_reg[R_PC] = P->sysaddr;
287 return (sp);
291 Psyscall_copyinargs(struct ps_prochandle *P, int nargs, argdes_t *argp,
292 uintptr_t ap)
294 int32_t arglist[MAXARGS+2];
295 int i;
296 argdes_t *adp;
298 for (i = 0, adp = argp; i < nargs; i++, adp++)
299 arglist[1 + i] = (int32_t)adp->arg_value;
301 arglist[0] = P->status.pr_lwp.pr_reg[R_PC];
302 if (Pwrite(P, &arglist[0], sizeof (int) * (nargs+1),
303 (uintptr_t)ap) != sizeof (int) * (nargs+1))
304 return (-1);
306 return (0);
310 Psyscall_copyoutargs(struct ps_prochandle *P, int nargs, argdes_t *argp,
311 uintptr_t ap)
313 uint32_t arglist[MAXARGS + 2];
314 int i;
315 argdes_t *adp;
317 if (Pread(P, &arglist[0], sizeof (int) * (nargs+1), (uintptr_t)ap)
318 != sizeof (int) * (nargs+1))
319 return (-1);
321 for (i = 0, adp = argp; i < nargs; i++, adp++)
322 adp->arg_value = arglist[i];
324 return (0);