Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/aix/vm/porting_aix.cpp
32284 views
/*1* Copyright 2012, 2013 SAP AG. 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 "asm/assembler.hpp"25#include "loadlib_aix.hpp"26#include "porting_aix.hpp"27#include "utilities/debug.hpp"2829#include <demangle.h>30#include <sys/debug.h>3132//////////////////////////////////33// Provide implementation for dladdr based on LoadedLibraries pool and34// traceback table scan (see getFuncName).3536// Search traceback table in stack,37// return procedure name from trace back table.38#define MAX_FUNC_SEARCH_LEN 0x1000039// Any PC below this value is considered toast.40#define MINIMUM_VALUE_FOR_PC ((unsigned int*)0x1024)4142#define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))4344// Align a pointer without having to cast.45inline char* align_ptr_up(char* ptr, intptr_t alignment) {46return (char*) align_size_up((intptr_t)ptr, alignment);47}4849// Trace if verbose to tty.50// I use these now instead of the Xtrace system because the latter is51// not available at init time, hence worthless. Until we fix this, all52// tracing here is done with -XX:+Verbose.53#define trcVerbose(fmt, ...) { \54if (Verbose) { \55fprintf(stderr, fmt, ##__VA_ARGS__); \56fputc('\n', stderr); fflush(stderr); \57} \58}59#define ERRBYE(s) { trcVerbose(s); return -1; }6061// Unfortunately, the interface of dladdr makes the implementator62// responsible for maintaining memory for function name/library63// name. I guess this is because most OS's keep those values as part64// of the mapped executable image ready to use. On AIX, this doesn't65// work, so I have to keep the returned strings. For now, I do this in66// a primitive string map. Should this turn out to be a performance67// problem, a better hashmap has to be used.68class fixed_strings {69struct node {70char* v;71node* next;72};7374node* first;7576public:7778fixed_strings() : first(0) {}79~fixed_strings() {80node* n = first;81while (n) {82node* p = n;83n = n->next;84free(p->v);85delete p;86}87}8889char* intern(const char* s) {90for (node* n = first; n; n = n->next) {91if (strcmp(n->v, s) == 0) {92return n->v;93}94}95node* p = new node;96p->v = strdup(s);97p->next = first;98first = p;99return p->v;100}101};102103static fixed_strings dladdr_fixed_strings;104105// Given a code pointer, returns the function name and the displacement.106// Function looks for the traceback table at the end of the function.107extern "C" int getFuncName(108codeptr_t pc, // [in] program counter109char* p_name, size_t namelen, // [out] optional: function name ("" if not available)110int* p_displacement, // [out] optional: displacement (-1 if not available)111const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further112// information (NULL if not available)113char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages114) {115struct tbtable* tb = 0;116unsigned int searchcount = 0;117118// initialize output parameters119if (p_name && namelen > 0) {120*p_name = '\0';121}122if (p_errmsg && errmsglen > 0) {123*p_errmsg = '\0';124}125if (p_displacement) {126*p_displacement = -1;127}128if (p_tb) {129*p_tb = NULL;130}131132// weed out obvious bogus states133if (pc < MINIMUM_VALUE_FOR_PC) {134ERRBYE("invalid program counter");135}136137codeptr_t pc2 = pc;138139// make sure the pointer is word aligned.140pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);141142// Find start of traceback table.143// (starts after code, is marked by word-aligned (32bit) zeros)144while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {145pc2++;146}147if (*pc2 != 0) {148ERRBYE("could not find traceback table within 5000 bytes of program counter");149}150//151// Set up addressability to the traceback table152//153tb = (struct tbtable*) (pc2 + 1);154155// Is this really a traceback table? No way to be sure but156// some indicators we can check.157if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {158// Language specifiers, go from 0 (C) to 14 (Objective C).159// According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.160ERRBYE("not a traceback table");161}162163// Existence of fields in the tbtable extension are contingent upon164// specific fields in the base table. Check for their existence so165// that we can address the function name if it exists.166pc2 = (codeptr_t) tb +167sizeof(struct tbtable_short)/sizeof(int);168if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)169pc2++;170171if (tb->tb.has_tboff == TRUE) {172173// I want to know the displacement174const unsigned int tb_offset = *pc2;175codeptr_t start_of_procedure =176(codeptr_t)(((char*)tb) - 4 - tb_offset); // (-4 to omit leading 0000)177178// Weed out the cases where we did find the wrong traceback table.179if (pc < start_of_procedure) {180ERRBYE("could not find (the real) traceback table within 5000 bytes of program counter");181}182183// return the displacement184if (p_displacement) {185(*p_displacement) = (int) PTRDIFF_BYTES(pc, start_of_procedure);186}187188pc2++;189} else {190// return -1 for displacement191if (p_displacement) {192(*p_displacement) = -1;193}194}195196if (tb->tb.int_hndl == TRUE)197pc2++;198199if (tb->tb.has_ctl == TRUE)200pc2 += (*pc2) + 1; // don't care201202//203// return function name if it exists.204//205if (p_name && namelen > 0) {206if (tb->tb.name_present) {207char buf[256];208const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);209memcpy(buf, (char*)pc2 + sizeof(short), l);210buf[l] = '\0';211212p_name[0] = '\0';213214// If it is a C++ name, try and demangle it using the Demangle interface (see demangle.h).215char* rest;216Name* const name = Demangle(buf, rest);217if (name) {218const char* const demangled_name = name->Text();219if (demangled_name) {220strncpy(p_name, demangled_name, namelen-1);221p_name[namelen-1] = '\0';222}223delete name;224}225226// Fallback: if demangling did not work, just provide the unmangled name.227if (p_name[0] == '\0') {228strncpy(p_name, buf, namelen-1);229p_name[namelen-1] = '\0';230}231232} else {233strncpy(p_name, "<nameless function>", namelen-1);234p_name[namelen-1] = '\0';235}236}237// Return traceback table, if user wants it.238if (p_tb) {239(*p_tb) = tb;240}241242return 0;243}244245// Special implementation of dladdr for Aix based on LoadedLibraries246// Note: dladdr returns non-zero for ok, 0 for error!247// Note: dladdr is not posix, but a non-standard GNU extension. So this tries to248// fulfill the contract of dladdr on Linux (see http://linux.die.net/man/3/dladdr)249// Note: addr may be both an AIX function descriptor or a real code pointer250// to the entry of a function.251extern "C"252int dladdr(void* addr, Dl_info* info) {253254if (!addr) {255return 0;256}257258assert(info, "");259260int rc = 0;261262const char* const ZEROSTRING = "";263264// Always return a string, even if a "" one. Linux dladdr manpage265// does not say anything about returning NULL266info->dli_fname = ZEROSTRING;267info->dli_sname = ZEROSTRING;268info->dli_saddr = NULL;269270address p = (address) addr;271const LoadedLibraryModule* lib = NULL;272273enum { noclue, code, data } type = noclue;274275trcVerbose("dladdr(%p)...", p);276277// Note: input address may be a function. I accept both a pointer to278// the entry of a function and a pointer to the function decriptor.279// (see ppc64 ABI)280lib = LoadedLibraries::find_for_text_address(p);281if (lib) {282type = code;283}284285if (!lib) {286// Not a pointer into any text segment. Is it a function descriptor?287const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;288p = pfd->entry();289if (p) {290lib = LoadedLibraries::find_for_text_address(p);291if (lib) {292type = code;293}294}295}296297if (!lib) {298// Neither direct code pointer nor function descriptor. A data ptr?299p = (address)addr;300lib = LoadedLibraries::find_for_data_address(p);301if (lib) {302type = data;303}304}305306// If we did find the shared library this address belongs to (either307// code or data segment) resolve library path and, if possible, the308// symbol name.309if (lib) {310const char* const interned_libpath =311dladdr_fixed_strings.intern(lib->get_fullpath());312if (interned_libpath) {313info->dli_fname = interned_libpath;314}315316if (type == code) {317318// For code symbols resolve function name and displacement. Use319// displacement to calc start of function.320char funcname[256] = "";321int displacement = 0;322323if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,324NULL, NULL, 0) == 0) {325if (funcname[0] != '\0') {326const char* const interned = dladdr_fixed_strings.intern(funcname);327info->dli_sname = interned;328trcVerbose("... function name: %s ...", interned);329}330331// From the displacement calculate the start of the function.332if (displacement != -1) {333info->dli_saddr = p - displacement;334} else {335info->dli_saddr = p;336}337} else {338339// No traceback table found. Just assume the pointer is it.340info->dli_saddr = p;341342}343344} else if (type == data) {345346// For data symbols.347info->dli_saddr = p;348349} else {350ShouldNotReachHere();351}352353rc = 1; // success: return 1 [sic]354355}356357// sanity checks.358if (rc) {359assert(info->dli_fname, "");360assert(info->dli_sname, "");361assert(info->dli_saddr, "");362}363364return rc; // error: return 0 [sic]365366}367368369