agent/src/os/bsd/ps_core.c
Index
Unified diffs
Context diffs
Sdiffs
Wdiffs
Patch
New
Old
Previous File
Next File
*** old/agent/src/os/bsd/ps_core.c Wed Mar 13 23:31:46 2013
--- new/agent/src/os/bsd/ps_core.c Wed Mar 13 23:31:45 2013
*** 1,7 ****
--- 1,7 ----
/*
! * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
! * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 26,51 ****
--- 26,51 ----
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <elf.h>
#include <link.h>
#include "libproc_impl.h"
#include "salibelf.h"
+ #ifdef __APPLE__
+ #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
+ #endif
+
// This file has the libproc implementation to read core files.
// For live processes, refer to ps_proc.c. Portions of this is adapted
// /modelled after Solaris libproc.so (in particular Pcore.c)
//----------------------------------------------------------------------
// ps_prochandle cleanup helper functions
// close all file descriptors
! static void close_elf_files(struct ps_prochandle* ph) {
! static void close_files(struct ps_prochandle* ph) {
lib_info* lib = NULL;
// close core file descriptor
if (ph->core->core_fd >= 0)
close(ph->core->core_fd);
// close exec file descriptor
*** 62,72 ****
--- 62,74 ----
// close all library file descriptors
lib = ph->libs;
while (lib) {
int fd = lib->fd;
if (fd >= 0 && fd != ph->core->exec_fd) close(fd);
+ if (fd >= 0 && fd != ph->core->exec_fd) {
+ close(fd);
+ }
lib = lib->next;
}
}
// clean all map_info stuff
*** 92,102 ****
--- 94,104 ----
}
// ps_prochandle operations
static void core_release(struct ps_prochandle* ph) {
if (ph->core) {
! close_elf_files(ph);
! close_files(ph);
destroy_map_info(ph);
free(ph->core);
}
}
*** 152,174 ****
--- 154,179 ----
int mid, lo = 0, hi = ph->core->num_maps - 1;
map_info *mp;
while (hi - lo > 1) {
mid = (lo + hi) / 2;
if (addr >= ph->core->map_array[mid]->vaddr)
+ if (addr >= ph->core->map_array[mid]->vaddr) {
lo = mid;
else
+ } else {
hi = mid;
}
+ }
if (addr < ph->core->map_array[hi]->vaddr)
+ if (addr < ph->core->map_array[hi]->vaddr) {
mp = ph->core->map_array[lo];
else
+ } else {
mp = ph->core->map_array[hi];
+ }
if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz)
+ if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
return (mp);
+ }
// Part of the class sharing workaround
// Unfortunately, we have no way of detecting -Xshare state.
// Check out the share maps atlast, if we don't find anywhere.
*** 175,191 ****
--- 180,194 ----
// This is done this way so to avoid reading share pages
// ahead of other normal maps. For eg. with -Xshare:off we don't
// want to prefer class sharing data to data from core.
mp = ph->core->class_share_maps;
if (mp) {
print_debug("can't locate map_info at 0x%lx, trying class share maps\n",
addr);
+ print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr);
}
while (mp) {
if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
print_debug("located map_info at 0x%lx from class share maps\n",
addr);
+ print_debug("located map_info at 0x%lx from class share maps\n", addr);
return (mp);
}
mp = mp->next;
}
*** 248,258 ****
--- 251,261 ----
}
}
static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) {
uintptr_t uip;
! if (ps_pread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) {
! if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) {
*pvalue = uip;
return true;
} else {
return false;
}
*** 262,300 ****
--- 265,318 ----
static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) {
size_t i = 0;
char c = ' ';
while (c != '\0') {
if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK)
+ if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) {
return false;
if (i < size - 1)
+ }
+ if (i < size - 1) {
buf[i] = c;
else // smaller buffer
+ } else {
+ // smaller buffer
return false;
+ }
i++; addr++;
}
buf[i] = '\0';
return true;
}
#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
+ #ifdef __APPLE__
+ #define USE_SHARED_SPACES_SYM "_UseSharedSpaces"
// mangled name of Arguments::SharedArchivePath
#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE"
+ #else
+ #define USE_SHARED_SPACES_SYM "UseSharedSpaces"
+ // mangled name of Arguments::SharedArchivePath
+ #define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE"
+ #endif // __APPLE_
static bool init_classsharing_workaround(struct ps_prochandle* ph) {
+ int m;
+ size_t n;
lib_info* lib = ph->libs;
while (lib != NULL) {
// we are iterating over shared objects from the core dump. look for
// libjvm[_g].so.
const char *jvm_name = 0;
+ #ifdef __APPLE__
+ if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 ||
+ (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0)
+ #else
if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
! (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) {
+ #endif // __APPLE__
+ {
char classes_jsa[PATH_MAX];
struct FileMapHeader header;
! size_t n = 0;
int fd = -1, m = 0;
! int fd = -1;
uintptr_t base = 0, useSharedSpacesAddr = 0;
uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0;
jboolean useSharedSpaces = 0;
memset(classes_jsa, 0, sizeof(classes_jsa));
*** 387,397 ****
--- 405,414 ----
lib = lib->next;
}
return true;
}
//---------------------------------------------------------------------------
// functions to handle map_info
// Order mappings based on virtual address. We use this function as the
// callback for sorting the array of map_info pointers.
*** 398,409 ****
--- 415,427 ----
static int core_cmp_mapping(const void *lhsp, const void *rhsp)
{
const map_info *lhs = *((const map_info **)lhsp);
const map_info *rhs = *((const map_info **)rhsp);
if (lhs->vaddr == rhs->vaddr)
+ if (lhs->vaddr == rhs->vaddr) {
return (0);
+ }
return (lhs->vaddr < rhs->vaddr ? -1 : 1);
}
// we sort map_info by starting virtual address so that we can do
*** 426,436 ****
--- 444,456 ----
i++;
map = map->next;
}
// sort is called twice. If this is second time, clear map array
if (ph->core->map_array) free(ph->core->map_array);
+ if (ph->core->map_array) {
+ free(ph->core->map_array);
+ }
ph->core->map_array = array;
// sort the map_info array by base virtual address.
qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*),
core_cmp_mapping);
*** 459,478 ****
--- 479,500 ----
uintptr_t mapoff;
ssize_t len, rem;
off_t off;
int fd;
! if (mp == NULL) {
break; /* No mapping for this address */
+ }
fd = mp->fd;
mapoff = addr - mp->vaddr;
len = MIN(resid, mp->memsz - mapoff);
off = mp->offset + mapoff;
! if ((len = pread(fd, buf, len, off)) <= 0) {
break;
+ }
resid -= len;
addr += len;
buf = (char *)buf + len;
*** 505,516 ****
--- 527,538 ----
return false;
}
static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id,
struct reg* regs) {
! // for core we have cached the lwp regs from NOTE section
! thread_info* thr = ph->threads;
! // for core we have cached the lwp regs after segment parsed
! sa_thread_info* thr = ph->threads;
while (thr) {
if (thr->lwp_id == lwp_id) {
memcpy(regs, &thr->regs, sizeof(struct reg));
return true;
}
*** 517,527 ****
--- 539,549 ----
thr = thr->next;
}
return false;
}
! static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) {
print_debug("core_get_lwp_info not implemented\n");
return false;
}
static ps_prochandle_ops core_ops = {
*** 530,545 ****
--- 552,1007 ----
.p_pwrite= core_write_data,
.get_lwp_regs= core_get_lwp_regs,
.get_lwp_info= core_get_lwp_info
};
// read regs and create thread from NT_PRSTATUS entries from core file
+ // from this point, mainly two blocks divided by def __APPLE__
+ // one for Macosx, the other for regular Bsd
+
+ #ifdef __APPLE__
+
+ void print_thread(sa_thread_info *threadinfo) {
+ print_debug("thread added: %d\n", threadinfo->lwp_id);
+ print_debug("registers:\n");
+ print_debug(" r_r15: 0x%" PRIx64 "\n", threadinfo->regs.r_r15);
+ print_debug(" r_r14: 0x%" PRIx64 "\n", threadinfo->regs.r_r14);
+ print_debug(" r_r13: 0x%" PRIx64 "\n", threadinfo->regs.r_r13);
+ print_debug(" r_r12: 0x%" PRIx64 "\n", threadinfo->regs.r_r12);
+ print_debug(" r_r11: 0x%" PRIx64 "\n", threadinfo->regs.r_r11);
+ print_debug(" r_r10: 0x%" PRIx64 "\n", threadinfo->regs.r_r10);
+ print_debug(" r_r9: 0x%" PRIx64 "\n", threadinfo->regs.r_r9);
+ print_debug(" r_r8: 0x%" PRIx64 "\n", threadinfo->regs.r_r8);
+ print_debug(" r_rdi: 0x%" PRIx64 "\n", threadinfo->regs.r_rdi);
+ print_debug(" r_rsi: 0x%" PRIx64 "\n", threadinfo->regs.r_rsi);
+ print_debug(" r_rbp: 0x%" PRIx64 "\n", threadinfo->regs.r_rbp);
+ print_debug(" r_rbx: 0x%" PRIx64 "\n", threadinfo->regs.r_rbx);
+ print_debug(" r_rdx: 0x%" PRIx64 "\n", threadinfo->regs.r_rdx);
+ print_debug(" r_rcx: 0x%" PRIx64 "\n", threadinfo->regs.r_rcx);
+ print_debug(" r_rax: 0x%" PRIx64 "\n", threadinfo->regs.r_rax);
+ print_debug(" r_fs: 0x%" PRIx32 "\n", threadinfo->regs.r_fs);
+ print_debug(" r_gs: 0x%" PRIx32 "\n", threadinfo->regs.r_gs);
+ print_debug(" r_rip 0x%" PRIx64 "\n", threadinfo->regs.r_rip);
+ print_debug(" r_cs: 0x%" PRIx64 "\n", threadinfo->regs.r_cs);
+ print_debug(" r_rsp: 0x%" PRIx64 "\n", threadinfo->regs.r_rsp);
+ print_debug(" r_rflags: 0x%" PRIx64 "\n", threadinfo->regs.r_rflags);
+ }
+
+ // read all segments64 commands from core file
+ // read all thread commands from core file
+ static bool read_core_segments(struct ps_prochandle* ph) {
+ int i = 0;
+ int num_threads = 0;
+ int fd = ph->core->core_fd;
+ off_t offset = 0;
+ mach_header_64 fhead;
+ load_command lcmd;
+ segment_command_64 segcmd;
+ // thread_command thrcmd;
+
+ lseek(fd, offset, SEEK_SET);
+ if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ goto err;
+ }
+ print_debug("total commands: %d\n", fhead.ncmds);
+ offset += sizeof(mach_header_64);
+ for (i = 0; i < fhead.ncmds; i++) {
+ lseek(fd, offset, SEEK_SET);
+ if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
+ goto err;
+ }
+ offset += lcmd.cmdsize; // next command position
+ if (lcmd.cmd == LC_SEGMENT_64) {
+ lseek(fd, -sizeof(load_command), SEEK_CUR);
+ if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) {
+ print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i);
+ goto err;
+ }
+ if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) {
+ print_debug("Failed to add map_info at i = %d\n", i);
+ goto err;
+ }
+ print_debug("segment added: %" PRIu64 " 0x%" PRIx64 " %d\n",
+ segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize);
+ } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) {
+ typedef struct thread_fc {
+ uint32_t flavor;
+ uint32_t count;
+ } thread_fc;
+ thread_fc fc;
+ uint32_t size = sizeof(load_command);
+ while (size < lcmd.cmdsize) {
+ if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) {
+ printf("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(thread_fc);
+ if (fc.flavor == x86_THREAD_STATE) {
+ x86_thread_state_t thrstate;
+ if (read(fd, (void *)&thrstate, sizeof(x86_thread_state_t)) != sizeof(x86_thread_state_t)) {
+ printf("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(x86_thread_state_t);
+ // create thread info list, update lwp_id later
+ sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++);
+ if (newthr == NULL) {
+ printf("create thread_info failed\n");
+ goto err;
+ }
+
+ // note __DARWIN_UNIX03 depengs on other definitions
+ #if __DARWIN_UNIX03
+ #define get_register_v(regst, regname) \
+ regst.uts.ts64.__##regname
+ #else
+ #define get_register_v(regst, regname) \
+ regst.uts.ts64.##regname
+ #endif // __DARWIN_UNIX03
+ newthr->regs.r_rax = get_register_v(thrstate, rax);
+ newthr->regs.r_rbx = get_register_v(thrstate, rbx);
+ newthr->regs.r_rcx = get_register_v(thrstate, rcx);
+ newthr->regs.r_rdx = get_register_v(thrstate, rdx);
+ newthr->regs.r_rdi = get_register_v(thrstate, rdi);
+ newthr->regs.r_rsi = get_register_v(thrstate, rsi);
+ newthr->regs.r_rbp = get_register_v(thrstate, rbp);
+ newthr->regs.r_rsp = get_register_v(thrstate, rsp);
+ newthr->regs.r_r8 = get_register_v(thrstate, r8);
+ newthr->regs.r_r9 = get_register_v(thrstate, r9);
+ newthr->regs.r_r10 = get_register_v(thrstate, r10);
+ newthr->regs.r_r11 = get_register_v(thrstate, r11);
+ newthr->regs.r_r12 = get_register_v(thrstate, r12);
+ newthr->regs.r_r13 = get_register_v(thrstate, r13);
+ newthr->regs.r_r14 = get_register_v(thrstate, r14);
+ newthr->regs.r_r15 = get_register_v(thrstate, r15);
+ newthr->regs.r_rip = get_register_v(thrstate, rip);
+ newthr->regs.r_rflags = get_register_v(thrstate, rflags);
+ newthr->regs.r_cs = get_register_v(thrstate, cs);
+ newthr->regs.r_fs = get_register_v(thrstate, fs);
+ newthr->regs.r_gs = get_register_v(thrstate, gs);
+ print_thread(newthr);
+ } else if (fc.flavor == x86_FLOAT_STATE) {
+ x86_float_state_t flstate;
+ if (read(fd, (void *)&flstate, sizeof(x86_float_state_t)) != sizeof(x86_float_state_t)) {
+ print_debug("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(x86_float_state_t);
+ } else if (fc.flavor == x86_EXCEPTION_STATE) {
+ x86_exception_state_t excpstate;
+ if (read(fd, (void *)&excpstate, sizeof(x86_exception_state_t)) != sizeof(x86_exception_state_t)) {
+ printf("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(x86_exception_state_t);
+ }
+ }
+ }
+ }
+ return true;
+ err:
+ return false;
+ }
+
+ /**local function **/
+ bool exists(const char *fname)
+ {
+ int fd;
+ if ((fd = open(fname, O_RDONLY)) > 0) {
+ close(fd);
+ return true;
+ }
+ return false;
+ }
+
+ // we check: 1. lib
+ // 2. lib/server
+ // 3. jre/lib
+ // 4. jre/lib/server
+ // from: 1. exe path
+ // 2. JAVA_HOME
+ // 3. DYLD_LIBRARY_PATH
+ static bool get_real_path(struct ps_prochandle* ph, char *rpath) {
+ /** check if they exist in JAVA ***/
+ char* execname = ph->core->exec_path;
+ char filepath[4096];
+ char* filename = strrchr(rpath, '/'); // like /libjvm.dylib
+ if (filename == NULL) {
+ return false;
+ }
+
+ char* posbin = strstr(execname, "/bin/java");
+ if (posbin != NULL) {
+ memcpy(filepath, execname, posbin - execname); // not include trailing '/'
+ filepath[posbin - execname] = '\0';
+ } else {
+ char* java_home = getenv("JAVA_HOME");
+ if (java_home != NULL) {
+ strcpy(filepath, java_home);
+ } else {
+ char* dyldpath = getenv("DYLD_LIBRARY_PATH");
+ char* dypath = strtok(dyldpath, ":");
+ while (dypath != NULL) {
+ strcpy(filepath, dypath);
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+ dypath = strtok(dyldpath, ":");
+ }
+ // not found
+ return false;
+ }
+ }
+ // for exec and java_home, jdkpath now is filepath
+ size_t filepath_base_size = strlen(filepath);
+
+ // first try /lib/ and /lib/server
+ strcat(filepath, "/lib");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+ char* pos = strstr(filepath, filename); // like /libjvm.dylib
+ *pos = '\0';
+ strcat(filepath, "/server");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+
+
+ // then try /jre/lib/ and /jre/lib/server
+ filepath[filepath_base_size] = '\0';
+ strcat(filepath, "/jre/lib");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+ pos = strstr(filepath, filename);
+ *pos = '\0';
+ strcat(filepath, "/server");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool read_shared_lib_info(struct ps_prochandle* ph) {
+ static int pagesize = 0;
+ int fd = ph->core->core_fd;
+ int i = 0, j;
+ uint32_t v;
+ mach_header_64 header; // used to check if a file header in segment
+ load_command lcmd;
+ dylib_command dylibcmd;
+
+ char name[BUF_SIZE]; // use to store name
+
+ if (pagesize == 0) {
+ pagesize = getpagesize();
+ print_debug("page size is %d\n", pagesize);
+ }
+ for (j = 0; j < ph->core->num_maps; j++) {
+ map_info *iter = ph->core->map_array[j]; // head
+ off_t fpos = iter->offset;
+ if (iter->fd != fd) {
+ // only search core file!
+ continue;
+ }
+ print_debug("map_info %d: vmaddr = 0x%016" PRIx64 " fileoff = %" PRIu64 " vmsize = %" PRIu64 "\n",
+ j, iter->vaddr, iter->offset, iter->memsz);
+ lseek(fd, fpos, SEEK_SET);
+ // we assume .dylib loaded at segment address --- which is true for JVM libraries
+ // multiple files may be loaded in one segment.
+ // if first word is not a magic word, means this segment does not contain lib file.
+ if (read(fd, (void *)&v, sizeof(uint32_t)) == sizeof(uint32_t)) {
+ if (v != MH_MAGIC_64) {
+ continue;
+ }
+ } else {
+ // may be encountered last map, which is not readable
+ continue;
+ }
+ while (ltell(fd) - iter->offset < iter->memsz) {
+ lseek(fd, fpos, SEEK_SET);
+ if (read(fd, (void *)&v, sizeof(uint32_t)) != sizeof(uint32_t)) {
+ break;
+ }
+ if (v != MH_MAGIC_64) {
+ fpos = (ltell(fd) + pagesize -1)/pagesize * pagesize;
+ continue;
+ }
+ lseek(fd, -sizeof(uint32_t), SEEK_CUR);
+ // this is the file begining to core file.
+ if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ goto err;
+ }
+ fpos = ltell(fd);
+
+ // found a mach-o file in this segment
+ for (i = 0; i < header.ncmds; i++) {
+ // read commands in this "file"
+ // LC_ID_DYLIB is the file itself for a .dylib
+ lseek(fd, fpos, SEEK_SET);
+ if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
+ return false; // error
+ }
+ fpos += lcmd.cmdsize; // next command position
+ // make sure still within seg size.
+ if (fpos - lcmd.cmdsize - iter->offset > iter->memsz) {
+ print_debug("Warning: out of segement limit: %ld \n", fpos - lcmd.cmdsize - iter->offset);
+ break; // no need to iterate all commands
+ }
+ if (lcmd.cmd == LC_ID_DYLIB) {
+ lseek(fd, -sizeof(load_command), SEEK_CUR);
+ if (read(fd, (void *)&dylibcmd, sizeof(dylib_command)) != sizeof(dylib_command)) {
+ return false;
+ }
+ /**** name stored at dylib_command.dylib.name.offset, is a C string */
+ lseek(fd, dylibcmd.dylib.name.offset - sizeof(dylib_command), SEEK_CUR);
+ int j = 0;
+ while (j < BUF_SIZE) {
+ read(fd, (void *)(name + j), sizeof(char));
+ if (name[j] == '\0') break;
+ j++;
+ }
+ print_debug("%s\n", name);
+ // changed name from @rpath/xxxx.dylib to real path
+ if (strrchr(name, '@')) {
+ get_real_path(ph, name);
+ print_debug("get_real_path returned: %s\n", name);
+ }
+ add_lib_info(ph, name, iter->vaddr);
+ break;
+ }
+ }
+ // done with the file, advanced to next page to search more files
+ fpos = (ltell(fd) + pagesize - 1) / pagesize * pagesize;
+ }
+ }
+ return true;
+ err:
+ return false;
+ }
+
+ bool read_macho64_header(int fd, mach_header_64* core_header) {
+ bool is_macho = false;
+ if (fd < 0) return false;
+ off_t pos = ltell(fd);
+ lseek(fd, 0, SEEK_SET);
+ if (read(fd, (void *)core_header, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ is_macho = false;
+ } else {
+ is_macho = (core_header->magic == MH_MAGIC_64 || core_header->magic == MH_CIGAM_64);
+ }
+ lseek(fd, pos, SEEK_SET);
+ return is_macho;
+ }
+
+ // the one and only one exposed stuff from this file
+ struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) {
+ mach_header_64 core_header;
+ mach_header_64 exec_header;
+
+ struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle));
+ if (ph == NULL) {
+ print_debug("cant allocate ps_prochandle\n");
+ return NULL;
+ }
+
+ if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) {
+ free(ph);
+ print_debug("can't allocate ps_prochandle\n");
+ return NULL;
+ }
+
+ // initialize ph
+ ph->ops = &core_ops;
+ ph->core->core_fd = -1;
+ ph->core->exec_fd = -1;
+ ph->core->interp_fd = -1;
+
+ print_debug("exec: %s core: %s", exec_file, core_file);
+
+ strncpy(ph->core->exec_path, exec_file, sizeof(ph->core->exec_path));
+
+ // open the core file
+ if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) {
+ print_error("can't open core file\n");
+ goto err;
+ }
+
+ // read core file header
+ if (read_macho64_header(ph->core->core_fd, &core_header) != true || core_header.filetype != MH_CORE) {
+ print_debug("core file is not a valid Mach-O file\n");
+ goto err;
+ }
+
+ if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) {
+ print_error("can't open executable file\n");
+ goto err;
+ }
+
+ if (read_macho64_header(ph->core->exec_fd, &exec_header) != true ||
+ exec_header.filetype != MH_EXECUTE) {
+ print_error("executable file is not a valid Mach-O file\n");
+ goto err;
+ }
+
+ // process core file segments
+ if (read_core_segments(ph) != true) {
+ print_error("failed to read core segments\n");
+ goto err;
+ }
+
+ // allocate and sort maps into map_array, we need to do this
+ // here because read_shared_lib_info needs to read from debuggee
+ // address space
+ if (sort_map_array(ph) != true) {
+ print_error("failed to sort segment map array\n");
+ goto err;
+ }
+
+ if (read_shared_lib_info(ph) != true) {
+ print_error("failed to read libraries\n");
+ goto err;
+ }
+
+ // sort again because we have added more mappings from shared objects
+ if (sort_map_array(ph) != true) {
+ print_error("failed to sort segment map array\n");
+ goto err;
+ }
+
+ if (init_classsharing_workaround(ph) != true) {
+ print_error("failed to workaround classshareing\n");
+ goto err;
+ }
+
+ print_debug("Leave Pgrab_core\n");
+ return ph;
+
+ err:
+ Prelease(ph);
+ return NULL;
+ }
+
+ #else // __APPLE__ (none macosx)
+
+ // read regs and create thread from core file
static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size_t nbytes) {
// we have to read prstatus_t from buf
// assert(nbytes == sizeof(prstaus_t), "size mismatch on prstatus_t");
prstatus_t* prstat = (prstatus_t*) buf;
! sa_thread_info* newthr;
print_debug("got integer regset for lwp %d\n", prstat->pr_pid);
// we set pthread_t to -1 for core dump
if((newthr = add_thread_info(ph, (pthread_t) -1, prstat->pr_pid)) == NULL)
return false;
*** 630,642 ****
--- 1092,1105 ----
char* descdata = p + sizeof(ELF_NHDR) + ROUNDUP(notep->n_namesz, 4);
print_debug("Note header with n_type = %d and n_descsz = %u\n",
notep->n_type, notep->n_descsz);
if (notep->n_type == NT_PRSTATUS) {
! if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) {
return false;
}
+ }
p = descdata + ROUNDUP(notep->n_descsz, 4);
}
free(buf);
return true;
*** 679,689 ****
--- 1142,1154 ----
*/
for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) {
switch (core_php->p_type) {
case PT_NOTE:
! if (core_handle_note(ph, core_php) != true) goto err;
! if (core_handle_note(ph, core_php) != true) {
+ goto err;
+ }
break;
case PT_LOAD: {
if (core_php->p_filesz != 0) {
if (add_map_info(ph, ph->core->core_fd, core_php->p_offset,
*** 798,808 ****
--- 1263,1272 ----
err:
free(phbuf);
return false;
}
#define FIRST_LINK_MAP_OFFSET offsetof(struct r_debug, r_map)
#define LD_BASE_OFFSET offsetof(struct r_debug, r_ldbase)
#define LINK_MAP_ADDR_OFFSET offsetof(struct link_map, l_addr)
#define LINK_MAP_NAME_OFFSET offsetof(struct link_map, l_name)
#define LINK_MAP_NEXT_OFFSET offsetof(struct link_map, l_next)
*** 847,864 ****
--- 1311,1328 ----
return false;
}
// read ld_base address from struct r_debug
// XXX: There is no r_ldbase member on BSD
! /*
if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr,
sizeof(uintptr_t)) != PS_OK) {
print_debug("can't read ld base address\n");
return false;
}
ph->core->ld_base_addr = ld_base_addr;
! */
ph->core->ld_base_addr = 0;
print_debug("interpreter base address is 0x%lx\n", ld_base_addr);
// now read segments from interp (i.e ld-elf.so.1)
*** 945,955 ****
--- 1409,1419 ----
ELF_EHDR core_ehdr;
ELF_EHDR exec_ehdr;
struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle));
if (ph == NULL) {
! print_debug("can't allocate ps_prochandle\n");
return NULL;
}
if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) {
free(ph);
*** 961,970 ****
--- 1425,1436 ----
ph->ops = &core_ops;
ph->core->core_fd = -1;
ph->core->exec_fd = -1;
ph->core->interp_fd = -1;
+ print_debug("exec: %s core: %s", exec_file, core_file);
+
// open the core file
if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) {
print_debug("can't open core file\n");
goto err;
}
*** 1012,1022 ****
--- 1478,1491 ----
goto err;
if (init_classsharing_workaround(ph) != true)
goto err;
+ print_debug("Leave Pgrab_core\n");
return ph;
err:
Prelease(ph);
return NULL;
}
+
+ #endif // __APPLE__
agent/src/os/bsd/ps_core.c
Index
Unified diffs
Context diffs
Sdiffs
Wdiffs
Patch
New
Old
Previous File
Next File