Mercurial > hg > truffle
annotate agent/src/os/bsd/ps_proc.c @ 17716:cdb71841f4bc
6498581: ThreadInterruptTest3 produces wrong output on Windows
Summary: There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set.
Reviewed-by: acorn, kvn
Contributed-by: david.holmes@oracle.com, yumin.qi@oracle.com
author | minqi |
---|---|
date | Wed, 26 Feb 2014 15:20:41 -0800 |
parents | 1a04de1aaedb |
children |
rev | line source |
---|---|
3960 | 1 /* |
8058 | 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
3960 | 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 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 * | |
23 */ | |
24 | |
25 #include <limits.h> | |
26 #include <stdio.h> | |
27 #include <stdlib.h> | |
28 #include <string.h> | |
29 #include <errno.h> | |
30 #include <sys/types.h> | |
31 #include <sys/wait.h> | |
32 #include <sys/ptrace.h> | |
33 #include <sys/param.h> | |
34 #include <sys/user.h> | |
35 #include <elf.h> | |
36 #include <sys/elf_common.h> | |
37 #include <sys/link_elf.h> | |
38 #include <libutil.h> | |
39 #include "libproc_impl.h" | |
40 #include "elfmacros.h" | |
41 | |
42 // This file has the libproc implementation specific to live process | |
43 // For core files, refer to ps_core.c | |
44 | |
45 static inline uintptr_t align(uintptr_t ptr, size_t size) { | |
46 return (ptr & ~(size - 1)); | |
47 } | |
48 | |
49 // --------------------------------------------- | |
50 // ptrace functions | |
51 // --------------------------------------------- | |
52 | |
53 // read "size" bytes of data from "addr" within the target process. | |
54 // unlike the standard ptrace() function, process_read_data() can handle | |
55 // unaligned address - alignment check, if required, should be done | |
56 // before calling process_read_data. | |
57 | |
58 static bool process_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) { | |
59 int rslt; | |
60 size_t i, words; | |
61 uintptr_t end_addr = addr + size; | |
62 uintptr_t aligned_addr = align(addr, sizeof(int)); | |
63 | |
64 if (aligned_addr != addr) { | |
65 char *ptr = (char *)&rslt; | |
66 errno = 0; | |
67 rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0); | |
68 if (errno) { | |
69 print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr); | |
70 return false; | |
71 } | |
72 for (; aligned_addr != addr; aligned_addr++, ptr++); | |
73 for (; ((intptr_t)aligned_addr % sizeof(int)) && aligned_addr < end_addr; | |
74 aligned_addr++) | |
75 *(buf++) = *(ptr++); | |
76 } | |
77 | |
78 words = (end_addr - aligned_addr) / sizeof(int); | |
79 | |
80 // assert((intptr_t)aligned_addr % sizeof(int) == 0); | |
81 for (i = 0; i < words; i++) { | |
82 errno = 0; | |
83 rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0); | |
84 if (errno) { | |
85 print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr); | |
86 return false; | |
87 } | |
88 *(int *)buf = rslt; | |
89 buf += sizeof(int); | |
90 aligned_addr += sizeof(int); | |
91 } | |
92 | |
93 if (aligned_addr != end_addr) { | |
94 char *ptr = (char *)&rslt; | |
95 errno = 0; | |
96 rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0); | |
97 if (errno) { | |
98 print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr); | |
99 return false; | |
100 } | |
101 for (; aligned_addr != end_addr; aligned_addr++) | |
102 *(buf++) = *(ptr++); | |
103 } | |
104 return true; | |
105 } | |
106 | |
107 // null implementation for write | |
108 static bool process_write_data(struct ps_prochandle* ph, | |
109 uintptr_t addr, const char *buf , size_t size) { | |
110 return false; | |
111 } | |
112 | |
113 // "user" should be a pointer to a reg | |
114 static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct reg *user) { | |
115 // we have already attached to all thread 'pid's, just use ptrace call | |
116 // to get regset now. Note that we don't cache regset upfront for processes. | |
117 if (ptrace(PT_GETREGS, pid, (caddr_t) user, 0) < 0) { | |
118 print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid); | |
119 return false; | |
120 } | |
121 return true; | |
122 } | |
123 | |
124 // fill in ptrace_lwpinfo for lid | |
125 static bool process_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { | |
126 errno = 0; | |
127 ptrace(PT_LWPINFO, lwp_id, linfo, sizeof(struct ptrace_lwpinfo)); | |
128 | |
129 return (errno == 0)? true: false; | |
130 } | |
131 | |
8058 | 132 static bool ptrace_continue(pid_t pid, int signal) { |
133 // pass the signal to the process so we don't swallow it | |
13002
1a04de1aaedb
8026950: Nits in agent ps_proc.c file breaks compilation of open hotspot
dsamersoff
parents:
8058
diff
changeset
|
134 if (ptrace(PT_CONTINUE, pid, NULL, signal) < 0) { |
8058 | 135 print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid); |
136 return false; | |
137 } | |
138 return true; | |
139 } | |
140 | |
141 // waits until the ATTACH has stopped the process | |
142 // by signal SIGSTOP | |
143 static bool ptrace_waitpid(pid_t pid) { | |
144 int ret; | |
145 int status; | |
146 do { | |
147 // Wait for debuggee to stop. | |
148 ret = waitpid(pid, &status, 0); | |
149 if (ret >= 0) { | |
150 if (WIFSTOPPED(status)) { | |
151 // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP | |
152 // will still be pending and delivered when the process is DETACHED and the process | |
153 // will go to sleep. | |
154 if (WSTOPSIG(status) == SIGSTOP) { | |
155 // Debuggee stopped by SIGSTOP. | |
156 return true; | |
157 } | |
158 if (!ptrace_continue(pid, WSTOPSIG(status))) { | |
159 print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); | |
160 return false; | |
161 } | |
162 } else { | |
163 print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); | |
164 return false; | |
165 } | |
166 } else { | |
167 switch (errno) { | |
168 case EINTR: | |
169 continue; | |
170 break; | |
171 case ECHILD: | |
172 print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); | |
173 break; | |
174 case EINVAL: | |
175 print_debug("waitpid() failed. Invalid options argument.\n"); | |
176 break; | |
177 default: | |
178 print_debug("waitpid() failed. Unexpected error %d\n",errno); | |
179 } | |
180 return false; | |
181 } | |
182 } while(true); | |
183 } | |
184 | |
3960 | 185 // attach to a process/thread specified by "pid" |
186 static bool ptrace_attach(pid_t pid) { | |
187 if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) { | |
188 print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); | |
189 return false; | |
190 } else { | |
8058 | 191 return ptrace_waitpid(pid); |
3960 | 192 } |
193 } | |
194 | |
195 // ------------------------------------------------------- | |
196 // functions for obtaining library information | |
197 // ------------------------------------------------------- | |
198 | |
199 // callback for read_thread_info | |
200 static bool add_new_thread(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { | |
201 return add_thread_info(ph, pthread_id, lwp_id) != NULL; | |
202 } | |
203 | |
204 #if defined(__FreeBSD__) && __FreeBSD_version < 701000 | |
205 /* | |
206 * TEXT_START_ADDR from binutils/ld/emulparams/<arch_spec>.sh | |
207 * Not the most robust but good enough. | |
208 */ | |
209 | |
210 #if defined(amd64) || defined(x86_64) | |
211 #define TEXT_START_ADDR 0x400000 | |
212 #elif defined(i386) | |
213 #define TEXT_START_ADDR 0x8048000 | |
214 #else | |
215 #error TEXT_START_ADDR not defined | |
216 #endif | |
217 | |
218 #define BUF_SIZE (PATH_MAX + NAME_MAX + 1) | |
219 | |
220 uintptr_t linkmap_addr(struct ps_prochandle *ph) { | |
221 uintptr_t ehdr_addr, phdr_addr, dyn_addr, dmap_addr, lmap_addr; | |
222 ELF_EHDR ehdr; | |
223 ELF_PHDR *phdrs, *phdr; | |
224 ELF_DYN *dyns, *dyn; | |
225 struct r_debug dmap; | |
226 unsigned long hdrs_size; | |
227 unsigned int i; | |
228 | |
229 /* read ELF_EHDR at TEXT_START_ADDR and validate */ | |
230 | |
231 ehdr_addr = (uintptr_t)TEXT_START_ADDR; | |
232 | |
233 if (process_read_data(ph, ehdr_addr, (char *)&ehdr, sizeof(ehdr)) != true) { | |
234 print_debug("process_read_data failed for ehdr_addr %p\n", ehdr_addr); | |
235 return (0); | |
236 } | |
237 | |
238 if (!IS_ELF(ehdr) || | |
239 ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS || | |
240 ehdr.e_ident[EI_DATA] != ELF_TARG_DATA || | |
241 ehdr.e_ident[EI_VERSION] != EV_CURRENT || | |
242 ehdr.e_phentsize != sizeof(ELF_PHDR) || | |
243 ehdr.e_version != ELF_TARG_VER || | |
244 ehdr.e_machine != ELF_TARG_MACH) { | |
245 print_debug("not an ELF_EHDR at %p\n", ehdr_addr); | |
246 return (0); | |
247 } | |
248 | |
249 /* allocate space for all ELF_PHDR's and read */ | |
250 | |
251 phdr_addr = ehdr_addr + ehdr.e_phoff; | |
252 hdrs_size = ehdr.e_phnum * sizeof(ELF_PHDR); | |
253 | |
254 if ((phdrs = malloc(hdrs_size)) == NULL) | |
255 return (0); | |
256 | |
257 if (process_read_data(ph, phdr_addr, (char *)phdrs, hdrs_size) != true) { | |
258 print_debug("process_read_data failed for phdr_addr %p\n", phdr_addr); | |
259 return (0); | |
260 } | |
261 | |
262 /* find PT_DYNAMIC section */ | |
263 | |
264 for (i = 0, phdr = phdrs; i < ehdr.e_phnum; i++, phdr++) { | |
265 if (phdr->p_type == PT_DYNAMIC) | |
266 break; | |
267 } | |
268 | |
269 if (i >= ehdr.e_phnum) { | |
270 print_debug("PT_DYNAMIC section not found!\n"); | |
271 free(phdrs); | |
272 return (0); | |
273 } | |
274 | |
275 /* allocate space and read in ELF_DYN headers */ | |
276 | |
277 dyn_addr = phdr->p_vaddr; | |
278 hdrs_size = phdr->p_memsz; | |
279 free(phdrs); | |
280 | |
281 if ((dyns = malloc(hdrs_size)) == NULL) | |
282 return (0); | |
283 | |
284 if (process_read_data(ph, dyn_addr, (char *)dyns, hdrs_size) != true) { | |
285 print_debug("process_read_data failed for dyn_addr %p\n", dyn_addr); | |
286 free(dyns); | |
287 return (0); | |
288 } | |
289 | |
290 /* find DT_DEBUG */ | |
291 | |
292 dyn = dyns; | |
293 while (dyn->d_tag != DT_DEBUG && dyn->d_tag != DT_NULL) { | |
294 dyn++; | |
295 } | |
296 | |
297 if (dyn->d_tag != DT_DEBUG) { | |
298 print_debug("failed to find DT_DEBUG\n"); | |
299 free(dyns); | |
300 return (0); | |
301 } | |
302 | |
303 /* read struct r_debug into dmap */ | |
304 | |
305 dmap_addr = (uintptr_t)dyn->d_un.d_ptr; | |
306 free(dyns); | |
307 | |
308 if (process_read_data(ph, dmap_addr, (char *)&dmap, sizeof(dmap)) != true) { | |
309 print_debug("process_read_data failed for dmap_addr %p\n", dmap_addr); | |
310 return (0); | |
311 } | |
312 | |
313 lmap_addr = (uintptr_t)dmap.r_map; | |
314 | |
315 return (lmap_addr); | |
316 } | |
317 #endif // __FreeBSD__ && __FreeBSD_version < 701000 | |
318 | |
319 static bool read_lib_info(struct ps_prochandle* ph) { | |
320 #if defined(__FreeBSD__) && __FreeBSD_version >= 701000 | |
321 struct kinfo_vmentry *freep, *kve; | |
322 int i, cnt; | |
323 | |
324 freep = kinfo_getvmmap(ph->pid, &cnt); | |
325 if (freep == NULL) { | |
326 print_debug("can't get vm map for pid\n", ph->pid); | |
327 return false; | |
328 } | |
329 | |
330 for (i = 0; i < cnt; i++) { | |
331 kve = &freep[i]; | |
332 if ((kve->kve_flags & KVME_FLAG_COW) && | |
333 kve->kve_path != NULL && | |
334 strlen(kve->kve_path) > 0) { | |
335 | |
336 if (find_lib(ph, kve->kve_path) == false) { | |
337 lib_info* lib; | |
338 if ((lib = add_lib_info(ph, kve->kve_path, | |
339 (uintptr_t) kve->kve_start)) == NULL) | |
340 continue; // ignore, add_lib_info prints error | |
341 | |
342 // we don't need to keep the library open, symtab is already | |
343 // built. Only for core dump we need to keep the fd open. | |
344 close(lib->fd); | |
345 lib->fd = -1; | |
346 } | |
347 } | |
348 } | |
349 | |
350 free(freep); | |
351 | |
352 return true; | |
353 #else | |
354 char *l_name; | |
355 struct link_map *lmap; | |
356 uintptr_t lmap_addr; | |
357 | |
358 if ((l_name = malloc(BUF_SIZE)) == NULL) | |
359 return false; | |
360 | |
361 if ((lmap = malloc(sizeof(*lmap))) == NULL) { | |
362 free(l_name); | |
363 return false; | |
364 } | |
365 | |
366 lmap_addr = linkmap_addr(ph); | |
367 | |
368 if (lmap_addr == 0) { | |
369 free(l_name); | |
370 free(lmap); | |
371 return false; | |
372 } | |
373 | |
374 do { | |
375 if (process_read_data(ph, lmap_addr, (char *)lmap, sizeof(*lmap)) != true) { | |
376 print_debug("process_read_data failed for lmap_addr %p\n", lmap_addr); | |
377 free (l_name); | |
378 free (lmap); | |
379 return false; | |
380 } | |
381 | |
382 if (process_read_data(ph, (uintptr_t)lmap->l_name, l_name, | |
383 BUF_SIZE) != true) { | |
384 print_debug("process_read_data failed for lmap->l_name %p\n", | |
385 lmap->l_name); | |
386 free (l_name); | |
387 free (lmap); | |
388 return false; | |
389 } | |
390 | |
391 if (find_lib(ph, l_name) == false) { | |
392 lib_info* lib; | |
393 if ((lib = add_lib_info(ph, l_name, | |
394 (uintptr_t) lmap->l_addr)) == NULL) | |
395 continue; // ignore, add_lib_info prints error | |
396 | |
397 // we don't need to keep the library open, symtab is already | |
398 // built. Only for core dump we need to keep the fd open. | |
399 close(lib->fd); | |
400 lib->fd = -1; | |
401 } | |
402 lmap_addr = (uintptr_t)lmap->l_next; | |
403 } while (lmap->l_next != NULL); | |
404 | |
405 free (l_name); | |
406 free (lmap); | |
407 | |
408 return true; | |
409 #endif | |
410 } | |
411 | |
412 // detach a given pid | |
413 static bool ptrace_detach(pid_t pid) { | |
414 if (pid && ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) { | |
415 print_debug("ptrace(PTRACE_DETACH, ..) failed for %d\n", pid); | |
416 return false; | |
417 } else { | |
418 return true; | |
419 } | |
420 } | |
421 | |
422 static void process_cleanup(struct ps_prochandle* ph) { | |
423 ptrace_detach(ph->pid); | |
424 } | |
425 | |
426 static ps_prochandle_ops process_ops = { | |
427 .release= process_cleanup, | |
428 .p_pread= process_read_data, | |
429 .p_pwrite= process_write_data, | |
430 .get_lwp_regs= process_get_lwp_regs, | |
431 .get_lwp_info= process_get_lwp_info | |
432 }; | |
433 | |
434 // attach to the process. One and only one exposed stuff | |
435 struct ps_prochandle* Pgrab(pid_t pid) { | |
436 struct ps_prochandle* ph = NULL; | |
437 | |
438 if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { | |
439 print_debug("can't allocate memory for ps_prochandle\n"); | |
440 return NULL; | |
441 } | |
442 | |
443 if (ptrace_attach(pid) != true) { | |
444 free(ph); | |
445 return NULL; | |
446 } | |
447 | |
448 // initialize ps_prochandle | |
449 ph->pid = pid; | |
450 | |
451 // initialize vtable | |
452 ph->ops = &process_ops; | |
453 | |
454 // read library info and symbol tables, must do this before attaching threads, | |
455 // as the symbols in the pthread library will be used to figure out | |
456 // the list of threads within the same process. | |
457 if (read_lib_info(ph) != true) { | |
458 ptrace_detach(pid); | |
459 free(ph); | |
460 return NULL; | |
461 } | |
462 | |
463 // read thread info | |
464 read_thread_info(ph, add_new_thread); | |
465 | |
466 return ph; | |
467 } |