Mercurial > hg > truffle
annotate agent/src/os/linux/ps_proc.c @ 3011:f00918f35c7f
inlining and runtime interface related changes:
added codeSize() and compilerStorage() to RiMethod
HotSpotMethodResolved uses reflective methods instead of vmIds and survives compilations
HotSpotResolvedType.isInitialized not represented as field (can change)
inlining stores graphs into method objects and reuses them
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Thu, 16 Jun 2011 20:36:17 +0200 |
parents | 0a8e0d4345b3 |
children | 2394a89e89f4 |
rev | line source |
---|---|
0 | 1 /* |
2042
0a8e0d4345b3
7010068: Update all 2010 Oracle-changed OpenJDK files to have the proper copyright dates - first pass
trims
parents:
1990
diff
changeset
|
2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
196
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
196
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
196
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 #include <stdio.h> | |
26 #include <stdlib.h> | |
27 #include <string.h> | |
28 #include <errno.h> | |
29 #include <sys/ptrace.h> | |
30 #include "libproc_impl.h" | |
31 | |
32 #if defined(x86_64) && !defined(amd64) | |
33 #define amd64 1 | |
34 #endif | |
35 | |
36 #ifndef __WALL | |
37 #define __WALL 0x40000000 // Copied from /usr/include/linux/wait.h | |
38 #endif | |
39 | |
40 // This file has the libproc implementation specific to live process | |
41 // For core files, refer to ps_core.c | |
42 | |
43 static inline uintptr_t align(uintptr_t ptr, size_t size) { | |
44 return (ptr & ~(size - 1)); | |
45 } | |
46 | |
47 // --------------------------------------------- | |
48 // ptrace functions | |
49 // --------------------------------------------- | |
50 | |
51 // read "size" bytes of data from "addr" within the target process. | |
52 // unlike the standard ptrace() function, process_read_data() can handle | |
53 // unaligned address - alignment check, if required, should be done | |
54 // before calling process_read_data. | |
55 | |
56 static bool process_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) { | |
57 long rslt; | |
58 size_t i, words; | |
59 uintptr_t end_addr = addr + size; | |
60 uintptr_t aligned_addr = align(addr, sizeof(long)); | |
61 | |
62 if (aligned_addr != addr) { | |
63 char *ptr = (char *)&rslt; | |
64 errno = 0; | |
65 rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0); | |
66 if (errno) { | |
67 print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr); | |
68 return false; | |
69 } | |
70 for (; aligned_addr != addr; aligned_addr++, ptr++); | |
71 for (; ((intptr_t)aligned_addr % sizeof(long)) && aligned_addr < end_addr; | |
72 aligned_addr++) | |
73 *(buf++) = *(ptr++); | |
74 } | |
75 | |
76 words = (end_addr - aligned_addr) / sizeof(long); | |
77 | |
78 // assert((intptr_t)aligned_addr % sizeof(long) == 0); | |
79 for (i = 0; i < words; i++) { | |
80 errno = 0; | |
81 rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0); | |
82 if (errno) { | |
83 print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr); | |
84 return false; | |
85 } | |
86 *(long *)buf = rslt; | |
87 buf += sizeof(long); | |
88 aligned_addr += sizeof(long); | |
89 } | |
90 | |
91 if (aligned_addr != end_addr) { | |
92 char *ptr = (char *)&rslt; | |
93 errno = 0; | |
94 rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0); | |
95 if (errno) { | |
96 print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr); | |
97 return false; | |
98 } | |
99 for (; aligned_addr != end_addr; aligned_addr++) | |
100 *(buf++) = *(ptr++); | |
101 } | |
102 return true; | |
103 } | |
104 | |
105 // null implementation for write | |
106 static bool process_write_data(struct ps_prochandle* ph, | |
107 uintptr_t addr, const char *buf , size_t size) { | |
108 return false; | |
109 } | |
110 | |
111 // "user" should be a pointer to a user_regs_struct | |
112 static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct user_regs_struct *user) { | |
113 // we have already attached to all thread 'pid's, just use ptrace call | |
114 // to get regset now. Note that we don't cache regset upfront for processes. | |
115 // Linux on x86 and sparc are different. On x86 ptrace(PTRACE_GETREGS, ...) | |
116 // uses pointer from 4th argument and ignores 3rd argument. On sparc it uses | |
117 // pointer from 3rd argument and ignores 4th argument | |
118 #if defined(sparc) || defined(sparcv9) | |
119 #define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, addr, data) | |
120 #else | |
121 #define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, data, addr) | |
122 #endif | |
123 | |
1990 | 124 #if defined(_LP64) && defined(PTRACE_GETREGS64) |
0 | 125 #define PTRACE_GETREGS_REQ PTRACE_GETREGS64 |
1990 | 126 #elif defined(PTRACE_GETREGS) |
127 #define PTRACE_GETREGS_REQ PTRACE_GETREGS | |
128 #elif defined(PT_GETREGS) | |
129 #define PTRACE_GETREGS_REQ PT_GETREGS | |
0 | 130 #endif |
131 | |
132 #ifdef PTRACE_GETREGS_REQ | |
133 if (ptrace_getregs(PTRACE_GETREGS_REQ, pid, user, NULL) < 0) { | |
134 print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid); | |
135 return false; | |
136 } | |
137 return true; | |
138 #else | |
139 print_debug("ptrace(PTRACE_GETREGS, ...) not supported\n"); | |
140 return false; | |
141 #endif | |
142 | |
143 } | |
144 | |
145 // attach to a process/thread specified by "pid" | |
146 static bool ptrace_attach(pid_t pid) { | |
147 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { | |
148 print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); | |
149 return false; | |
150 } else { | |
151 int ret; | |
152 int status; | |
153 do { | |
154 // Wait for debuggee to stop. | |
155 ret = waitpid(pid, &status, 0); | |
156 if (ret == -1 && errno == ECHILD) { | |
157 // try cloned process. | |
158 ret = waitpid(pid, &status, __WALL); | |
159 } | |
160 if (ret >= 0) { | |
161 if (WIFSTOPPED(status)) { | |
162 // Debuggee stopped. | |
163 return true; | |
164 } else { | |
165 print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); | |
166 return false; | |
167 } | |
168 } else { | |
169 switch (errno) { | |
170 case EINTR: | |
171 continue; | |
172 break; | |
173 case ECHILD: | |
174 print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); | |
175 break; | |
176 case EINVAL: | |
177 print_debug("waitpid() failed. Invalid options argument.\n"); | |
178 break; | |
179 default: | |
180 print_debug("waitpid() failed. Unexpected error %d\n",errno); | |
181 } | |
182 return false; | |
183 } | |
184 } while(true); | |
185 } | |
186 } | |
187 | |
188 // ------------------------------------------------------- | |
189 // functions for obtaining library information | |
190 // ------------------------------------------------------- | |
191 | |
192 /* | |
193 * splits a string _str_ into substrings with delimiter _delim_ by replacing old * delimiters with _new_delim_ (ideally, '\0'). the address of each substring | |
194 * is stored in array _ptrs_ as the return value. the maximum capacity of _ptrs_ * array is specified by parameter _n_. | |
195 * RETURN VALUE: total number of substrings (always <= _n_) | |
196 * NOTE: string _str_ is modified if _delim_!=_new_delim_ | |
197 */ | |
198 static int split_n_str(char * str, int n, char ** ptrs, char delim, char new_delim) | |
199 { | |
200 int i; | |
201 for(i = 0; i < n; i++) ptrs[i] = NULL; | |
202 if (str == NULL || n < 1 ) return 0; | |
203 | |
204 i = 0; | |
205 | |
206 // skipping leading blanks | |
207 while(*str&&*str==delim) str++; | |
208 | |
209 while(*str&&i<n){ | |
210 ptrs[i++] = str; | |
211 while(*str&&*str!=delim) str++; | |
212 while(*str&&*str==delim) *(str++) = new_delim; | |
213 } | |
214 | |
215 return i; | |
216 } | |
217 | |
218 /* | |
219 * fgets without storing '\n' at the end of the string | |
220 */ | |
221 static char * fgets_no_cr(char * buf, int n, FILE *fp) | |
222 { | |
223 char * rslt = fgets(buf, n, fp); | |
224 if (rslt && buf && *buf){ | |
225 char *p = strchr(buf, '\0'); | |
226 if (*--p=='\n') *p='\0'; | |
227 } | |
228 return rslt; | |
229 } | |
230 | |
231 // callback for read_thread_info | |
232 static bool add_new_thread(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { | |
233 return add_thread_info(ph, pthread_id, lwp_id) != NULL; | |
234 } | |
235 | |
236 static bool read_lib_info(struct ps_prochandle* ph) { | |
237 char fname[32]; | |
238 char buf[256]; | |
239 FILE *fp = NULL; | |
240 | |
241 sprintf(fname, "/proc/%d/maps", ph->pid); | |
242 fp = fopen(fname, "r"); | |
243 if (fp == NULL) { | |
244 print_debug("can't open /proc/%d/maps file\n", ph->pid); | |
245 return false; | |
246 } | |
247 | |
248 while(fgets_no_cr(buf, 256, fp)){ | |
249 char * word[6]; | |
250 int nwords = split_n_str(buf, 6, word, ' ', '\0'); | |
251 if (nwords > 5 && find_lib(ph, word[5]) == false) { | |
252 intptr_t base; | |
253 lib_info* lib; | |
1681
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1552
diff
changeset
|
254 #ifdef _LP64 |
0 | 255 sscanf(word[0], "%lx", &base); |
1681
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1552
diff
changeset
|
256 #else |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1552
diff
changeset
|
257 sscanf(word[0], "%x", &base); |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1552
diff
changeset
|
258 #endif |
0 | 259 if ((lib = add_lib_info(ph, word[5], (uintptr_t)base)) == NULL) |
260 continue; // ignore, add_lib_info prints error | |
261 | |
262 // we don't need to keep the library open, symtab is already | |
263 // built. Only for core dump we need to keep the fd open. | |
264 close(lib->fd); | |
265 lib->fd = -1; | |
266 } | |
267 } | |
268 fclose(fp); | |
269 return true; | |
270 } | |
271 | |
272 // detach a given pid | |
273 static bool ptrace_detach(pid_t pid) { | |
274 if (pid && ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) { | |
275 print_debug("ptrace(PTRACE_DETACH, ..) failed for %d\n", pid); | |
276 return false; | |
277 } else { | |
278 return true; | |
279 } | |
280 } | |
281 | |
282 // detach all pids of a ps_prochandle | |
283 static void detach_all_pids(struct ps_prochandle* ph) { | |
284 thread_info* thr = ph->threads; | |
285 while (thr) { | |
286 ptrace_detach(thr->lwp_id); | |
287 thr = thr->next; | |
288 } | |
289 } | |
290 | |
291 static void process_cleanup(struct ps_prochandle* ph) { | |
292 detach_all_pids(ph); | |
293 } | |
294 | |
295 static ps_prochandle_ops process_ops = { | |
50
485d403e94e1
6452081: 3/4 Allow for Linux builds with Sun Studio Linux compilers
dcubed
parents:
0
diff
changeset
|
296 .release= process_cleanup, |
485d403e94e1
6452081: 3/4 Allow for Linux builds with Sun Studio Linux compilers
dcubed
parents:
0
diff
changeset
|
297 .p_pread= process_read_data, |
485d403e94e1
6452081: 3/4 Allow for Linux builds with Sun Studio Linux compilers
dcubed
parents:
0
diff
changeset
|
298 .p_pwrite= process_write_data, |
485d403e94e1
6452081: 3/4 Allow for Linux builds with Sun Studio Linux compilers
dcubed
parents:
0
diff
changeset
|
299 .get_lwp_regs= process_get_lwp_regs |
0 | 300 }; |
301 | |
302 // attach to the process. One and only one exposed stuff | |
303 struct ps_prochandle* Pgrab(pid_t pid) { | |
304 struct ps_prochandle* ph = NULL; | |
305 thread_info* thr = NULL; | |
306 | |
307 if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { | |
308 print_debug("can't allocate memory for ps_prochandle\n"); | |
309 return NULL; | |
310 } | |
311 | |
312 if (ptrace_attach(pid) != true) { | |
313 free(ph); | |
314 return NULL; | |
315 } | |
316 | |
317 // initialize ps_prochandle | |
318 ph->pid = pid; | |
319 | |
320 // initialize vtable | |
321 ph->ops = &process_ops; | |
322 | |
323 // read library info and symbol tables, must do this before attaching threads, | |
324 // as the symbols in the pthread library will be used to figure out | |
325 // the list of threads within the same process. | |
326 read_lib_info(ph); | |
327 | |
328 // read thread info | |
329 read_thread_info(ph, add_new_thread); | |
330 | |
331 // attach to the threads | |
332 thr = ph->threads; | |
333 while (thr) { | |
334 // don't attach to the main thread again | |
335 if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id) != true) { | |
336 // even if one attach fails, we get return NULL | |
337 Prelease(ph); | |
338 return NULL; | |
339 } | |
340 thr = thr->next; | |
341 } | |
342 return ph; | |
343 } |