Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/agent/src/os/linux/ps_proc.c
38833 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include <stdio.h>25#include <stdlib.h>26#include <string.h>27#include <signal.h>28#include <errno.h>29#include <elf.h>30#include <ctype.h>31#include <sys/types.h>32#include <sys/wait.h>33#include <sys/ptrace.h>34#include <sys/uio.h>35#include "libproc_impl.h"3637#if defined(x86_64) && !defined(amd64)38#define amd64 139#endif4041#ifndef __WALL42#define __WALL 0x40000000 // Copied from /usr/include/linux/wait.h43#endif4445// This file has the libproc implementation specific to live process46// For core files, refer to ps_core.c4748typedef enum {49ATTACH_SUCCESS,50ATTACH_FAIL,51ATTACH_THREAD_DEAD52} attach_state_t;5354static inline uintptr_t align(uintptr_t ptr, size_t size) {55return (ptr & ~(size - 1));56}5758// ---------------------------------------------59// ptrace functions60// ---------------------------------------------6162// read "size" bytes of data from "addr" within the target process.63// unlike the standard ptrace() function, process_read_data() can handle64// unaligned address - alignment check, if required, should be done65// before calling process_read_data.6667static bool process_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) {68long rslt;69size_t i, words;70uintptr_t end_addr = addr + size;71uintptr_t aligned_addr = align(addr, sizeof(long));7273if (aligned_addr != addr) {74char *ptr = (char *)&rslt;75errno = 0;76rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0);77if (errno) {78print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr);79return false;80}81for (; aligned_addr != addr; aligned_addr++, ptr++);82for (; ((intptr_t)aligned_addr % sizeof(long)) && aligned_addr < end_addr;83aligned_addr++)84*(buf++) = *(ptr++);85}8687words = (end_addr - aligned_addr) / sizeof(long);8889// assert((intptr_t)aligned_addr % sizeof(long) == 0);90for (i = 0; i < words; i++) {91errno = 0;92rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0);93if (errno) {94print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr);95return false;96}97*(long *)buf = rslt;98buf += sizeof(long);99aligned_addr += sizeof(long);100}101102if (aligned_addr != end_addr) {103char *ptr = (char *)&rslt;104errno = 0;105rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0);106if (errno) {107print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr);108return false;109}110for (; aligned_addr != end_addr; aligned_addr++)111*(buf++) = *(ptr++);112}113return true;114}115116// null implementation for write117static bool process_write_data(struct ps_prochandle* ph,118uintptr_t addr, const char *buf , size_t size) {119return false;120}121122// "user" should be a pointer to a user_regs_struct123static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct user_regs_struct *user) {124// we have already attached to all thread 'pid's, just use ptrace call125// to get regset now. Note that we don't cache regset upfront for processes.126// Linux on x86 and sparc are different. On x86 ptrace(PTRACE_GETREGS, ...)127// uses pointer from 4th argument and ignores 3rd argument. On sparc it uses128// pointer from 3rd argument and ignores 4th argument129#if defined(sparc) || defined(sparcv9)130#define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, addr, data)131#else132#define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, data, addr)133#endif134135#if defined(_LP64) && defined(PTRACE_GETREGS64)136#define PTRACE_GETREGS_REQ PTRACE_GETREGS64137#elif defined(PTRACE_GETREGS)138#define PTRACE_GETREGS_REQ PTRACE_GETREGS139#elif defined(PT_GETREGS)140#define PTRACE_GETREGS_REQ PT_GETREGS141#endif142143#ifdef PTRACE_GETREGS_REQ144if (ptrace_getregs(PTRACE_GETREGS_REQ, pid, user, NULL) < 0) {145print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid);146return false;147}148return true;149#elif defined(PTRACE_GETREGSET)150struct iovec iov;151iov.iov_base = user;152iov.iov_len = sizeof(*user);153if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, (void*) &iov) < 0) {154print_debug("ptrace(PTRACE_GETREGSET, ...) failed for lwp %d\n", pid);155return false;156}157return true;158#else159print_debug("ptrace(PTRACE_GETREGS, ...) not supported\n");160return false;161#endif162163}164165static bool ptrace_continue(pid_t pid, int signal) {166// pass the signal to the process so we don't swallow it167if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) {168print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid);169return false;170}171return true;172}173174// waits until the ATTACH has stopped the process175// by signal SIGSTOP176static attach_state_t ptrace_waitpid(pid_t pid) {177int ret;178int status;179errno = 0;180while (true) {181// Wait for debuggee to stop.182ret = waitpid(pid, &status, 0);183if (ret == -1 && errno == ECHILD) {184// try cloned process.185ret = waitpid(pid, &status, __WALL);186}187if (ret >= 0) {188if (WIFSTOPPED(status)) {189// Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP190// will still be pending and delivered when the process is DETACHED and the process191// will go to sleep.192if (WSTOPSIG(status) == SIGSTOP) {193// Debuggee stopped by SIGSTOP.194return ATTACH_SUCCESS;195}196if (!ptrace_continue(pid, WSTOPSIG(status))) {197print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));198return ATTACH_FAIL;199}200} else {201print_debug("waitpid(): Child process %d exited/terminated (status = 0x%x)\n", pid, status);202return ATTACH_THREAD_DEAD;203}204} else {205switch (errno) {206case EINTR:207continue;208break;209case ECHILD:210print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);211return ATTACH_THREAD_DEAD;212case EINVAL:213print_error("waitpid() failed. Invalid options argument.\n");214return ATTACH_FAIL;215default:216print_error("waitpid() failed. Unexpected error %d\n",errno);217return ATTACH_FAIL;218}219} // else220} // while221}222223// checks the state of the thread/process specified by "pid", by reading224// in the 'State:' value from the /proc/<pid>/status file. From the proc225// man page, "Current state of the process. One of "R (running)",226// "S (sleeping)", "D (disk sleep)", "T (stopped)", "T (tracing stop)",227// "Z (zombie)", or "X (dead)"." Assumes that the thread is dead if we228// don't find the status file or if the status is 'X' or 'Z'.229static bool process_doesnt_exist(pid_t pid) {230char fname[32];231char buf[30];232FILE *fp = NULL;233const char state_string[] = "State:";234235sprintf(fname, "/proc/%d/status", pid);236fp = fopen(fname, "r");237if (fp == NULL) {238print_debug("can't open /proc/%d/status file\n", pid);239// Assume the thread does not exist anymore.240return true;241}242bool found_state = false;243size_t state_len = strlen(state_string);244while (fgets(buf, sizeof(buf), fp) != NULL) {245char *state = NULL;246if (strncmp (buf, state_string, state_len) == 0) {247found_state = true;248state = buf + state_len;249// Skip the spaces250while (isspace(*state)) {251state++;252}253// A state value of 'X' indicates that the thread is dead. 'Z'254// indicates that the thread is a zombie.255if (*state == 'X' || *state == 'Z') {256fclose (fp);257return true;258}259break;260}261}262// If the state value is not 'X' or 'Z', the thread exists.263if (!found_state) {264// We haven't found the line beginning with 'State:'.265// Assuming the thread exists.266print_error("Could not find the 'State:' string in the /proc/%d/status file\n", pid);267}268fclose (fp);269return false;270}271272// attach to a process/thread specified by "pid"273static attach_state_t ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) {274errno = 0;275if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {276if (errno == EPERM || errno == ESRCH) {277// Check if the process/thread is exiting or is a zombie278if (process_doesnt_exist(pid)) {279print_debug("Thread with pid %d does not exist\n", pid);280return ATTACH_THREAD_DEAD;281}282}283char buf[200];284char* msg = strerror_r(errno, buf, sizeof(buf));285snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg);286print_error("%s\n", err_buf);287return ATTACH_FAIL;288} else {289attach_state_t wait_ret = ptrace_waitpid(pid);290if (wait_ret == ATTACH_THREAD_DEAD) {291print_debug("Thread with pid %d does not exist\n", pid);292}293return wait_ret;294}295}296297// -------------------------------------------------------298// functions for obtaining library information299// -------------------------------------------------------300301/*302* splits a string _str_ into substrings with delimiter _delim_ by replacing old * delimiters with _new_delim_ (ideally, '\0'). the address of each substring303* is stored in array _ptrs_ as the return value. the maximum capacity of _ptrs_ * array is specified by parameter _n_.304* RETURN VALUE: total number of substrings (always <= _n_)305* NOTE: string _str_ is modified if _delim_!=_new_delim_306*/307static int split_n_str(char * str, int n, char ** ptrs, char delim, char new_delim)308{309int i;310for(i = 0; i < n; i++) ptrs[i] = NULL;311if (str == NULL || n < 1 ) return 0;312313i = 0;314315// skipping leading blanks316while(*str&&*str==delim) str++;317318while(*str&&i<n){319ptrs[i++] = str;320while(*str&&*str!=delim) str++;321while(*str&&*str==delim) *(str++) = new_delim;322}323324return i;325}326327/*328* fgets without storing '\n' at the end of the string329*/330static char * fgets_no_cr(char * buf, int n, FILE *fp)331{332char * rslt = fgets(buf, n, fp);333if (rslt && buf && *buf){334char *p = strchr(buf, '\0');335if (*--p=='\n') *p='\0';336}337return rslt;338}339340// callback for read_thread_info341static bool add_new_thread(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {342return add_thread_info(ph, pthread_id, lwp_id) != NULL;343}344345static bool read_lib_info(struct ps_prochandle* ph) {346char fname[32];347char buf[PATH_MAX];348FILE *fp = NULL;349350sprintf(fname, "/proc/%d/maps", ph->pid);351fp = fopen(fname, "r");352if (fp == NULL) {353print_debug("can't open /proc/%d/maps file\n", ph->pid);354return false;355}356357while(fgets_no_cr(buf, PATH_MAX, fp)){358char * word[7];359int nwords = split_n_str(buf, 7, word, ' ', '\0');360361if (nwords < 6) {362// not a shared library entry. ignore.363continue;364}365366// SA does not handle the lines with patterns:367// "[stack]", "[heap]", "[vdso]", "[vsyscall]", etc.368if (word[5][0] == '[') {369// not a shared library entry. ignore.370continue;371}372373if (nwords > 6) {374// prelink altered mapfile when the program is running.375// Entries like one below have to be skipped376// /lib64/libc-2.15.so (deleted)377// SO name in entries like one below have to be stripped.378// /lib64/libpthread-2.15.so.#prelink#.EECVts379char *s = strstr(word[5],".#prelink#");380if (s == NULL) {381// No prelink keyword. skip deleted library382print_debug("skip shared object %s deleted by prelink\n", word[5]);383continue;384}385386// Fall through387print_debug("rectifying shared object name %s changed by prelink\n", word[5]);388*s = 0;389}390391if (find_lib(ph, word[5]) == false) {392intptr_t base;393lib_info* lib;394#ifdef _LP64395sscanf(word[0], "%lx", &base);396#else397sscanf(word[0], "%x", &base);398#endif399if ((lib = add_lib_info(ph, word[5], (uintptr_t)base)) == NULL)400continue; // ignore, add_lib_info prints error401402// we don't need to keep the library open, symtab is already403// built. Only for core dump we need to keep the fd open.404close(lib->fd);405lib->fd = -1;406}407}408fclose(fp);409return true;410}411412// detach a given pid413static bool ptrace_detach(pid_t pid) {414if (pid && ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {415print_debug("ptrace(PTRACE_DETACH, ..) failed for %d\n", pid);416return false;417} else {418return true;419}420}421422// detach all pids of a ps_prochandle423static void detach_all_pids(struct ps_prochandle* ph) {424thread_info* thr = ph->threads;425while (thr) {426ptrace_detach(thr->lwp_id);427thr = thr->next;428}429}430431static void process_cleanup(struct ps_prochandle* ph) {432detach_all_pids(ph);433}434435static ps_prochandle_ops process_ops = {436.release= process_cleanup,437.p_pread= process_read_data,438.p_pwrite= process_write_data,439.get_lwp_regs= process_get_lwp_regs440};441442// attach to the process. One and only one exposed stuff443struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) {444struct ps_prochandle* ph = NULL;445thread_info* thr = NULL;446attach_state_t attach_status = ATTACH_SUCCESS;447448if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {449snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle");450print_debug("%s\n", err_buf);451return NULL;452}453454if ((attach_status = ptrace_attach(pid, err_buf, err_buf_len)) != ATTACH_SUCCESS) {455if (attach_status == ATTACH_THREAD_DEAD) {456print_error("The process with pid %d does not exist.\n", pid);457}458free(ph);459return NULL;460}461462// initialize ps_prochandle463ph->pid = pid;464465// initialize vtable466ph->ops = &process_ops;467468// read library info and symbol tables, must do this before attaching threads,469// as the symbols in the pthread library will be used to figure out470// the list of threads within the same process.471read_lib_info(ph);472473// read thread info474read_thread_info(ph, add_new_thread);475476// attach to the threads477thr = ph->threads;478479while (thr) {480thread_info* current_thr = thr;481thr = thr->next;482// don't attach to the main thread again483if (ph->pid != current_thr->lwp_id) {484if ((attach_status = ptrace_attach(current_thr->lwp_id, err_buf, err_buf_len)) != ATTACH_SUCCESS) {485if (attach_status == ATTACH_THREAD_DEAD) {486// Remove this thread from the threads list487delete_thread_info(ph, current_thr);488}489else {490Prelease(ph);491return NULL;492} // ATTACH_THREAD_DEAD493} // !ATTACH_SUCCESS494}495}496return ph;497}498499500