Path: blob/jdk8u272-b10-aarch32-20201026/hotspot/agent/src/os/linux/libproc_impl.c
48792 views
/*1* Copyright (c) 2003, 2019, 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*/23#include <stdarg.h>24#include <stdio.h>25#include <stdlib.h>26#include <string.h>27#include <fcntl.h>28#include <thread_db.h>29#include "libproc_impl.h"3031#define SA_ALTROOT "SA_ALTROOT"3233int pathmap_open(const char* name) {34static const char *alt_root = NULL;35static int alt_root_initialized = 0;3637int fd;38char alt_path[PATH_MAX + 1], *alt_path_end;39const char *s;4041if (!alt_root_initialized) {42alt_root_initialized = -1;43alt_root = getenv(SA_ALTROOT);44}4546if (alt_root == NULL) {47return open(name, O_RDONLY);48}4950strcpy(alt_path, alt_root);51alt_path_end = alt_path + strlen(alt_path);5253// Strip path items one by one and try to open file with alt_root prepended54s = name;55while (1) {56strcat(alt_path, s);57s += 1;5859fd = open(alt_path, O_RDONLY);60if (fd >= 0) {61print_debug("path %s substituted for %s\n", alt_path, name);62return fd;63}6465// Linker always put full path to solib to process, so we can rely66// on presence of /. If slash is not present, it means, that SOlib doesn't67// physically exist (e.g. linux-gate.so) and we fail opening it anyway68if ((s = strchr(s, '/')) == NULL) {69break;70}7172*alt_path_end = 0;73}7475return -1;76}7778static bool _libsaproc_debug;7980void print_debug(const char* format,...) {81if (_libsaproc_debug) {82va_list alist;8384va_start(alist, format);85fputs("libsaproc DEBUG: ", stderr);86vfprintf(stderr, format, alist);87va_end(alist);88}89}9091void print_error(const char* format,...) {92va_list alist;93va_start(alist, format);94fputs("ERROR: ", stderr);95vfprintf(stderr, format, alist);96va_end(alist);97}9899bool is_debug() {100return _libsaproc_debug;101}102103// initialize libproc104bool init_libproc(bool debug) {105// init debug mode106_libsaproc_debug = debug;107108// initialize the thread_db library109if (td_init() != TD_OK) {110print_debug("libthread_db's td_init failed\n");111return false;112}113114return true;115}116117static void destroy_lib_info(struct ps_prochandle* ph) {118lib_info* lib = ph->libs;119while (lib) {120lib_info *next = lib->next;121if (lib->symtab) {122destroy_symtab(lib->symtab);123}124free(lib);125lib = next;126}127}128129static void destroy_thread_info(struct ps_prochandle* ph) {130thread_info* thr = ph->threads;131while (thr) {132thread_info *next = thr->next;133free(thr);134thr = next;135}136}137138// ps_prochandle cleanup139140// ps_prochandle cleanup141void Prelease(struct ps_prochandle* ph) {142// do the "derived class" clean-up first143ph->ops->release(ph);144destroy_lib_info(ph);145destroy_thread_info(ph);146free(ph);147}148149lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {150return add_lib_info_fd(ph, libname, -1, base);151}152153lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {154lib_info* newlib;155156if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {157print_debug("can't allocate memory for lib_info\n");158return NULL;159}160161if (strlen(libname) >= sizeof(newlib->name)) {162print_debug("libname %s too long\n", libname);163return NULL;164}165strcpy(newlib->name, libname);166167newlib->base = base;168169if (fd == -1) {170if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {171print_debug("can't open shared object %s\n", newlib->name);172free(newlib);173return NULL;174}175} else {176newlib->fd = fd;177}178179// check whether we have got an ELF file. /proc/<pid>/map180// gives out all file mappings and not just shared objects181if (is_elf_file(newlib->fd) == false) {182close(newlib->fd);183free(newlib);184return NULL;185}186187newlib->symtab = build_symtab(newlib->fd, libname);188if (newlib->symtab == NULL) {189print_debug("symbol table build failed for %s\n", newlib->name);190}191192// even if symbol table building fails, we add the lib_info.193// This is because we may need to read from the ELF file for core file194// address read functionality. lookup_symbol checks for NULL symtab.195if (ph->libs) {196ph->lib_tail->next = newlib;197ph->lib_tail = newlib;198} else {199ph->libs = ph->lib_tail = newlib;200}201ph->num_libs++;202203return newlib;204}205206// lookup for a specific symbol207uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,208const char* sym_name) {209// ignore object_name. search in all libraries210// FIXME: what should we do with object_name?? The library names are obtained211// by parsing /proc/<pid>/maps, which may not be the same as object_name.212// What we need is a utility to map object_name to real file name, something213// dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For214// now, we just ignore object_name and do a global search for the symbol.215216lib_info* lib = ph->libs;217while (lib) {218if (lib->symtab) {219uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);220if (res) return res;221}222lib = lib->next;223}224225print_debug("lookup failed for symbol '%s' in obj '%s'\n",226sym_name, object_name);227return (uintptr_t) NULL;228}229230231const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) {232const char* res = NULL;233lib_info* lib = ph->libs;234while (lib) {235if (lib->symtab && addr >= lib->base) {236res = nearest_symbol(lib->symtab, addr - lib->base, poffset);237if (res) return res;238}239lib = lib->next;240}241return NULL;242}243244// add a thread to ps_prochandle245thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {246thread_info* newthr;247if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) {248print_debug("can't allocate memory for thread_info\n");249return NULL;250}251252// initialize thread info253newthr->pthread_id = pthread_id;254newthr->lwp_id = lwp_id;255256// add new thread to the list257newthr->next = ph->threads;258ph->threads = newthr;259ph->num_threads++;260return newthr;261}262263void delete_thread_info(struct ps_prochandle* ph, thread_info* thr_to_be_removed) {264thread_info* current_thr = ph->threads;265266if (thr_to_be_removed == ph->threads) {267ph->threads = ph->threads->next;268} else {269thread_info* previous_thr;270while (current_thr && current_thr != thr_to_be_removed) {271previous_thr = current_thr;272current_thr = current_thr->next;273}274if (current_thr == NULL) {275print_error("Could not find the thread to be removed");276return;277}278previous_thr->next = current_thr->next;279}280ph->num_threads--;281free(current_thr);282}283284// struct used for client data from thread_db callback285struct thread_db_client_data {286struct ps_prochandle* ph;287thread_info_callback callback;288};289290// callback function for libthread_db291static int thread_db_callback(const td_thrhandle_t *th_p, void *data) {292struct thread_db_client_data* ptr = (struct thread_db_client_data*) data;293td_thrinfo_t ti;294td_err_e err;295296memset(&ti, 0, sizeof(ti));297err = td_thr_get_info(th_p, &ti);298if (err != TD_OK) {299print_debug("libthread_db : td_thr_get_info failed, can't get thread info\n");300return err;301}302303print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid);304305if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) {306print_debug("Skipping pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid);307return TD_OK;308}309310if (ptr->callback(ptr->ph, ti.ti_tid, ti.ti_lid) != true)311return TD_ERR;312313return TD_OK;314}315316// read thread_info using libthread_db317bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) {318struct thread_db_client_data mydata;319td_thragent_t* thread_agent = NULL;320if (td_ta_new(ph, &thread_agent) != TD_OK) {321print_debug("can't create libthread_db agent\n");322return false;323}324325mydata.ph = ph;326mydata.callback = cb;327328// we use libthread_db iterator to iterate thru list of threads.329if (td_ta_thr_iter(thread_agent, thread_db_callback, &mydata,330TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,331TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS) != TD_OK) {332td_ta_delete(thread_agent);333return false;334}335336// delete thread agent337td_ta_delete(thread_agent);338return true;339}340341342// get number of threads343int get_num_threads(struct ps_prochandle* ph) {344return ph->num_threads;345}346347// get lwp_id of n'th thread348lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) {349int count = 0;350thread_info* thr = ph->threads;351while (thr) {352if (count == index) {353return thr->lwp_id;354}355count++;356thr = thr->next;357}358return -1;359}360361// get regs for a given lwp362bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct user_regs_struct* regs) {363return ph->ops->get_lwp_regs(ph, lwp_id, regs);364}365366// get number of shared objects367int get_num_libs(struct ps_prochandle* ph) {368return ph->num_libs;369}370371// get name of n'th solib372const char* get_lib_name(struct ps_prochandle* ph, int index) {373int count = 0;374lib_info* lib = ph->libs;375while (lib) {376if (count == index) {377return lib->name;378}379count++;380lib = lib->next;381}382return NULL;383}384385// get base address of a lib386uintptr_t get_lib_base(struct ps_prochandle* ph, int index) {387int count = 0;388lib_info* lib = ph->libs;389while (lib) {390if (count == index) {391return lib->base;392}393count++;394lib = lib->next;395}396return (uintptr_t)NULL;397}398399bool find_lib(struct ps_prochandle* ph, const char *lib_name) {400lib_info *p = ph->libs;401while (p) {402if (strcmp(p->name, lib_name) == 0) {403return true;404}405p = p->next;406}407return false;408}409410//--------------------------------------------------------------------------411// proc service functions412413// get process id414pid_t ps_getpid(struct ps_prochandle *ph) {415return ph->pid;416}417418// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table419// of the load object object_name in the target process identified by ph.420// It returns the symbol's value as an address in the target process in421// *sym_addr.422423ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,424const char *sym_name, psaddr_t *sym_addr) {425*sym_addr = (psaddr_t) lookup_symbol(ph, object_name, sym_name);426return (*sym_addr ? PS_OK : PS_NOSYM);427}428429// read "size" bytes info "buf" from address "addr"430ps_err_e ps_pdread(struct ps_prochandle *ph, psaddr_t addr,431void *buf, size_t size) {432return ph->ops->p_pread(ph, (uintptr_t) addr, buf, size)? PS_OK: PS_ERR;433}434435// write "size" bytes of data to debuggee at address "addr"436ps_err_e ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr,437const void *buf, size_t size) {438return ph->ops->p_pwrite(ph, (uintptr_t)addr, buf, size)? PS_OK: PS_ERR;439}440441// ------------------------------------------------------------------------442// Functions below this point are not yet implemented. They are here only443// to make the linker happy.444445ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) {446print_debug("ps_lsetfpregs not implemented\n");447return PS_OK;448}449450ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lid, const prgregset_t gregset) {451print_debug("ps_lsetregs not implemented\n");452return PS_OK;453}454455ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lid, prfpregset_t *fpregs) {456print_debug("ps_lgetfpregs not implemented\n");457return PS_OK;458}459460ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) {461print_debug("ps_lgetfpregs not implemented\n");462return PS_OK;463}464465// new libthread_db of NPTL seem to require this symbol466ps_err_e ps_get_thread_area() {467print_debug("ps_get_thread_area not implemented\n");468return PS_OK;469}470471472