提交 9d011637 编写于 作者: D dcubed

Merge

# #
# Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -22,34 +22,60 @@ ...@@ -22,34 +22,60 @@
# #
# #
ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi ) ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "x86_64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi )
OS := $(shell uname -s)
GCC = gcc GCC = gcc
JAVAH = ${JAVA_HOME}/bin/javah JAVAH = ${JAVA_HOME}/bin/javah
ifneq ($(OS), Darwin)
SOURCES = salibelf.c \ SOURCES = salibelf.c \
symtab.c \ symtab.c \
libproc_impl.c \ libproc_impl.c \
ps_proc.c \ ps_proc.c \
ps_core.c \ ps_core.c \
BsdDebuggerLocal.c BsdDebuggerLocal.c
OBJS = $(SOURCES:.c=.o)
OBJSPLUS = $(OBJS) sadis.o
LIBSA = $(ARCH)/libsaproc.so
INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") LIBS = -lutil -lthread_db
OBJS = $(SOURCES:.c=.o) else
LIBS = -lutil -lthread_db SOURCES = symtab.c \
libproc_impl.c \
ps_core.c
OBJS = $(SOURCES:.c=.o)
OBJSPLUS = MacosxDebuggerLocal.o sadis.o $(OBJS)
EXTINCLUDE = -I/System/Library/Frameworks/JavaVM.framework/Headers -I.
EXTCFLAGS = -m64 -D__APPLE__ -framework JavaNativeFoundation
FOUNDATIONFLAGS = -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation
LIBSA = $(ARCH)/libsaproc.dylib
endif # Darwin
INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") $(EXTINCLUDE)
CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) $(EXTCFLAGS)
CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES)
LIBSA = $(ARCH)/libsaproc.so
all: $(LIBSA) all: $(LIBSA)
BsdDebuggerLocal.o: BsdDebuggerLocal.c MacosxDebuggerLocal.o: MacosxDebuggerLocal.m
$(JAVAH) -jni -classpath ../../../../../build/bsd-i586/hotspot/outputdir/bsd_i486_compiler2/generated/saclasses \ echo "OS="$(OS)
$(JAVAH) -jni -classpath ../../../build/classes \
sun.jvm.hotspot.debugger.x86.X86ThreadContext \ sun.jvm.hotspot.debugger.x86.X86ThreadContext \
sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
$(GCC) $(CFLAGS) $(FOUNDATIONFLAGS) $<
sadis.o: ../../share/native/sadis.c
$(JAVAH) -jni -classpath ../../../build/classes \
sun.jvm.hotspot.asm.Disassembler
$(GCC) $(CFLAGS) $< $(GCC) $(CFLAGS) $<
.c.obj: .c.obj:
...@@ -59,9 +85,9 @@ ifndef LDNOMAP ...@@ -59,9 +85,9 @@ ifndef LDNOMAP
LFLAGS_LIBSA = -Xlinker --version-script=mapfile LFLAGS_LIBSA = -Xlinker --version-script=mapfile
endif endif
$(LIBSA): $(OBJS) mapfile $(LIBSA): $(OBJSPLUS) mapfile
if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi
$(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS) $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(FOUNDATIONFLAGS) $(OBJSPLUS) $(LIBS) $(SALIBS)
test.o: $(LIBSA) test.c test.o: $(LIBSA) test.c
$(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c $(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c
...@@ -71,7 +97,6 @@ test: test.o ...@@ -71,7 +97,6 @@ test: test.o
clean: clean:
rm -f $(LIBSA) rm -f $(LIBSA)
rm -f $(OBJS) rm -f *.o
rm -f test.o rm -f test.o
-rmdir $(ARCH) -rmdir $(ARCH)
/* /*
* Copyright (c) 2003, 2007, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,9 +27,38 @@ ...@@ -27,9 +27,38 @@
#include <unistd.h> #include <unistd.h>
#include <stdint.h> #include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#ifdef __APPLE__
typedef enum ps_err_e {
PS_OK, PS_ERR, PS_BADPID, PS_BADLID,
PS_BADADDR, PS_NOSYM, PS_NOFREGS
} ps_err_e;
#ifndef psaddr_t
#define psaddr_t uintptr_t
#endif
#ifndef bool
typedef int bool;
#define true 1
#define false 0
#endif // bool
#ifndef lwpid_t
#define lwpid_t uintptr_t
#endif
#include <mach/thread_status.h>
#else // __APPLE__
#include <elf.h>
#include <link.h>
#include <machine/reg.h> #include <machine/reg.h>
#include <proc_service.h> #include <proc_service.h>
#if defined(sparc) || defined(sparcv9) #if defined(sparc) || defined(sparcv9)
/* /*
If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64 If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64
...@@ -44,6 +73,14 @@ ...@@ -44,6 +73,14 @@
#endif //sparc or sparcv9 #endif //sparc or sparcv9
// This C bool type must be int for compatibility with BSD calls and
// it would be a mistake to equivalence it to C++ bool on many platforms
typedef int bool;
#define true 1
#define false 0
#endif // __APPLE__
/************************************************************************************ /************************************************************************************
0. This is very minimal subset of Solaris libproc just enough for current application. 0. This is very minimal subset of Solaris libproc just enough for current application.
...@@ -72,13 +109,7 @@ combination of ptrace and /proc calls. ...@@ -72,13 +109,7 @@ combination of ptrace and /proc calls.
*************************************************************************************/ *************************************************************************************/
// This C bool type must be int for compatibility with BSD calls and struct reg;
// it would be a mistake to equivalence it to C++ bool on many platforms
typedef int bool;
#define true 1
#define false 0
struct ps_prochandle; struct ps_prochandle;
// attach to a process // attach to a process
......
...@@ -21,12 +21,6 @@ ...@@ -21,12 +21,6 @@
* questions. * questions.
* *
*/ */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <thread_db.h>
#include "libproc_impl.h" #include "libproc_impl.h"
static const char* alt_root = NULL; static const char* alt_root = NULL;
...@@ -34,61 +28,65 @@ static int alt_root_len = -1; ...@@ -34,61 +28,65 @@ static int alt_root_len = -1;
#define SA_ALTROOT "SA_ALTROOT" #define SA_ALTROOT "SA_ALTROOT"
off_t ltell(int fd) {
return lseek(fd, 0, SEEK_CUR);
}
static void init_alt_root() { static void init_alt_root() {
if (alt_root_len == -1) { if (alt_root_len == -1) {
alt_root = getenv(SA_ALTROOT); alt_root = getenv(SA_ALTROOT);
if (alt_root) { if (alt_root) {
alt_root_len = strlen(alt_root); alt_root_len = strlen(alt_root);
} else { } else {
alt_root_len = 0; alt_root_len = 0;
} }
} }
} }
int pathmap_open(const char* name) { int pathmap_open(const char* name) {
int fd; int fd;
char alt_path[PATH_MAX + 1]; char alt_path[PATH_MAX + 1];
init_alt_root();
init_alt_root(); if (alt_root_len > 0) {
fd = open(name, O_RDONLY); strcpy(alt_path, alt_root);
if (fd >= 0) { strcat(alt_path, name);
fd = open(alt_path, O_RDONLY);
if (fd >= 0) {
print_debug("path %s substituted for %s\n", alt_path, name);
return fd; return fd;
} }
if (alt_root_len > 0) { if (strrchr(name, '/')) {
strcpy(alt_path, alt_root); strcpy(alt_path, alt_root);
strcat(alt_path, name); strcat(alt_path, strrchr(name, '/'));
fd = open(alt_path, O_RDONLY); fd = open(alt_path, O_RDONLY);
if (fd >= 0) { if (fd >= 0) {
print_debug("path %s substituted for %s\n", alt_path, name); print_debug("path %s substituted for %s\n", alt_path, name);
return fd; return fd;
}
if (strrchr(name, '/')) {
strcpy(alt_path, alt_root);
strcat(alt_path, strrchr(name, '/'));
fd = open(alt_path, O_RDONLY);
if (fd >= 0) {
print_debug("path %s substituted for %s\n", alt_path, name);
return fd;
}
} }
} }
} else {
return -1; fd = open(name, O_RDONLY);
if (fd >= 0) {
return fd;
}
}
return -1;
} }
static bool _libsaproc_debug; static bool _libsaproc_debug;
void print_debug(const char* format,...) { void print_debug(const char* format,...) {
if (_libsaproc_debug) { if (_libsaproc_debug) {
va_list alist; va_list alist;
va_start(alist, format); va_start(alist, format);
fputs("libsaproc DEBUG: ", stderr); fputs("libsaproc DEBUG: ", stderr);
vfprintf(stderr, format, alist); vfprintf(stderr, format, alist);
va_end(alist); va_end(alist);
} }
} }
void print_error(const char* format,...) { void print_error(const char* format,...) {
...@@ -100,172 +98,235 @@ void print_error(const char* format,...) { ...@@ -100,172 +98,235 @@ void print_error(const char* format,...) {
} }
bool is_debug() { bool is_debug() {
return _libsaproc_debug; return _libsaproc_debug;
} }
#ifdef __APPLE__
// get arch offset in file
bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) {
struct fat_header fatheader;
struct fat_arch fatarch;
off_t img_start = 0;
off_t pos = ltell(fd);
if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) {
return false;
}
if (fatheader.magic == FAT_CIGAM) {
int i;
for (i = 0; i < ntohl(fatheader.nfat_arch); i++) {
if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) {
return false;
}
if (ntohl(fatarch.cputype) == cputype) {
print_debug("fat offset=%x\n", ntohl(fatarch.offset));
img_start = ntohl(fatarch.offset);
break;
}
}
if (img_start == 0) {
return false;
}
}
lseek(fd, pos, SEEK_SET);
*offset = img_start;
return true;
}
bool is_macho_file(int fd) {
mach_header_64 fhdr;
off_t x86_64_off;
if (fd < 0) {
print_debug("Invalid file handle passed to is_macho_file\n");
return false;
}
off_t pos = ltell(fd);
// check fat header
if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) {
print_debug("failed to get fat header\n");
return false;
}
lseek(fd, x86_64_off, SEEK_SET);
if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
return false;
}
lseek(fd, pos, SEEK_SET); // restore
print_debug("fhdr.magic %x\n", fhdr.magic);
return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64);
}
#endif //__APPLE__
// initialize libproc // initialize libproc
bool init_libproc(bool debug) { bool init_libproc(bool debug) {
// init debug mode
_libsaproc_debug = debug; _libsaproc_debug = debug;
#ifndef __APPLE__
// initialize the thread_db library // initialize the thread_db library
if (td_init() != TD_OK) { if (td_init() != TD_OK) {
print_debug("libthread_db's td_init failed\n"); print_debug("libthread_db's td_init failed\n");
return false; return false;
} }
#endif // __APPLE__
return true; return true;
} }
static void destroy_lib_info(struct ps_prochandle* ph) { void destroy_lib_info(struct ps_prochandle* ph) {
lib_info* lib = ph->libs; lib_info* lib = ph->libs;
while (lib) { while (lib) {
lib_info *next = lib->next; lib_info* next = lib->next;
if (lib->symtab) { if (lib->symtab) {
destroy_symtab(lib->symtab); destroy_symtab(lib->symtab);
} }
free(lib); free(lib);
lib = next; lib = next;
} }
} }
static void destroy_thread_info(struct ps_prochandle* ph) { void destroy_thread_info(struct ps_prochandle* ph) {
thread_info* thr = ph->threads; sa_thread_info* thr = ph->threads;
while (thr) { while (thr) {
thread_info *next = thr->next; sa_thread_info* n = thr->next;
free(thr); free(thr);
thr = next; thr = n;
} }
} }
// ps_prochandle cleanup
// ps_prochandle cleanup // ps_prochandle cleanup
void Prelease(struct ps_prochandle* ph) { void Prelease(struct ps_prochandle* ph) {
// do the "derived class" clean-up first // do the "derived class" clean-up first
ph->ops->release(ph); ph->ops->release(ph);
destroy_lib_info(ph); destroy_lib_info(ph);
destroy_thread_info(ph); destroy_thread_info(ph);
free(ph); free(ph);
} }
lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {
return add_lib_info_fd(ph, libname, -1, base); return add_lib_info_fd(ph, libname, -1, base);
} }
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {
lib_info* newlib; lib_info* newlib;
print_debug("add_lib_info_fd %s\n", libname);
if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
print_debug("can't allocate memory for lib_info\n"); print_debug("can't allocate memory for lib_info\n");
return NULL; return NULL;
} }
strncpy(newlib->name, libname, sizeof(newlib->name)); strncpy(newlib->name, libname, sizeof(newlib->name));
newlib->base = base; newlib->base = base;
if (fd == -1) { if (fd == -1) {
if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
print_debug("can't open shared object %s\n", newlib->name); print_debug("can't open shared object %s\n", newlib->name);
free(newlib);
return NULL;
}
} else {
newlib->fd = fd;
}
// check whether we have got an ELF file. /proc/<pid>/map
// gives out all file mappings and not just shared objects
if (is_elf_file(newlib->fd) == false) {
close(newlib->fd);
free(newlib); free(newlib);
return NULL; return NULL;
} }
} else {
newlib->fd = fd;
}
newlib->symtab = build_symtab(newlib->fd); #ifdef __APPLE__
if (newlib->symtab == NULL) { // check whether we have got an Macho file.
print_debug("symbol table build failed for %s\n", newlib->name); if (is_macho_file(newlib->fd) == false) {
} close(newlib->fd);
else { free(newlib);
print_debug("built symbol table for %s\n", newlib->name); print_debug("not a mach-o file\n");
} return NULL;
}
#else
// check whether we have got an ELF file. /proc/<pid>/map
// gives out all file mappings and not just shared objects
if (is_elf_file(newlib->fd) == false) {
close(newlib->fd);
free(newlib);
return NULL;
}
#endif // __APPLE__
// even if symbol table building fails, we add the lib_info. newlib->symtab = build_symtab(newlib->fd);
// This is because we may need to read from the ELF file for core file if (newlib->symtab == NULL) {
// address read functionality. lookup_symbol checks for NULL symtab. print_debug("symbol table build failed for %s\n", newlib->name);
if (ph->libs) { } else {
ph->lib_tail->next = newlib; print_debug("built symbol table for %s\n", newlib->name);
ph->lib_tail = newlib; }
} else {
ph->libs = ph->lib_tail = newlib;
}
ph->num_libs++;
return newlib; // even if symbol table building fails, we add the lib_info.
// This is because we may need to read from the ELF file or MachO file for core file
// address read functionality. lookup_symbol checks for NULL symtab.
if (ph->libs) {
ph->lib_tail->next = newlib;
ph->lib_tail = newlib;
} else {
ph->libs = ph->lib_tail = newlib;
}
ph->num_libs++;
return newlib;
} }
// lookup for a specific symbol // lookup for a specific symbol
uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
const char* sym_name) { const char* sym_name) {
// ignore object_name. search in all libraries // ignore object_name. search in all libraries
// FIXME: what should we do with object_name?? The library names are obtained // FIXME: what should we do with object_name?? The library names are obtained
// by parsing /proc/<pid>/maps, which may not be the same as object_name. // by parsing /proc/<pid>/maps, which may not be the same as object_name.
// What we need is a utility to map object_name to real file name, something // What we need is a utility to map object_name to real file name, something
// dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For
// now, we just ignore object_name and do a global search for the symbol. // now, we just ignore object_name and do a global search for the symbol.
lib_info* lib = ph->libs; lib_info* lib = ph->libs;
while (lib) { while (lib) {
if (lib->symtab) { if (lib->symtab) {
uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);
if (res) return res; if (res) return res;
} }
lib = lib->next; lib = lib->next;
} }
print_debug("lookup failed for symbol '%s' in obj '%s'\n", print_debug("lookup failed for symbol '%s' in obj '%s'\n",
sym_name, object_name); sym_name, object_name);
return (uintptr_t) NULL; return (uintptr_t) NULL;
} }
const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) {
const char* res = NULL; const char* res = NULL;
lib_info* lib = ph->libs; lib_info* lib = ph->libs;
while (lib) { while (lib) {
if (lib->symtab && addr >= lib->base) { if (lib->symtab && addr >= lib->base) {
res = nearest_symbol(lib->symtab, addr - lib->base, poffset); res = nearest_symbol(lib->symtab, addr - lib->base, poffset);
if (res) return res; if (res) return res;
} }
lib = lib->next; lib = lib->next;
} }
return NULL; return NULL;
} }
// add a thread to ps_prochandle // add a thread to ps_prochandle
thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
thread_info* newthr; sa_thread_info* newthr;
if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) {
print_debug("can't allocate memory for thread_info\n"); print_debug("can't allocate memory for thread_info\n");
return NULL; return NULL;
} }
// initialize thread info // initialize thread info
newthr->pthread_id = pthread_id; newthr->pthread_id = pthread_id;
newthr->lwp_id = lwp_id; newthr->lwp_id = lwp_id;
// add new thread to the list // add new thread to the list
newthr->next = ph->threads; newthr->next = ph->threads;
ph->threads = newthr; ph->threads = newthr;
ph->num_threads++; ph->num_threads++;
return newthr; return newthr;
} }
#ifndef __APPLE__
// struct used for client data from thread_db callback // struct used for client data from thread_db callback
struct thread_db_client_data { struct thread_db_client_data {
struct ps_prochandle* ph; struct ps_prochandle* ph;
thread_info_callback callback; thread_info_callback callback;
}; };
// callback function for libthread_db // callback function for libthread_db
...@@ -314,6 +375,7 @@ bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) { ...@@ -314,6 +375,7 @@ bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) {
return true; return true;
} }
#endif // __APPLE__
// get number of threads // get number of threads
int get_num_threads(struct ps_prochandle* ph) { int get_num_threads(struct ps_prochandle* ph) {
...@@ -322,18 +384,54 @@ int get_num_threads(struct ps_prochandle* ph) { ...@@ -322,18 +384,54 @@ int get_num_threads(struct ps_prochandle* ph) {
// get lwp_id of n'th thread // get lwp_id of n'th thread
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) { lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) {
int count = 0; int count = 0;
thread_info* thr = ph->threads; sa_thread_info* thr = ph->threads;
while (thr) { while (thr) {
if (count == index) { if (count == index) {
return thr->lwp_id; return thr->lwp_id;
} }
count++; count++;
thr = thr->next; thr = thr->next;
} }
return -1; return 0;
} }
#ifdef __APPLE__
// set lwp_id of n'th thread
bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) {
int count = 0;
sa_thread_info* thr = ph->threads;
while (thr) {
if (count == index) {
thr->lwp_id = lwpid;
return true;
}
count++;
thr = thr->next;
}
return false;
}
// get regs of n-th thread, only used in fillThreads the first time called
bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) {
int count = 0;
sa_thread_info* thr = ph->threads;
while (thr) {
if (count == index) {
break;
}
count++;
thr = thr->next;
}
if (thr != NULL) {
memcpy(regs, &thr->regs, sizeof(struct reg));
return true;
}
return false;
}
#endif // __APPLE__
// get regs for a given lwp // get regs for a given lwp
bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) {
return ph->ops->get_lwp_regs(ph, lwp_id, regs); return ph->ops->get_lwp_regs(ph, lwp_id, regs);
...@@ -341,35 +439,35 @@ bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { ...@@ -341,35 +439,35 @@ bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) {
// get number of shared objects // get number of shared objects
int get_num_libs(struct ps_prochandle* ph) { int get_num_libs(struct ps_prochandle* ph) {
return ph->num_libs; return ph->num_libs;
} }
// get name of n'th solib // get name of n'th solib
const char* get_lib_name(struct ps_prochandle* ph, int index) { const char* get_lib_name(struct ps_prochandle* ph, int index) {
int count = 0; int count = 0;
lib_info* lib = ph->libs; lib_info* lib = ph->libs;
while (lib) { while (lib) {
if (count == index) { if (count == index) {
return lib->name; return lib->name;
} }
count++; count++;
lib = lib->next; lib = lib->next;
} }
return NULL; return NULL;
} }
// get base address of a lib // get base address of a lib
uintptr_t get_lib_base(struct ps_prochandle* ph, int index) { uintptr_t get_lib_base(struct ps_prochandle* ph, int index) {
int count = 0; int count = 0;
lib_info* lib = ph->libs; lib_info* lib = ph->libs;
while (lib) { while (lib) {
if (count == index) { if (count == index) {
return lib->base; return lib->base;
} }
count++; count++;
lib = lib->next; lib = lib->next;
} }
return (uintptr_t)NULL; return (uintptr_t)NULL;
} }
bool find_lib(struct ps_prochandle* ph, const char *lib_name) { bool find_lib(struct ps_prochandle* ph, const char *lib_name) {
...@@ -425,6 +523,7 @@ ps_plog (const char *format, ...) ...@@ -425,6 +523,7 @@ ps_plog (const char *format, ...)
va_end(alist); va_end(alist);
} }
#ifndef __APPLE__
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Functions below this point are not yet implemented. They are here only // Functions below this point are not yet implemented. They are here only
// to make the linker happy. // to make the linker happy.
...@@ -458,3 +557,4 @@ ps_err_e ps_pcontinue(struct ps_prochandle *ph) { ...@@ -458,3 +557,4 @@ ps_err_e ps_pcontinue(struct ps_prochandle *ph) {
print_debug("ps_pcontinue not implemented\n"); print_debug("ps_pcontinue not implemented\n");
return PS_OK; return PS_OK;
} }
#endif // __APPLE__
...@@ -30,6 +30,60 @@ ...@@ -30,6 +30,60 @@
#include "libproc.h" #include "libproc.h"
#include "symtab.h" #include "symtab.h"
#ifdef __APPLE__
#include <inttypes.h> // for PRIx64, 32, ...
#include <pthread.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/fat.h>
#ifndef register_t
#define register_t uint64_t
#endif
/*** registers copied from bsd/amd64 */
typedef struct reg {
register_t r_r15;
register_t r_r14;
register_t r_r13;
register_t r_r12;
register_t r_r11;
register_t r_r10;
register_t r_r9;
register_t r_r8;
register_t r_rdi;
register_t r_rsi;
register_t r_rbp;
register_t r_rbx;
register_t r_rdx;
register_t r_rcx;
register_t r_rax;
uint32_t r_trapno; // not used
uint16_t r_fs;
uint16_t r_gs;
uint32_t r_err; // not used
uint16_t r_es; // not used
uint16_t r_ds; // not used
register_t r_rip;
register_t r_cs;
register_t r_rflags;
register_t r_rsp;
register_t r_ss; // not used
} reg;
// convenient defs
typedef struct mach_header_64 mach_header_64;
typedef struct load_command load_command;
typedef struct segment_command_64 segment_command_64;
typedef struct thread_command thread_command;
typedef struct dylib_command dylib_command;
typedef struct symtab_command symtab_command;
typedef struct nlist_64 nlist_64;
#else
#include <thread_db.h>
#include "salibelf.h"
#endif // __APPLE__
// data structures in this file mimic those of Solaris 8.0 - libproc's Pcontrol.h // data structures in this file mimic those of Solaris 8.0 - libproc's Pcontrol.h
#define BUF_SIZE (PATH_MAX + NAME_MAX + 1) #define BUF_SIZE (PATH_MAX + NAME_MAX + 1)
...@@ -44,12 +98,12 @@ typedef struct lib_info { ...@@ -44,12 +98,12 @@ typedef struct lib_info {
} lib_info; } lib_info;
// list of threads // list of threads
typedef struct thread_info { typedef struct sa_thread_info {
lwpid_t lwp_id; lwpid_t lwp_id; // same as pthread_t
pthread_t pthread_id; // not used cores, always -1 pthread_t pthread_id; //
struct reg regs; // not for process, core uses for caching regset struct reg regs; // not for process, core uses for caching regset
struct thread_info* next; struct sa_thread_info* next;
} thread_info; } sa_thread_info;
// list of virtual memory maps // list of virtual memory maps
typedef struct map_info { typedef struct map_info {
...@@ -91,6 +145,7 @@ struct core_data { ...@@ -91,6 +145,7 @@ struct core_data {
// part of the class sharing workaround // part of the class sharing workaround
map_info* class_share_maps;// class share maps in a linked list map_info* class_share_maps;// class share maps in a linked list
map_info** map_array; // sorted (by vaddr) array of map_info pointers map_info** map_array; // sorted (by vaddr) array of map_info pointers
char exec_path[4096]; // file name java
}; };
struct ps_prochandle { struct ps_prochandle {
...@@ -100,12 +155,11 @@ struct ps_prochandle { ...@@ -100,12 +155,11 @@ struct ps_prochandle {
lib_info* libs; // head of lib list lib_info* libs; // head of lib list
lib_info* lib_tail; // tail of lib list - to append at the end lib_info* lib_tail; // tail of lib list - to append at the end
int num_threads; int num_threads;
thread_info* threads; // head of thread list sa_thread_info* threads; // head of thread list
struct core_data* core; // data only used for core dumps, NULL for process struct core_data* core; // data only used for core dumps, NULL for process
}; };
int pathmap_open(const char* name); int pathmap_open(const char* name);
void print_debug(const char* format,...); void print_debug(const char* format,...);
void print_error(const char* format,...); void print_error(const char* format,...);
bool is_debug(); bool is_debug();
...@@ -122,10 +176,45 @@ lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t ...@@ -122,10 +176,45 @@ lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
uintptr_t base); uintptr_t base);
// adds a new thread to threads list, returns NULL on failure sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id);
thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id);
// a test for ELF signature without using libelf // a test for ELF signature without using libelf
#ifdef __APPLE__
// a test for Mach-O signature
bool is_macho_file(int fd);
// skip fat head to get image start offset of cpu_type_t
// return false if any error happens, else value in offset.
bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset);
#else
bool is_elf_file(int fd); bool is_elf_file(int fd);
#endif // __APPLE__
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index);
bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid);
bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs);
// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table
// of the load object object_name in the target process identified by ph.
// It returns the symbol's value as an address in the target process in
// *sym_addr.
ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
const char *sym_name, psaddr_t *sym_addr);
// read "size" bytes info "buf" from address "addr"
ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr,
void *buf, size_t size);
// write "size" bytes of data to debuggee at address "addr"
ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr,
const void *buf, size_t size);
// fill in ptrace_lwpinfo for lid
ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo);
// needed for when libthread_db is compiled with TD_DEBUG defined
void ps_plog (const char *format, ...);
// untility, tells the position in file
off_t ltell(int fd);
#endif //_LIBPROC_IMPL_H_ #endif //_LIBPROC_IMPL_H_
此差异已折叠。
/* /*
* Copyright (c) 2003, 2010, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -28,32 +28,182 @@ ...@@ -28,32 +28,182 @@
#include <string.h> #include <string.h>
#include <db.h> #include <db.h>
#include <fcntl.h> #include <fcntl.h>
#include "libproc_impl.h"
#include "symtab.h" #include "symtab.h"
#ifndef __APPLE__
#include "salibelf.h" #include "salibelf.h"
#endif // __APPLE__
// ---------------------------------------------------- // ----------------------------------------------------
// functions for symbol lookups // functions for symbol lookups
// ---------------------------------------------------- // ----------------------------------------------------
struct elf_section { typedef struct symtab_symbol {
ELF_SHDR *c_shdr; char *name; // name like __ZThread_...
void *c_data; uintptr_t offset; // to loaded address
}; uintptr_t size; // size strlen
} symtab_symbol;
struct elf_symbol {
char *name;
uintptr_t offset;
uintptr_t size;
};
typedef struct symtab { typedef struct symtab {
char *strs; char *strs; // all symbols "__symbol1__'\0'__symbol2__...."
size_t num_symbols; size_t num_symbols;
struct elf_symbol *symbols;
DB* hash_table; DB* hash_table;
symtab_symbol* symbols;
} symtab_t; } symtab_t;
#ifdef __APPLE__
void build_search_table(symtab_t *symtab) {
int i;
for (i = 0; i < symtab->num_symbols; i++) {
DBT key, value;
key.data = symtab->symbols[i].name;
key.size = strlen(key.data) + 1;
value.data = &(symtab->symbols[i]);
value.size = sizeof(symtab_symbol);
(*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
// check result
if (is_debug()) {
DBT rkey, rvalue;
char* tmp = (char *)malloc(strlen(symtab->symbols[i].name) + 1);
strcpy(tmp, symtab->symbols[i].name);
rkey.data = tmp;
rkey.size = strlen(tmp) + 1;
(*symtab->hash_table->get)(symtab->hash_table, &rkey, &rvalue, 0);
// we may get a copy back so compare contents
symtab_symbol *res = (symtab_symbol *)rvalue.data;
if (strcmp(res->name, symtab->symbols[i].name) ||
res->offset != symtab->symbols[i].offset ||
res->size != symtab->symbols[i].size) {
print_debug("error to get hash_table value!\n");
}
free(tmp);
}
}
}
// read symbol table from given fd.
struct symtab* build_symtab(int fd) {
symtab_t* symtab = NULL;
int i;
mach_header_64 header;
off_t image_start;
if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) {
print_debug("failed in get fat header\n");
return NULL;
}
lseek(fd, image_start, SEEK_SET);
if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
print_debug("reading header failed!\n");
return NULL;
}
// header
if (header.magic != MH_MAGIC_64) {
print_debug("not a valid .dylib file\n");
return NULL;
}
load_command lcmd;
symtab_command symtabcmd;
nlist_64 lentry;
bool lcsymtab_exist = false;
long filepos = ltell(fd);
for (i = 0; i < header.ncmds; i++) {
lseek(fd, filepos, SEEK_SET);
if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
print_debug("read load_command failed for file\n");
return NULL;
}
filepos += lcmd.cmdsize; // next command position
if (lcmd.cmd == LC_SYMTAB) {
lseek(fd, -sizeof(load_command), SEEK_CUR);
lcsymtab_exist = true;
break;
}
}
if (!lcsymtab_exist) {
print_debug("No symtab command found!\n");
return NULL;
}
if (read(fd, (void *)&symtabcmd, sizeof(symtab_command)) != sizeof(symtab_command)) {
print_debug("read symtab_command failed for file");
return NULL;
}
symtab = (symtab_t *)malloc(sizeof(symtab_t));
if (symtab == NULL) {
print_debug("out of memory: allocating symtab\n");
return NULL;
}
// create hash table, we use berkeley db to
// manipulate the hash table.
symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);
if (symtab->hash_table == NULL)
goto quit;
symtab->num_symbols = symtabcmd.nsyms;
symtab->symbols = (symtab_symbol *)malloc(sizeof(symtab_symbol) * symtab->num_symbols);
symtab->strs = (char *)malloc(sizeof(char) * symtabcmd.strsize);
if (symtab->symbols == NULL || symtab->strs == NULL) {
print_debug("out of memory: allocating symtab.symbol or symtab.strs\n");
goto quit;
}
lseek(fd, image_start + symtabcmd.symoff, SEEK_SET);
for (i = 0; i < symtab->num_symbols; i++) {
if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) {
print_debug("read nlist_64 failed at %i\n", i);
goto quit;
}
symtab->symbols[i].offset = lentry.n_value;
symtab->symbols[i].size = lentry.n_un.n_strx; // index
}
// string table
lseek(fd, image_start + symtabcmd.stroff, SEEK_SET);
int size = read(fd, (void *)(symtab->strs), symtabcmd.strsize * sizeof(char));
if (size != symtabcmd.strsize * sizeof(char)) {
print_debug("reading string table failed\n");
goto quit;
}
for (i = 0; i < symtab->num_symbols; i++) {
symtab->symbols[i].name = symtab->strs + symtab->symbols[i].size;
if (i > 0) {
// fix size
symtab->symbols[i - 1].size = symtab->symbols[i].size - symtab->symbols[i - 1].size;
print_debug("%s size = %d\n", symtab->symbols[i - 1].name, symtab->symbols[i - 1].size);
}
if (i == symtab->num_symbols - 1) {
// last index
symtab->symbols[i].size =
symtabcmd.strsize - symtab->symbols[i].size;
print_debug("%s size = %d\n", symtab->symbols[i].name, symtab->symbols[i].size);
}
}
// build a hashtable for fast query
build_search_table(symtab);
return symtab;
quit:
if (symtab) destroy_symtab(symtab);
return NULL;
}
#else // __APPLE__
struct elf_section {
ELF_SHDR *c_shdr;
void *c_data;
};
// read symbol table from given fd. // read symbol table from given fd.
struct symtab* build_symtab(int fd) { struct symtab* build_symtab(int fd) {
ELF_EHDR ehdr; ELF_EHDR ehdr;
...@@ -176,7 +326,7 @@ struct symtab* build_symtab(int fd) { ...@@ -176,7 +326,7 @@ struct symtab* build_symtab(int fd) {
key.data = sym_name; key.data = sym_name;
key.size = strlen(sym_name) + 1; key.size = strlen(sym_name) + 1;
value.data = &(symtab->symbols[j]); value.data = &(symtab->symbols[j]);
value.size = sizeof(void *); value.size = sizeof(symtab_symbol);
(*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0); (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
} }
} }
...@@ -201,30 +351,29 @@ quit: ...@@ -201,30 +351,29 @@ quit:
return symtab; return symtab;
} }
void destroy_symtab(struct symtab* symtab) { #endif // __APPLE__
void destroy_symtab(symtab_t* symtab) {
if (!symtab) return; if (!symtab) return;
if (symtab->strs) free(symtab->strs); free(symtab->strs);
if (symtab->symbols) free(symtab->symbols); free(symtab->symbols);
if (symtab->hash_table) {
(*symtab->hash_table->close)(symtab->hash_table);
}
free(symtab); free(symtab);
} }
uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, const char *sym_name, int *sym_size) {
const char *sym_name, int *sym_size) {
DBT key, value; DBT key, value;
int ret; int ret;
// library does not have symbol table // library does not have symbol table
if (!symtab || !symtab->hash_table) if (!symtab || !symtab->hash_table) {
return 0; return 0;
}
key.data = (char*)(uintptr_t)sym_name; key.data = (char*)(uintptr_t)sym_name;
key.size = strlen(sym_name) + 1; key.size = strlen(sym_name) + 1;
ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0); ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0);
if (ret == 0) { if (ret == 0) {
struct elf_symbol *sym = value.data; symtab_symbol *sym = value.data;
uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset); uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
if (sym_size) *sym_size = sym->size; if (sym_size) *sym_size = sym->size;
return rslt; return rslt;
...@@ -238,7 +387,7 @@ const char* nearest_symbol(struct symtab* symtab, uintptr_t offset, ...@@ -238,7 +387,7 @@ const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
int n = 0; int n = 0;
if (!symtab) return NULL; if (!symtab) return NULL;
for (; n < symtab->num_symbols; n++) { for (; n < symtab->num_symbols; n++) {
struct elf_symbol* sym = &(symtab->symbols[n]); symtab_symbol* sym = &(symtab->symbols[n]);
if (sym->name != NULL && if (sym->name != NULL &&
offset >= sym->offset && offset < sym->offset + sym->size) { offset >= sym->offset && offset < sym->offset + sym->size) {
if (poffset) *poffset = (offset - sym->offset); if (poffset) *poffset = (offset - sym->offset);
......
/* /*
* Copyright (c) 2003, 2010, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,11 +27,11 @@ ...@@ -27,11 +27,11 @@
#include <stdint.h> #include <stdint.h>
// interface to manage ELF symbol tables // interface to manage ELF or MachO symbol tables
struct symtab; struct symtab;
// build symbol table for a given ELF file descriptor // build symbol table for a given ELF or MachO file escriptor
struct symtab* build_symtab(int fd); struct symtab* build_symtab(int fd);
// destroy the symbol table // destroy the symbol table
......
/* /*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -34,11 +34,18 @@ public class BsdVtblAccess extends BasicVtblAccess { ...@@ -34,11 +34,18 @@ public class BsdVtblAccess extends BasicVtblAccess {
public BsdVtblAccess(SymbolLookup symbolLookup, public BsdVtblAccess(SymbolLookup symbolLookup,
String[] dllNames) { String[] dllNames) {
super(symbolLookup, dllNames); super(symbolLookup, dllNames);
boolean oldVT = false;
if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null || boolean isDarwin = dllNames[0].lastIndexOf(".dylib") != -1;
symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) { String vtJavaThread = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread";
for (String dllName : dllNames) {
if (symbolLookup.lookup(dllName, vtJavaThread) != null) {
oldVT = true;
break;
}
}
if (oldVT) {
// old C++ ABI // old C++ ABI
vt = "__vt_"; vt = isDarwin ? "_vt_" : "__vt_";
} else { } else {
// new C++ ABI // new C++ ABI
vt = "_ZTV"; vt = "_ZTV";
......
...@@ -1517,7 +1517,7 @@ public class CommandProcessor { ...@@ -1517,7 +1517,7 @@ public class CommandProcessor {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos)); thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) { if (all || bos.toString().equals(name)) {
out.println(bos.toString() + " = " + thread.getAddress()); out.println("Thread " + bos.toString() + " Address: " + thread.getAddress());
HTMLGenerator gen = new HTMLGenerator(false); HTMLGenerator gen = new HTMLGenerator(false);
try { try {
out.println(gen.genHTMLForJavaStackTrace(thread)); out.println(gen.genHTMLForJavaStackTrace(thread));
...@@ -1546,7 +1546,7 @@ public class CommandProcessor { ...@@ -1546,7 +1546,7 @@ public class CommandProcessor {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos)); thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) { if (all || bos.toString().equals(name)) {
out.println(bos.toString() + " = " + thread.getAddress()); out.println("Thread " + bos.toString() + " Address " + thread.getAddress());
if (!all) return; if (!all) return;
} }
} }
......
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -311,6 +311,8 @@ public class HotSpotAgent { ...@@ -311,6 +311,8 @@ public class HotSpotAgent {
setupDebuggerLinux(); setupDebuggerLinux();
} else if (os.equals("bsd")) { } else if (os.equals("bsd")) {
setupDebuggerBsd(); setupDebuggerBsd();
} else if (os.equals("darwin")) {
setupDebuggerDarwin();
} else { } else {
// Add support for more operating systems here // Add support for more operating systems here
throw new DebuggerException("Operating system " + os + " not yet supported"); throw new DebuggerException("Operating system " + os + " not yet supported");
...@@ -370,6 +372,10 @@ public class HotSpotAgent { ...@@ -370,6 +372,10 @@ public class HotSpotAgent {
db = new HotSpotTypeDataBase(machDesc, db = new HotSpotTypeDataBase(machDesc,
new BsdVtblAccess(debugger, jvmLibNames), new BsdVtblAccess(debugger, jvmLibNames),
debugger, jvmLibNames); debugger, jvmLibNames);
} else if (os.equals("darwin")) {
db = new HotSpotTypeDataBase(machDesc,
new BsdVtblAccess(debugger, jvmLibNames),
debugger, jvmLibNames);
} else { } else {
throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)"); throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)");
} }
...@@ -459,6 +465,8 @@ public class HotSpotAgent { ...@@ -459,6 +465,8 @@ public class HotSpotAgent {
setupJVMLibNamesLinux(); setupJVMLibNamesLinux();
} else if (os.equals("bsd")) { } else if (os.equals("bsd")) {
setupJVMLibNamesBsd(); setupJVMLibNamesBsd();
} else if (os.equals("darwin")) {
setupJVMLibNamesDarwin();
} else { } else {
throw new RuntimeException("Unknown OS type"); throw new RuntimeException("Unknown OS type");
} }
...@@ -567,6 +575,29 @@ public class HotSpotAgent { ...@@ -567,6 +575,29 @@ public class HotSpotAgent {
jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
} }
//
// Darwin
//
private void setupDebuggerDarwin() {
setupJVMLibNamesDarwin();
if (cpu.equals("amd64") || cpu.equals("x86_64")) {
machDesc = new MachineDescriptionAMD64();
} else {
throw new DebuggerException("Darwin only supported on x86_64. Current arch: " + cpu);
}
BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer);
debugger = dbg;
attachDebugger();
}
private void setupJVMLibNamesDarwin() {
jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" };
}
/** Convenience routine which should be called by per-platform /** Convenience routine which should be called by per-platform
debugger setup. Should not be called when startupMode is debugger setup. Should not be called when startupMode is
REMOTE_MODE. */ REMOTE_MODE. */
......
/* /*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -31,6 +31,9 @@ import sun.jvm.hotspot.debugger.*; ...@@ -31,6 +31,9 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.x86.*; import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.utilities.*; import sun.jvm.hotspot.utilities.*;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.runtime.Threads;
import sun.jvm.hotspot.runtime.JavaThread;
import java.lang.reflect.*; import java.lang.reflect.*;
/** <P> An implementation of the JVMDebugger interface. The basic debug /** <P> An implementation of the JVMDebugger interface. The basic debug
...@@ -51,10 +54,11 @@ import java.lang.reflect.*; ...@@ -51,10 +54,11 @@ import java.lang.reflect.*;
public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
private boolean useGCC32ABI; private boolean useGCC32ABI;
private boolean attached; private boolean attached;
private long p_ps_prochandle; // native debugger handle private long p_ps_prochandle; // native debugger handle
private long symbolicator; // macosx symbolicator handle private long symbolicator; // macosx symbolicator handle
private long task; // macosx task handle private long task; // macosx task handle
private boolean isCore; private boolean isCore;
private boolean isDarwin; // variant for bsd
// CDebugger support // CDebugger support
private BsdCDebugger cdbg; private BsdCDebugger cdbg;
...@@ -208,6 +212,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { ...@@ -208,6 +212,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
} }
} }
isDarwin = getOS().equals("darwin");
workerThread = new BsdDebuggerLocalWorkerThread(this); workerThread = new BsdDebuggerLocalWorkerThread(this);
workerThread.start(); workerThread.start();
} }
...@@ -240,8 +245,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { ...@@ -240,8 +245,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
/* called from attach methods */ /* called from attach methods */
private void findABIVersion() throws DebuggerException { private void findABIVersion() throws DebuggerException {
if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 || String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so";
lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) { String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so";
String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread";
if (lookupByName0(libjvmName, javaThreadVt) != 0 ||
lookupByName0(libjvm_gName, javaThreadVt) != 0) {
// old C++ ABI // old C++ ABI
useGCC32ABI = false; useGCC32ABI = false;
} else { } else {
...@@ -360,7 +368,8 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { ...@@ -360,7 +368,8 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
} }
if (isCore) { if (isCore) {
long addr = lookupByName0(objectName, symbol); // MacOSX symbol with "_" as leading
long addr = lookupByName0(objectName, isDarwin ? "_" + symbol : symbol);
return (addr == 0)? null : new BsdAddress(this, handleGCC32ABI(addr, symbol)); return (addr == 0)? null : new BsdAddress(this, handleGCC32ABI(addr, symbol));
} else { } else {
class LookupByNameTask implements WorkerThreadTask { class LookupByNameTask implements WorkerThreadTask {
...@@ -403,12 +412,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { ...@@ -403,12 +412,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) { public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) {
return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr); return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr);
} }
@Override @Override
public ThreadProxy getThreadForIdentifierAddress(Address addr) { public ThreadProxy getThreadForIdentifierAddress(Address addr) {
throw new RuntimeException("unimplemented"); throw new RuntimeException("unimplemented");
} }
/** From the ThreadAccess interface via Debugger and JVMDebugger */ /** From the ThreadAccess interface via Debugger and JVMDebugger */
public ThreadProxy getThreadForThreadId(long id) { public ThreadProxy getThreadForThreadId(long id) {
return new BsdThread(this, id); return new BsdThread(this, id);
...@@ -601,6 +610,33 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { ...@@ -601,6 +610,33 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
throw new DebuggerException("Unimplemented"); throw new DebuggerException("Unimplemented");
} }
/** this functions used for core file reading and called from native attach0,
it returns an array of long integers as
[thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for
all java threads recorded in Threads. Also adds the ThreadProxy to threadList */
public long[] getJavaThreadsInfo() {
requireAttach();
Threads threads = VM.getVM().getThreads();
int len = threads.getNumberOfThreads();
long[] result = new long[len * 3]; // triple
JavaThread t = threads.first();
long beg, end;
int i = 0;
while (t != null) {
end = t.getStackBaseValue();
beg = end - t.getStackSize();
BsdThread bsdt = (BsdThread)t.getThreadProxy();
long uid = bsdt.getUniqueThreadId();
if (threadList != null) threadList.add(bsdt);
result[i] = uid;
result[i + 1] = beg;
result[i + 2] = end;
t = t.next();
i += 3;
}
return result;
}
static { static {
System.loadLibrary("saproc"); System.loadLibrary("saproc");
init0(); init0();
......
/* /*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -44,7 +44,8 @@ class BsdThread implements ThreadProxy { ...@@ -44,7 +44,8 @@ class BsdThread implements ThreadProxy {
BsdThread(BsdDebugger debugger, long id) { BsdThread(BsdDebugger debugger, long id) {
this.debugger = debugger; this.debugger = debugger;
this.thread_id = (int) id; // use unique_thread_id to identify thread
this.unique_thread_id = id;
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
...@@ -52,7 +53,7 @@ class BsdThread implements ThreadProxy { ...@@ -52,7 +53,7 @@ class BsdThread implements ThreadProxy {
return false; return false;
} }
return (((BsdThread) obj).thread_id == thread_id); return (((BsdThread) obj).unique_thread_id == unique_thread_id);
} }
public int hashCode() { public int hashCode() {
...@@ -80,4 +81,9 @@ class BsdThread implements ThreadProxy { ...@@ -80,4 +81,9 @@ class BsdThread implements ThreadProxy {
throws IllegalThreadStateException, DebuggerException { throws IllegalThreadStateException, DebuggerException {
throw new DebuggerException("Unimplemented"); throw new DebuggerException("Unimplemented");
} }
/** this is not interface function, used in core file to get unique thread id on Macosx*/
public long getUniqueThreadId() {
return unique_thread_id;
}
} }
/* /*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -320,6 +320,10 @@ public class JavaThread extends Thread { ...@@ -320,6 +320,10 @@ public class JavaThread extends Thread {
return stackBaseField.getValue(addr); return stackBaseField.getValue(addr);
} }
public long getStackBaseValue() {
return VM.getVM().getAddressValue(getStackBase());
}
public long getStackSize() { public long getStackSize() {
return stackSizeField.getValue(addr); return stackSizeField.getValue(addr);
} }
......
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -42,6 +42,7 @@ import sun.jvm.hotspot.utilities.*; ...@@ -42,6 +42,7 @@ import sun.jvm.hotspot.utilities.*;
public class Threads { public class Threads {
private static JavaThreadFactory threadFactory; private static JavaThreadFactory threadFactory;
private static AddressField threadListField; private static AddressField threadListField;
private static CIntegerField numOfThreadsField;
private static VirtualConstructor virtualConstructor; private static VirtualConstructor virtualConstructor;
private static JavaThreadPDAccess access; private static JavaThreadPDAccess access;
...@@ -57,6 +58,7 @@ public class Threads { ...@@ -57,6 +58,7 @@ public class Threads {
Type type = db.lookupType("Threads"); Type type = db.lookupType("Threads");
threadListField = type.getAddressField("_thread_list"); threadListField = type.getAddressField("_thread_list");
numOfThreadsField = type.getCIntegerField("_number_of_threads");
// Instantiate appropriate platform-specific JavaThreadFactory // Instantiate appropriate platform-specific JavaThreadFactory
String os = VM.getVM().getOS(); String os = VM.getVM().getOS();
...@@ -102,6 +104,10 @@ public class Threads { ...@@ -102,6 +104,10 @@ public class Threads {
} else if (cpu.equals("amd64") || cpu.equals("x86_64")) { } else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
access = new BsdAMD64JavaThreadPDAccess(); access = new BsdAMD64JavaThreadPDAccess();
} }
} else if (os.equals("darwin")) {
if (cpu.equals("amd64") || cpu.equals("x86_64")) {
access = new BsdAMD64JavaThreadPDAccess();
}
} }
if (access == null) { if (access == null) {
...@@ -144,6 +150,10 @@ public class Threads { ...@@ -144,6 +150,10 @@ public class Threads {
return createJavaThreadWrapper(threadAddr); return createJavaThreadWrapper(threadAddr);
} }
public int getNumberOfThreads() {
return (int) numOfThreadsField.getValue();
}
/** Routine for instantiating appropriately-typed wrapper for a /** Routine for instantiating appropriately-typed wrapper for a
JavaThread. Currently needs to be public for OopUtilities to JavaThread. Currently needs to be public for OopUtilities to
access it. */ access it. */
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -32,6 +32,7 @@ import sun.jvm.hotspot.debugger.*; ...@@ -32,6 +32,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.utilities.PlatformInfo;
public class PStack extends Tool { public class PStack extends Tool {
// in non-verbose mode, Method*s are not printed in java frames // in non-verbose mode, Method*s are not printed in java frames
...@@ -54,6 +55,11 @@ public class PStack extends Tool { ...@@ -54,6 +55,11 @@ public class PStack extends Tool {
} }
public void run(PrintStream out, Debugger dbg) { public void run(PrintStream out, Debugger dbg) {
if (PlatformInfo.getOS().equals("darwin")) {
out.println("Not available on Darwin");
return;
}
CDebugger cdbg = dbg.getCDebugger(); CDebugger cdbg = dbg.getCDebugger();
if (cdbg != null) { if (cdbg != null) {
ConcurrentLocksPrinter concLocksPrinter = null; ConcurrentLocksPrinter concLocksPrinter = null;
......
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -43,8 +43,8 @@ public class PlatformInfo { ...@@ -43,8 +43,8 @@ public class PlatformInfo {
return "bsd"; return "bsd";
} else if (os.equals("OpenBSD")) { } else if (os.equals("OpenBSD")) {
return "bsd"; return "bsd";
} else if (os.equals("Darwin") || os.contains("OS X")) { } else if (os.contains("Darwin") || os.contains("OS X")) {
return "bsd"; return "darwin";
} else if (os.startsWith("Windows")) { } else if (os.startsWith("Windows")) {
return "win32"; return "win32";
} else { } else {
......
/* /*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -48,7 +48,10 @@ ...@@ -48,7 +48,10 @@
#include <string.h> #include <string.h>
#include <dlfcn.h> #include <dlfcn.h>
#ifndef __APPLE__
#include <link.h> #include <link.h>
#endif
#endif #endif
...@@ -109,9 +112,7 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIE ...@@ -109,9 +112,7 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIE
jstring libname_s) { jstring libname_s) {
uintptr_t func = 0; uintptr_t func = 0;
const char* error_message = NULL; const char* error_message = NULL;
const char* java_home;
jboolean isCopy; jboolean isCopy;
uintptr_t *handle = NULL;
const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/ const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/
const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy);
...@@ -167,7 +168,8 @@ typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va, ...@@ -167,7 +168,8 @@ typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va,
void* event_stream, void* event_stream,
int (*printf_callback)(void*, const char*, ...), int (*printf_callback)(void*, const char*, ...),
void* printf_stream, void* printf_stream,
const char* options); const char* options,
int newline);
/* container for call back state when decoding instructions */ /* container for call back state when decoding instructions */
typedef struct { typedef struct {
...@@ -281,7 +283,7 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env ...@@ -281,7 +283,7 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env
end - start, end - start,
&event_to_env, (void*) &denv, &event_to_env, (void*) &denv,
&printf_to_env, (void*) &denv, &printf_to_env, (void*) &denv,
options); options, 0 /* newline */);
/* cleanup */ /* cleanup */
(*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
......
# #
# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
# Rules to build serviceability agent library, used by vm.make # Rules to build serviceability agent library, used by vm.make
# libsaproc.so: serviceability agent # libsaproc.so(dylib): serviceability agent
SAPROC = saproc SAPROC = saproc
ifeq ($(OS_VENDOR), Darwin) ifeq ($(OS_VENDOR), Darwin)
...@@ -37,7 +37,7 @@ AGENT_DIR = $(GAMMADIR)/agent ...@@ -37,7 +37,7 @@ AGENT_DIR = $(GAMMADIR)/agent
SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family) SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family)
NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ BSD_NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \
$(SASRCDIR)/symtab.c \ $(SASRCDIR)/symtab.c \
$(SASRCDIR)/libproc_impl.c \ $(SASRCDIR)/libproc_impl.c \
$(SASRCDIR)/ps_proc.c \ $(SASRCDIR)/ps_proc.c \
...@@ -45,13 +45,19 @@ NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ ...@@ -45,13 +45,19 @@ NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \
$(SASRCDIR)/BsdDebuggerLocal.c \ $(SASRCDIR)/BsdDebuggerLocal.c \
$(AGENT_DIR)/src/share/native/sadis.c $(AGENT_DIR)/src/share/native/sadis.c
DARWIN_NON_STUB_SASRCFILES = $(SASRCDIR)/symtab.c \
$(SASRCDIR)/libproc_impl.c \
$(SASRCDIR)/ps_core.c \
$(SASRCDIR)/MacosxDebuggerLocal.m \
$(AGENT_DIR)/src/share/native/sadis.c
ifeq ($(OS_VENDOR), FreeBSD) ifeq ($(OS_VENDOR), FreeBSD)
SASRCFILES = $(NON_STUB_SASRCFILES) SASRCFILES = $(BSD_NON_STUB_SASRCFILES)
SALIBS = -lutil -lthread_db SALIBS = -lutil -lthread_db
SAARCH = $(ARCHFLAG) SAARCH = $(ARCHFLAG)
else else
ifeq ($(OS_VENDOR), Darwin) ifeq ($(OS_VENDOR), Darwin)
SASRCFILES = $(SASRCDIR)/MacosxDebuggerLocal.m SASRCFILES = $(DARWIN_NON_STUB_SASRCFILES)
SALIBS = -g -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation SALIBS = -g -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation
#objc compiler blows up on -march=i586, perhaps it should not be included in the macosx intel 32-bit C++ compiles? #objc compiler blows up on -march=i586, perhaps it should not be included in the macosx intel 32-bit C++ compiles?
SAARCH = $(subst -march=i586,,$(ARCHFLAG)) SAARCH = $(subst -march=i586,,$(ARCHFLAG))
...@@ -102,7 +108,7 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) ...@@ -102,7 +108,7 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE)
fi fi
@echo Making SA debugger back-end... @echo Making SA debugger back-end...
$(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \
$(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \
-I$(SASRCDIR) \ -I$(SASRCDIR) \
-I$(GENERATED) \ -I$(GENERATED) \
$(BOOT_JAVA_INCLUDES) \ $(BOOT_JAVA_INCLUDES) \
......
...@@ -105,6 +105,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m ...@@ -105,6 +105,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m
void ClassLoaderData::classes_do(KlassClosure* klass_closure) { void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) { for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
klass_closure->do_klass(k); klass_closure->do_klass(k);
assert(k != k->next_link(), "no loops!");
} }
} }
...@@ -113,6 +114,7 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) { ...@@ -113,6 +114,7 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
if (k->oop_is_instance()) { if (k->oop_is_instance()) {
f(InstanceKlass::cast(k)); f(InstanceKlass::cast(k));
} }
assert(k != k->next_link(), "no loops!");
} }
} }
...@@ -258,6 +260,7 @@ void ClassLoaderData::remove_class(Klass* scratch_class) { ...@@ -258,6 +260,7 @@ void ClassLoaderData::remove_class(Klass* scratch_class) {
return; return;
} }
prev = k; prev = k;
assert(k != k->next_link(), "no loops!");
} }
ShouldNotReachHere(); // should have found this class!! ShouldNotReachHere(); // should have found this class!!
} }
...@@ -439,6 +442,7 @@ void ClassLoaderData::dump(outputStream * const out) { ...@@ -439,6 +442,7 @@ void ClassLoaderData::dump(outputStream * const out) {
while (k != NULL) { while (k != NULL) {
out->print_cr("klass "PTR_FORMAT", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(), out->print_cr("klass "PTR_FORMAT", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(),
k->has_modified_oops(), k->has_accumulated_modified_oops()); k->has_modified_oops(), k->has_accumulated_modified_oops());
assert(k != k->next_link(), "no loops!");
k = k->next_link(); k = k->next_link();
} }
} }
...@@ -465,6 +469,7 @@ void ClassLoaderData::verify() { ...@@ -465,6 +469,7 @@ void ClassLoaderData::verify() {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) { for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
guarantee(k->class_loader_data() == this, "Must be the same"); guarantee(k->class_loader_data() == this, "Must be the same");
k->verify(); k->verify();
assert(k != k->next_link(), "no loops!");
} }
} }
......
...@@ -804,6 +804,32 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla ...@@ -804,6 +804,32 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla
} }
} // load_instance_class loop } // load_instance_class loop
if (HAS_PENDING_EXCEPTION) {
// An exception, such as OOM could have happened at various places inside
// load_instance_class. We might have partially initialized a shared class
// and need to clean it up.
if (class_loader.is_null()) {
// In some cases k may be null. Let's find the shared class again.
instanceKlassHandle ik(THREAD, find_shared_class(name));
if (ik.not_null()) {
if (ik->class_loader_data() == NULL) {
// We didn't go as far as Klass::restore_unshareable_info(),
// so nothing to clean up.
} else {
MutexLocker mu(SystemDictionary_lock, THREAD);
Klass* kk = find_class(name, ik->class_loader_data());
if (kk != NULL) {
// No clean up is needed if the shared class has been entered
// into system dictionary, as load_shared_class() won't be called
// again.
} else {
clean_up_shared_class(ik, class_loader, THREAD);
}
}
}
}
}
if (load_instance_added == true) { if (load_instance_added == true) {
// clean up placeholder entries for LOAD_INSTANCE success or error // clean up placeholder entries for LOAD_INSTANCE success or error
// This brackets the SystemDictionary updates for both defining // This brackets the SystemDictionary updates for both defining
...@@ -1140,11 +1166,6 @@ instanceKlassHandle SystemDictionary::load_shared_class( ...@@ -1140,11 +1166,6 @@ instanceKlassHandle SystemDictionary::load_shared_class(
return load_shared_class(ik, class_loader, THREAD); return load_shared_class(ik, class_loader, THREAD);
} }
// Note well! Changes to this method may affect oop access order
// in the shared archive. Please take care to not make changes that
// adversely affect cold start time by changing the oop access order
// that is specified in dump.cpp MarkAndMoveOrderedReadOnly and
// MarkAndMoveOrderedReadWrite closures.
instanceKlassHandle SystemDictionary::load_shared_class( instanceKlassHandle SystemDictionary::load_shared_class(
instanceKlassHandle ik, Handle class_loader, TRAPS) { instanceKlassHandle ik, Handle class_loader, TRAPS) {
assert(class_loader.is_null(), "non-null classloader for shared class?"); assert(class_loader.is_null(), "non-null classloader for shared class?");
...@@ -1205,6 +1226,19 @@ instanceKlassHandle SystemDictionary::load_shared_class( ...@@ -1205,6 +1226,19 @@ instanceKlassHandle SystemDictionary::load_shared_class(
return ik; return ik;
} }
void SystemDictionary::clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS) {
// Updating methods must be done under a lock so multiple
// threads don't update these in parallel
// Shared classes are all currently loaded by the bootstrap
// classloader, so this will never cause a deadlock on
// a custom class loader lock.
{
Handle lockObject = compute_loader_lock_object(class_loader, THREAD);
check_loader_lock_contention(lockObject, THREAD);
ObjectLocker ol(lockObject, THREAD, true);
ik->remove_unshareable_info();
}
}
instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
instanceKlassHandle nh = instanceKlassHandle(); // null Handle instanceKlassHandle nh = instanceKlassHandle(); // null Handle
......
...@@ -621,6 +621,7 @@ private: ...@@ -621,6 +621,7 @@ private:
Handle class_loader, TRAPS); Handle class_loader, TRAPS);
static instanceKlassHandle load_shared_class(instanceKlassHandle ik, static instanceKlassHandle load_shared_class(instanceKlassHandle ik,
Handle class_loader, TRAPS); Handle class_loader, TRAPS);
static void clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS);
static instanceKlassHandle load_instance_class(Symbol* class_name, Handle class_loader, TRAPS); static instanceKlassHandle load_instance_class(Symbol* class_name, Handle class_loader, TRAPS);
static Handle compute_loader_lock_object(Handle class_loader, TRAPS); static Handle compute_loader_lock_object(Handle class_loader, TRAPS);
static void check_loader_lock_contention(Handle loader_lock, TRAPS); static void check_loader_lock_contention(Handle loader_lock, TRAPS);
......
...@@ -334,6 +334,9 @@ class VirtualSpaceNode : public CHeapObj<mtClass> { ...@@ -334,6 +334,9 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
// byte_size is the size of the associated virtualspace. // byte_size is the size of the associated virtualspace.
VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) { VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) {
// align up to vm allocation granularity
byte_size = align_size_up(byte_size, os::vm_allocation_granularity());
// This allocates memory with mmap. For DumpSharedspaces, allocate the // This allocates memory with mmap. For DumpSharedspaces, allocate the
// space at low memory so that other shared images don't conflict. // space at low memory so that other shared images don't conflict.
// This is the same address as memory needed for UseCompressedOops but // This is the same address as memory needed for UseCompressedOops but
......
...@@ -486,6 +486,12 @@ void Klass::oops_do(OopClosure* cl) { ...@@ -486,6 +486,12 @@ void Klass::oops_do(OopClosure* cl) {
} }
void Klass::remove_unshareable_info() { void Klass::remove_unshareable_info() {
if (!DumpSharedSpaces) {
// Clean up after OOM during class loading
if (class_loader_data() != NULL) {
class_loader_data()->remove_class(this);
}
}
set_subklass(NULL); set_subklass(NULL);
set_next_sibling(NULL); set_next_sibling(NULL);
// Clear the java mirror // Clear the java mirror
......
...@@ -798,7 +798,15 @@ void Method::unlink_method() { ...@@ -798,7 +798,15 @@ void Method::unlink_method() {
backedge_counter()->reset(); backedge_counter()->reset();
_adapter = NULL; _adapter = NULL;
_from_compiled_entry = NULL; _from_compiled_entry = NULL;
assert(_method_data == NULL, "unexpected method data?");
// In case of DumpSharedSpaces, _method_data should always be NULL.
//
// During runtime (!DumpSharedSpaces), when we are cleaning a
// shared class that failed to load, this->link_method() may
// have already been called (before an exception happened), so
// this->_method_data may not be NULL.
assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?");
set_method_data(NULL); set_method_data(NULL);
set_interpreter_throwout_count(0); set_interpreter_throwout_count(0);
set_interpreter_invocation_count(0); set_interpreter_invocation_count(0);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册