Mercurial > hg > truffle
annotate agent/src/os/bsd/ps_core.c @ 17716:cdb71841f4bc
6498581: ThreadInterruptTest3 produces wrong output on Windows
Summary: There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set.
Reviewed-by: acorn, kvn
Contributed-by: david.holmes@oracle.com, yumin.qi@oracle.com
author | minqi |
---|---|
date | Wed, 26 Feb 2014 15:20:41 -0800 |
parents | 5705c7ee6dd7 |
children |
rev | line source |
---|---|
3960 | 1 /* |
8750 | 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
3960 | 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 #include <jni.h> | |
26 #include <unistd.h> | |
27 #include <fcntl.h> | |
28 #include <string.h> | |
29 #include <stdlib.h> | |
30 #include <stddef.h> | |
31 #include "libproc_impl.h" | |
8750 | 32 |
33 #ifdef __APPLE__ | |
34 #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" | |
35 #endif | |
3960 | 36 |
37 // This file has the libproc implementation to read core files. | |
38 // For live processes, refer to ps_proc.c. Portions of this is adapted | |
39 // /modelled after Solaris libproc.so (in particular Pcore.c) | |
40 | |
41 //---------------------------------------------------------------------- | |
42 // ps_prochandle cleanup helper functions | |
43 | |
44 // close all file descriptors | |
8750 | 45 static void close_files(struct ps_prochandle* ph) { |
46 lib_info* lib = NULL; | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
47 |
8750 | 48 // close core file descriptor |
49 if (ph->core->core_fd >= 0) | |
50 close(ph->core->core_fd); | |
3960 | 51 |
8750 | 52 // close exec file descriptor |
53 if (ph->core->exec_fd >= 0) | |
54 close(ph->core->exec_fd); | |
3960 | 55 |
8750 | 56 // close interp file descriptor |
57 if (ph->core->interp_fd >= 0) | |
58 close(ph->core->interp_fd); | |
3960 | 59 |
8750 | 60 // close class share archive file |
61 if (ph->core->classes_jsa_fd >= 0) | |
62 close(ph->core->classes_jsa_fd); | |
3960 | 63 |
8750 | 64 // close all library file descriptors |
65 lib = ph->libs; | |
66 while (lib) { | |
67 int fd = lib->fd; | |
68 if (fd >= 0 && fd != ph->core->exec_fd) { | |
69 close(fd); | |
70 } | |
71 lib = lib->next; | |
72 } | |
3960 | 73 } |
74 | |
75 // clean all map_info stuff | |
76 static void destroy_map_info(struct ps_prochandle* ph) { | |
77 map_info* map = ph->core->maps; | |
78 while (map) { | |
8750 | 79 map_info* next = map->next; |
80 free(map); | |
81 map = next; | |
3960 | 82 } |
83 | |
84 if (ph->core->map_array) { | |
8750 | 85 free(ph->core->map_array); |
3960 | 86 } |
87 | |
88 // Part of the class sharing workaround | |
89 map = ph->core->class_share_maps; | |
90 while (map) { | |
8750 | 91 map_info* next = map->next; |
92 free(map); | |
93 map = next; | |
3960 | 94 } |
95 } | |
96 | |
97 // ps_prochandle operations | |
98 static void core_release(struct ps_prochandle* ph) { | |
8750 | 99 if (ph->core) { |
100 close_files(ph); | |
101 destroy_map_info(ph); | |
102 free(ph->core); | |
103 } | |
3960 | 104 } |
105 | |
106 static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) { | |
8750 | 107 map_info* map; |
108 if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { | |
109 print_debug("can't allocate memory for map_info\n"); | |
110 return NULL; | |
111 } | |
3960 | 112 |
8750 | 113 // initialize map |
114 map->fd = fd; | |
115 map->offset = offset; | |
116 map->vaddr = vaddr; | |
117 map->memsz = memsz; | |
118 return map; | |
3960 | 119 } |
120 | |
121 // add map info with given fd, offset, vaddr and memsz | |
122 static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, | |
123 uintptr_t vaddr, size_t memsz) { | |
8750 | 124 map_info* map; |
125 if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { | |
126 return NULL; | |
127 } | |
3960 | 128 |
8750 | 129 // add this to map list |
130 map->next = ph->core->maps; | |
131 ph->core->maps = map; | |
132 ph->core->num_maps++; | |
3960 | 133 |
8750 | 134 return map; |
3960 | 135 } |
136 | |
137 // Part of the class sharing workaround | |
138 static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, | |
139 uintptr_t vaddr, size_t memsz) { | |
8750 | 140 map_info* map; |
141 if ((map = allocate_init_map(ph->core->classes_jsa_fd, | |
142 offset, vaddr, memsz)) == NULL) { | |
143 return NULL; | |
144 } | |
3960 | 145 |
8750 | 146 map->next = ph->core->class_share_maps; |
147 ph->core->class_share_maps = map; | |
148 return map; | |
3960 | 149 } |
150 | |
151 // Return the map_info for the given virtual address. We keep a sorted | |
152 // array of pointers in ph->map_array, so we can binary search. | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
153 static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { |
8750 | 154 int mid, lo = 0, hi = ph->core->num_maps - 1; |
155 map_info *mp; | |
3960 | 156 |
8750 | 157 while (hi - lo > 1) { |
158 mid = (lo + hi) / 2; | |
159 if (addr >= ph->core->map_array[mid]->vaddr) { | |
160 lo = mid; | |
161 } else { | |
162 hi = mid; | |
163 } | |
164 } | |
3960 | 165 |
8750 | 166 if (addr < ph->core->map_array[hi]->vaddr) { |
167 mp = ph->core->map_array[lo]; | |
168 } else { | |
169 mp = ph->core->map_array[hi]; | |
170 } | |
3960 | 171 |
8750 | 172 if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { |
173 return (mp); | |
174 } | |
3960 | 175 |
176 | |
8750 | 177 // Part of the class sharing workaround |
178 // Unfortunately, we have no way of detecting -Xshare state. | |
179 // Check out the share maps atlast, if we don't find anywhere. | |
180 // This is done this way so to avoid reading share pages | |
181 // ahead of other normal maps. For eg. with -Xshare:off we don't | |
182 // want to prefer class sharing data to data from core. | |
183 mp = ph->core->class_share_maps; | |
184 if (mp) { | |
185 print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr); | |
186 } | |
187 while (mp) { | |
188 if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { | |
189 print_debug("located map_info at 0x%lx from class share maps\n", addr); | |
190 return (mp); | |
191 } | |
192 mp = mp->next; | |
193 } | |
3960 | 194 |
8750 | 195 print_debug("can't locate map_info at 0x%lx\n", addr); |
196 return (NULL); | |
3960 | 197 } |
198 | |
199 //--------------------------------------------------------------- | |
200 // Part of the class sharing workaround: | |
201 // | |
10229 | 202 // With class sharing, pages are mapped from classes.jsa file. |
3960 | 203 // The read-only class sharing pages are mapped as MAP_SHARED, |
204 // PROT_READ pages. These pages are not dumped into core dump. | |
10229 | 205 // With this workaround, these pages are read from classes.jsa. |
3960 | 206 |
207 // FIXME: !HACK ALERT! | |
208 // The format of sharing achive file header is needed to read shared heap | |
209 // file mappings. For now, I am hard coding portion of FileMapHeader here. | |
210 // Refer to filemap.hpp. | |
211 | |
212 // FileMapHeader describes the shared space data in the file to be | |
213 // mapped. This structure gets written to a file. It is not a class, | |
214 // so that the compilers don't add any compiler-private data to it. | |
215 | |
216 #define NUM_SHARED_MAPS 4 | |
217 | |
218 // Refer to FileMapInfo::_current_version in filemap.hpp | |
219 #define CURRENT_ARCHIVE_VERSION 1 | |
220 | |
221 struct FileMapHeader { | |
222 int _magic; // identify file type. | |
223 int _version; // (from enum, above.) | |
224 size_t _alignment; // how shared archive should be aligned | |
225 | |
226 struct space_info { | |
227 int _file_offset; // sizeof(this) rounded to vm page size | |
228 char* _base; // copy-on-write base address | |
229 size_t _capacity; // for validity checking | |
230 size_t _used; // for setting space top on read | |
231 | |
232 // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
233 // the C type matching the C++ bool type on any given platform. |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
234 // We assume the corresponding C type is char but licensees |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
235 // may need to adjust the type of these fields. |
3960 | 236 char _read_only; // read only space? |
237 char _allow_exec; // executable code in space? | |
238 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
3960
diff
changeset
|
239 } _space[NUM_SHARED_MAPS]; |
3960 | 240 |
241 // Ignore the rest of the FileMapHeader. We don't need those fields here. | |
242 }; | |
243 | |
244 static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { | |
8750 | 245 jboolean i; |
246 if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { | |
247 *pvalue = i; | |
248 return true; | |
249 } else { | |
250 return false; | |
251 } | |
3960 | 252 } |
253 | |
254 static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) { | |
8750 | 255 uintptr_t uip; |
256 if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) { | |
257 *pvalue = uip; | |
258 return true; | |
259 } else { | |
260 return false; | |
261 } | |
3960 | 262 } |
263 | |
264 // used to read strings from debuggee | |
265 static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) { | |
8750 | 266 size_t i = 0; |
267 char c = ' '; | |
3960 | 268 |
8750 | 269 while (c != '\0') { |
270 if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) { | |
271 return false; | |
272 } | |
273 if (i < size - 1) { | |
274 buf[i] = c; | |
275 } else { | |
276 // smaller buffer | |
277 return false; | |
278 } | |
279 i++; addr++; | |
280 } | |
281 buf[i] = '\0'; | |
282 return true; | |
3960 | 283 } |
284 | |
8750 | 285 #ifdef __APPLE__ |
286 #define USE_SHARED_SPACES_SYM "_UseSharedSpaces" | |
287 // mangled name of Arguments::SharedArchivePath | |
288 #define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
289 #define LIBJVM_NAME "/libjvm.dylib" |
8750 | 290 #else |
3960 | 291 #define USE_SHARED_SPACES_SYM "UseSharedSpaces" |
292 // mangled name of Arguments::SharedArchivePath | |
8750 | 293 #define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
294 #define LIBJVM_NAME "/libjvm.so" |
8750 | 295 #endif // __APPLE_ |
3960 | 296 |
297 static bool init_classsharing_workaround(struct ps_prochandle* ph) { | |
8750 | 298 int m; |
299 size_t n; | |
300 lib_info* lib = ph->libs; | |
301 while (lib != NULL) { | |
302 // we are iterating over shared objects from the core dump. look for | |
10229 | 303 // libjvm.so. |
8750 | 304 const char *jvm_name = 0; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
305 if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) { |
8750 | 306 char classes_jsa[PATH_MAX]; |
307 struct FileMapHeader header; | |
308 int fd = -1; | |
309 uintptr_t base = 0, useSharedSpacesAddr = 0; | |
310 uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; | |
311 jboolean useSharedSpaces = 0; | |
3960 | 312 |
8750 | 313 memset(classes_jsa, 0, sizeof(classes_jsa)); |
314 jvm_name = lib->name; | |
315 useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); | |
316 if (useSharedSpacesAddr == 0) { | |
317 print_debug("can't lookup 'UseSharedSpaces' flag\n"); | |
318 return false; | |
319 } | |
3960 | 320 |
8750 | 321 // Hotspot vm types are not exported to build this library. So |
322 // using equivalent type jboolean to read the value of | |
323 // UseSharedSpaces which is same as hotspot type "bool". | |
324 if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { | |
325 print_debug("can't read the value of 'UseSharedSpaces' flag\n"); | |
326 return false; | |
327 } | |
3960 | 328 |
8750 | 329 if ((int)useSharedSpaces == 0) { |
330 print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); | |
331 return true; | |
332 } | |
3960 | 333 |
8750 | 334 sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); |
335 if (sharedArchivePathAddrAddr == 0) { | |
336 print_debug("can't lookup shared archive path symbol\n"); | |
337 return false; | |
338 } | |
3960 | 339 |
8750 | 340 if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { |
341 print_debug("can't read shared archive path pointer\n"); | |
342 return false; | |
343 } | |
3960 | 344 |
8750 | 345 if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { |
346 print_debug("can't read shared archive path value\n"); | |
347 return false; | |
348 } | |
3960 | 349 |
8750 | 350 print_debug("looking for %s\n", classes_jsa); |
351 // open the class sharing archive file | |
352 fd = pathmap_open(classes_jsa); | |
353 if (fd < 0) { | |
354 print_debug("can't open %s!\n", classes_jsa); | |
355 ph->core->classes_jsa_fd = -1; | |
356 return false; | |
357 } else { | |
358 print_debug("opened %s\n", classes_jsa); | |
359 } | |
3960 | 360 |
8750 | 361 // read FileMapHeader from the file |
362 memset(&header, 0, sizeof(struct FileMapHeader)); | |
363 if ((n = read(fd, &header, sizeof(struct FileMapHeader))) | |
364 != sizeof(struct FileMapHeader)) { | |
365 print_debug("can't read shared archive file map header from %s\n", classes_jsa); | |
366 close(fd); | |
367 return false; | |
368 } | |
3960 | 369 |
8750 | 370 // check file magic |
371 if (header._magic != 0xf00baba2) { | |
372 print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", | |
373 classes_jsa, header._magic); | |
374 close(fd); | |
375 return false; | |
376 } | |
377 | |
378 // check version | |
379 if (header._version != CURRENT_ARCHIVE_VERSION) { | |
380 print_debug("%s has wrong shared archive file version %d, expecting %d\n", | |
381 classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); | |
382 close(fd); | |
383 return false; | |
384 } | |
3960 | 385 |
8750 | 386 ph->core->classes_jsa_fd = fd; |
10229 | 387 // add read-only maps from classes.jsa to the list of maps |
8750 | 388 for (m = 0; m < NUM_SHARED_MAPS; m++) { |
389 if (header._space[m]._read_only) { | |
390 base = (uintptr_t) header._space[m]._base; | |
391 // no need to worry about the fractional pages at-the-end. | |
392 // possible fractional pages are handled by core_read_data. | |
393 add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, | |
394 base, (size_t) header._space[m]._used); | |
395 print_debug("added a share archive map at 0x%lx\n", base); | |
396 } | |
3960 | 397 } |
8750 | 398 return true; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
399 } |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
400 lib = lib->next; |
8750 | 401 } |
402 return true; | |
3960 | 403 } |
404 | |
405 //--------------------------------------------------------------------------- | |
406 // functions to handle map_info | |
407 | |
408 // Order mappings based on virtual address. We use this function as the | |
409 // callback for sorting the array of map_info pointers. | |
410 static int core_cmp_mapping(const void *lhsp, const void *rhsp) | |
411 { | |
8750 | 412 const map_info *lhs = *((const map_info **)lhsp); |
413 const map_info *rhs = *((const map_info **)rhsp); | |
3960 | 414 |
8750 | 415 if (lhs->vaddr == rhs->vaddr) { |
416 return (0); | |
417 } | |
3960 | 418 |
8750 | 419 return (lhs->vaddr < rhs->vaddr ? -1 : 1); |
3960 | 420 } |
421 | |
422 // we sort map_info by starting virtual address so that we can do | |
423 // binary search to read from an address. | |
424 static bool sort_map_array(struct ps_prochandle* ph) { | |
8750 | 425 size_t num_maps = ph->core->num_maps; |
426 map_info* map = ph->core->maps; | |
427 int i = 0; | |
3960 | 428 |
8750 | 429 // allocate map_array |
430 map_info** array; | |
431 if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
432 print_debug("can't allocate memory for map array\n"); |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
433 return false; |
8750 | 434 } |
3960 | 435 |
8750 | 436 // add maps to array |
437 while (map) { | |
438 array[i] = map; | |
439 i++; | |
440 map = map->next; | |
441 } | |
3960 | 442 |
8750 | 443 // sort is called twice. If this is second time, clear map array |
444 if (ph->core->map_array) { | |
445 free(ph->core->map_array); | |
446 } | |
447 ph->core->map_array = array; | |
448 // sort the map_info array by base virtual address. | |
449 qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
450 core_cmp_mapping); |
3960 | 451 |
8750 | 452 // print map |
453 if (is_debug()) { | |
454 int j = 0; | |
455 print_debug("---- sorted virtual address map ----\n"); | |
456 for (j = 0; j < ph->core->num_maps; j++) { | |
457 print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
458 ph->core->map_array[j]->memsz); |
8750 | 459 } |
460 } | |
3960 | 461 |
8750 | 462 return true; |
3960 | 463 } |
464 | |
465 #ifndef MIN | |
466 #define MIN(x, y) (((x) < (y))? (x): (y)) | |
467 #endif | |
468 | |
469 static bool core_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) { | |
470 ssize_t resid = size; | |
471 int page_size=sysconf(_SC_PAGE_SIZE); | |
472 while (resid != 0) { | |
473 map_info *mp = core_lookup(ph, addr); | |
474 uintptr_t mapoff; | |
475 ssize_t len, rem; | |
476 off_t off; | |
477 int fd; | |
478 | |
8750 | 479 if (mp == NULL) { |
3960 | 480 break; /* No mapping for this address */ |
8750 | 481 } |
3960 | 482 |
483 fd = mp->fd; | |
484 mapoff = addr - mp->vaddr; | |
485 len = MIN(resid, mp->memsz - mapoff); | |
486 off = mp->offset + mapoff; | |
487 | |
8750 | 488 if ((len = pread(fd, buf, len, off)) <= 0) { |
3960 | 489 break; |
8750 | 490 } |
3960 | 491 |
492 resid -= len; | |
493 addr += len; | |
494 buf = (char *)buf + len; | |
495 | |
496 // mappings always start at page boundary. But, may end in fractional | |
497 // page. fill zeros for possible fractional page at the end of a mapping. | |
498 rem = mp->memsz % page_size; | |
499 if (rem > 0) { | |
500 rem = page_size - rem; | |
501 len = MIN(resid, rem); | |
502 resid -= len; | |
503 addr += len; | |
504 // we are not assuming 'buf' to be zero initialized. | |
505 memset(buf, 0, len); | |
506 buf += len; | |
507 } | |
508 } | |
509 | |
510 if (resid) { | |
511 print_debug("core read failed for %d byte(s) @ 0x%lx (%d more bytes)\n", | |
512 size, addr, resid); | |
513 return false; | |
514 } else { | |
515 return true; | |
516 } | |
517 } | |
518 | |
519 // null implementation for write | |
520 static bool core_write_data(struct ps_prochandle* ph, | |
521 uintptr_t addr, const char *buf , size_t size) { | |
522 return false; | |
523 } | |
524 | |
525 static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, | |
526 struct reg* regs) { | |
8750 | 527 // for core we have cached the lwp regs after segment parsed |
528 sa_thread_info* thr = ph->threads; | |
3960 | 529 while (thr) { |
530 if (thr->lwp_id == lwp_id) { | |
531 memcpy(regs, &thr->regs, sizeof(struct reg)); | |
532 return true; | |
533 } | |
534 thr = thr->next; | |
535 } | |
536 return false; | |
537 } | |
538 | |
8750 | 539 static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t id, void *info) { |
3960 | 540 print_debug("core_get_lwp_info not implemented\n"); |
541 return false; | |
542 } | |
543 | |
544 static ps_prochandle_ops core_ops = { | |
545 .release= core_release, | |
546 .p_pread= core_read_data, | |
547 .p_pwrite= core_write_data, | |
548 .get_lwp_regs= core_get_lwp_regs, | |
549 .get_lwp_info= core_get_lwp_info | |
550 }; | |
551 | |
8750 | 552 // from this point, mainly two blocks divided by def __APPLE__ |
553 // one for Macosx, the other for regular Bsd | |
554 | |
555 #ifdef __APPLE__ | |
556 | |
557 void print_thread(sa_thread_info *threadinfo) { | |
558 print_debug("thread added: %d\n", threadinfo->lwp_id); | |
559 print_debug("registers:\n"); | |
560 print_debug(" r_r15: 0x%" PRIx64 "\n", threadinfo->regs.r_r15); | |
561 print_debug(" r_r14: 0x%" PRIx64 "\n", threadinfo->regs.r_r14); | |
562 print_debug(" r_r13: 0x%" PRIx64 "\n", threadinfo->regs.r_r13); | |
563 print_debug(" r_r12: 0x%" PRIx64 "\n", threadinfo->regs.r_r12); | |
564 print_debug(" r_r11: 0x%" PRIx64 "\n", threadinfo->regs.r_r11); | |
565 print_debug(" r_r10: 0x%" PRIx64 "\n", threadinfo->regs.r_r10); | |
566 print_debug(" r_r9: 0x%" PRIx64 "\n", threadinfo->regs.r_r9); | |
567 print_debug(" r_r8: 0x%" PRIx64 "\n", threadinfo->regs.r_r8); | |
568 print_debug(" r_rdi: 0x%" PRIx64 "\n", threadinfo->regs.r_rdi); | |
569 print_debug(" r_rsi: 0x%" PRIx64 "\n", threadinfo->regs.r_rsi); | |
570 print_debug(" r_rbp: 0x%" PRIx64 "\n", threadinfo->regs.r_rbp); | |
571 print_debug(" r_rbx: 0x%" PRIx64 "\n", threadinfo->regs.r_rbx); | |
572 print_debug(" r_rdx: 0x%" PRIx64 "\n", threadinfo->regs.r_rdx); | |
573 print_debug(" r_rcx: 0x%" PRIx64 "\n", threadinfo->regs.r_rcx); | |
574 print_debug(" r_rax: 0x%" PRIx64 "\n", threadinfo->regs.r_rax); | |
575 print_debug(" r_fs: 0x%" PRIx32 "\n", threadinfo->regs.r_fs); | |
576 print_debug(" r_gs: 0x%" PRIx32 "\n", threadinfo->regs.r_gs); | |
577 print_debug(" r_rip 0x%" PRIx64 "\n", threadinfo->regs.r_rip); | |
578 print_debug(" r_cs: 0x%" PRIx64 "\n", threadinfo->regs.r_cs); | |
579 print_debug(" r_rsp: 0x%" PRIx64 "\n", threadinfo->regs.r_rsp); | |
580 print_debug(" r_rflags: 0x%" PRIx64 "\n", threadinfo->regs.r_rflags); | |
581 } | |
582 | |
583 // read all segments64 commands from core file | |
584 // read all thread commands from core file | |
585 static bool read_core_segments(struct ps_prochandle* ph) { | |
586 int i = 0; | |
587 int num_threads = 0; | |
588 int fd = ph->core->core_fd; | |
589 off_t offset = 0; | |
590 mach_header_64 fhead; | |
591 load_command lcmd; | |
592 segment_command_64 segcmd; | |
593 // thread_command thrcmd; | |
594 | |
595 lseek(fd, offset, SEEK_SET); | |
596 if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) { | |
597 goto err; | |
598 } | |
599 print_debug("total commands: %d\n", fhead.ncmds); | |
600 offset += sizeof(mach_header_64); | |
601 for (i = 0; i < fhead.ncmds; i++) { | |
602 lseek(fd, offset, SEEK_SET); | |
603 if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { | |
604 goto err; | |
605 } | |
606 offset += lcmd.cmdsize; // next command position | |
607 if (lcmd.cmd == LC_SEGMENT_64) { | |
608 lseek(fd, -sizeof(load_command), SEEK_CUR); | |
609 if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) { | |
610 print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i); | |
611 goto err; | |
612 } | |
613 if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) { | |
614 print_debug("Failed to add map_info at i = %d\n", i); | |
615 goto err; | |
616 } | |
617 print_debug("segment added: %" PRIu64 " 0x%" PRIx64 " %d\n", | |
618 segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize); | |
619 } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) { | |
620 typedef struct thread_fc { | |
621 uint32_t flavor; | |
622 uint32_t count; | |
623 } thread_fc; | |
624 thread_fc fc; | |
625 uint32_t size = sizeof(load_command); | |
626 while (size < lcmd.cmdsize) { | |
627 if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) { | |
628 printf("Reading flavor, count failed.\n"); | |
629 goto err; | |
630 } | |
631 size += sizeof(thread_fc); | |
632 if (fc.flavor == x86_THREAD_STATE) { | |
633 x86_thread_state_t thrstate; | |
634 if (read(fd, (void *)&thrstate, sizeof(x86_thread_state_t)) != sizeof(x86_thread_state_t)) { | |
635 printf("Reading flavor, count failed.\n"); | |
636 goto err; | |
637 } | |
638 size += sizeof(x86_thread_state_t); | |
639 // create thread info list, update lwp_id later | |
640 sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++); | |
641 if (newthr == NULL) { | |
642 printf("create thread_info failed\n"); | |
643 goto err; | |
644 } | |
645 | |
646 // note __DARWIN_UNIX03 depengs on other definitions | |
647 #if __DARWIN_UNIX03 | |
648 #define get_register_v(regst, regname) \ | |
649 regst.uts.ts64.__##regname | |
650 #else | |
651 #define get_register_v(regst, regname) \ | |
652 regst.uts.ts64.##regname | |
653 #endif // __DARWIN_UNIX03 | |
654 newthr->regs.r_rax = get_register_v(thrstate, rax); | |
655 newthr->regs.r_rbx = get_register_v(thrstate, rbx); | |
656 newthr->regs.r_rcx = get_register_v(thrstate, rcx); | |
657 newthr->regs.r_rdx = get_register_v(thrstate, rdx); | |
658 newthr->regs.r_rdi = get_register_v(thrstate, rdi); | |
659 newthr->regs.r_rsi = get_register_v(thrstate, rsi); | |
660 newthr->regs.r_rbp = get_register_v(thrstate, rbp); | |
661 newthr->regs.r_rsp = get_register_v(thrstate, rsp); | |
662 newthr->regs.r_r8 = get_register_v(thrstate, r8); | |
663 newthr->regs.r_r9 = get_register_v(thrstate, r9); | |
664 newthr->regs.r_r10 = get_register_v(thrstate, r10); | |
665 newthr->regs.r_r11 = get_register_v(thrstate, r11); | |
666 newthr->regs.r_r12 = get_register_v(thrstate, r12); | |
667 newthr->regs.r_r13 = get_register_v(thrstate, r13); | |
668 newthr->regs.r_r14 = get_register_v(thrstate, r14); | |
669 newthr->regs.r_r15 = get_register_v(thrstate, r15); | |
670 newthr->regs.r_rip = get_register_v(thrstate, rip); | |
671 newthr->regs.r_rflags = get_register_v(thrstate, rflags); | |
672 newthr->regs.r_cs = get_register_v(thrstate, cs); | |
673 newthr->regs.r_fs = get_register_v(thrstate, fs); | |
674 newthr->regs.r_gs = get_register_v(thrstate, gs); | |
675 print_thread(newthr); | |
676 } else if (fc.flavor == x86_FLOAT_STATE) { | |
677 x86_float_state_t flstate; | |
678 if (read(fd, (void *)&flstate, sizeof(x86_float_state_t)) != sizeof(x86_float_state_t)) { | |
679 print_debug("Reading flavor, count failed.\n"); | |
680 goto err; | |
681 } | |
682 size += sizeof(x86_float_state_t); | |
683 } else if (fc.flavor == x86_EXCEPTION_STATE) { | |
684 x86_exception_state_t excpstate; | |
685 if (read(fd, (void *)&excpstate, sizeof(x86_exception_state_t)) != sizeof(x86_exception_state_t)) { | |
686 printf("Reading flavor, count failed.\n"); | |
687 goto err; | |
688 } | |
689 size += sizeof(x86_exception_state_t); | |
690 } | |
691 } | |
692 } | |
693 } | |
694 return true; | |
695 err: | |
696 return false; | |
697 } | |
698 | |
699 /**local function **/ | |
700 bool exists(const char *fname) | |
701 { | |
702 int fd; | |
703 if ((fd = open(fname, O_RDONLY)) > 0) { | |
704 close(fd); | |
705 return true; | |
706 } | |
707 return false; | |
708 } | |
709 | |
710 // we check: 1. lib | |
711 // 2. lib/server | |
712 // 3. jre/lib | |
713 // 4. jre/lib/server | |
714 // from: 1. exe path | |
715 // 2. JAVA_HOME | |
716 // 3. DYLD_LIBRARY_PATH | |
717 static bool get_real_path(struct ps_prochandle* ph, char *rpath) { | |
718 /** check if they exist in JAVA ***/ | |
719 char* execname = ph->core->exec_path; | |
720 char filepath[4096]; | |
721 char* filename = strrchr(rpath, '/'); // like /libjvm.dylib | |
722 if (filename == NULL) { | |
723 return false; | |
724 } | |
725 | |
726 char* posbin = strstr(execname, "/bin/java"); | |
727 if (posbin != NULL) { | |
728 memcpy(filepath, execname, posbin - execname); // not include trailing '/' | |
729 filepath[posbin - execname] = '\0'; | |
730 } else { | |
731 char* java_home = getenv("JAVA_HOME"); | |
732 if (java_home != NULL) { | |
733 strcpy(filepath, java_home); | |
734 } else { | |
735 char* dyldpath = getenv("DYLD_LIBRARY_PATH"); | |
736 char* dypath = strtok(dyldpath, ":"); | |
737 while (dypath != NULL) { | |
738 strcpy(filepath, dypath); | |
739 strcat(filepath, filename); | |
740 if (exists(filepath)) { | |
741 strcpy(rpath, filepath); | |
742 return true; | |
743 } | |
744 dypath = strtok(dyldpath, ":"); | |
745 } | |
746 // not found | |
747 return false; | |
748 } | |
749 } | |
750 // for exec and java_home, jdkpath now is filepath | |
751 size_t filepath_base_size = strlen(filepath); | |
752 | |
753 // first try /lib/ and /lib/server | |
754 strcat(filepath, "/lib"); | |
755 strcat(filepath, filename); | |
756 if (exists(filepath)) { | |
757 strcpy(rpath, filepath); | |
758 return true; | |
759 } | |
760 char* pos = strstr(filepath, filename); // like /libjvm.dylib | |
761 *pos = '\0'; | |
762 strcat(filepath, "/server"); | |
763 strcat(filepath, filename); | |
764 if (exists(filepath)) { | |
765 strcpy(rpath, filepath); | |
766 return true; | |
767 } | |
768 | |
769 // then try /jre/lib/ and /jre/lib/server | |
770 filepath[filepath_base_size] = '\0'; | |
771 strcat(filepath, "/jre/lib"); | |
772 strcat(filepath, filename); | |
773 if (exists(filepath)) { | |
774 strcpy(rpath, filepath); | |
775 return true; | |
776 } | |
777 pos = strstr(filepath, filename); | |
778 *pos = '\0'; | |
779 strcat(filepath, "/server"); | |
780 strcat(filepath, filename); | |
781 if (exists(filepath)) { | |
782 strcpy(rpath, filepath); | |
783 return true; | |
784 } | |
785 | |
786 return false; | |
787 } | |
788 | |
789 static bool read_shared_lib_info(struct ps_prochandle* ph) { | |
790 static int pagesize = 0; | |
791 int fd = ph->core->core_fd; | |
792 int i = 0, j; | |
793 uint32_t v; | |
794 mach_header_64 header; // used to check if a file header in segment | |
795 load_command lcmd; | |
796 dylib_command dylibcmd; | |
797 | |
798 char name[BUF_SIZE]; // use to store name | |
799 | |
800 if (pagesize == 0) { | |
801 pagesize = getpagesize(); | |
802 print_debug("page size is %d\n", pagesize); | |
803 } | |
804 for (j = 0; j < ph->core->num_maps; j++) { | |
805 map_info *iter = ph->core->map_array[j]; // head | |
806 off_t fpos = iter->offset; | |
807 if (iter->fd != fd) { | |
808 // only search core file! | |
809 continue; | |
810 } | |
811 print_debug("map_info %d: vmaddr = 0x%016" PRIx64 " fileoff = %" PRIu64 " vmsize = %" PRIu64 "\n", | |
812 j, iter->vaddr, iter->offset, iter->memsz); | |
813 lseek(fd, fpos, SEEK_SET); | |
814 // we assume .dylib loaded at segment address --- which is true for JVM libraries | |
815 // multiple files may be loaded in one segment. | |
816 // if first word is not a magic word, means this segment does not contain lib file. | |
817 if (read(fd, (void *)&v, sizeof(uint32_t)) == sizeof(uint32_t)) { | |
818 if (v != MH_MAGIC_64) { | |
819 continue; | |
820 } | |
821 } else { | |
822 // may be encountered last map, which is not readable | |
823 continue; | |
824 } | |
825 while (ltell(fd) - iter->offset < iter->memsz) { | |
826 lseek(fd, fpos, SEEK_SET); | |
827 if (read(fd, (void *)&v, sizeof(uint32_t)) != sizeof(uint32_t)) { | |
828 break; | |
829 } | |
830 if (v != MH_MAGIC_64) { | |
831 fpos = (ltell(fd) + pagesize -1)/pagesize * pagesize; | |
832 continue; | |
833 } | |
834 lseek(fd, -sizeof(uint32_t), SEEK_CUR); | |
835 // this is the file begining to core file. | |
836 if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { | |
837 goto err; | |
838 } | |
839 fpos = ltell(fd); | |
840 | |
841 // found a mach-o file in this segment | |
842 for (i = 0; i < header.ncmds; i++) { | |
843 // read commands in this "file" | |
844 // LC_ID_DYLIB is the file itself for a .dylib | |
845 lseek(fd, fpos, SEEK_SET); | |
846 if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { | |
847 return false; // error | |
848 } | |
849 fpos += lcmd.cmdsize; // next command position | |
850 // make sure still within seg size. | |
851 if (fpos - lcmd.cmdsize - iter->offset > iter->memsz) { | |
852 print_debug("Warning: out of segement limit: %ld \n", fpos - lcmd.cmdsize - iter->offset); | |
853 break; // no need to iterate all commands | |
854 } | |
855 if (lcmd.cmd == LC_ID_DYLIB) { | |
856 lseek(fd, -sizeof(load_command), SEEK_CUR); | |
857 if (read(fd, (void *)&dylibcmd, sizeof(dylib_command)) != sizeof(dylib_command)) { | |
858 return false; | |
859 } | |
860 /**** name stored at dylib_command.dylib.name.offset, is a C string */ | |
861 lseek(fd, dylibcmd.dylib.name.offset - sizeof(dylib_command), SEEK_CUR); | |
862 int j = 0; | |
863 while (j < BUF_SIZE) { | |
864 read(fd, (void *)(name + j), sizeof(char)); | |
865 if (name[j] == '\0') break; | |
866 j++; | |
867 } | |
868 print_debug("%s\n", name); | |
869 // changed name from @rpath/xxxx.dylib to real path | |
870 if (strrchr(name, '@')) { | |
871 get_real_path(ph, name); | |
872 print_debug("get_real_path returned: %s\n", name); | |
873 } | |
874 add_lib_info(ph, name, iter->vaddr); | |
875 break; | |
876 } | |
877 } | |
878 // done with the file, advanced to next page to search more files | |
879 fpos = (ltell(fd) + pagesize - 1) / pagesize * pagesize; | |
880 } | |
881 } | |
882 return true; | |
883 err: | |
884 return false; | |
885 } | |
886 | |
887 bool read_macho64_header(int fd, mach_header_64* core_header) { | |
888 bool is_macho = false; | |
889 if (fd < 0) return false; | |
890 off_t pos = ltell(fd); | |
891 lseek(fd, 0, SEEK_SET); | |
892 if (read(fd, (void *)core_header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { | |
893 is_macho = false; | |
894 } else { | |
895 is_macho = (core_header->magic == MH_MAGIC_64 || core_header->magic == MH_CIGAM_64); | |
896 } | |
897 lseek(fd, pos, SEEK_SET); | |
898 return is_macho; | |
899 } | |
900 | |
901 // the one and only one exposed stuff from this file | |
902 struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { | |
903 mach_header_64 core_header; | |
904 mach_header_64 exec_header; | |
905 | |
906 struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); | |
907 if (ph == NULL) { | |
908 print_debug("cant allocate ps_prochandle\n"); | |
909 return NULL; | |
910 } | |
911 | |
912 if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { | |
913 free(ph); | |
914 print_debug("can't allocate ps_prochandle\n"); | |
915 return NULL; | |
916 } | |
917 | |
918 // initialize ph | |
919 ph->ops = &core_ops; | |
920 ph->core->core_fd = -1; | |
921 ph->core->exec_fd = -1; | |
922 ph->core->interp_fd = -1; | |
923 | |
924 print_debug("exec: %s core: %s", exec_file, core_file); | |
925 | |
926 strncpy(ph->core->exec_path, exec_file, sizeof(ph->core->exec_path)); | |
927 | |
928 // open the core file | |
929 if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { | |
930 print_error("can't open core file\n"); | |
931 goto err; | |
932 } | |
933 | |
934 // read core file header | |
935 if (read_macho64_header(ph->core->core_fd, &core_header) != true || core_header.filetype != MH_CORE) { | |
936 print_debug("core file is not a valid Mach-O file\n"); | |
937 goto err; | |
938 } | |
939 | |
940 if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { | |
941 print_error("can't open executable file\n"); | |
942 goto err; | |
943 } | |
944 | |
945 if (read_macho64_header(ph->core->exec_fd, &exec_header) != true || | |
946 exec_header.filetype != MH_EXECUTE) { | |
947 print_error("executable file is not a valid Mach-O file\n"); | |
948 goto err; | |
949 } | |
950 | |
951 // process core file segments | |
952 if (read_core_segments(ph) != true) { | |
953 print_error("failed to read core segments\n"); | |
954 goto err; | |
955 } | |
956 | |
957 // allocate and sort maps into map_array, we need to do this | |
958 // here because read_shared_lib_info needs to read from debuggee | |
959 // address space | |
960 if (sort_map_array(ph) != true) { | |
961 print_error("failed to sort segment map array\n"); | |
962 goto err; | |
963 } | |
964 | |
965 if (read_shared_lib_info(ph) != true) { | |
966 print_error("failed to read libraries\n"); | |
967 goto err; | |
968 } | |
969 | |
970 // sort again because we have added more mappings from shared objects | |
971 if (sort_map_array(ph) != true) { | |
972 print_error("failed to sort segment map array\n"); | |
973 goto err; | |
974 } | |
975 | |
976 if (init_classsharing_workaround(ph) != true) { | |
977 print_error("failed to workaround classshareing\n"); | |
978 goto err; | |
979 } | |
980 | |
981 print_debug("Leave Pgrab_core\n"); | |
982 return ph; | |
983 | |
984 err: | |
985 Prelease(ph); | |
986 return NULL; | |
987 } | |
988 | |
989 #else // __APPLE__ (none macosx) | |
990 | |
991 // read regs and create thread from core file | |
3960 | 992 static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size_t nbytes) { |
993 // we have to read prstatus_t from buf | |
994 // assert(nbytes == sizeof(prstaus_t), "size mismatch on prstatus_t"); | |
995 prstatus_t* prstat = (prstatus_t*) buf; | |
8750 | 996 sa_thread_info* newthr; |
3960 | 997 print_debug("got integer regset for lwp %d\n", prstat->pr_pid); |
998 // we set pthread_t to -1 for core dump | |
999 if((newthr = add_thread_info(ph, (pthread_t) -1, prstat->pr_pid)) == NULL) | |
1000 return false; | |
1001 | |
1002 // copy regs | |
1003 memcpy(&newthr->regs, &prstat->pr_reg, sizeof(struct reg)); | |
1004 | |
1005 if (is_debug()) { | |
1006 print_debug("integer regset\n"); | |
1007 #ifdef i386 | |
1008 // print the regset | |
1009 print_debug("\teax = 0x%x\n", newthr->regs.r_eax); | |
1010 print_debug("\tebx = 0x%x\n", newthr->regs.r_ebx); | |
1011 print_debug("\tecx = 0x%x\n", newthr->regs.r_ecx); | |
1012 print_debug("\tedx = 0x%x\n", newthr->regs.r_edx); | |
1013 print_debug("\tesp = 0x%x\n", newthr->regs.r_esp); | |
1014 print_debug("\tebp = 0x%x\n", newthr->regs.r_ebp); | |
1015 print_debug("\tesi = 0x%x\n", newthr->regs.r_esi); | |
1016 print_debug("\tedi = 0x%x\n", newthr->regs.r_edi); | |
1017 print_debug("\teip = 0x%x\n", newthr->regs.r_eip); | |
1018 #endif | |
1019 | |
1020 #if defined(amd64) || defined(x86_64) | |
1021 // print the regset | |
1022 print_debug("\tr15 = 0x%lx\n", newthr->regs.r_r15); | |
1023 print_debug("\tr14 = 0x%lx\n", newthr->regs.r_r14); | |
1024 print_debug("\tr13 = 0x%lx\n", newthr->regs.r_r13); | |
1025 print_debug("\tr12 = 0x%lx\n", newthr->regs.r_r12); | |
1026 print_debug("\trbp = 0x%lx\n", newthr->regs.r_rbp); | |
1027 print_debug("\trbx = 0x%lx\n", newthr->regs.r_rbx); | |
1028 print_debug("\tr11 = 0x%lx\n", newthr->regs.r_r11); | |
1029 print_debug("\tr10 = 0x%lx\n", newthr->regs.r_r10); | |
1030 print_debug("\tr9 = 0x%lx\n", newthr->regs.r_r9); | |
1031 print_debug("\tr8 = 0x%lx\n", newthr->regs.r_r8); | |
1032 print_debug("\trax = 0x%lx\n", newthr->regs.r_rax); | |
1033 print_debug("\trcx = 0x%lx\n", newthr->regs.r_rcx); | |
1034 print_debug("\trdx = 0x%lx\n", newthr->regs.r_rdx); | |
1035 print_debug("\trsi = 0x%lx\n", newthr->regs.r_rsi); | |
1036 print_debug("\trdi = 0x%lx\n", newthr->regs.r_rdi); | |
1037 //print_debug("\torig_rax = 0x%lx\n", newthr->regs.orig_rax); | |
1038 print_debug("\trip = 0x%lx\n", newthr->regs.r_rip); | |
1039 print_debug("\tcs = 0x%lx\n", newthr->regs.r_cs); | |
1040 //print_debug("\teflags = 0x%lx\n", newthr->regs.eflags); | |
1041 print_debug("\trsp = 0x%lx\n", newthr->regs.r_rsp); | |
1042 print_debug("\tss = 0x%lx\n", newthr->regs.r_ss); | |
1043 //print_debug("\tfs_base = 0x%lx\n", newthr->regs.fs_base); | |
1044 //print_debug("\tgs_base = 0x%lx\n", newthr->regs.gs_base); | |
1045 //print_debug("\tds = 0x%lx\n", newthr->regs.ds); | |
1046 //print_debug("\tes = 0x%lx\n", newthr->regs.es); | |
1047 //print_debug("\tfs = 0x%lx\n", newthr->regs.fs); | |
1048 //print_debug("\tgs = 0x%lx\n", newthr->regs.gs); | |
1049 #endif | |
1050 } | |
1051 | |
1052 return true; | |
1053 } | |
1054 | |
1055 #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) | |
1056 | |
1057 // read NT_PRSTATUS entries from core NOTE segment | |
1058 static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) { | |
1059 char* buf = NULL; | |
1060 char* p = NULL; | |
1061 size_t size = note_phdr->p_filesz; | |
1062 | |
1063 // we are interested in just prstatus entries. we will ignore the rest. | |
1064 // Advance the seek pointer to the start of the PT_NOTE data | |
1065 if (lseek(ph->core->core_fd, note_phdr->p_offset, SEEK_SET) == (off_t)-1) { | |
1066 print_debug("failed to lseek to PT_NOTE data\n"); | |
1067 return false; | |
1068 } | |
1069 | |
1070 // Now process the PT_NOTE structures. Each one is preceded by | |
1071 // an Elf{32/64}_Nhdr structure describing its type and size. | |
1072 if ( (buf = (char*) malloc(size)) == NULL) { | |
1073 print_debug("can't allocate memory for reading core notes\n"); | |
1074 goto err; | |
1075 } | |
1076 | |
1077 // read notes into buffer | |
1078 if (read(ph->core->core_fd, buf, size) != size) { | |
1079 print_debug("failed to read notes, core file must have been truncated\n"); | |
1080 goto err; | |
1081 } | |
1082 | |
1083 p = buf; | |
1084 while (p < buf + size) { | |
1085 ELF_NHDR* notep = (ELF_NHDR*) p; | |
1086 char* descdata = p + sizeof(ELF_NHDR) + ROUNDUP(notep->n_namesz, 4); | |
1087 print_debug("Note header with n_type = %d and n_descsz = %u\n", | |
1088 notep->n_type, notep->n_descsz); | |
1089 | |
1090 if (notep->n_type == NT_PRSTATUS) { | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1091 if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1092 return false; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1093 } |
3960 | 1094 } |
1095 p = descdata + ROUNDUP(notep->n_descsz, 4); | |
1096 } | |
1097 | |
1098 free(buf); | |
1099 return true; | |
1100 | |
1101 err: | |
1102 if (buf) free(buf); | |
1103 return false; | |
1104 } | |
1105 | |
1106 // read all segments from core file | |
1107 static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) { | |
1108 int i = 0; | |
1109 ELF_PHDR* phbuf = NULL; | |
1110 ELF_PHDR* core_php = NULL; | |
1111 | |
1112 if ((phbuf = read_program_header_table(ph->core->core_fd, core_ehdr)) == NULL) | |
1113 return false; | |
1114 | |
1115 /* | |
1116 * Now iterate through the program headers in the core file. | |
1117 * We're interested in two types of Phdrs: PT_NOTE (which | |
1118 * contains a set of saved /proc structures), and PT_LOAD (which | |
1119 * represents a memory mapping from the process's address space). | |
1120 * | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1121 * Difference b/w Solaris PT_NOTE and Linux/BSD PT_NOTE: |
3960 | 1122 * |
1123 * In Solaris there are two PT_NOTE segments the first PT_NOTE (if present) | |
1124 * contains /proc structs in the pre-2.6 unstructured /proc format. the last | |
1125 * PT_NOTE has data in new /proc format. | |
1126 * | |
1127 * In Solaris, there is only one pstatus (process status). pstatus contains | |
1128 * integer register set among other stuff. For each LWP, we have one lwpstatus | |
1129 * entry that has integer regset for that LWP. | |
1130 * | |
1131 * Linux threads are actually 'clone'd processes. To support core analysis | |
1132 * of "multithreaded" process, Linux creates more than one pstatus (called | |
1133 * "prstatus") entry in PT_NOTE. Each prstatus entry has integer regset for one | |
1134 * "thread". Please refer to Linux kernel src file 'fs/binfmt_elf.c', in particular | |
1135 * function "elf_core_dump". | |
1136 */ | |
1137 | |
1138 for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) { | |
1139 switch (core_php->p_type) { | |
1140 case PT_NOTE: | |
8750 | 1141 if (core_handle_note(ph, core_php) != true) { |
1142 goto err; | |
1143 } | |
3960 | 1144 break; |
1145 | |
1146 case PT_LOAD: { | |
1147 if (core_php->p_filesz != 0) { | |
1148 if (add_map_info(ph, ph->core->core_fd, core_php->p_offset, | |
1149 core_php->p_vaddr, core_php->p_filesz) == NULL) goto err; | |
1150 } | |
1151 break; | |
1152 } | |
1153 } | |
1154 | |
1155 core_php++; | |
1156 } | |
1157 | |
1158 free(phbuf); | |
1159 return true; | |
1160 err: | |
1161 free(phbuf); | |
1162 return false; | |
1163 } | |
1164 | |
1165 // read segments of a shared object | |
1166 static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) { | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1167 int i = 0; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1168 ELF_PHDR* phbuf; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1169 ELF_PHDR* lib_php = NULL; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1170 |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1171 int page_size=sysconf(_SC_PAGE_SIZE); |
3960 | 1172 |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1173 if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1174 return false; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1175 } |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1176 |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1177 // we want to process only PT_LOAD segments that are not writable. |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1178 // i.e., text segments. The read/write/exec (data) segments would |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1179 // have been already added from core file segments. |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1180 for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1181 if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1182 |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1183 uintptr_t target_vaddr = lib_php->p_vaddr + lib_base; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1184 map_info *existing_map = core_lookup(ph, target_vaddr); |
3960 | 1185 |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1186 if (existing_map == NULL){ |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1187 if (add_map_info(ph, lib_fd, lib_php->p_offset, |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1188 target_vaddr, lib_php->p_filesz) == NULL) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1189 goto err; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1190 } |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1191 } else { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1192 if ((existing_map->memsz != page_size) && |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1193 (existing_map->fd != lib_fd) && |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1194 (existing_map->memsz != lib_php->p_filesz)){ |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1195 |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1196 print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)", |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1197 target_vaddr, lib_php->p_filesz, lib_php->p_flags); |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1198 goto err; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1199 } |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1200 |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1201 /* replace PT_LOAD segment with library segment */ |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1202 print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n", |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1203 existing_map->memsz, lib_php->p_filesz); |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1204 |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1205 existing_map->fd = lib_fd; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1206 existing_map->offset = lib_php->p_offset; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1207 existing_map->memsz = lib_php->p_filesz; |
3960 | 1208 } |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1209 } |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1210 |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1211 lib_php++; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1212 } |
3960 | 1213 |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1214 free(phbuf); |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1215 return true; |
3960 | 1216 err: |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1217 free(phbuf); |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1218 return false; |
3960 | 1219 } |
1220 | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1221 // process segments from interpreter (ld.so or ld-linux.so or ld-elf.so) |
3960 | 1222 static bool read_interp_segments(struct ps_prochandle* ph) { |
1223 ELF_EHDR interp_ehdr; | |
1224 | |
1225 if (read_elf_header(ph->core->interp_fd, &interp_ehdr) != true) { | |
1226 print_debug("interpreter is not a valid ELF file\n"); | |
1227 return false; | |
1228 } | |
1229 | |
1230 if (read_lib_segments(ph, ph->core->interp_fd, &interp_ehdr, ph->core->ld_base_addr) != true) { | |
1231 print_debug("can't read segments of interpreter\n"); | |
1232 return false; | |
1233 } | |
1234 | |
1235 return true; | |
1236 } | |
1237 | |
1238 // process segments of a a.out | |
1239 static bool read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehdr) { | |
1240 int i = 0; | |
1241 ELF_PHDR* phbuf = NULL; | |
1242 ELF_PHDR* exec_php = NULL; | |
1243 | |
1244 if ((phbuf = read_program_header_table(ph->core->exec_fd, exec_ehdr)) == NULL) | |
1245 return false; | |
1246 | |
1247 for (exec_php = phbuf, i = 0; i < exec_ehdr->e_phnum; i++) { | |
1248 switch (exec_php->p_type) { | |
1249 | |
1250 // add mappings for PT_LOAD segments | |
1251 case PT_LOAD: { | |
1252 // add only non-writable segments of non-zero filesz | |
1253 if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) { | |
1254 if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz) == NULL) goto err; | |
1255 } | |
1256 break; | |
1257 } | |
1258 | |
1259 // read the interpreter and it's segments | |
1260 case PT_INTERP: { | |
1261 char interp_name[BUF_SIZE]; | |
1262 | |
1263 pread(ph->core->exec_fd, interp_name, MIN(exec_php->p_filesz, BUF_SIZE), exec_php->p_offset); | |
1264 print_debug("ELF interpreter %s\n", interp_name); | |
1265 // read interpreter segments as well | |
1266 if ((ph->core->interp_fd = pathmap_open(interp_name)) < 0) { | |
1267 print_debug("can't open runtime loader\n"); | |
1268 goto err; | |
1269 } | |
1270 break; | |
1271 } | |
1272 | |
1273 // from PT_DYNAMIC we want to read address of first link_map addr | |
1274 case PT_DYNAMIC: { | |
1275 ph->core->dynamic_addr = exec_php->p_vaddr; | |
1276 print_debug("address of _DYNAMIC is 0x%lx\n", ph->core->dynamic_addr); | |
1277 break; | |
1278 } | |
1279 | |
1280 } // switch | |
1281 exec_php++; | |
1282 } // for | |
1283 | |
1284 free(phbuf); | |
1285 return true; | |
1286 err: | |
1287 free(phbuf); | |
1288 return false; | |
1289 } | |
1290 | |
1291 #define FIRST_LINK_MAP_OFFSET offsetof(struct r_debug, r_map) | |
1292 #define LD_BASE_OFFSET offsetof(struct r_debug, r_ldbase) | |
1293 #define LINK_MAP_ADDR_OFFSET offsetof(struct link_map, l_addr) | |
1294 #define LINK_MAP_NAME_OFFSET offsetof(struct link_map, l_name) | |
1295 #define LINK_MAP_NEXT_OFFSET offsetof(struct link_map, l_next) | |
1296 | |
1297 // read shared library info from runtime linker's data structures. | |
1298 // This work is done by librtlb_db in Solaris | |
1299 static bool read_shared_lib_info(struct ps_prochandle* ph) { | |
8750 | 1300 uintptr_t addr = ph->core->dynamic_addr; |
1301 uintptr_t debug_base; | |
1302 uintptr_t first_link_map_addr; | |
1303 uintptr_t ld_base_addr; | |
1304 uintptr_t link_map_addr; | |
1305 uintptr_t lib_base_diff; | |
1306 uintptr_t lib_base; | |
1307 uintptr_t lib_name_addr; | |
1308 char lib_name[BUF_SIZE]; | |
1309 ELF_DYN dyn; | |
1310 ELF_EHDR elf_ehdr; | |
1311 int lib_fd; | |
3960 | 1312 |
8750 | 1313 // _DYNAMIC has information of the form |
1314 // [tag] [data] [tag] [data] ..... | |
1315 // Both tag and data are pointer sized. | |
1316 // We look for dynamic info with DT_DEBUG. This has shared object info. | |
1317 // refer to struct r_debug in link.h | |
3960 | 1318 |
8750 | 1319 dyn.d_tag = DT_NULL; |
1320 while (dyn.d_tag != DT_DEBUG) { | |
1321 if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { | |
1322 print_debug("can't read debug info from _DYNAMIC\n"); | |
1323 return false; | |
1324 } | |
1325 addr += sizeof(ELF_DYN); | |
1326 } | |
3960 | 1327 |
8750 | 1328 // we have got Dyn entry with DT_DEBUG |
1329 debug_base = dyn.d_un.d_ptr; | |
1330 // at debug_base we have struct r_debug. This has first link map in r_map field | |
1331 if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1332 &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { |
8750 | 1333 print_debug("can't read first link map address\n"); |
1334 return false; | |
1335 } | |
3960 | 1336 |
8750 | 1337 // read ld_base address from struct r_debug |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1338 #if 0 // There is no r_ldbase member on BSD |
8750 | 1339 if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, |
1340 sizeof(uintptr_t)) != PS_OK) { | |
1341 print_debug("can't read ld base address\n"); | |
1342 return false; | |
1343 } | |
1344 ph->core->ld_base_addr = ld_base_addr; | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1345 #else |
8750 | 1346 ph->core->ld_base_addr = 0; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1347 #endif |
3960 | 1348 |
8750 | 1349 print_debug("interpreter base address is 0x%lx\n", ld_base_addr); |
3960 | 1350 |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1351 // now read segments from interp (i.e ld.so or ld-linux.so or ld-elf.so) |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1352 if (read_interp_segments(ph) != true) { |
8750 | 1353 return false; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1354 } |
3960 | 1355 |
8750 | 1356 // after adding interpreter (ld.so) mappings sort again |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1357 if (sort_map_array(ph) != true) { |
8750 | 1358 return false; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1359 } |
3960 | 1360 |
8750 | 1361 print_debug("first link map is at 0x%lx\n", first_link_map_addr); |
3960 | 1362 |
8750 | 1363 link_map_addr = first_link_map_addr; |
1364 while (link_map_addr != 0) { | |
1365 // read library base address of the .so. Note that even though <sys/link.h> calls | |
1366 // link_map->l_addr as "base address", this is * not * really base virtual | |
1367 // address of the shared object. This is actually the difference b/w the virtual | |
1368 // address mentioned in shared object and the actual virtual base where runtime | |
1369 // linker loaded it. We use "base diff" in read_lib_segments call below. | |
3960 | 1370 |
8750 | 1371 if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, |
1372 &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { | |
1373 print_debug("can't read shared object base address diff\n"); | |
1374 return false; | |
1375 } | |
3960 | 1376 |
8750 | 1377 // read address of the name |
1378 if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, | |
1379 &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { | |
1380 print_debug("can't read address of shared object name\n"); | |
1381 return false; | |
1382 } | |
3960 | 1383 |
8750 | 1384 // read name of the shared object |
1385 if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) { | |
1386 print_debug("can't read shared object name\n"); | |
1387 return false; | |
1388 } | |
3960 | 1389 |
8750 | 1390 if (lib_name[0] != '\0') { |
1391 // ignore empty lib names | |
1392 lib_fd = pathmap_open(lib_name); | |
3960 | 1393 |
8750 | 1394 if (lib_fd < 0) { |
1395 print_debug("can't open shared object %s\n", lib_name); | |
1396 // continue with other libraries... | |
1397 } else { | |
1398 if (read_elf_header(lib_fd, &elf_ehdr)) { | |
1399 lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); | |
1400 print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", | |
1401 lib_name, lib_base, lib_base_diff); | |
1402 // while adding library mappings we need to use "base difference". | |
1403 if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { | |
1404 print_debug("can't read shared object's segments\n"); | |
1405 close(lib_fd); | |
1406 return false; | |
1407 } | |
1408 add_lib_info_fd(ph, lib_name, lib_fd, lib_base); | |
1409 // Map info is added for the library (lib_name) so | |
1410 // we need to re-sort it before calling the p_pdread. | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1411 if (sort_map_array(ph) != true) { |
8750 | 1412 return false; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1413 } |
8750 | 1414 } else { |
1415 print_debug("can't read ELF header for shared object %s\n", lib_name); | |
1416 close(lib_fd); | |
1417 // continue with other libraries... | |
1418 } | |
3960 | 1419 } |
8750 | 1420 } |
3960 | 1421 |
8750 | 1422 // read next link_map address |
1423 if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1424 &link_map_addr, sizeof(uintptr_t)) != PS_OK) { |
8750 | 1425 print_debug("can't read next link in link_map\n"); |
1426 return false; | |
1427 } | |
1428 } | |
3960 | 1429 |
8750 | 1430 return true; |
3960 | 1431 } |
1432 | |
1433 // the one and only one exposed stuff from this file | |
1434 struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { | |
8750 | 1435 ELF_EHDR core_ehdr; |
1436 ELF_EHDR exec_ehdr; | |
3960 | 1437 |
8750 | 1438 struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); |
1439 if (ph == NULL) { | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1440 print_debug("can't allocate ps_prochandle\n"); |
8750 | 1441 return NULL; |
1442 } | |
3960 | 1443 |
8750 | 1444 if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { |
1445 free(ph); | |
1446 print_debug("can't allocate ps_prochandle\n"); | |
1447 return NULL; | |
1448 } | |
3960 | 1449 |
8750 | 1450 // initialize ph |
1451 ph->ops = &core_ops; | |
1452 ph->core->core_fd = -1; | |
1453 ph->core->exec_fd = -1; | |
1454 ph->core->interp_fd = -1; | |
1455 | |
1456 print_debug("exec: %s core: %s", exec_file, core_file); | |
3960 | 1457 |
8750 | 1458 // open the core file |
1459 if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { | |
1460 print_debug("can't open core file\n"); | |
1461 goto err; | |
1462 } | |
3960 | 1463 |
8750 | 1464 // read core file ELF header |
1465 if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { | |
1466 print_debug("core file is not a valid ELF ET_CORE file\n"); | |
1467 goto err; | |
1468 } | |
3960 | 1469 |
8750 | 1470 if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { |
1471 print_debug("can't open executable file\n"); | |
1472 goto err; | |
1473 } | |
3960 | 1474 |
8750 | 1475 if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1476 print_debug("executable file is not a valid ELF ET_EXEC file\n"); |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1477 goto err; |
8750 | 1478 } |
3960 | 1479 |
8750 | 1480 // process core file segments |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1481 if (read_core_segments(ph, &core_ehdr) != true) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1482 goto err; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1483 } |
3960 | 1484 |
8750 | 1485 // process exec file segments |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1486 if (read_exec_segments(ph, &exec_ehdr) != true) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1487 goto err; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1488 } |
3960 | 1489 |
8750 | 1490 // exec file is also treated like a shared object for symbol search |
1491 if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1492 (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) { |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1493 goto err; |
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1494 } |
3960 | 1495 |
8750 | 1496 // allocate and sort maps into map_array, we need to do this |
1497 // here because read_shared_lib_info needs to read from debuggee | |
1498 // address space | |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1499 if (sort_map_array(ph) != true) { |
8750 | 1500 goto err; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1501 } |
3960 | 1502 |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1503 if (read_shared_lib_info(ph) != true) { |
8750 | 1504 goto err; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1505 } |
3960 | 1506 |
8750 | 1507 // sort again because we have added more mappings from shared objects |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1508 if (sort_map_array(ph) != true) { |
8750 | 1509 goto err; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1510 } |
3960 | 1511 |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1512 if (init_classsharing_workaround(ph) != true) { |
8750 | 1513 goto err; |
12807
5705c7ee6dd7
8025250: SA: Sync linux and bsd versions of ps_core file
dsamersoff
parents:
10229
diff
changeset
|
1514 } |
3960 | 1515 |
8750 | 1516 print_debug("Leave Pgrab_core\n"); |
1517 return ph; | |
3960 | 1518 |
1519 err: | |
8750 | 1520 Prelease(ph); |
1521 return NULL; | |
3960 | 1522 } |
8750 | 1523 |
1524 #endif // __APPLE__ |