Path: blob/master/src/hotspot/os/aix/loadlib_aix.cpp
40930 views
/*1* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2012, 2019 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/242526// Implementation of LoadedLibraries and friends2728// Ultimately this just uses loadquery()29// See:30// http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp31// ?topic=/com.ibm.aix.basetechref/doc/basetrf1/loadquery.htm3233#include "loadlib_aix.hpp"34#include "misc_aix.hpp"35#include "porting_aix.hpp"36#include "utilities/debug.hpp"37#include "utilities/ostream.hpp"3839// For loadquery()40#include <sys/ldr.h>4142// Use raw malloc instead of os::malloc - this code gets used for error reporting.4344// A class to "intern" eternal strings.45// TODO: similar coding exists in AIX version of dladdr and potentially elsewhere: consolidate!46class StringList {4748char** _list;49int _cap;50int _num;5152// Enlarge list. If oom, leave old list intact and return false.53bool enlarge() {54int cap2 = _cap + 64;55char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2);56if (!l2) {57return false;58}59_list = l2;60_cap = cap2;61return true;62}6364// Append string to end of list.65// Returns NULL if oom.66char* append(const char* s) {67if (_cap == _num) {68if (!enlarge()) {69return NULL;70}71}72assert0(_cap > _num);73char* s2 = ::strdup(s);74if (!s2) {75return NULL;76}77_list[_num] = s2;78trcVerbose("StringDir: added %s at pos %d", s2, _num);79_num ++;80return s2;81}8283public:8485StringList()86: _list(NULL)87, _cap(0)88, _num(0)89{}9091// String is copied into the list; pointer to copy is returned.92// Returns NULL if oom.93char* add (const char* s) {94for (int i = 0; i < _num; i++) {95if (strcmp(_list[i], s) == 0) {96return _list[i];97}98}99return append(s);100}101102};103104static StringList g_stringlist;105106//////////////////////107108// Entries are kept in a linked list ordered by text address. Entries are not109// eternal - this list is rebuilt on every reload.110// Note that we do not hand out those entries, but copies of them.111112struct entry_t {113entry_t* next;114loaded_module_t info;115};116117static void print_entry(const entry_t* e, outputStream* os) {118const loaded_module_t* const lm = &(e->info);119os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT120", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " "121"%s",122(lm->is_in_vm ? '*' : ' '),123lm->text, (uintptr_t)lm->text + lm->text_len,124lm->data, (uintptr_t)lm->data + lm->data_len,125lm->path);126if (lm->member) {127os->print("(%s)", lm->member);128}129}130131static entry_t* g_first = NULL;132133static entry_t* find_entry_for_text_address(const void* p) {134for (entry_t* e = g_first; e; e = e->next) {135if ((uintptr_t)p >= (uintptr_t)e->info.text &&136(uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len)) {137return e;138}139}140return NULL;141}142143static entry_t* find_entry_for_data_address(const void* p) {144for (entry_t* e = g_first; e; e = e->next) {145if ((uintptr_t)p >= (uintptr_t)e->info.data &&146(uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) {147return e;148}149}150return NULL;151}152153// Adds a new entry to the list (ordered by text address ascending).154static void add_entry_to_list(entry_t* e, entry_t** start) {155entry_t* last = NULL;156entry_t* e2 = *start;157while (e2 && e2->info.text < e->info.text) {158last = e2;159e2 = e2->next;160}161if (last) {162last->next = e;163} else {164*start = e;165}166e->next = e2;167}168169static void free_entry_list(entry_t** start) {170entry_t* e = *start;171while (e) {172entry_t* const e2 = e->next;173::free(e);174e = e2;175}176*start = NULL;177}178179180// Rebuild the internal module table. If an error occurs, old table remains181// unchanged.182static bool reload_table() {183184bool rc = false;185186trcVerbose("reload module table...");187188entry_t* new_list = NULL;189const struct ld_info* ldi = NULL;190191// Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery192// requires a large enough buffer.193uint8_t* buffer = NULL;194size_t buflen = 1024;195for (;;) {196buffer = (uint8_t*) ::realloc(buffer, buflen);197if (loadquery(L_GETINFO, buffer, buflen) == -1) {198if (errno == ENOMEM) {199buflen *= 2;200} else {201trcVerbose("loadquery failed (%d)", errno);202goto cleanup;203}204} else {205break;206}207}208209trcVerbose("loadquery buffer size is " SIZE_FORMAT ".", buflen);210211// Iterate over the loadquery result. For details see sys/ldr.h on AIX.212ldi = (struct ld_info*) buffer;213214for (;;) {215216entry_t* e = (entry_t*) ::malloc(sizeof(entry_t));217if (!e) {218trcVerbose("OOM.");219goto cleanup;220}221222memset(e, 0, sizeof(entry_t));223224e->info.text = ldi->ldinfo_textorg;225e->info.text_len = ldi->ldinfo_textsize;226e->info.data = ldi->ldinfo_dataorg;227e->info.data_len = ldi->ldinfo_datasize;228229e->info.path = g_stringlist.add(ldi->ldinfo_filename);230if (!e->info.path) {231trcVerbose("OOM.");232goto cleanup;233}234235// Extract short name236{237const char* p = strrchr(e->info.path, '/');238if (p) {239p ++;240e->info.shortname = p;241} else {242e->info.shortname = e->info.path;243}244}245246// Do we have a member name as well (see ldr.h)?247const char* p_mbr_name =248ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1;249if (*p_mbr_name) {250e->info.member = g_stringlist.add(p_mbr_name);251if (!e->info.member) {252trcVerbose("OOM.");253goto cleanup;254}255} else {256e->info.member = NULL;257}258259if (strcmp(e->info.shortname, "libjvm.so") == 0) {260// Note that this, theoretically, is fuzzy. We may accidentally contain261// more than one libjvm.so. But that is improbable, so lets go with this262// solution.263e->info.is_in_vm = true;264}265266trcVerbose("entry: %p " SIZE_FORMAT ", %p " SIZE_FORMAT ", %s %s %s, %d",267e->info.text, e->info.text_len,268e->info.data, e->info.data_len,269e->info.path, e->info.shortname,270(e->info.member ? e->info.member : "NULL"),271e->info.is_in_vm272);273274// Add to list.275add_entry_to_list(e, &new_list);276277// Next entry...278if (ldi->ldinfo_next) {279ldi = (struct ld_info*)(((char*)ldi) + ldi->ldinfo_next);280} else {281break;282}283}284285// We are done. All is well. Free old list and swap to new one.286if (g_first) {287free_entry_list(&g_first);288}289g_first = new_list;290new_list = NULL;291292rc = true;293294cleanup:295296if (new_list) {297free_entry_list(&new_list);298}299300::free(buffer);301302return rc;303304} // end LoadedLibraries::reload()305306307///////////////////////////////////////////////////////////////////////////////308// Externals309310static MiscUtils::CritSect g_cs;311312// Rebuild the internal module table. If an error occurs, old table remains313// unchanged.314bool LoadedLibraries::reload() {315MiscUtils::AutoCritSect lck(&g_cs);316return reload_table();317}318319void LoadedLibraries::print(outputStream* os) {320MiscUtils::AutoCritSect lck(&g_cs);321if (!g_first) {322reload_table();323}324for (entry_t* e = g_first; e; e = e->next) {325print_entry(e, os);326os->cr();327}328}329330bool LoadedLibraries::find_for_text_address(const void* p,331loaded_module_t* info) {332MiscUtils::AutoCritSect lck(&g_cs);333if (!g_first) {334reload_table();335}336const entry_t* const e = find_entry_for_text_address(p);337if (e) {338if (info) {339*info = e->info;340}341return true;342}343return false;344}345346347bool LoadedLibraries::find_for_data_address (348const void* p,349loaded_module_t* info // optional. can be NULL:350) {351MiscUtils::AutoCritSect lck(&g_cs);352if (!g_first) {353reload_table();354}355const entry_t* const e = find_entry_for_data_address(p);356if (e) {357if (info) {358*info = e->info;359}360return true;361}362return false;363}364365366367