8231986: [SA] Consolidate parts of the Linux and MacOSX versions of ps_core.c
Reviewed-by: sspitsyn, cjplummer
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c Thu Oct 10 13:26:22 2019 +0200
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c Thu Oct 10 10:47:45 2019 -0700
@@ -31,336 +31,14 @@
#include <elf.h>
#include <link.h>
#include "libproc_impl.h"
+#include "ps_core_common.h"
#include "proc_service.h"
#include "salibelf.h"
-#include "cds.h"
// This file has the libproc implementation to read core files.
// For live processes, refer to ps_proc.c. Portions of this is adapted
// /modelled after Solaris libproc.so (in particular Pcore.c)
-//----------------------------------------------------------------------
-// ps_prochandle cleanup helper functions
-
-// close all file descriptors
-static void close_files(struct ps_prochandle* ph) {
- lib_info* lib = NULL;
-
- // close core file descriptor
- if (ph->core->core_fd >= 0)
- close(ph->core->core_fd);
-
- // close exec file descriptor
- if (ph->core->exec_fd >= 0)
- close(ph->core->exec_fd);
-
- // close interp file descriptor
- if (ph->core->interp_fd >= 0)
- close(ph->core->interp_fd);
-
- // close class share archive file
- if (ph->core->classes_jsa_fd >= 0)
- close(ph->core->classes_jsa_fd);
-
- // close all library file descriptors
- lib = ph->libs;
- while (lib) {
- int fd = lib->fd;
- if (fd >= 0 && fd != ph->core->exec_fd) {
- close(fd);
- }
- lib = lib->next;
- }
-}
-
-// clean all map_info stuff
-static void destroy_map_info(struct ps_prochandle* ph) {
- map_info* map = ph->core->maps;
- while (map) {
- map_info* next = map->next;
- free(map);
- map = next;
- }
-
- if (ph->core->map_array) {
- free(ph->core->map_array);
- }
-
- // Part of the class sharing workaround
- map = ph->core->class_share_maps;
- while (map) {
- map_info* next = map->next;
- free(map);
- map = next;
- }
-}
-
-// ps_prochandle operations
-static void core_release(struct ps_prochandle* ph) {
- if (ph->core) {
- close_files(ph);
- destroy_map_info(ph);
- free(ph->core);
- }
-}
-
-static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) {
- print_debug("can't allocate memory for map_info\n");
- return NULL;
- }
-
- // initialize map
- map->fd = fd;
- map->offset = offset;
- map->vaddr = vaddr;
- map->memsz = memsz;
- return map;
-}
-
-// add map info with given fd, offset, vaddr and memsz
-static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
- uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) {
- return NULL;
- }
-
- // add this to map list
- map->next = ph->core->maps;
- ph->core->maps = map;
- ph->core->num_maps++;
-
- return map;
-}
-
-// Part of the class sharing workaround
-static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset,
- uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ((map = allocate_init_map(ph->core->classes_jsa_fd,
- offset, vaddr, memsz)) == NULL) {
- return NULL;
- }
-
- map->next = ph->core->class_share_maps;
- ph->core->class_share_maps = map;
- return map;
-}
-
-// Return the map_info for the given virtual address. We keep a sorted
-// array of pointers in ph->map_array, so we can binary search.
-static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) {
- int mid, lo = 0, hi = ph->core->num_maps - 1;
- map_info *mp;
-
- while (hi - lo > 1) {
- mid = (lo + hi) / 2;
- if (addr >= ph->core->map_array[mid]->vaddr) {
- lo = mid;
- } else {
- hi = mid;
- }
- }
-
- if (addr < ph->core->map_array[hi]->vaddr) {
- mp = ph->core->map_array[lo];
- } else {
- mp = ph->core->map_array[hi];
- }
-
- if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
- return (mp);
- }
-
-
- // Part of the class sharing workaround
- // Unfortunately, we have no way of detecting -Xshare state.
- // Check out the share maps atlast, if we don't find anywhere.
- // This is done this way so to avoid reading share pages
- // ahead of other normal maps. For eg. with -Xshare:off we don't
- // want to prefer class sharing data to data from core.
- mp = ph->core->class_share_maps;
- if (mp) {
- print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr);
- }
- while (mp) {
- if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
- print_debug("located map_info at 0x%lx from class share maps\n", addr);
- return (mp);
- }
- mp = mp->next;
- }
-
- print_debug("can't locate map_info at 0x%lx\n", addr);
- return (NULL);
-}
-
-//---------------------------------------------------------------
-// Part of the class sharing workaround:
-//
-// With class sharing, pages are mapped from classes.jsa file.
-// The read-only class sharing pages are mapped as MAP_SHARED,
-// PROT_READ pages. These pages are not dumped into core dump.
-// With this workaround, these pages are read from classes.jsa.
-
-static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) {
- jboolean i;
- if (ps_pdread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) {
- *pvalue = i;
- return true;
- } else {
- return false;
- }
-}
-
-static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) {
- uintptr_t uip;
- if (ps_pdread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) {
- *pvalue = uip;
- return true;
- } else {
- return false;
- }
-}
-
-// used to read strings from debuggee
-static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) {
- size_t i = 0;
- char c = ' ';
-
- while (c != '\0') {
- if (ps_pdread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) {
- return false;
- }
- if (i < size - 1) {
- buf[i] = c;
- } else {
- // smaller buffer
- return false;
- }
- i++; addr++;
- }
-
- buf[i] = '\0';
- return true;
-}
-
-#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
-// mangled name of Arguments::SharedArchivePath
-#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE"
-#define LIBJVM_NAME "/libjvm.so"
-
-static bool init_classsharing_workaround(struct ps_prochandle* ph) {
- lib_info* lib = ph->libs;
- while (lib != NULL) {
- // we are iterating over shared objects from the core dump. look for
- // libjvm.so.
- const char *jvm_name = 0;
- if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) {
- char classes_jsa[PATH_MAX];
- CDSFileMapHeaderBase header;
- int fd = -1;
- int m = 0;
- size_t n = 0;
- uintptr_t base = 0, useSharedSpacesAddr = 0;
- uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0;
- jboolean useSharedSpaces = 0;
- map_info* mi = 0;
-
- memset(classes_jsa, 0, sizeof(classes_jsa));
- jvm_name = lib->name;
- useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM);
- if (useSharedSpacesAddr == 0) {
- print_debug("can't lookup 'UseSharedSpaces' flag\n");
- return false;
- }
-
- // Hotspot vm types are not exported to build this library. So
- // using equivalent type jboolean to read the value of
- // UseSharedSpaces which is same as hotspot type "bool".
- if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) {
- print_debug("can't read the value of 'UseSharedSpaces' flag\n");
- return false;
- }
-
- if ((int)useSharedSpaces == 0) {
- print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
- return true;
- }
-
- sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM);
- if (sharedArchivePathAddrAddr == 0) {
- print_debug("can't lookup shared archive path symbol\n");
- return false;
- }
-
- if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
- print_debug("can't read shared archive path pointer\n");
- return false;
- }
-
- if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
- print_debug("can't read shared archive path value\n");
- return false;
- }
-
- print_debug("looking for %s\n", classes_jsa);
- // open the class sharing archive file
- fd = pathmap_open(classes_jsa);
- if (fd < 0) {
- print_debug("can't open %s!\n", classes_jsa);
- ph->core->classes_jsa_fd = -1;
- return false;
- } else {
- print_debug("opened %s\n", classes_jsa);
- }
-
- // read CDSFileMapHeaderBase from the file
- memset(&header, 0, sizeof(CDSFileMapHeaderBase));
- if ((n = read(fd, &header, sizeof(CDSFileMapHeaderBase)))
- != sizeof(CDSFileMapHeaderBase)) {
- print_debug("can't read shared archive file map header from %s\n", classes_jsa);
- close(fd);
- return false;
- }
-
- // check file magic
- if (header._magic != CDS_ARCHIVE_MAGIC) {
- print_debug("%s has bad shared archive file magic number 0x%x, expecting 0x%x\n",
- classes_jsa, header._magic, CDS_ARCHIVE_MAGIC);
- close(fd);
- return false;
- }
-
- // check version
- if (header._version != CURRENT_CDS_ARCHIVE_VERSION) {
- print_debug("%s has wrong shared archive file version %d, expecting %d\n",
- classes_jsa, header._version, CURRENT_CDS_ARCHIVE_VERSION);
- close(fd);
- return false;
- }
-
- ph->core->classes_jsa_fd = fd;
- // add read-only maps from classes.jsa to the list of maps
- for (m = 0; m < NUM_CDS_REGIONS; m++) {
- if (header._space[m]._read_only) {
- base = (uintptr_t) header._space[m]._addr._base;
- // no need to worry about the fractional pages at-the-end.
- // possible fractional pages are handled by core_read_data.
- add_class_share_map_info(ph, (off_t) header._space[m]._file_offset,
- base, (size_t) header._space[m]._used);
- print_debug("added a share archive map at 0x%lx\n", base);
- }
- }
- return true;
- }
- lib = lib->next;
- }
- return true;
-}
-
//---------------------------------------------------------------------------
// functions to handle map_info
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c Thu Oct 10 13:26:22 2019 +0200
+++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c Thu Oct 10 10:47:45 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
#include <stdlib.h>
#include <stddef.h>
#include "libproc_impl.h"
-#include "cds.h"
+#include "ps_core_common.h"
#ifdef __APPLE__
#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
@@ -39,332 +39,6 @@
// For live processes, refer to ps_proc.c. Portions of this is adapted
// /modelled after Solaris libproc.so (in particular Pcore.c)
-//----------------------------------------------------------------------
-// ps_prochandle cleanup helper functions
-
-// close all file descriptors
-static void close_files(struct ps_prochandle* ph) {
- lib_info* lib = NULL;
-
- // close core file descriptor
- if (ph->core->core_fd >= 0)
- close(ph->core->core_fd);
-
- // close exec file descriptor
- if (ph->core->exec_fd >= 0)
- close(ph->core->exec_fd);
-
- // close interp file descriptor
- if (ph->core->interp_fd >= 0)
- close(ph->core->interp_fd);
-
- // close class share archive file
- if (ph->core->classes_jsa_fd >= 0)
- close(ph->core->classes_jsa_fd);
-
- // close all library file descriptors
- lib = ph->libs;
- while (lib) {
- int fd = lib->fd;
- if (fd >= 0 && fd != ph->core->exec_fd) {
- close(fd);
- }
- lib = lib->next;
- }
-}
-
-// clean all map_info stuff
-static void destroy_map_info(struct ps_prochandle* ph) {
- map_info* map = ph->core->maps;
- while (map) {
- map_info* next = map->next;
- free(map);
- map = next;
- }
-
- if (ph->core->map_array) {
- free(ph->core->map_array);
- }
-
- // Part of the class sharing workaround
- map = ph->core->class_share_maps;
- while (map) {
- map_info* next = map->next;
- free(map);
- map = next;
- }
-}
-
-// ps_prochandle operations
-static void core_release(struct ps_prochandle* ph) {
- if (ph->core) {
- close_files(ph);
- destroy_map_info(ph);
- free(ph->core);
- }
-}
-
-static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) {
- print_debug("can't allocate memory for map_info\n");
- return NULL;
- }
-
- // initialize map
- map->fd = fd;
- map->offset = offset;
- map->vaddr = vaddr;
- map->memsz = memsz;
- return map;
-}
-
-// add map info with given fd, offset, vaddr and memsz
-static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
- uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) {
- return NULL;
- }
-
- // add this to map list
- map->next = ph->core->maps;
- ph->core->maps = map;
- ph->core->num_maps++;
-
- return map;
-}
-
-// Part of the class sharing workaround
-static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset,
- uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ((map = allocate_init_map(ph->core->classes_jsa_fd,
- offset, vaddr, memsz)) == NULL) {
- return NULL;
- }
-
- map->next = ph->core->class_share_maps;
- ph->core->class_share_maps = map;
- return map;
-}
-
-// Return the map_info for the given virtual address. We keep a sorted
-// array of pointers in ph->map_array, so we can binary search.
-static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) {
- int mid, lo = 0, hi = ph->core->num_maps - 1;
- map_info *mp;
-
- while (hi - lo > 1) {
- mid = (lo + hi) / 2;
- if (addr >= ph->core->map_array[mid]->vaddr) {
- lo = mid;
- } else {
- hi = mid;
- }
- }
-
- if (addr < ph->core->map_array[hi]->vaddr) {
- mp = ph->core->map_array[lo];
- } else {
- mp = ph->core->map_array[hi];
- }
-
- if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
- return (mp);
- }
-
-
- // Part of the class sharing workaround
- // Unfortunately, we have no way of detecting -Xshare state.
- // Check out the share maps atlast, if we don't find anywhere.
- // This is done this way so to avoid reading share pages
- // ahead of other normal maps. For eg. with -Xshare:off we don't
- // want to prefer class sharing data to data from core.
- mp = ph->core->class_share_maps;
- if (mp) {
- print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr);
- }
- while (mp) {
- if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
- print_debug("located map_info at 0x%lx from class share maps\n", addr);
- return (mp);
- }
- mp = mp->next;
- }
-
- print_debug("can't locate map_info at 0x%lx\n", addr);
- return (NULL);
-}
-
-//---------------------------------------------------------------
-// Part of the class sharing workaround:
-//
-// With class sharing, pages are mapped from classes.jsa file.
-// The read-only class sharing pages are mapped as MAP_SHARED,
-// PROT_READ pages. These pages are not dumped into core dump.
-// With this workaround, these pages are read from classes.jsa.
-
-static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) {
- jboolean i;
- if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) {
- *pvalue = i;
- return true;
- } else {
- return false;
- }
-}
-
-static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) {
- uintptr_t uip;
- if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) {
- *pvalue = uip;
- return true;
- } else {
- return false;
- }
-}
-
-// used to read strings from debuggee
-static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) {
- size_t i = 0;
- char c = ' ';
-
- while (c != '\0') {
- if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) {
- return false;
- }
- if (i < size - 1) {
- buf[i] = c;
- } else {
- // smaller buffer
- return false;
- }
- i++; addr++;
- }
- buf[i] = '\0';
- return true;
-}
-
-// mangled name of Arguments::SharedArchivePath
-#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE"
-
-#ifdef __APPLE__
-#define USE_SHARED_SPACES_SYM "_UseSharedSpaces"
-#define LIBJVM_NAME "/libjvm.dylib"
-#else
-#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
-#define LIBJVM_NAME "/libjvm.so"
-#endif // __APPLE_
-
-static bool init_classsharing_workaround(struct ps_prochandle* ph) {
- int m;
- size_t n;
- lib_info* lib = ph->libs;
- while (lib != NULL) {
- // we are iterating over shared objects from the core dump. look for
- // libjvm.so.
- const char *jvm_name = 0;
- if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) {
- char classes_jsa[PATH_MAX];
- CDSFileMapHeaderBase header;
- int fd = -1;
- uintptr_t base = 0, useSharedSpacesAddr = 0;
- uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0;
- jboolean useSharedSpaces = 0;
-
- memset(classes_jsa, 0, sizeof(classes_jsa));
- jvm_name = lib->name;
- useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM);
- if (useSharedSpacesAddr == 0) {
- print_debug("can't lookup 'UseSharedSpaces' flag\n");
- return false;
- }
-
- // Hotspot vm types are not exported to build this library. So
- // using equivalent type jboolean to read the value of
- // UseSharedSpaces which is same as hotspot type "bool".
- if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) {
- print_debug("can't read the value of 'UseSharedSpaces' flag\n");
- return false;
- }
-
- if ((int)useSharedSpaces == 0) {
- print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
- return true;
- }
-
- sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM);
- if (sharedArchivePathAddrAddr == 0) {
- print_debug("can't lookup shared archive path symbol\n");
- return false;
- }
-
- if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
- print_debug("can't read shared archive path pointer\n");
- return false;
- }
-
- if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
- print_debug("can't read shared archive path value\n");
- return false;
- }
-
- print_debug("looking for %s\n", classes_jsa);
- // open the class sharing archive file
- fd = pathmap_open(classes_jsa);
- if (fd < 0) {
- print_debug("can't open %s!\n", classes_jsa);
- ph->core->classes_jsa_fd = -1;
- return false;
- } else {
- print_debug("opened %s\n", classes_jsa);
- }
-
- // read CDSFileMapHeaderBase from the file
- memset(&header, 0, sizeof(CDSFileMapHeaderBase));
- if ((n = read(fd, &header, sizeof(CDSFileMapHeaderBase)))
- != sizeof(CDSFileMapHeaderBase)) {
- print_debug("can't read shared archive file map header from %s\n", classes_jsa);
- close(fd);
- return false;
- }
-
- // check file magic
- if (header._magic != CDS_ARCHIVE_MAGIC) {
- print_debug("%s has bad shared archive file magic number 0x%x, expecting 0x%x\n",
- classes_jsa, header._magic, CDS_ARCHIVE_MAGIC);
- close(fd);
- return false;
- }
-
- // check version
- if (header._version != CURRENT_CDS_ARCHIVE_VERSION) {
- print_debug("%s has wrong shared archive file version %d, expecting %d\n",
- classes_jsa, header._version, CURRENT_CDS_ARCHIVE_VERSION);
- close(fd);
- return false;
- }
-
- ph->core->classes_jsa_fd = fd;
- // add read-only maps from classes.jsa to the list of maps
- for (m = 0; m < NUM_CDS_REGIONS; m++) {
- if (header._space[m]._read_only) {
- base = (uintptr_t) header._space[m]._addr._base;
- // no need to worry about the fractional pages at-the-end.
- // possible fractional pages are handled by core_read_data.
- add_class_share_map_info(ph, (off_t) header._space[m]._file_offset,
- base, (size_t) header._space[m]._used);
- print_debug("added a share archive map at 0x%lx\n", base);
- }
- }
- return true;
- }
- lib = lib->next;
- }
- return true;
-}
-
//---------------------------------------------------------------------------
// functions to handle map_info
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c Thu Oct 10 10:47:45 2019 -0700
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include <jni.h> // just include something, or else solaris compiler will complain that this file is empty
+
+#if defined(LINUX) || defined(__APPLE__)
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#ifdef LINUX
+#include <elf.h>
+#include <link.h>
+#include "proc_service.h"
+#include "salibelf.h"
+#endif
+#include "libproc_impl.h"
+#include "cds.h"
+
+#ifdef __APPLE__
+#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
+#endif
+
+#ifdef LINUX
+// I have no idea why this function is called ps_pread() on macos but ps_pdread on linux.
+#define ps_pread ps_pdread
+#endif
+
+// Common code shared between linux/native/libsaproc/ps_core.c and macosx/native/libsaproc/ps_core.c
+
+//----------------------------------------------------------------------
+// ps_prochandle cleanup helper functions
+
+// close all file descriptors
+static void close_files(struct ps_prochandle* ph) {
+ lib_info* lib = NULL;
+
+ // close core file descriptor
+ if (ph->core->core_fd >= 0)
+ close(ph->core->core_fd);
+
+ // close exec file descriptor
+ if (ph->core->exec_fd >= 0)
+ close(ph->core->exec_fd);
+
+ // close interp file descriptor
+ if (ph->core->interp_fd >= 0)
+ close(ph->core->interp_fd);
+
+ // close class share archive file
+ if (ph->core->classes_jsa_fd >= 0)
+ close(ph->core->classes_jsa_fd);
+
+ // close all library file descriptors
+ lib = ph->libs;
+ while (lib) {
+ int fd = lib->fd;
+ if (fd >= 0 && fd != ph->core->exec_fd) {
+ close(fd);
+ }
+ lib = lib->next;
+ }
+}
+
+// clean all map_info stuff
+static void destroy_map_info(struct ps_prochandle* ph) {
+ map_info* map = ph->core->maps;
+ while (map) {
+ map_info* next = map->next;
+ free(map);
+ map = next;
+ }
+
+ if (ph->core->map_array) {
+ free(ph->core->map_array);
+ }
+
+ // Part of the class sharing workaround
+ map = ph->core->class_share_maps;
+ while (map) {
+ map_info* next = map->next;
+ free(map);
+ map = next;
+ }
+}
+
+// ps_prochandle operations
+void core_release(struct ps_prochandle* ph) {
+ if (ph->core) {
+ close_files(ph);
+ destroy_map_info(ph);
+ free(ph->core);
+ }
+}
+
+static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) {
+ map_info* map;
+ if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) {
+ print_debug("can't allocate memory for map_info\n");
+ return NULL;
+ }
+
+ // initialize map
+ map->fd = fd;
+ map->offset = offset;
+ map->vaddr = vaddr;
+ map->memsz = memsz;
+ return map;
+}
+
+// add map info with given fd, offset, vaddr and memsz
+map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
+ uintptr_t vaddr, size_t memsz) {
+ map_info* map;
+ if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) {
+ return NULL;
+ }
+
+ // add this to map list
+ map->next = ph->core->maps;
+ ph->core->maps = map;
+ ph->core->num_maps++;
+
+ return map;
+}
+
+// Part of the class sharing workaround
+static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset,
+ uintptr_t vaddr, size_t memsz) {
+ map_info* map;
+ if ((map = allocate_init_map(ph->core->classes_jsa_fd,
+ offset, vaddr, memsz)) == NULL) {
+ return NULL;
+ }
+
+ map->next = ph->core->class_share_maps;
+ ph->core->class_share_maps = map;
+ return map;
+}
+
+// Return the map_info for the given virtual address. We keep a sorted
+// array of pointers in ph->map_array, so we can binary search.
+map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) {
+ int mid, lo = 0, hi = ph->core->num_maps - 1;
+ map_info *mp;
+
+ while (hi - lo > 1) {
+ mid = (lo + hi) / 2;
+ if (addr >= ph->core->map_array[mid]->vaddr) {
+ lo = mid;
+ } else {
+ hi = mid;
+ }
+ }
+
+ if (addr < ph->core->map_array[hi]->vaddr) {
+ mp = ph->core->map_array[lo];
+ } else {
+ mp = ph->core->map_array[hi];
+ }
+
+ if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
+ return (mp);
+ }
+
+
+ // Part of the class sharing workaround
+ // Unfortunately, we have no way of detecting -Xshare state.
+ // Check out the share maps atlast, if we don't find anywhere.
+ // This is done this way so to avoid reading share pages
+ // ahead of other normal maps. For eg. with -Xshare:off we don't
+ // want to prefer class sharing data to data from core.
+ mp = ph->core->class_share_maps;
+ if (mp) {
+ print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr);
+ }
+ while (mp) {
+ if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
+ print_debug("located map_info at 0x%lx from class share maps\n", addr);
+ return (mp);
+ }
+ mp = mp->next;
+ }
+
+ print_debug("can't locate map_info at 0x%lx\n", addr);
+ return (NULL);
+}
+
+//---------------------------------------------------------------
+// Part of the class sharing workaround:
+//
+// With class sharing, pages are mapped from classes.jsa file.
+// The read-only class sharing pages are mapped as MAP_SHARED,
+// PROT_READ pages. These pages are not dumped into core dump.
+// With this workaround, these pages are read from classes.jsa.
+
+static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) {
+ jboolean i;
+ if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) {
+ *pvalue = i;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) {
+ uintptr_t uip;
+ if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) {
+ *pvalue = uip;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// used to read strings from debuggee
+bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) {
+ size_t i = 0;
+ char c = ' ';
+
+ while (c != '\0') {
+ if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) {
+ return false;
+ }
+ if (i < size - 1) {
+ buf[i] = c;
+ } else {
+ // smaller buffer
+ return false;
+ }
+ i++; addr++;
+ }
+ buf[i] = '\0';
+ return true;
+}
+
+#ifdef LINUX
+// mangled name of Arguments::SharedArchivePath
+#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE"
+#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
+#define LIBJVM_NAME "/libjvm.so"
+#endif
+
+#ifdef __APPLE__
+// mangled name of Arguments::SharedArchivePath
+#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE"
+#define USE_SHARED_SPACES_SYM "_UseSharedSpaces"
+#define LIBJVM_NAME "/libjvm.dylib"
+#endif
+
+bool init_classsharing_workaround(struct ps_prochandle* ph) {
+ lib_info* lib = ph->libs;
+ while (lib != NULL) {
+ // we are iterating over shared objects from the core dump. look for
+ // libjvm.so.
+ const char *jvm_name = 0;
+ if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) {
+ char classes_jsa[PATH_MAX];
+ CDSFileMapHeaderBase header;
+ int fd = -1;
+ uintptr_t base = 0, useSharedSpacesAddr = 0;
+ uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0;
+ jboolean useSharedSpaces = 0;
+ int m;
+ size_t n;
+
+ memset(classes_jsa, 0, sizeof(classes_jsa));
+ jvm_name = lib->name;
+ useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM);
+ if (useSharedSpacesAddr == 0) {
+ print_debug("can't lookup 'UseSharedSpaces' flag\n");
+ return false;
+ }
+
+ // Hotspot vm types are not exported to build this library. So
+ // using equivalent type jboolean to read the value of
+ // UseSharedSpaces which is same as hotspot type "bool".
+ if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) {
+ print_debug("can't read the value of 'UseSharedSpaces' flag\n");
+ return false;
+ }
+
+ if ((int)useSharedSpaces == 0) {
+ print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
+ return true;
+ }
+
+ sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM);
+ if (sharedArchivePathAddrAddr == 0) {
+ print_debug("can't lookup shared archive path symbol\n");
+ return false;
+ }
+
+ if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
+ print_debug("can't read shared archive path pointer\n");
+ return false;
+ }
+
+ if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
+ print_debug("can't read shared archive path value\n");
+ return false;
+ }
+
+ print_debug("looking for %s\n", classes_jsa);
+ // open the class sharing archive file
+ fd = pathmap_open(classes_jsa);
+ if (fd < 0) {
+ print_debug("can't open %s!\n", classes_jsa);
+ ph->core->classes_jsa_fd = -1;
+ return false;
+ } else {
+ print_debug("opened %s\n", classes_jsa);
+ }
+
+ // read CDSFileMapHeaderBase from the file
+ memset(&header, 0, sizeof(CDSFileMapHeaderBase));
+ if ((n = read(fd, &header, sizeof(CDSFileMapHeaderBase)))
+ != sizeof(CDSFileMapHeaderBase)) {
+ print_debug("can't read shared archive file map header from %s\n", classes_jsa);
+ close(fd);
+ return false;
+ }
+
+ // check file magic
+ if (header._magic != CDS_ARCHIVE_MAGIC) {
+ print_debug("%s has bad shared archive file magic number 0x%x, expecting 0x%x\n",
+ classes_jsa, header._magic, CDS_ARCHIVE_MAGIC);
+ close(fd);
+ return false;
+ }
+
+ // check version
+ if (header._version != CURRENT_CDS_ARCHIVE_VERSION) {
+ print_debug("%s has wrong shared archive file version %d, expecting %d\n",
+ classes_jsa, header._version, CURRENT_CDS_ARCHIVE_VERSION);
+ close(fd);
+ return false;
+ }
+
+ ph->core->classes_jsa_fd = fd;
+ // add read-only maps from classes.jsa to the list of maps
+ for (m = 0; m < NUM_CDS_REGIONS; m++) {
+ if (header._space[m]._read_only) {
+ // With *some* linux versions, the core file doesn't include read-only mmap'ed
+ // files regions, so let's add them here. This is harmless if the core file also
+ // include these regions.
+ base = (uintptr_t) header._space[m]._addr._base;
+ // no need to worry about the fractional pages at-the-end.
+ // possible fractional pages are handled by core_read_data.
+ add_class_share_map_info(ph, (off_t) header._space[m]._file_offset,
+ base, (size_t) header._space[m]._used);
+ print_debug("added a share archive map at 0x%lx\n", base);
+ }
+ }
+ return true;
+ }
+ lib = lib->next;
+ }
+ return true;
+}
+
+#endif // defined(LINUX) || defined(__APPLE__)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.h Thu Oct 10 10:47:45 2019 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef _PS_CORE_COMMON_H_
+#define _PS_CORE_COMMON_H_
+
+map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr);
+map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
+ uintptr_t vaddr, size_t memsz);
+void core_release(struct ps_prochandle* ph);
+bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size);
+bool init_classsharing_workaround(struct ps_prochandle* ph);
+
+#endif // _PS_CORE_COMMON_H_