| File: | jdk/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c |
| Warning: | line 361, column 12 Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. |
| 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 | #if defined(LINUX1) || defined(__APPLE__) |
| 26 | #include <unistd.h> |
| 27 | #include <fcntl.h> |
| 28 | #include <string.h> |
| 29 | #include <stdlib.h> |
| 30 | #include <stddef.h> |
| 31 | #ifdef LINUX1 |
| 32 | #include <elf.h> |
| 33 | #include <link.h> |
| 34 | #include "proc_service.h" |
| 35 | #include "salibelf.h" |
| 36 | #endif |
| 37 | #include "libproc_impl.h" |
| 38 | #include "cds.h" |
| 39 | |
| 40 | #ifdef __APPLE__ |
| 41 | #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" |
| 42 | #endif |
| 43 | |
| 44 | // Define a segment permission flag allowing read if there is a read flag. Otherwise use 0. |
| 45 | #ifdef PF_R(1 << 2) |
| 46 | #define MAP_R_FLAG(1 << 2) PF_R(1 << 2) |
| 47 | #else |
| 48 | #define MAP_R_FLAG(1 << 2) 0 |
| 49 | #endif |
| 50 | |
| 51 | #ifdef LINUX1 |
| 52 | // I have no idea why this function is called ps_pread() on macos but ps_pdread on linux. |
| 53 | #define ps_preadps_pdread ps_pdread |
| 54 | #endif |
| 55 | |
| 56 | // Common code shared between linux/native/libsaproc/ps_core.c and macosx/native/libsaproc/ps_core.c |
| 57 | |
| 58 | //---------------------------------------------------------------------- |
| 59 | // ps_prochandle cleanup helper functions |
| 60 | |
| 61 | // close all file descriptors |
| 62 | static void close_files(struct ps_prochandle* ph) { |
| 63 | lib_info* lib = NULL((void*)0); |
| 64 | |
| 65 | // close core file descriptor |
| 66 | if (ph->core->core_fd >= 0) |
| 67 | close(ph->core->core_fd); |
| 68 | |
| 69 | // close exec file descriptor |
| 70 | if (ph->core->exec_fd >= 0) |
| 71 | close(ph->core->exec_fd); |
| 72 | |
| 73 | // close interp file descriptor |
| 74 | if (ph->core->interp_fd >= 0) |
| 75 | close(ph->core->interp_fd); |
| 76 | |
| 77 | // close class share archive file |
| 78 | if (ph->core->classes_jsa_fd >= 0) |
| 79 | close(ph->core->classes_jsa_fd); |
| 80 | |
| 81 | // close all library file descriptors |
| 82 | lib = ph->libs; |
| 83 | while (lib) { |
| 84 | int fd = lib->fd; |
| 85 | if (fd >= 0 && fd != ph->core->exec_fd) { |
| 86 | close(fd); |
| 87 | } |
| 88 | lib = lib->next; |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // clean all map_info stuff |
| 93 | static void destroy_map_info(struct ps_prochandle* ph) { |
| 94 | map_info* map = ph->core->maps; |
| 95 | while (map) { |
| 96 | map_info* next = map->next; |
| 97 | free(map); |
| 98 | map = next; |
| 99 | } |
| 100 | |
| 101 | if (ph->core->map_array) { |
| 102 | free(ph->core->map_array); |
| 103 | } |
| 104 | |
| 105 | // Part of the class sharing workaround |
| 106 | map = ph->core->class_share_maps; |
| 107 | while (map) { |
| 108 | map_info* next = map->next; |
| 109 | free(map); |
| 110 | map = next; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | // ps_prochandle operations |
| 115 | void core_release(struct ps_prochandle* ph) { |
| 116 | if (ph->core) { |
| 117 | close_files(ph); |
| 118 | destroy_map_info(ph); |
| 119 | free(ph->core); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz, uint32_t flags) { |
| 124 | map_info* map; |
| 125 | if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL((void*)0)) { |
| 126 | print_debug("can't allocate memory for map_info\n"); |
| 127 | return NULL((void*)0); |
| 128 | } |
| 129 | |
| 130 | // initialize map |
| 131 | map->fd = fd; |
| 132 | map->offset = offset; |
| 133 | map->vaddr = vaddr; |
| 134 | map->memsz = memsz; |
| 135 | map->flags = flags; |
| 136 | return map; |
| 137 | } |
| 138 | |
| 139 | // add map info with given fd, offset, vaddr and memsz |
| 140 | map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, |
| 141 | uintptr_t vaddr, size_t memsz, uint32_t flags) { |
| 142 | map_info* map; |
| 143 | if ((map = allocate_init_map(fd, offset, vaddr, memsz, flags)) == NULL((void*)0)) { |
| 144 | return NULL((void*)0); |
| 145 | } |
| 146 | |
| 147 | // add this to map list |
| 148 | map->next = ph->core->maps; |
| 149 | ph->core->maps = map; |
| 150 | ph->core->num_maps++; |
| 151 | |
| 152 | return map; |
| 153 | } |
| 154 | |
| 155 | // Part of the class sharing workaround |
| 156 | static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, |
| 157 | uintptr_t vaddr, size_t memsz) { |
| 158 | map_info* map; |
| 159 | if ((map = allocate_init_map(ph->core->classes_jsa_fd, |
| 160 | offset, vaddr, memsz, MAP_R_FLAG(1 << 2))) == NULL((void*)0)) { |
| 161 | return NULL((void*)0); |
| 162 | } |
| 163 | |
| 164 | map->next = ph->core->class_share_maps; |
| 165 | ph->core->class_share_maps = map; |
| 166 | return map; |
| 167 | } |
| 168 | |
| 169 | // Return the map_info for the given virtual address. We keep a sorted |
| 170 | // array of pointers in ph->map_array, so we can binary search. |
| 171 | map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { |
| 172 | int mid, lo = 0, hi = ph->core->num_maps - 1; |
| 173 | map_info *mp; |
| 174 | |
| 175 | while (hi - lo > 1) { |
| 176 | mid = (lo + hi) / 2; |
| 177 | if (addr >= ph->core->map_array[mid]->vaddr) { |
| 178 | lo = mid; |
| 179 | } else { |
| 180 | hi = mid; |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | if (addr < ph->core->map_array[hi]->vaddr) { |
| 185 | mp = ph->core->map_array[lo]; |
| 186 | } else { |
| 187 | mp = ph->core->map_array[hi]; |
| 188 | } |
| 189 | |
| 190 | if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { |
| 191 | return (mp); |
| 192 | } |
| 193 | |
| 194 | |
| 195 | // Part of the class sharing workaround |
| 196 | // Unfortunately, we have no way of detecting -Xshare state. |
| 197 | // Check out the share maps atlast, if we don't find anywhere. |
| 198 | // This is done this way so to avoid reading share pages |
| 199 | // ahead of other normal maps. For eg. with -Xshare:off we don't |
| 200 | // want to prefer class sharing data to data from core. |
| 201 | mp = ph->core->class_share_maps; |
| 202 | if (mp) { |
| 203 | print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr); |
| 204 | } |
| 205 | while (mp) { |
| 206 | if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { |
| 207 | print_debug("located map_info at 0x%lx from class share maps\n", addr); |
| 208 | return (mp); |
| 209 | } |
| 210 | mp = mp->next; |
| 211 | } |
| 212 | |
| 213 | print_debug("can't locate map_info at 0x%lx\n", addr); |
| 214 | return (NULL((void*)0)); |
| 215 | } |
| 216 | |
| 217 | //--------------------------------------------------------------- |
| 218 | // Part of the class sharing workaround: |
| 219 | // |
| 220 | // With class sharing, pages are mapped from classes.jsa file. |
| 221 | // The read-only class sharing pages are mapped as MAP_SHARED, |
| 222 | // PROT_READ pages. These pages are not dumped into core dump. |
| 223 | // With this workaround, these pages are read from classes.jsa. |
| 224 | |
| 225 | static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { |
| 226 | jboolean i; |
| 227 | if (ps_preadps_pdread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { |
| 228 | *pvalue = i; |
| 229 | return true1; |
| 230 | } else { |
| 231 | return false0; |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) { |
| 236 | uintptr_t uip; |
| 237 | if (ps_preadps_pdread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) { |
| 238 | *pvalue = uip; |
| 239 | return true1; |
| 240 | } else { |
| 241 | return false0; |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | // used to read strings from debuggee |
| 246 | bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) { |
| 247 | size_t i = 0; |
| 248 | char c = ' '; |
| 249 | |
| 250 | while (c != '\0') { |
| 251 | if (ps_preadps_pdread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) { |
| 252 | return false0; |
| 253 | } |
| 254 | if (i < size - 1) { |
| 255 | buf[i] = c; |
| 256 | } else { |
| 257 | // smaller buffer |
| 258 | return false0; |
| 259 | } |
| 260 | i++; addr++; |
| 261 | } |
| 262 | buf[i] = '\0'; |
| 263 | return true1; |
| 264 | } |
| 265 | |
| 266 | #ifdef LINUX1 |
| 267 | // mangled name of Arguments::SharedArchivePath |
| 268 | #define SHARED_ARCHIVE_PATH_SYM"_ZN9Arguments17SharedArchivePathE" "_ZN9Arguments17SharedArchivePathE" |
| 269 | #define USE_SHARED_SPACES_SYM"UseSharedSpaces" "UseSharedSpaces" |
| 270 | #define SHARED_BASE_ADDRESS_SYM"SharedBaseAddress" "SharedBaseAddress" |
| 271 | #define LIBJVM_NAME"/libjvm.so" "/libjvm.so" |
| 272 | #endif |
| 273 | |
| 274 | #ifdef __APPLE__ |
| 275 | // mangled name of Arguments::SharedArchivePath |
| 276 | #define SHARED_ARCHIVE_PATH_SYM"_ZN9Arguments17SharedArchivePathE" "__ZN9Arguments17SharedArchivePathE" |
| 277 | #define USE_SHARED_SPACES_SYM"UseSharedSpaces" "_UseSharedSpaces" |
| 278 | #define SHARED_BASE_ADDRESS_SYM"SharedBaseAddress" "_SharedBaseAddress" |
| 279 | #define LIBJVM_NAME"/libjvm.so" "/libjvm.dylib" |
| 280 | #endif |
| 281 | |
| 282 | bool init_classsharing_workaround(struct ps_prochandle* ph) { |
| 283 | lib_info* lib = ph->libs; |
| 284 | while (lib != NULL((void*)0)) { |
| 285 | // we are iterating over shared objects from the core dump. look for |
| 286 | // libjvm.so. |
| 287 | const char *jvm_name = 0; |
| 288 | if ((jvm_name = strstr(lib->name, LIBJVM_NAME"/libjvm.so")) != 0) { |
| 289 | char classes_jsa[PATH_MAX4096]; |
| 290 | CDSFileMapHeaderBase header; |
| 291 | int fd = -1; |
| 292 | uintptr_t useSharedSpacesAddr = 0; |
| 293 | uintptr_t sharedBaseAddressAddr = 0, sharedBaseAddress = 0; |
| 294 | uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; |
| 295 | jboolean useSharedSpaces = 0; |
| 296 | int m; |
| 297 | size_t n; |
| 298 | |
| 299 | memset(classes_jsa, 0, sizeof(classes_jsa)); |
| 300 | jvm_name = lib->name; |
| 301 | useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM"UseSharedSpaces"); |
| 302 | if (useSharedSpacesAddr == 0) { |
| 303 | print_debug("can't lookup 'UseSharedSpaces' symbol\n"); |
| 304 | return false0; |
| 305 | } |
| 306 | |
| 307 | // Hotspot vm types are not exported to build this library. So |
| 308 | // using equivalent type jboolean to read the value of |
| 309 | // UseSharedSpaces which is same as hotspot type "bool". |
| 310 | if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true1) { |
| 311 | print_debug("can't read the value of 'UseSharedSpaces' symbol\n"); |
| 312 | return false0; |
| 313 | } |
| 314 | |
| 315 | if ((int)useSharedSpaces == 0) { |
| 316 | print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); |
| 317 | return true1; |
| 318 | } |
| 319 | |
| 320 | sharedBaseAddressAddr = lookup_symbol(ph, jvm_name, SHARED_BASE_ADDRESS_SYM"SharedBaseAddress"); |
| 321 | if (sharedBaseAddressAddr == 0) { |
| 322 | print_debug("can't lookup 'SharedBaseAddress' flag\n"); |
| 323 | return false0; |
| 324 | } |
| 325 | |
| 326 | if (read_pointer(ph, sharedBaseAddressAddr, &sharedBaseAddress) != true1) { |
| 327 | print_debug("can't read the value of 'SharedBaseAddress' flag\n"); |
| 328 | return false0; |
| 329 | } |
| 330 | |
| 331 | sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM"_ZN9Arguments17SharedArchivePathE"); |
| 332 | if (sharedArchivePathAddrAddr == 0) { |
| 333 | print_debug("can't lookup shared archive path symbol\n"); |
| 334 | return false0; |
| 335 | } |
| 336 | |
| 337 | if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true1) { |
| 338 | print_debug("can't read shared archive path pointer\n"); |
| 339 | return false0; |
| 340 | } |
| 341 | |
| 342 | if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true1) { |
| 343 | print_debug("can't read shared archive path value\n"); |
| 344 | return false0; |
| 345 | } |
| 346 | |
| 347 | print_debug("looking for %s\n", classes_jsa); |
| 348 | // open the class sharing archive file |
| 349 | fd = pathmap_open(classes_jsa); |
| 350 | if (fd < 0) { |
| 351 | print_debug("can't open %s!\n", classes_jsa); |
| 352 | ph->core->classes_jsa_fd = -1; |
| 353 | return false0; |
| 354 | } else { |
| 355 | print_debug("opened %s\n", classes_jsa); |
| 356 | } |
| 357 | |
| 358 | // read CDSFileMapHeaderBase from the file |
| 359 | size_t header_size = sizeof(CDSFileMapHeaderBase); |
| 360 | memset(&header, 0, header_size); |
| 361 | if ((n = read(fd, &header, header_size)) |
Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n' | |
| 362 | != header_size) { |
| 363 | print_debug("can't read shared archive file map header from %s\n", classes_jsa); |
| 364 | close(fd); |
| 365 | return false0; |
| 366 | } |
| 367 | |
| 368 | // check file magic |
| 369 | if (header._generic_header._magic != CDS_ARCHIVE_MAGIC0xf00baba2) { |
| 370 | print_debug("%s has bad shared archive file magic number 0x%x, expecting 0x%x\n", |
| 371 | classes_jsa, header._generic_header._magic, CDS_ARCHIVE_MAGIC0xf00baba2); |
| 372 | close(fd); |
| 373 | return false0; |
| 374 | } |
| 375 | |
| 376 | // check version |
| 377 | if (header._generic_header._version != CURRENT_CDS_ARCHIVE_VERSION12) { |
| 378 | print_debug("%s has wrong shared archive file version %d, expecting %d\n", |
| 379 | classes_jsa, header._generic_header._version, CURRENT_CDS_ARCHIVE_VERSION12); |
| 380 | close(fd); |
| 381 | return false0; |
| 382 | } |
| 383 | |
| 384 | ph->core->classes_jsa_fd = fd; |
| 385 | // add read-only maps from classes.jsa to the list of maps |
| 386 | for (m = 0; m < NUM_CDS_REGIONS7; m++) { |
| 387 | if (header._space[m]._read_only && |
| 388 | !header._space[m]._is_heap_region && |
| 389 | !header._space[m]._is_bitmap_region) { |
| 390 | // With *some* linux versions, the core file doesn't include read-only mmap'ed |
| 391 | // files regions, so let's add them here. This is harmless if the core file also |
| 392 | // include these regions. |
| 393 | uintptr_t base = sharedBaseAddress + (uintptr_t) header._space[m]._mapping_offset; |
| 394 | size_t size = header._space[m]._used; |
| 395 | // no need to worry about the fractional pages at-the-end. |
| 396 | // possible fractional pages are handled by core_read_data. |
| 397 | add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, |
| 398 | base, size); |
| 399 | print_debug("added a share archive map [%d] at 0x%lx (size 0x%lx bytes)\n", m, base, size); |
| 400 | } |
| 401 | } |
| 402 | return true1; |
| 403 | } |
| 404 | lib = lib->next; |
| 405 | } |
| 406 | return true1; |
| 407 | } |
| 408 | |
| 409 | #endif // defined(LINUX) || defined(__APPLE__) |