File: | jdk/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c |
Warning: | line 288, column 10 Although the value stored to 'jvm_name' is used in the enclosing expression, the value is never actually read from 'jvm_name' |
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) { |
Although the value stored to 'jvm_name' is used in the enclosing expression, the value is never actually read from 'jvm_name' | |
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)) |
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__) |