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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
42 #define BLKSIZE (8 * 1024)
45 * Look for a SYSCALL instruction in the process's address space.
48 Pscantext(struct ps_prochandle
*P
)
50 char mapfile
[PATH_MAX
];
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 */
65 /* try the most recently-seen syscall address */
68 if (P
->sysaddr
!= 0 &&
69 (syspri
= Pissyscall(P
, 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
],
77 if (sysaddr
!= 0 && syspri
== 1) {
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
));
90 /* allocate a plausible initial buffer size */
93 /* read all the map structures, allocating more space as needed */
95 prbuf
= malloc(nmap
* sizeof (prmap_t
));
97 dprintf("Pscantext: failed to allocate buffer\n");
101 nmappings
= pread(mapfd
, prbuf
, nmap
* sizeof (prmap_t
), 0L);
103 dprintf("Pscantext: failed to read map file: %s\n",
109 nmappings
/= sizeof (prmap_t
);
110 if (nmappings
< nmap
) /* we read them all */
112 /* allocate a bigger buffer */
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
))
140 (void) lseek(P
->asfd
, (off_t
)offset
, 0);
142 if ((nbytes
= read(P
->asfd
, buf
, 2*BLKSIZE
)) <= 0)
145 if (nbytes
< BLKSIZE
)
148 n2bytes
= nbytes
- BLKSIZE
;
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)
160 &buf
[BLKSIZE
/ sizeof (buf
[0])],
164 if (nbytes
== BLKSIZE
&&
165 offset
+ BLKSIZE
< endoff
)
166 n2bytes
= read(P
->asfd
,
167 &buf
[BLKSIZE
/ sizeof (buf
[0])],
171 if (syspri
= Pissyscall_text(P
, p
, nbytes
))
174 p
+= sizeof (instr_t
);
175 offset
+= sizeof (instr_t
);
176 nbytes
-= sizeof (instr_t
);
182 if ((P
->sysaddr
= sysaddr
) != 0)