Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/bsd/vm/decoder_machO.cpp
32284 views
/*1* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"2526#ifdef __APPLE__27#include "decoder_machO.hpp"2829#include <cxxabi.h>30#include <mach-o/loader.h>31#include <mach-o/nlist.h>323334bool MachODecoder::demangle(const char* symbol, char *buf, int buflen) {35int status;36char* result;37size_t size = (size_t)buflen;38// Don't pass buf to __cxa_demangle. In case of the 'buf' is too small,39// __cxa_demangle will call system "realloc" for additional memory, which40// may use different malloc/realloc mechanism that allocates 'buf'.41if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) {42jio_snprintf(buf, buflen, "%s", result);43// call c library's free44::free(result);45return true;46}47return false;48}4950bool MachODecoder::decode(address addr, char *buf,51int buflen, int *offset, const void *mach_base) {52struct symtab_command * symt = (struct symtab_command *)53mach_find_command((struct mach_header_64 *)mach_base, LC_SYMTAB);54if (symt == NULL) {55DEBUG_ONLY(tty->print_cr("no symtab in mach file at 0x%lx", p2i(mach_base)));56return false;57}58uint32_t off = symt->symoff; /* symbol table offset (within this mach file) */59uint32_t nsyms = symt->nsyms; /* number of symbol table entries */60uint32_t stroff = symt->stroff; /* string table offset */61uint32_t strsize = symt->strsize; /* string table size in bytes */6263// iterate through symbol table trying to match our offset6465uint32_t addr_relative = (uintptr_t) mach_base - (uintptr_t) addr; // offset we seek in the symtab66void * symtab_addr = (void*) ((uintptr_t) mach_base + off);67struct nlist_64 *cur_nlist = (struct nlist_64 *) symtab_addr;68struct nlist_64 *last_nlist = cur_nlist; // no size stored in an entry, so keep previously seen nlist6970int32_t found_strx = 0;71int32_t found_symval = 0;7273for (uint32_t i=0; i < nsyms; i++) {74uint32_t this_value = cur_nlist->n_value;7576if (addr_relative == this_value) {77found_strx = cur_nlist->n_un.n_strx;78found_symval = this_value;79break;80} else if (addr_relative > this_value) {81// gone past it, use previously seen nlist:82found_strx = last_nlist->n_un.n_strx;83found_symval = last_nlist->n_value;84break;85}86last_nlist = cur_nlist;87cur_nlist = cur_nlist + sizeof(struct nlist_64);88}89if (found_strx == 0) {90return false;91}92// write the offset:93*offset = addr_relative - found_symval;9495// lookup found_strx in the string table96char * symname = mach_find_in_stringtable((char*) ((uintptr_t)mach_base + stroff), strsize, found_strx);97if (symname) {98strncpy(buf, symname, buflen);99buf[buflen - 1] = '\0';100return true;101}102DEBUG_ONLY(tty->print_cr("no string or null string found."));103return false;104}105106void* MachODecoder::mach_find_command(struct mach_header_64 * mach_base, uint32_t command_wanted) {107// possibly verify it is a mach_header, use magic number.108// commands begin immediately after the header.109struct load_command *pos = (struct load_command *) mach_base + sizeof(struct mach_header_64);110for (uint32_t i = 0; i < mach_base->ncmds; i++) {111struct load_command *this_cmd = (struct load_command *) pos;112if (this_cmd->cmd == command_wanted) {113return pos;114}115int cmdsize = this_cmd->cmdsize;116pos += cmdsize;117}118return NULL;119}120121char* MachODecoder::mach_find_in_stringtable(char *strtab, uint32_t tablesize, int strx_wanted) {122123if (strx_wanted == 0) {124return NULL;125}126char *strtab_end = strtab + tablesize;127128// find the first string, skip over the space char129// (or the four zero bytes we see e.g. in libclient)130if (*strtab == ' ') {131strtab++;132if (*strtab != 0) {133DEBUG_ONLY(tty->print_cr("string table has leading space but no following zero."));134return NULL;135}136strtab++;137} else {138if ((uint32_t) *strtab != 0) {139DEBUG_ONLY(tty->print_cr("string table without leading space or leading int of zero."));140return NULL;141}142strtab+=4;143}144// read the real strings starting at index 1145int cur_strx = 1;146while (strtab < strtab_end) {147if (cur_strx == strx_wanted) {148return strtab;149}150// find start of next string151while (*strtab != 0) {152strtab++;153}154strtab++; // skip the terminating zero155cur_strx++;156}157DEBUG_ONLY(tty->print_cr("string number %d not found.", strx_wanted));158return NULL;159}160161162#endif163164165166167