dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libproc / common / Pscantext.c
blob08470bcd22ff82f33697f59ab7e32b78000d7c24
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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <limits.h>
37 #include "libproc.h"
38 #include "Pcontrol.h"
39 #include "Pisadep.h"
40 #include "Putil.h"
42 #define BLKSIZE (8 * 1024)
45 * Look for a SYSCALL instruction in the process's address space.
47 int
48 Pscantext(struct ps_prochandle *P)
50 char mapfile[PATH_MAX];
51 int mapfd;
52 off_t offset; /* offset in text section */
53 off_t endoff; /* ending offset in text section */
54 uintptr_t sysaddr; /* address of SYSCALL instruction */
55 int syspri; /* priority of SYSCALL instruction */
56 int nbytes; /* number of bytes in buffer */
57 int n2bytes; /* number of bytes in second buffer */
58 int nmappings; /* current number of mappings */
59 prmap_t *pdp; /* pointer to map descriptor */
60 prmap_t *prbuf; /* buffer for map descriptors */
61 unsigned nmap; /* number of map descriptors */
62 uint32_t buf[2 * BLKSIZE / sizeof (uint32_t)]; /* text buffer */
63 uchar_t *p;
65 /* try the most recently-seen syscall address */
66 syspri = 0;
67 sysaddr = 0;
68 if (P->sysaddr != 0 &&
69 (syspri = Pissyscall(P, P->sysaddr)))
70 sysaddr = P->sysaddr;
72 /* try the previous instruction */
73 if (sysaddr == 0 || syspri != 1)
74 syspri = Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC],
75 &sysaddr);
77 if (sysaddr != 0 && syspri == 1) {
78 P->sysaddr = sysaddr;
79 return (0);
82 /* open the /proc/<pid>/map file */
83 (void) snprintf(mapfile, sizeof (mapfile), "%s/%d/map",
84 procfs_path, (int)P->pid);
85 if ((mapfd = open(mapfile, O_RDONLY)) < 0) {
86 dprintf("failed to open %s: %s\n", mapfile, strerror(errno));
87 return (-1);
90 /* allocate a plausible initial buffer size */
91 nmap = 50;
93 /* read all the map structures, allocating more space as needed */
94 for (;;) {
95 prbuf = malloc(nmap * sizeof (prmap_t));
96 if (prbuf == NULL) {
97 dprintf("Pscantext: failed to allocate buffer\n");
98 (void) close(mapfd);
99 return (-1);
101 nmappings = pread(mapfd, prbuf, nmap * sizeof (prmap_t), 0L);
102 if (nmappings < 0) {
103 dprintf("Pscantext: failed to read map file: %s\n",
104 strerror(errno));
105 free(prbuf);
106 (void) close(mapfd);
107 return (-1);
109 nmappings /= sizeof (prmap_t);
110 if (nmappings < nmap) /* we read them all */
111 break;
112 /* allocate a bigger buffer */
113 free(prbuf);
114 nmap *= 2;
116 (void) close(mapfd);
119 * Scan each executable mapping looking for a syscall instruction.
120 * In dynamically linked executables, syscall instructions are
121 * typically only found in shared libraries. Because shared libraries
122 * are most often mapped at the top of the address space, we minimize
123 * our expected search time by starting at the last mapping and working
124 * our way down to the first mapping.
126 for (pdp = &prbuf[nmappings - 1]; sysaddr == 0 && syspri != 1 &&
127 pdp >= prbuf; pdp--) {
129 offset = (off_t)pdp->pr_vaddr; /* beginning of text */
130 endoff = offset + pdp->pr_size;
132 /* avoid non-EXEC mappings; avoid the stack and heap */
133 if ((pdp->pr_mflags&MA_EXEC) == 0 ||
134 (endoff > P->status.pr_stkbase &&
135 offset < P->status.pr_stkbase + P->status.pr_stksize) ||
136 (endoff > P->status.pr_brkbase &&
137 offset < P->status.pr_brkbase + P->status.pr_brksize))
138 continue;
140 (void) lseek(P->asfd, (off_t)offset, 0);
142 if ((nbytes = read(P->asfd, buf, 2*BLKSIZE)) <= 0)
143 continue;
145 if (nbytes < BLKSIZE)
146 n2bytes = 0;
147 else {
148 n2bytes = nbytes - BLKSIZE;
149 nbytes = BLKSIZE;
152 p = (uchar_t *)buf;
154 /* search text for a SYSCALL instruction */
155 while (sysaddr == 0 && syspri != 1 && offset < endoff) {
156 if (nbytes <= 0) { /* shift buffers */
157 if ((nbytes = n2bytes) <= 0)
158 break;
159 (void) memcpy(buf,
160 &buf[BLKSIZE / sizeof (buf[0])],
161 nbytes);
162 n2bytes = 0;
163 p = (uchar_t *)buf;
164 if (nbytes == BLKSIZE &&
165 offset + BLKSIZE < endoff)
166 n2bytes = read(P->asfd,
167 &buf[BLKSIZE / sizeof (buf[0])],
168 BLKSIZE);
171 if (syspri = Pissyscall_text(P, p, nbytes))
172 sysaddr = offset;
174 p += sizeof (instr_t);
175 offset += sizeof (instr_t);
176 nbytes -= sizeof (instr_t);
180 free(prbuf);
182 if ((P->sysaddr = sysaddr) != 0)
183 return (0);
184 else
185 return (-1);