diff --git a/src/os/bsd/vm/decoder_machO.cpp b/src/os/bsd/vm/decoder_machO.cpp index d77a32f7eddd9d66faac29c056ef87ff64b41ec7..75250d19514d712f4d4acad38c7d07e9396df997 100644 --- a/src/os/bsd/vm/decoder_machO.cpp +++ b/src/os/bsd/vm/decoder_machO.cpp @@ -26,6 +26,139 @@ #ifdef __APPLE__ #include "decoder_machO.hpp" + +#include +#include +#include + + +bool MachODecoder::demangle(const char* symbol, char *buf, int buflen) { + int status; + char* result; + size_t size = (size_t)buflen; + // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small, + // __cxa_demangle will call system "realloc" for additional memory, which + // may use different malloc/realloc mechanism that allocates 'buf'. + if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) { + jio_snprintf(buf, buflen, "%s", result); + // call c library's free + ::free(result); + return true; + } + return false; +} + +bool MachODecoder::decode(address addr, char *buf, + int buflen, int *offset, const void *mach_base) { + struct symtab_command * symt = (struct symtab_command *) + mach_find_command((struct mach_header_64 *)mach_base, LC_SYMTAB); + if (symt == NULL) { + DEBUG_ONLY(tty->print_cr("no symtab in mach file at 0x%lx", mach_base)); + return false; + } + uint32_t off = symt->symoff; /* symbol table offset (within this mach file) */ + uint32_t nsyms = symt->nsyms; /* number of symbol table entries */ + uint32_t stroff = symt->stroff; /* string table offset */ + uint32_t strsize = symt->strsize; /* string table size in bytes */ + + // iterate through symbol table trying to match our offset + + uint32_t addr_relative = (uintptr_t) mach_base - (uintptr_t) addr; // offset we seek in the symtab + void * symtab_addr = (void*) ((uintptr_t) mach_base + off); + struct nlist_64 *cur_nlist = (struct nlist_64 *) symtab_addr; + struct nlist_64 *last_nlist = cur_nlist; // no size stored in an entry, so keep previously seen nlist + + int32_t found_strx = 0; + int32_t found_symval = 0; + + for (uint32_t i=0; i < nsyms; i++) { + uint32_t this_value = cur_nlist->n_value; + + if (addr_relative == this_value) { + found_strx = cur_nlist->n_un.n_strx; + found_symval = this_value; + break; + } else if (addr_relative > this_value) { + // gone past it, use previously seen nlist: + found_strx = last_nlist->n_un.n_strx; + found_symval = last_nlist->n_value; + break; + } + last_nlist = cur_nlist; + cur_nlist = cur_nlist + sizeof(struct nlist_64); + } + if (found_strx == 0) { + return false; + } + // write the offset: + *offset = addr_relative - found_symval; + + // lookup found_strx in the string table + char * symname = mach_find_in_stringtable((char*) ((uintptr_t)mach_base + stroff), strsize, found_strx); + if (symname) { + strncpy(buf, symname, buflen); + return true; + } + DEBUG_ONLY(tty->print_cr("no string or null string found.")); + return false; +} + +void* MachODecoder::mach_find_command(struct mach_header_64 * mach_base, uint32_t command_wanted) { + // possibly verify it is a mach_header, use magic number. + // commands begin immediately after the header. + struct load_command *pos = (struct load_command *) mach_base + sizeof(struct mach_header_64); + for (uint32_t i = 0; i < mach_base->ncmds; i++) { + struct load_command *this_cmd = (struct load_command *) pos; + if (this_cmd->cmd == command_wanted) { + return pos; + } + int cmdsize = this_cmd->cmdsize; + pos += cmdsize; + } + return NULL; +} + +char* MachODecoder::mach_find_in_stringtable(char *strtab, uint32_t tablesize, int strx_wanted) { + + if (strx_wanted == 0) { + return NULL; + } + char *strtab_end = strtab + tablesize; + + // find the first string, skip over the space char + // (or the four zero bytes we see e.g. in libclient) + if (*strtab == ' ') { + strtab++; + if (*strtab != 0) { + DEBUG_ONLY(tty->print_cr("string table has leading space but no following zero.")); + return NULL; + } + strtab++; + } else { + if ((uint32_t) *strtab != 0) { + DEBUG_ONLY(tty->print_cr("string table without leading space or leading int of zero.")); + return NULL; + } + strtab+=4; + } + // read the real strings starting at index 1 + int cur_strx = 1; + while (strtab < strtab_end) { + if (cur_strx == strx_wanted) { + return strtab; + } + // find start of next string + while (*strtab != 0) { + strtab++; + } + strtab++; // skip the terminating zero + cur_strx++; + } + DEBUG_ONLY(tty->print_cr("string number %d not found.", strx_wanted)); + return NULL; +} + + #endif diff --git a/src/os/bsd/vm/decoder_machO.hpp b/src/os/bsd/vm/decoder_machO.hpp index 9fb16899c4f9e5c9cc340cff2f180491de76b7c5..25dedc6aa0e45178a01b086f878f46c3aa51abf1 100644 --- a/src/os/bsd/vm/decoder_machO.hpp +++ b/src/os/bsd/vm/decoder_machO.hpp @@ -31,10 +31,25 @@ // Just a placehold for now, a real implementation should derive // from AbstractDecoder -class MachODecoder : public NullDecoder { -public: +class MachODecoder : public AbstractDecoder { + public: MachODecoder() { } ~MachODecoder() { } + virtual bool can_decode_C_frame_in_vm() const { + return true; + } + virtual bool demangle(const char* symbol, char* buf, int buflen); + virtual bool decode(address pc, char* buf, int buflen, int* offset, + const void* base); + virtual bool decode(address pc, char* buf, int buflen, int* offset, + const char* module_path = NULL) { + ShouldNotReachHere(); + return false; + } + + private: + void * mach_find_command(struct mach_header_64 * mach_base, uint32_t command_wanted); + char * mach_find_in_stringtable(char *strtab, uint32_t tablesize, int strx_wanted); }; #endif diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp index 68ab3fc4c3b2f78325f590a1722b30558e0bb5e3..a1c4121827026f07454a276095afe6550615588a 100644 --- a/src/os/bsd/vm/os_bsd.cpp +++ b/src/os/bsd/vm/os_bsd.cpp @@ -1946,10 +1946,16 @@ bool os::address_is_in_vm(address addr) { return false; } + +#define MACH_MAXSYMLEN 256 + bool os::dll_address_to_function_name(address addr, char *buf, int buflen, int *offset) { Dl_info dlinfo; + char localbuf[MACH_MAXSYMLEN]; + // dladdr will find names of dynamic functions only, but does + // it set dli_fbase with mach_header address when it "fails" ? if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) { if (buf != NULL) { if(!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) { @@ -1965,6 +1971,14 @@ bool os::dll_address_to_function_name(address addr, char *buf, } } + // Handle non-dymanic manually: + if (dlinfo.dli_fbase != NULL && + Decoder::decode(addr, localbuf, MACH_MAXSYMLEN, offset, dlinfo.dli_fbase)) { + if(!Decoder::demangle(localbuf, buf, buflen)) { + jio_snprintf(buf, buflen, "%s", localbuf); + } + return true; + } if (buf != NULL) buf[0] = '\0'; if (offset != NULL) *offset = -1; return false; diff --git a/src/os/windows/vm/decoder_windows.cpp b/src/os/windows/vm/decoder_windows.cpp index 847e2310840c20e3ba3fd07efe6238bfc90cefe2..6500e59302f72c28745e9e69dc27e466c8e2bdc8 100644 --- a/src/os/windows/vm/decoder_windows.cpp +++ b/src/os/windows/vm/decoder_windows.cpp @@ -72,10 +72,10 @@ void WindowsDecoder::initialize() { // find out if jvm.dll contains private symbols, by decoding // current function and comparing the result - address addr = (address)Decoder::decode; + address addr = (address)Decoder::demangle; char buf[MAX_PATH]; if (decode(addr, buf, sizeof(buf), NULL)) { - _can_decode_in_vm = !strcmp(buf, "Decoder::decode"); + _can_decode_in_vm = !strcmp(buf, "Decoder::demangle"); } } } diff --git a/src/os/windows/vm/decoder_windows.hpp b/src/os/windows/vm/decoder_windows.hpp index 05a5dc25fc4f91cee1e134673d0af669be60dfb4..ad80e5b9c12d365177b677e43689e056be213caf 100644 --- a/src/os/windows/vm/decoder_windows.hpp +++ b/src/os/windows/vm/decoder_windows.hpp @@ -45,6 +45,10 @@ public: bool can_decode_C_frame_in_vm() const; bool demangle(const char* symbol, char *buf, int buflen); bool decode(address addr, char *buf, int buflen, int* offset, const char* modulepath = NULL); + bool decode(address addr, char *buf, int buflen, int* offset, const void* base) { + ShouldNotReachHere(); + return false; + } private: void initialize(); diff --git a/src/share/vm/utilities/decoder.cpp b/src/share/vm/utilities/decoder.cpp index cf7be329f8493d00e28684a3889b9b4bff85073b..4a9266f0b0702535224c60870271105f47258397 100644 --- a/src/share/vm/utilities/decoder.cpp +++ b/src/share/vm/utilities/decoder.cpp @@ -91,6 +91,18 @@ bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const cha return decoder->decode(addr, buf, buflen, offset, modulepath); } +bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const void* base) { + assert(_shared_decoder_lock != NULL, "Just check"); + bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid; + MutexLockerEx locker(error_handling_thread ? NULL : _shared_decoder_lock, true); + AbstractDecoder* decoder = error_handling_thread ? + get_error_handler_instance(): get_shared_instance(); + assert(decoder != NULL, "null decoder"); + + return decoder->decode(addr, buf, buflen, offset, base); +} + + bool Decoder::demangle(const char* symbol, char* buf, int buflen) { assert(_shared_decoder_lock != NULL, "Just check"); bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid; diff --git a/src/share/vm/utilities/decoder.hpp b/src/share/vm/utilities/decoder.hpp index a24f771b7bb213b650d7e91303532a4686bd203e..0d2af80986c67643b19741463156b71e555f22da 100644 --- a/src/share/vm/utilities/decoder.hpp +++ b/src/share/vm/utilities/decoder.hpp @@ -47,6 +47,8 @@ public: // the function virtual bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL) = 0; + virtual bool decode(address pc, char* buf, int buflen, int* offset, const void* base) = 0; + // demangle a C++ symbol virtual bool demangle(const char* symbol, char* buf, int buflen) = 0; // if the decoder can decode symbols in vm @@ -82,6 +84,10 @@ public: return false; } + virtual bool decode(address pc, char* buf, int buflen, int* offset, const void* base) { + return false; + } + virtual bool demangle(const char* symbol, char* buf, int buflen) { return false; } @@ -95,6 +101,7 @@ public: class Decoder : AllStatic { public: static bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL); + static bool decode(address pc, char* buf, int buflen, int* offset, const void* base); static bool demangle(const char* symbol, char* buf, int buflen); static bool can_decode_C_frame_in_vm(); diff --git a/src/share/vm/utilities/decoder_elf.hpp b/src/share/vm/utilities/decoder_elf.hpp index 971cd3c227230eb6182347a8c347857267d4012c..79652aefff1c44628e51c66fd035bef96db0d917 100644 --- a/src/share/vm/utilities/decoder_elf.hpp +++ b/src/share/vm/utilities/decoder_elf.hpp @@ -43,6 +43,10 @@ public: bool demangle(const char* symbol, char *buf, int buflen); bool decode(address addr, char *buf, int buflen, int* offset, const char* filepath = NULL); + bool decode(address addr, char *buf, int buflen, int* offset, const void *base) { + ShouldNotReachHere(); + return false; + } private: ElfFile* get_elf_file(const char* filepath);