mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 11:34:38 +02:00
8140645
: Recent Developments for AIX
Port recent developments from SAP for AIX to the OpenJDK Reviewed-by: goetz
This commit is contained in:
parent
e3e3e02480
commit
c230209787
8 changed files with 592 additions and 359 deletions
|
@ -5572,7 +5572,6 @@ instruct loadN2P_unscaled(iRegPdst dst, memory mem) %{
|
||||||
|
|
||||||
instruct loadN2P_klass_unscaled(iRegPdst dst, memory mem) %{
|
instruct loadN2P_klass_unscaled(iRegPdst dst, memory mem) %{
|
||||||
match(Set dst (DecodeNKlass (LoadNKlass mem)));
|
match(Set dst (DecodeNKlass (LoadNKlass mem)));
|
||||||
// SAPJVM GL 2014-05-21 Differs.
|
|
||||||
predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0 &&
|
predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0 &&
|
||||||
_kids[0]->_leaf->as_Load()->is_unordered());
|
_kids[0]->_leaf->as_Load()->is_unordered());
|
||||||
ins_cost(MEMORY_REF_COST);
|
ins_cost(MEMORY_REF_COST);
|
||||||
|
@ -10949,7 +10948,7 @@ instruct cmpFastLock(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iR
|
||||||
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
|
||||||
__ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register,
|
__ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register,
|
||||||
$tmp3$$Register, $tmp1$$Register, $tmp2$$Register,
|
$tmp3$$Register, $tmp1$$Register, $tmp2$$Register,
|
||||||
UseBiasedLocking && !UseOptoBiasInlining); // SAPJVM MD 2014-11-06 UseOptoBiasInlining
|
UseBiasedLocking && !UseOptoBiasInlining);
|
||||||
// If locking was successfull, crx should indicate 'EQ'.
|
// If locking was successfull, crx should indicate 'EQ'.
|
||||||
// The compiler generates a branch to the runtime call to
|
// The compiler generates a branch to the runtime call to
|
||||||
// _complete_monitor_locking_Java for the case where crx is 'NE'.
|
// _complete_monitor_locking_Java for the case where crx is 'NE'.
|
||||||
|
|
|
@ -33,153 +33,337 @@
|
||||||
#ifndef __STDC_FORMAT_MACROS
|
#ifndef __STDC_FORMAT_MACROS
|
||||||
#define __STDC_FORMAT_MACROS
|
#define __STDC_FORMAT_MACROS
|
||||||
#endif
|
#endif
|
||||||
// 'allocation.inline.hpp' triggers the inclusion of 'inttypes.h' which defines macros
|
|
||||||
// required by the definitions in 'globalDefinitions.hpp'. But these macros in 'inttypes.h'
|
#include "loadlib_aix.hpp"
|
||||||
// are only defined if '__STDC_FORMAT_MACROS' is defined!
|
// for CritSect
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "misc_aix.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "porting_aix.hpp"
|
||||||
#include "runtime/threadCritical.hpp"
|
|
||||||
#include "utilities/debug.hpp"
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
#include "loadlib_aix.hpp"
|
|
||||||
#include "porting_aix.hpp"
|
|
||||||
|
|
||||||
// For loadquery()
|
// For loadquery()
|
||||||
#include <sys/ldr.h>
|
#include <sys/ldr.h>
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
// Use raw malloc instead of os::malloc - this code gets used for error reporting.
|
||||||
// Implementation for LoadedLibraryModule
|
|
||||||
|
|
||||||
// output debug info
|
// A class to "intern" eternal strings.
|
||||||
void LoadedLibraryModule::print(outputStream* os) const {
|
// TODO: similar coding exists in AIX version of dladdr and potentially elsewhere: consolidate!
|
||||||
os->print("%15.15s: text: " INTPTR_FORMAT " - " INTPTR_FORMAT
|
class StringList {
|
||||||
", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " ",
|
|
||||||
shortname, text_from, text_to, data_from, data_to);
|
char** _list;
|
||||||
os->print(" %s", fullpath);
|
int _cap;
|
||||||
if (strlen(membername) > 0) {
|
int _num;
|
||||||
os->print("(%s)", membername);
|
|
||||||
|
// Enlarge list. If oom, leave old list intact and return false.
|
||||||
|
bool enlarge() {
|
||||||
|
int cap2 = _cap + 64;
|
||||||
|
char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2);
|
||||||
|
if (!l2) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
os->cr();
|
_list = l2;
|
||||||
|
_cap = cap2;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Append string to end of list.
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
// Returns NULL if oom.
|
||||||
// Implementation for LoadedLibraries
|
char* append(const char* s) {
|
||||||
|
if (_cap == _num) {
|
||||||
// class variables
|
if (!enlarge()) {
|
||||||
LoadedLibraryModule LoadedLibraries::tab[MAX_MODULES];
|
return NULL;
|
||||||
int LoadedLibraries::num_loaded = 0;
|
|
||||||
|
|
||||||
// Checks whether the address p points to any of the loaded code segments.
|
|
||||||
// If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
|
|
||||||
// static
|
|
||||||
const LoadedLibraryModule* LoadedLibraries::find_for_text_address(const unsigned char* p) {
|
|
||||||
|
|
||||||
if (num_loaded == 0) {
|
|
||||||
reload();
|
|
||||||
}
|
}
|
||||||
for (int i = 0; i < num_loaded; i++) {
|
}
|
||||||
if (tab[i].is_in_text(p)) {
|
assert0(_cap > _num);
|
||||||
return &tab[i];
|
char* s2 = ::strdup(s);
|
||||||
|
if (!s2) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
_list[_num] = s2;
|
||||||
|
trcVerbose("StringDir: added %s at pos %d", s2, _num);
|
||||||
|
_num ++;
|
||||||
|
return s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
StringList()
|
||||||
|
: _list(NULL)
|
||||||
|
, _cap(0)
|
||||||
|
, _num(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// String is copied into the list; pointer to copy is returned.
|
||||||
|
// Returns NULL if oom.
|
||||||
|
char* add (const char* s) {
|
||||||
|
for (int i = 0; i < _num; i++) {
|
||||||
|
if (strcmp(_list[i], s) == 0) {
|
||||||
|
return _list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static StringList g_stringlist;
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
// Entries are kept in a linked list ordered by text address. Entries are not
|
||||||
|
// eternal - this list is rebuilt on every reload.
|
||||||
|
// Note that we do not hand out those entries, but copies of them.
|
||||||
|
|
||||||
|
struct entry_t {
|
||||||
|
entry_t* next;
|
||||||
|
loaded_module_t info;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print_entry(const entry_t* e, outputStream* os) {
|
||||||
|
const loaded_module_t* const lm = &(e->info);
|
||||||
|
os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT
|
||||||
|
", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " "
|
||||||
|
"%s",
|
||||||
|
(lm->is_in_vm ? '*' : ' '),
|
||||||
|
lm->text, (uintptr_t)lm->text + lm->text_len,
|
||||||
|
lm->data, (uintptr_t)lm->data + lm->data_len,
|
||||||
|
lm->path);
|
||||||
|
if (lm->member) {
|
||||||
|
os->print("(%s)", lm->member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static entry_t* g_first = NULL;
|
||||||
|
|
||||||
|
static entry_t* find_entry_for_text_address(const void* p) {
|
||||||
|
for (entry_t* e = g_first; e; e = e->next) {
|
||||||
|
if ((uintptr_t)p >= (uintptr_t)e->info.text &&
|
||||||
|
(uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len)) {
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the address p points to any of the loaded data segments.
|
static entry_t* find_entry_for_data_address(const void* p) {
|
||||||
// If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
|
for (entry_t* e = g_first; e; e = e->next) {
|
||||||
// static
|
if ((uintptr_t)p >= (uintptr_t)e->info.data &&
|
||||||
const LoadedLibraryModule* LoadedLibraries::find_for_data_address(const unsigned char* p) {
|
(uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) {
|
||||||
if (num_loaded == 0) {
|
return e;
|
||||||
reload();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < num_loaded; i++) {
|
|
||||||
if (tab[i].is_in_data(p)) {
|
|
||||||
return &tab[i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebuild the internal table of LoadedLibraryModule objects
|
// Adds a new entry to the list (ordered by text address ascending).
|
||||||
// static
|
static void add_entry_to_list(entry_t* e, entry_t** start) {
|
||||||
void LoadedLibraries::reload() {
|
entry_t* last = NULL;
|
||||||
|
entry_t* e2 = *start;
|
||||||
|
while (e2 && e2->info.text < e->info.text) {
|
||||||
|
last = e2;
|
||||||
|
e2 = e2->next;
|
||||||
|
}
|
||||||
|
if (last) {
|
||||||
|
last->next = e;
|
||||||
|
} else {
|
||||||
|
*start = e;
|
||||||
|
}
|
||||||
|
e->next = e2;
|
||||||
|
}
|
||||||
|
|
||||||
ThreadCritical cs;
|
static void free_entry_list(entry_t** start) {
|
||||||
|
entry_t* e = *start;
|
||||||
|
while (e) {
|
||||||
|
entry_t* const e2 = e->next;
|
||||||
|
::free(e);
|
||||||
|
e = e2;
|
||||||
|
}
|
||||||
|
*start = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// discard old content
|
|
||||||
num_loaded = 0;
|
|
||||||
|
|
||||||
// Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX.
|
// Rebuild the internal module table. If an error occurs, old table remains
|
||||||
size_t buf_size = 4096;
|
// unchanged.
|
||||||
char* loadquery_buf = AllocateHeap(buf_size, mtInternal);
|
static bool reload_table() {
|
||||||
|
|
||||||
while(loadquery(L_GETINFO, loadquery_buf, buf_size) == -1) {
|
bool rc = false;
|
||||||
|
|
||||||
|
trcVerbose("reload module table...");
|
||||||
|
|
||||||
|
entry_t* new_list = NULL;
|
||||||
|
const struct ld_info* ldi = NULL;
|
||||||
|
|
||||||
|
// Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery
|
||||||
|
// requires a large enough buffer.
|
||||||
|
uint8_t* buffer = NULL;
|
||||||
|
size_t buflen = 1024;
|
||||||
|
for (;;) {
|
||||||
|
buffer = (uint8_t*) ::realloc(buffer, buflen);
|
||||||
|
if (loadquery(L_GETINFO, buffer, buflen) == -1) {
|
||||||
if (errno == ENOMEM) {
|
if (errno == ENOMEM) {
|
||||||
buf_size *= 2;
|
buflen *= 2;
|
||||||
loadquery_buf = ReallocateHeap(loadquery_buf, buf_size, mtInternal);
|
|
||||||
} else {
|
} else {
|
||||||
FreeHeap(loadquery_buf);
|
trcVerbose("loadquery failed (%d)", errno);
|
||||||
// Ensure that the uintptr_t pointer is valid
|
goto cleanup;
|
||||||
assert(errno != EFAULT, "loadquery: Invalid uintptr_t in info buffer.");
|
|
||||||
fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate over the loadquery result. For details see sys/ldr.h on AIX.
|
|
||||||
const struct ld_info* p = (struct ld_info*) loadquery_buf;
|
|
||||||
|
|
||||||
// Ensure we have all loaded libs.
|
|
||||||
bool all_loaded = false;
|
|
||||||
while(num_loaded < MAX_MODULES) {
|
|
||||||
LoadedLibraryModule& mod = tab[num_loaded];
|
|
||||||
mod.text_from = (const unsigned char*) p->ldinfo_textorg;
|
|
||||||
mod.text_to = (const unsigned char*) (((char*)p->ldinfo_textorg) + p->ldinfo_textsize);
|
|
||||||
mod.data_from = (const unsigned char*) p->ldinfo_dataorg;
|
|
||||||
mod.data_to = (const unsigned char*) (((char*)p->ldinfo_dataorg) + p->ldinfo_datasize);
|
|
||||||
sprintf(mod.fullpath, "%.*s", sizeof(mod.fullpath), p->ldinfo_filename);
|
|
||||||
// do we have a member name as well (see ldr.h)?
|
|
||||||
const char* p_mbr_name = p->ldinfo_filename + strlen(p->ldinfo_filename) + 1;
|
|
||||||
if (*p_mbr_name) {
|
|
||||||
sprintf(mod.membername, "%.*s", sizeof(mod.membername), p_mbr_name);
|
|
||||||
} else {
|
} else {
|
||||||
mod.membername[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill in the short name
|
|
||||||
const char* p_slash = strrchr(mod.fullpath, '/');
|
|
||||||
if (p_slash) {
|
|
||||||
sprintf(mod.shortname, "%.*s", sizeof(mod.shortname), p_slash + 1);
|
|
||||||
} else {
|
|
||||||
sprintf(mod.shortname, "%.*s", sizeof(mod.shortname), mod.fullpath);
|
|
||||||
}
|
|
||||||
num_loaded ++;
|
|
||||||
|
|
||||||
// next entry...
|
|
||||||
if (p->ldinfo_next) {
|
|
||||||
p = (struct ld_info*)(((char*)p) + p->ldinfo_next);
|
|
||||||
} else {
|
|
||||||
all_loaded = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeHeap(loadquery_buf);
|
trcVerbose("loadquery buffer size is %llu.", buflen);
|
||||||
|
|
||||||
// Ensure we have all loaded libs
|
// Iterate over the loadquery result. For details see sys/ldr.h on AIX.
|
||||||
assert(all_loaded, "loadquery returned more entries then expected. Please increase MAX_MODULES");
|
ldi = (struct ld_info*) buffer;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
entry_t* e = (entry_t*) ::malloc(sizeof(entry_t));
|
||||||
|
if (!e) {
|
||||||
|
trcVerbose("OOM.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(e, 0, sizeof(entry_t));
|
||||||
|
|
||||||
|
e->info.text = ldi->ldinfo_textorg;
|
||||||
|
e->info.text_len = ldi->ldinfo_textsize;
|
||||||
|
e->info.data = ldi->ldinfo_dataorg;
|
||||||
|
e->info.data_len = ldi->ldinfo_datasize;
|
||||||
|
|
||||||
|
e->info.path = g_stringlist.add(ldi->ldinfo_filename);
|
||||||
|
if (!e->info.path) {
|
||||||
|
trcVerbose("OOM.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract short name
|
||||||
|
{
|
||||||
|
const char* p = strrchr(e->info.path, '/');
|
||||||
|
if (p) {
|
||||||
|
p ++;
|
||||||
|
e->info.shortname = p;
|
||||||
|
} else {
|
||||||
|
e->info.shortname = e->info.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have a member name as well (see ldr.h)?
|
||||||
|
const char* p_mbr_name =
|
||||||
|
ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1;
|
||||||
|
if (*p_mbr_name) {
|
||||||
|
e->info.member = g_stringlist.add(p_mbr_name);
|
||||||
|
if (!e->info.member) {
|
||||||
|
trcVerbose("OOM.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e->info.member = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(e->info.shortname, "libjvm.so") == 0) {
|
||||||
|
// Note that this, theoretically, is fuzzy. We may accidentally contain
|
||||||
|
// more than one libjvm.so. But that is improbable, so lets go with this
|
||||||
|
// solution.
|
||||||
|
e->info.is_in_vm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
trcVerbose("entry: %p %llu, %p %llu, %s %s %s, %d",
|
||||||
|
e->info.text, e->info.text_len,
|
||||||
|
e->info.data, e->info.data_len,
|
||||||
|
e->info.path, e->info.shortname,
|
||||||
|
(e->info.member ? e->info.member : "NULL"),
|
||||||
|
e->info.is_in_vm
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add to list.
|
||||||
|
add_entry_to_list(e, &new_list);
|
||||||
|
|
||||||
|
// Next entry...
|
||||||
|
if (ldi->ldinfo_next) {
|
||||||
|
ldi = (struct ld_info*)(((char*)ldi) + ldi->ldinfo_next);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done. All is well. Free old list and swap to new one.
|
||||||
|
if (g_first) {
|
||||||
|
free_entry_list(&g_first);
|
||||||
|
}
|
||||||
|
g_first = new_list;
|
||||||
|
new_list = NULL;
|
||||||
|
|
||||||
|
rc = true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
if (new_list) {
|
||||||
|
free_entry_list(&new_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
::free(buffer);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
} // end LoadedLibraries::reload()
|
} // end LoadedLibraries::reload()
|
||||||
|
|
||||||
|
|
||||||
// output loaded libraries table
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//static
|
// Externals
|
||||||
|
|
||||||
|
static MiscUtils::CritSect g_cs;
|
||||||
|
|
||||||
|
// Rebuild the internal module table. If an error occurs, old table remains
|
||||||
|
// unchanged.
|
||||||
|
bool LoadedLibraries::reload() {
|
||||||
|
MiscUtils::AutoCritSect lck(&g_cs);
|
||||||
|
return reload_table();
|
||||||
|
}
|
||||||
|
|
||||||
void LoadedLibraries::print(outputStream* os) {
|
void LoadedLibraries::print(outputStream* os) {
|
||||||
|
MiscUtils::AutoCritSect lck(&g_cs);
|
||||||
for (int i = 0; i < num_loaded; i++) {
|
if (!g_first) {
|
||||||
tab[i].print(os);
|
reload_table();
|
||||||
|
}
|
||||||
|
for (entry_t* e = g_first; e; e = e->next) {
|
||||||
|
print_entry(e, os);
|
||||||
|
os->cr();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LoadedLibraries::find_for_text_address(const void* p,
|
||||||
|
loaded_module_t* info) {
|
||||||
|
MiscUtils::AutoCritSect lck(&g_cs);
|
||||||
|
if (!g_first) {
|
||||||
|
reload_table();
|
||||||
|
}
|
||||||
|
const entry_t* const e = find_entry_for_text_address(p);
|
||||||
|
if (e) {
|
||||||
|
if (info) {
|
||||||
|
*info = e->info;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LoadedLibraries::find_for_data_address (
|
||||||
|
const void* p,
|
||||||
|
loaded_module_t* info // optional. can be NULL:
|
||||||
|
) {
|
||||||
|
MiscUtils::AutoCritSect lck(&g_cs);
|
||||||
|
if (!g_first) {
|
||||||
|
reload_table();
|
||||||
|
}
|
||||||
|
const entry_t* const e = find_entry_for_data_address(p);
|
||||||
|
if (e) {
|
||||||
|
if (info) {
|
||||||
|
*info = e->info;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,73 +26,47 @@
|
||||||
// Loadlib_aix.cpp contains support code for analysing the memory
|
// Loadlib_aix.cpp contains support code for analysing the memory
|
||||||
// layout of loaded binaries in ones own process space.
|
// layout of loaded binaries in ones own process space.
|
||||||
//
|
//
|
||||||
// It is needed, among other things, to provide a dladdr() emulation, because
|
// It is needed, among other things, to provide dladdr(3), which is
|
||||||
// that one is not provided by AIX
|
// missing on AIX.
|
||||||
|
|
||||||
#ifndef OS_AIX_VM_LOADLIB_AIX_HPP
|
#ifndef OS_AIX_VM_LOADLIB_AIX_HPP
|
||||||
#define OS_AIX_VM_LOADLIB_AIX_HPP
|
#define OS_AIX_VM_LOADLIB_AIX_HPP
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
class outputStream;
|
class outputStream;
|
||||||
|
|
||||||
// This class holds information about a single loaded library module.
|
// Struct holds information about a single loaded library module.
|
||||||
// Note that on AIX, a single library can be spread over multiple
|
// Note that on AIX, a single library can be spread over multiple
|
||||||
// uintptr_t range on a module base, eg.
|
// uintptr_t ranges on a module base, eg.
|
||||||
// libC.a(shr3_64.o) or libC.a(shrcore_64.o).
|
// libC.a(shr3_64.o) or libC.a(shrcore_64.o).
|
||||||
class LoadedLibraryModule {
|
|
||||||
|
|
||||||
friend class LoadedLibraries;
|
// Note: all pointers to strings (path, member) point to strings which are immortal.
|
||||||
|
struct loaded_module_t {
|
||||||
|
|
||||||
char fullpath[512]; // eg /usr/lib/libC.a
|
// Points to the full path of the lodaed module, e.g.
|
||||||
char shortname[30]; // eg libC.a
|
// "/usr/lib/libC.a".
|
||||||
char membername[30]; // eg shrcore_64.o
|
const char* path;
|
||||||
const unsigned char* text_from;
|
|
||||||
const unsigned char* text_to;
|
|
||||||
const unsigned char* data_from;
|
|
||||||
const unsigned char* data_to;
|
|
||||||
|
|
||||||
public:
|
// Host library name without path
|
||||||
|
const char* shortname;
|
||||||
|
|
||||||
const char* get_fullpath() const {
|
// Points to the object file (AIX specific stuff)
|
||||||
return fullpath;
|
// e.g "shrcore_64.o".
|
||||||
}
|
const char* member;
|
||||||
const char* get_shortname() const {
|
|
||||||
return shortname;
|
|
||||||
}
|
|
||||||
const char* get_membername() const {
|
|
||||||
return membername;
|
|
||||||
}
|
|
||||||
|
|
||||||
// text_from, text_to: returns the range of the text (code)
|
// Text area from, to
|
||||||
// segment for that module
|
const void* text;
|
||||||
const unsigned char* get_text_from() const {
|
size_t text_len;
|
||||||
return text_from;
|
|
||||||
}
|
|
||||||
const unsigned char* get_text_to() const {
|
|
||||||
return text_to;
|
|
||||||
}
|
|
||||||
|
|
||||||
// data_from/data_to: returns the range of the data
|
// Data area from, to
|
||||||
// segment for that module
|
const void* data;
|
||||||
const unsigned char* get_data_from() const {
|
size_t data_len;
|
||||||
return data_from;
|
|
||||||
}
|
|
||||||
const unsigned char* get_data_to() const {
|
|
||||||
return data_to;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if the
|
// True if this module is part of the vm.
|
||||||
bool is_in_text(const unsigned char* p) const {
|
bool is_in_vm;
|
||||||
return p >= text_from && p < text_to ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_in_data(const unsigned char* p) const {
|
};
|
||||||
return p >= data_from && p < data_to ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// output debug info
|
|
||||||
void print(outputStream* os) const;
|
|
||||||
|
|
||||||
}; // end LoadedLibraryModule
|
|
||||||
|
|
||||||
// This class is a singleton holding a map of all loaded binaries
|
// This class is a singleton holding a map of all loaded binaries
|
||||||
// in the AIX process space.
|
// in the AIX process space.
|
||||||
|
@ -100,29 +74,31 @@ class LoadedLibraries
|
||||||
// : AllStatic (including allocation.hpp just for AllStatic is overkill.)
|
// : AllStatic (including allocation.hpp just for AllStatic is overkill.)
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
enum {MAX_MODULES = 100};
|
|
||||||
static LoadedLibraryModule tab[MAX_MODULES];
|
|
||||||
static int num_loaded;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// rebuild the internal table of LoadedLibraryModule objects
|
// Rebuild the internal module table. If an error occurs, internal module
|
||||||
static void reload();
|
// table remains untouched.
|
||||||
|
static bool reload();
|
||||||
|
|
||||||
// checks whether the address p points to any of the loaded code segments.
|
// Check whether the given address points into the text segment of a
|
||||||
// If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
|
// loaded module. Return true if this is the case.
|
||||||
static const LoadedLibraryModule* find_for_text_address(const unsigned char* p);
|
// Optionally, information about the module is returned (info)
|
||||||
|
static bool find_for_text_address (
|
||||||
|
const void* p,
|
||||||
|
loaded_module_t* info // Optional, leave NULL if not needed.
|
||||||
|
);
|
||||||
|
|
||||||
// checks whether the address p points to any of the loaded data segments.
|
// Check whether the given address points into the data segment of a
|
||||||
// If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
|
// loaded module. Return true if this is the case.
|
||||||
static const LoadedLibraryModule* find_for_data_address(const unsigned char* p);
|
// Optionally, information about the module is returned (info)
|
||||||
|
static bool find_for_data_address (
|
||||||
|
const void* p,
|
||||||
|
loaded_module_t* info // Optional, leave NULL if not needed.
|
||||||
|
);
|
||||||
|
|
||||||
// output debug info
|
// Output debug info
|
||||||
static void print(outputStream* os);
|
static void print(outputStream* os);
|
||||||
|
|
||||||
}; // end LoadedLibraries
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // OS_AIX_VM_LOADLIB_AIX_HPP
|
#endif // OS_AIX_VM_LOADLIB_AIX_HPP
|
||||||
|
|
61
hotspot/src/os/aix/vm/misc_aix.cpp
Normal file
61
hotspot/src/os/aix/vm/misc_aix.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 SAP AG. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "misc_aix.hpp"
|
||||||
|
#include "runtime/stubRoutines.hpp"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void MiscUtils::init_critsect(MiscUtils::critsect_t* cs) {
|
||||||
|
const int rc = pthread_mutex_init(cs, NULL);
|
||||||
|
assert0(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscUtils::free_critsect(MiscUtils::critsect_t* cs) {
|
||||||
|
const int rc = pthread_mutex_destroy(cs);
|
||||||
|
assert0(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscUtils::enter_critsect(MiscUtils::critsect_t* cs) {
|
||||||
|
const int rc = pthread_mutex_lock(cs);
|
||||||
|
assert0(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscUtils::leave_critsect(MiscUtils::critsect_t* cs) {
|
||||||
|
const int rc = pthread_mutex_unlock(cs);
|
||||||
|
assert0(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MiscUtils::is_readable_pointer(const void* p) {
|
||||||
|
if (!CanUseSafeFetch32()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int* const aligned = (int*) align_size_down((intptr_t)p, 4);
|
||||||
|
int cafebabe = 0xcafebabe;
|
||||||
|
int deadbeef = 0xdeadbeef;
|
||||||
|
return (SafeFetch32(aligned, cafebabe) != cafebabe) ||
|
||||||
|
(SafeFetch32(aligned, deadbeef) != deadbeef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
101
hotspot/src/os/aix/vm/misc_aix.hpp
Normal file
101
hotspot/src/os/aix/vm/misc_aix.hpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012, 2015 SAP AG. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef OS_AIX_VM_MISC_AIX_HPP
|
||||||
|
#define OS_AIX_VM_MISC_AIX_HPP
|
||||||
|
|
||||||
|
// misc_aix.hpp, misc_aix.cpp: convenience functions needed for the OpenJDK AIX
|
||||||
|
// port.
|
||||||
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
// Trace if verbose to tty.
|
||||||
|
#define trcVerbose(fmt, ...) { \
|
||||||
|
if (Verbose) { \
|
||||||
|
fprintf(stderr, fmt, ##__VA_ARGS__); \
|
||||||
|
fputc('\n', stderr); fflush(stderr); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#define ERRBYE(s) { trcVerbose(s); return -1; }
|
||||||
|
#define trc(fmt, ...)
|
||||||
|
|
||||||
|
#define assert0(b) assert((b), "")
|
||||||
|
#define guarantee0(b) guarantee((b), "")
|
||||||
|
template <class T1, class T2> bool is_aligned_to(T1 what, T2 alignment) {
|
||||||
|
return (((uintx)(what)) & (((uintx)(alignment)) - 1)) == 0 ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CritSect: simple critical section implementation using pthread mutexes.
|
||||||
|
namespace MiscUtils {
|
||||||
|
typedef pthread_mutex_t critsect_t;
|
||||||
|
|
||||||
|
void init_critsect(MiscUtils::critsect_t* cs);
|
||||||
|
void free_critsect(MiscUtils::critsect_t* cs);
|
||||||
|
void enter_critsect(MiscUtils::critsect_t* cs);
|
||||||
|
void leave_critsect(MiscUtils::critsect_t* cs);
|
||||||
|
|
||||||
|
// Need to wrap this in an object because we need to dynamically initialize
|
||||||
|
// critical section (because of windows, where there is no way to initialize
|
||||||
|
// a CRITICAL_SECTION statically. On Unix, we could use
|
||||||
|
// PTHREAD_MUTEX_INITIALIZER).
|
||||||
|
|
||||||
|
// Note: The critical section does NOT get cleaned up in the destructor. That is
|
||||||
|
// by design: the CritSect class is only ever used as global objects whose
|
||||||
|
// lifetime spans the whole VM life; in that context we don't want the lock to
|
||||||
|
// be cleaned up when global C++ objects are destroyed, but to continue to work
|
||||||
|
// correctly right to the very end of the process life.
|
||||||
|
class CritSect {
|
||||||
|
critsect_t _cs;
|
||||||
|
public:
|
||||||
|
CritSect() { init_critsect(&_cs); }
|
||||||
|
//~CritSect() { free_critsect(&_cs); }
|
||||||
|
void enter() { enter_critsect(&_cs); }
|
||||||
|
void leave() { leave_critsect(&_cs); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class AutoCritSect {
|
||||||
|
CritSect* const _pcsobj;
|
||||||
|
public:
|
||||||
|
AutoCritSect(CritSect* pcsobj)
|
||||||
|
: _pcsobj(pcsobj)
|
||||||
|
{
|
||||||
|
_pcsobj->enter();
|
||||||
|
}
|
||||||
|
~AutoCritSect() {
|
||||||
|
_pcsobj->leave();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns true if pointer can be dereferenced without triggering a segment
|
||||||
|
// violation. Returns false if pointer is invalid.
|
||||||
|
// Note: Depends on stub routines; prior to stub routine generation, will
|
||||||
|
// always return true. Use CanUseSafeFetch32 to handle this case.
|
||||||
|
bool is_readable_pointer(const void* p);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OS_AIX_VM_MISC_AIX_HPP
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "loadlib_aix.hpp"
|
#include "loadlib_aix.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/filemap.hpp"
|
#include "memory/filemap.hpp"
|
||||||
|
#include "misc_aix.hpp"
|
||||||
#include "mutex_aix.inline.hpp"
|
#include "mutex_aix.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "os_aix.inline.hpp"
|
#include "os_aix.inline.hpp"
|
||||||
|
@ -159,23 +160,10 @@ typedef stackslot_t* stackptr_t;
|
||||||
#define PV_8_Compat 0x308000 /* Power PC 8 */
|
#define PV_8_Compat 0x308000 /* Power PC 8 */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define trcVerbose(fmt, ...) { /* PPC port */ \
|
|
||||||
if (Verbose) { \
|
|
||||||
fprintf(stderr, fmt, ##__VA_ARGS__); \
|
|
||||||
fputc('\n', stderr); fflush(stderr); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#define trc(fmt, ...) /* PPC port */
|
|
||||||
|
|
||||||
#define ERRBYE(s) { \
|
|
||||||
trcVerbose(s); \
|
|
||||||
return -1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query dimensions of the stack of the calling thread.
|
// Query dimensions of the stack of the calling thread.
|
||||||
static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size);
|
static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size);
|
||||||
|
|
||||||
// function to check a given stack pointer against given stack limits
|
// Function to check a given stack pointer against given stack limits.
|
||||||
inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) {
|
inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) {
|
||||||
if (((uintptr_t)sp) & 0x7) {
|
if (((uintptr_t)sp) & 0x7) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -189,7 +177,7 @@ inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t s
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if function is a valid codepointer
|
// Returns true if function is a valid codepointer.
|
||||||
inline bool is_valid_codepointer(codeptr_t p) {
|
inline bool is_valid_codepointer(codeptr_t p) {
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -197,7 +185,7 @@ inline bool is_valid_codepointer(codeptr_t p) {
|
||||||
if (((uintptr_t)p) & 0x3) {
|
if (((uintptr_t)p) & 0x3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (LoadedLibraries::find_for_text_address((address)p) == NULL) {
|
if (!LoadedLibraries::find_for_text_address(p, NULL)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1387,26 +1375,15 @@ bool os::address_is_in_vm(address addr) {
|
||||||
|
|
||||||
// Input could be a real pc or a function pointer literal. The latter
|
// Input could be a real pc or a function pointer literal. The latter
|
||||||
// would be a function descriptor residing in the data segment of a module.
|
// would be a function descriptor residing in the data segment of a module.
|
||||||
|
loaded_module_t lm;
|
||||||
|
if (LoadedLibraries::find_for_text_address(addr, &lm) != NULL) {
|
||||||
|
return lm.is_in_vm;
|
||||||
|
} else if (LoadedLibraries::find_for_data_address(addr, &lm) != NULL) {
|
||||||
|
return lm.is_in_vm;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(addr);
|
|
||||||
if (lib) {
|
|
||||||
if (strcmp(lib->get_shortname(), "libjvm.so") == 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lib = LoadedLibraries::find_for_data_address(addr);
|
|
||||||
if (lib) {
|
|
||||||
if (strcmp(lib->get_shortname(), "libjvm.so") == 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve an AIX function descriptor literal to a code pointer.
|
// Resolve an AIX function descriptor literal to a code pointer.
|
||||||
|
@ -1418,21 +1395,18 @@ bool os::address_is_in_vm(address addr) {
|
||||||
// NULL is returned.
|
// NULL is returned.
|
||||||
static address resolve_function_descriptor_to_code_pointer(address p) {
|
static address resolve_function_descriptor_to_code_pointer(address p) {
|
||||||
|
|
||||||
const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(p);
|
if (LoadedLibraries::find_for_text_address(p, NULL) != NULL) {
|
||||||
if (lib) {
|
// It is a real code pointer.
|
||||||
// its a real code pointer
|
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else if (LoadedLibraries::find_for_data_address(p, NULL) != NULL) {
|
||||||
lib = LoadedLibraries::find_for_data_address(p);
|
// Pointer to data segment, potential function descriptor.
|
||||||
if (lib) {
|
|
||||||
// pointer to data segment, potential function descriptor
|
|
||||||
address code_entry = (address)(((FunctionDescriptor*)p)->entry());
|
address code_entry = (address)(((FunctionDescriptor*)p)->entry());
|
||||||
if (LoadedLibraries::find_for_text_address(code_entry)) {
|
if (LoadedLibraries::find_for_text_address(code_entry, NULL) != NULL) {
|
||||||
// Its a function descriptor
|
// It is a function descriptor.
|
||||||
return code_entry;
|
return code_entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1461,7 +1435,6 @@ static int getModuleName(codeptr_t pc, // [in] program counte
|
||||||
char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
|
char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// initialize output parameters
|
|
||||||
if (p_name && namelen > 0) {
|
if (p_name && namelen > 0) {
|
||||||
*p_name = '\0';
|
*p_name = '\0';
|
||||||
}
|
}
|
||||||
|
@ -1469,16 +1442,15 @@ static int getModuleName(codeptr_t pc, // [in] program counte
|
||||||
*p_errmsg = '\0';
|
*p_errmsg = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoadedLibraryModule* const lib = LoadedLibraries::find_for_text_address((address)pc);
|
|
||||||
if (lib) {
|
|
||||||
if (p_name && namelen > 0) {
|
if (p_name && namelen > 0) {
|
||||||
sprintf(p_name, "%.*s", namelen, lib->get_shortname());
|
loaded_module_t lm;
|
||||||
|
if (LoadedLibraries::find_for_text_address(pc, &lm) != NULL) {
|
||||||
|
strncpy(p_name, lm.shortname, namelen);
|
||||||
|
p_name[namelen - 1] = '\0';
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
trcVerbose("pc outside any module");
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3781,18 +3753,11 @@ bool os::find(address addr, outputStream* st) {
|
||||||
|
|
||||||
st->print(PTR_FORMAT ": ", addr);
|
st->print(PTR_FORMAT ": ", addr);
|
||||||
|
|
||||||
const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(addr);
|
loaded_module_t lm;
|
||||||
if (lib) {
|
if (LoadedLibraries::find_for_text_address(addr, &lm) != NULL ||
|
||||||
lib->print(st);
|
LoadedLibraries::find_for_data_address(addr, &lm) != NULL) {
|
||||||
|
st->print("%s", lm.path);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
lib = LoadedLibraries::find_for_data_address(addr);
|
|
||||||
if (lib) {
|
|
||||||
lib->print(st);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
st->print_cr("(outside any module)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -23,11 +23,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "asm/assembler.hpp"
|
#include "asm/assembler.hpp"
|
||||||
|
#include "loadlib_aix.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "runtime/os.hpp"
|
// For CritSect
|
||||||
#include "loadlib_aix.hpp"
|
#include "misc_aix.hpp"
|
||||||
#include "porting_aix.hpp"
|
#include "porting_aix.hpp"
|
||||||
|
#include "runtime/os.hpp"
|
||||||
#include "utilities/debug.hpp"
|
#include "utilities/debug.hpp"
|
||||||
|
|
||||||
#include <demangle.h>
|
#include <demangle.h>
|
||||||
|
@ -45,23 +47,6 @@
|
||||||
|
|
||||||
#define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))
|
#define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))
|
||||||
|
|
||||||
// Align a pointer without having to cast.
|
|
||||||
inline char* align_ptr_up(char* ptr, intptr_t alignment) {
|
|
||||||
return (char*) align_size_up((intptr_t)ptr, alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trace if verbose to tty.
|
|
||||||
// I use these now instead of the Xtrace system because the latter is
|
|
||||||
// not available at init time, hence worthless. Until we fix this, all
|
|
||||||
// tracing here is done with -XX:+Verbose.
|
|
||||||
#define trcVerbose(fmt, ...) { \
|
|
||||||
if (Verbose) { \
|
|
||||||
fprintf(stderr, fmt, ##__VA_ARGS__); \
|
|
||||||
fputc('\n', stderr); fflush(stderr); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#define ERRBYE(s) { trcVerbose(s); return -1; }
|
|
||||||
|
|
||||||
// Unfortunately, the interface of dladdr makes the implementator
|
// Unfortunately, the interface of dladdr makes the implementator
|
||||||
// responsible for maintaining memory for function name/library
|
// responsible for maintaining memory for function name/library
|
||||||
// name. I guess this is because most OS's keep those values as part
|
// name. I guess this is because most OS's keep those values as part
|
||||||
|
@ -139,18 +124,37 @@ extern "C" int getFuncName(
|
||||||
ERRBYE("invalid program counter");
|
ERRBYE("invalid program counter");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We see random but frequent crashes in this function since some months mainly on shutdown
|
||||||
|
// (-XX:+DumpInfoAtExit). It appears the page we are reading is randomly disappearing while
|
||||||
|
// we read it (?).
|
||||||
|
// As the pc cannot be trusted to be anything sensible lets make all reads via SafeFetch. Also
|
||||||
|
// bail if this is not a text address right now.
|
||||||
|
if (!LoadedLibraries::find_for_text_address(pc, NULL)) {
|
||||||
|
ERRBYE("not a text address");
|
||||||
|
}
|
||||||
|
|
||||||
|
// .. (Note that is_readable_pointer returns true if safefetch stubs are not there yet;
|
||||||
|
// in that case I try reading the traceback table unsafe - I rather risk secondary crashes in
|
||||||
|
// error files than not having a callstack.)
|
||||||
|
#define CHECK_POINTER_READABLE(p) \
|
||||||
|
if (!MiscUtils::is_readable_pointer(p)) { \
|
||||||
|
ERRBYE("pc not readable"); \
|
||||||
|
}
|
||||||
|
|
||||||
codeptr_t pc2 = pc;
|
codeptr_t pc2 = pc;
|
||||||
|
|
||||||
// make sure the pointer is word aligned.
|
// Make sure the pointer is word aligned.
|
||||||
pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
|
pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
|
||||||
|
CHECK_POINTER_READABLE(pc2)
|
||||||
|
|
||||||
// Find start of traceback table.
|
// Find start of traceback table.
|
||||||
// (starts after code, is marked by word-aligned (32bit) zeros)
|
// (starts after code, is marked by word-aligned (32bit) zeros)
|
||||||
while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
|
while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
|
||||||
|
CHECK_POINTER_READABLE(pc2)
|
||||||
pc2++;
|
pc2++;
|
||||||
}
|
}
|
||||||
if (*pc2 != 0) {
|
if (*pc2 != 0) {
|
||||||
ERRBYE("could not find traceback table within 5000 bytes of program counter");
|
ERRBYE("no traceback table found");
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Set up addressability to the traceback table
|
// Set up addressability to the traceback table
|
||||||
|
@ -162,7 +166,7 @@ extern "C" int getFuncName(
|
||||||
if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
|
if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
|
||||||
// Language specifiers, go from 0 (C) to 14 (Objective C).
|
// Language specifiers, go from 0 (C) to 14 (Objective C).
|
||||||
// According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.
|
// According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.
|
||||||
ERRBYE("not a traceback table");
|
ERRBYE("no traceback table found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Existence of fields in the tbtable extension are contingent upon
|
// Existence of fields in the tbtable extension are contingent upon
|
||||||
|
@ -173,6 +177,8 @@ extern "C" int getFuncName(
|
||||||
if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
|
if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
|
||||||
pc2++;
|
pc2++;
|
||||||
|
|
||||||
|
CHECK_POINTER_READABLE(pc2)
|
||||||
|
|
||||||
if (tb->tb.has_tboff == TRUE) {
|
if (tb->tb.has_tboff == TRUE) {
|
||||||
|
|
||||||
// I want to know the displacement
|
// I want to know the displacement
|
||||||
|
@ -182,7 +188,7 @@ extern "C" int getFuncName(
|
||||||
|
|
||||||
// Weed out the cases where we did find the wrong traceback table.
|
// Weed out the cases where we did find the wrong traceback table.
|
||||||
if (pc < start_of_procedure) {
|
if (pc < start_of_procedure) {
|
||||||
ERRBYE("could not find (the real) traceback table within 5000 bytes of program counter");
|
ERRBYE("no traceback table found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the displacement
|
// return the displacement
|
||||||
|
@ -204,15 +210,24 @@ extern "C" int getFuncName(
|
||||||
if (tb->tb.has_ctl == TRUE)
|
if (tb->tb.has_ctl == TRUE)
|
||||||
pc2 += (*pc2) + 1; // don't care
|
pc2 += (*pc2) + 1; // don't care
|
||||||
|
|
||||||
|
CHECK_POINTER_READABLE(pc2)
|
||||||
|
|
||||||
//
|
//
|
||||||
// return function name if it exists.
|
// return function name if it exists.
|
||||||
//
|
//
|
||||||
if (p_name && namelen > 0) {
|
if (p_name && namelen > 0) {
|
||||||
if (tb->tb.name_present) {
|
if (tb->tb.name_present) {
|
||||||
|
// Copy name from text because it may not be zero terminated.
|
||||||
|
// 256 is good enough for most cases; do not use large buffers here.
|
||||||
char buf[256];
|
char buf[256];
|
||||||
const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
|
const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
|
||||||
memcpy(buf, (char*)pc2 + sizeof(short), l);
|
// Be very careful.
|
||||||
buf[l] = '\0';
|
int i = 0; char* const p = (char*)pc2 + sizeof(short);
|
||||||
|
while (i < l && MiscUtils::is_readable_pointer(p + i)) {
|
||||||
|
buf[i] = p[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
|
||||||
p_name[0] = '\0';
|
p_name[0] = '\0';
|
||||||
|
|
||||||
|
@ -275,7 +290,8 @@ int dladdr(void* addr, Dl_info* info) {
|
||||||
info->dli_saddr = NULL;
|
info->dli_saddr = NULL;
|
||||||
|
|
||||||
address p = (address) addr;
|
address p = (address) addr;
|
||||||
const LoadedLibraryModule* lib = NULL;
|
loaded_module_t lm;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
enum { noclue, code, data } type = noclue;
|
enum { noclue, code, data } type = noclue;
|
||||||
|
|
||||||
|
@ -284,28 +300,28 @@ int dladdr(void* addr, Dl_info* info) {
|
||||||
// Note: input address may be a function. I accept both a pointer to
|
// Note: input address may be a function. I accept both a pointer to
|
||||||
// the entry of a function and a pointer to the function decriptor.
|
// the entry of a function and a pointer to the function decriptor.
|
||||||
// (see ppc64 ABI)
|
// (see ppc64 ABI)
|
||||||
lib = LoadedLibraries::find_for_text_address(p);
|
found = LoadedLibraries::find_for_text_address(p, &lm);
|
||||||
if (lib) {
|
if (found) {
|
||||||
type = code;
|
type = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lib) {
|
if (!found) {
|
||||||
// Not a pointer into any text segment. Is it a function descriptor?
|
// Not a pointer into any text segment. Is it a function descriptor?
|
||||||
const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
|
const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
|
||||||
p = pfd->entry();
|
p = pfd->entry();
|
||||||
if (p) {
|
if (p) {
|
||||||
lib = LoadedLibraries::find_for_text_address(p);
|
found = LoadedLibraries::find_for_text_address(p, &lm);
|
||||||
if (lib) {
|
if (found) {
|
||||||
type = code;
|
type = code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lib) {
|
if (!found) {
|
||||||
// Neither direct code pointer nor function descriptor. A data ptr?
|
// Neither direct code pointer nor function descriptor. A data ptr?
|
||||||
p = (address)addr;
|
p = (address)addr;
|
||||||
lib = LoadedLibraries::find_for_data_address(p);
|
found = LoadedLibraries::find_for_data_address(p, &lm);
|
||||||
if (lib) {
|
if (found) {
|
||||||
type = data;
|
type = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,12 +329,10 @@ int dladdr(void* addr, Dl_info* info) {
|
||||||
// If we did find the shared library this address belongs to (either
|
// If we did find the shared library this address belongs to (either
|
||||||
// code or data segment) resolve library path and, if possible, the
|
// code or data segment) resolve library path and, if possible, the
|
||||||
// symbol name.
|
// symbol name.
|
||||||
if (lib) {
|
if (found) {
|
||||||
const char* const interned_libpath =
|
|
||||||
dladdr_fixed_strings.intern(lib->get_fullpath());
|
// No need to intern the libpath, that one is already interned one layer below.
|
||||||
if (interned_libpath) {
|
info->dli_fname = lm.path;
|
||||||
info->dli_fname = interned_libpath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == code) {
|
if (type == code) {
|
||||||
|
|
||||||
|
@ -328,7 +342,7 @@ int dladdr(void* addr, Dl_info* info) {
|
||||||
int displacement = 0;
|
int displacement = 0;
|
||||||
|
|
||||||
if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
|
if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
|
||||||
NULL, NULL, 0, true /* demangle */) == 0) {
|
NULL, NULL, 0, false) == 0) {
|
||||||
if (funcname[0] != '\0') {
|
if (funcname[0] != '\0') {
|
||||||
const char* const interned = dladdr_fixed_strings.intern(funcname);
|
const char* const interned = dladdr_fixed_strings.intern(funcname);
|
||||||
info->dli_sname = interned;
|
info->dli_sname = interned;
|
||||||
|
|
|
@ -27,13 +27,6 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
// PPC port only:
|
|
||||||
#define assert0(b) assert( (b), "" )
|
|
||||||
#define guarantee0(b) assert( (b), "" )
|
|
||||||
template <class T1, class T2> bool is_aligned_to(T1 what, T2 alignment) {
|
|
||||||
return ( ((uintx)(what)) & (((uintx)(alignment)) - 1) ) == 0 ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header file to contain porting-relevant code which does not have a
|
// Header file to contain porting-relevant code which does not have a
|
||||||
// home anywhere else and which can not go into os_<platform>.h because
|
// home anywhere else and which can not go into os_<platform>.h because
|
||||||
// that header is included inside the os class definition, hence all
|
// that header is included inside the os class definition, hence all
|
||||||
|
@ -68,14 +61,10 @@ extern "C"
|
||||||
#endif
|
#endif
|
||||||
int dladdr(void *addr, Dl_info *info);
|
int dladdr(void *addr, Dl_info *info);
|
||||||
|
|
||||||
|
|
||||||
// The semantics in this file are thus that codeptr_t is a *real code ptr*.
|
|
||||||
// This means that any function taking codeptr_t as arguments will assume
|
|
||||||
// a real codeptr and won't handle function descriptors (eg getFuncName),
|
|
||||||
// whereas functions taking address as args will deal with function
|
|
||||||
// descriptors (eg os::dll_address_to_library_name).
|
|
||||||
typedef unsigned int* codeptr_t;
|
typedef unsigned int* codeptr_t;
|
||||||
|
|
||||||
|
struct tbtable;
|
||||||
|
|
||||||
// helper function - given a program counter, tries to locate the traceback table and
|
// helper function - given a program counter, tries to locate the traceback table and
|
||||||
// returns info from it (like, most importantly, function name, displacement of the
|
// returns info from it (like, most importantly, function name, displacement of the
|
||||||
// pc inside the function, and the traceback table itself.
|
// pc inside the function, and the traceback table itself.
|
||||||
|
@ -88,64 +77,8 @@ int getFuncName(
|
||||||
int* p_displacement, // [out] optional: displacement
|
int* p_displacement, // [out] optional: displacement
|
||||||
const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further information
|
const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further information
|
||||||
char* p_errmsg, size_t errmsglen, // [out] optional: user provided buffer for error messages
|
char* p_errmsg, size_t errmsglen, // [out] optional: user provided buffer for error messages
|
||||||
bool demangle = true // [in] whether to demangle the name
|
bool demangle // [in] whether to demangle the name
|
||||||
);
|
);
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// A simple critical section which shall be based upon OS critical
|
|
||||||
// sections (CRITICAL_SECTION resp. Posix Mutex) and nothing else.
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
namespace MiscUtils {
|
|
||||||
typedef pthread_mutex_t critsect_t;
|
|
||||||
|
|
||||||
inline void init_critsect(MiscUtils::critsect_t* cs) {
|
|
||||||
pthread_mutex_init(cs, NULL);
|
|
||||||
}
|
|
||||||
inline void free_critsect(MiscUtils::critsect_t* cs) {
|
|
||||||
pthread_mutex_destroy(cs);
|
|
||||||
}
|
|
||||||
inline void enter_critsect(MiscUtils::critsect_t* cs) {
|
|
||||||
pthread_mutex_lock(cs);
|
|
||||||
}
|
|
||||||
inline void leave_critsect(MiscUtils::critsect_t* cs) {
|
|
||||||
pthread_mutex_unlock(cs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to wrap this in an object because we need to dynamically initialize
|
|
||||||
// critical section (because of windows, where there is no way to initialize
|
|
||||||
// a CRITICAL_SECTION statically. On Unix, we could use
|
|
||||||
// PTHREAD_MUTEX_INITIALIZER)
|
|
||||||
|
|
||||||
// Note: The critical section does NOT get cleaned up in the destructor. That is
|
|
||||||
// by design: the CritSect class is only ever used as global objects whose
|
|
||||||
// lifetime spans the whole VM life; in that context we don't want the lock to
|
|
||||||
// be cleaned up when global C++ objects are destroyed, but to continue to work
|
|
||||||
// correctly right to the very end of the process life.
|
|
||||||
class CritSect {
|
|
||||||
critsect_t _cs;
|
|
||||||
public:
|
|
||||||
CritSect() { init_critsect(&_cs); }
|
|
||||||
//~CritSect() { free_critsect(&_cs); }
|
|
||||||
void enter() { enter_critsect(&_cs); }
|
|
||||||
void leave() { leave_critsect(&_cs); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class AutoCritSect {
|
|
||||||
CritSect* const _pcsobj;
|
|
||||||
public:
|
|
||||||
AutoCritSect(CritSect* pcsobj)
|
|
||||||
: _pcsobj(pcsobj)
|
|
||||||
{
|
|
||||||
_pcsobj->enter();
|
|
||||||
}
|
|
||||||
~AutoCritSect() {
|
|
||||||
_pcsobj->leave();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // OS_AIX_VM_PORTING_AIX_HPP
|
#endif // OS_AIX_VM_PORTING_AIX_HPP
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue