agent/src/os/bsd/ps_core.c

Wed, 02 Oct 2013 22:27:23 +0400

author
dsamersoff
date
Wed, 02 Oct 2013 22:27:23 +0400
changeset 5832
5705c7ee6dd7
parent 5061
f6a055fcf47d
child 6876
710a3c8b516e
permissions
-rw-r--r--

8025250: SA: Sync linux and bsd versions of ps_core file
Summary: linux/ps_core.c and bsd/ps_core.c share most of code, but it has different formatting, comments etc.
Reviewed-by: sla, minqi

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

mercurial