changeset 9665:4338b5465f50

8140645: Recent Developments for AIX Summary: Port recent developments from SAP for AIX to the OpenJDK Reviewed-by: goetz
author stuefe
date Fri, 30 Oct 2015 12:36:54 +0100
parents b390353dd19e
children 69e84ea906d5 797a0f7a8631
files src/cpu/ppc/vm/ppc.ad src/os/aix/vm/loadlib_aix.cpp src/os/aix/vm/loadlib_aix.hpp src/os/aix/vm/misc_aix.cpp src/os/aix/vm/misc_aix.hpp src/os/aix/vm/os_aix.cpp src/os/aix/vm/porting_aix.cpp src/os/aix/vm/porting_aix.hpp
diffstat 8 files changed, 592 insertions(+), 359 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/ppc/vm/ppc.ad	Mon Nov 02 09:13:39 2015 +0100
+++ b/src/cpu/ppc/vm/ppc.ad	Fri Oct 30 12:36:54 2015 +0100
@@ -5572,7 +5572,6 @@
 
 instruct loadN2P_klass_unscaled(iRegPdst dst, memory mem) %{
   match(Set dst (DecodeNKlass (LoadNKlass mem)));
-  // SAPJVM GL 2014-05-21 Differs.
   predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0 &&
             _kids[0]->_leaf->as_Load()->is_unordered());
   ins_cost(MEMORY_REF_COST);
@@ -10949,7 +10948,7 @@
     // TODO: PPC port $archOpcode(ppc64Opcode_compound);
     __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$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'.
     // The compiler generates a branch to the runtime call to
     // _complete_monitor_locking_Java for the case where crx is 'NE'.
--- a/src/os/aix/vm/loadlib_aix.cpp	Mon Nov 02 09:13:39 2015 +0100
+++ b/src/os/aix/vm/loadlib_aix.cpp	Fri Oct 30 12:36:54 2015 +0100
@@ -33,153 +33,337 @@
 #ifndef __STDC_FORMAT_MACROS
 #define __STDC_FORMAT_MACROS
 #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'
-// are only defined if '__STDC_FORMAT_MACROS' is defined!
-#include "memory/allocation.inline.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/threadCritical.hpp"
+
+#include "loadlib_aix.hpp"
+// for CritSect
+#include "misc_aix.hpp"
+#include "porting_aix.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/ostream.hpp"
-#include "loadlib_aix.hpp"
-#include "porting_aix.hpp"
 
 // For loadquery()
 #include <sys/ldr.h>
 
-///////////////////////////////////////////////////////////////////////////////
-// Implementation for LoadedLibraryModule
+// Use raw malloc instead of os::malloc - this code gets used for error reporting.
 
-// output debug info
-void LoadedLibraryModule::print(outputStream* os) const {
-  os->print("%15.15s: text: " INTPTR_FORMAT " - " INTPTR_FORMAT
-               ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " ",
-      shortname, text_from, text_to, data_from, data_to);
-  os->print(" %s", fullpath);
-  if (strlen(membername) > 0) {
-    os->print("(%s)", membername);
+// A class to "intern" eternal strings.
+// TODO: similar coding exists in AIX version of dladdr and potentially elsewhere: consolidate!
+class StringList {
+
+  char** _list;
+  int _cap;
+  int _num;
+
+  // 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;
+    }
+    _list = l2;
+    _cap = cap2;
+    return true;
   }
-  os->cr();
+
+  // Append string to end of list.
+  // Returns NULL if oom.
+  char* append(const char* s) {
+    if (_cap == _num) {
+      if (!enlarge()) {
+        return NULL;
+      }
+    }
+    assert0(_cap > _num);
+    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;
 
-///////////////////////////////////////////////////////////////////////////////
-// Implementation for LoadedLibraries
-
-// class variables
-LoadedLibraryModule LoadedLibraries::tab[MAX_MODULES];
-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)) {
-      return &tab[i];
+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;
 }
 
-// Checks whether the address p points to any of the loaded data segments.
-// If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
-// static
-const LoadedLibraryModule* LoadedLibraries::find_for_data_address(const unsigned char* p) {
-  if (num_loaded == 0) {
-    reload();
-  }
-  for (int i = 0; i < num_loaded; i++) {
-    if (tab[i].is_in_data(p)) {
-      return &tab[i];
+static entry_t* find_entry_for_data_address(const void* p) {
+  for (entry_t* e = g_first; e; e = e->next) {
+    if ((uintptr_t)p >= (uintptr_t)e->info.data &&
+        (uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) {
+      return e;
     }
   }
   return NULL;
 }
 
-// Rebuild the internal table of LoadedLibraryModule objects
-// static
-void LoadedLibraries::reload() {
+// Adds a new entry to the list (ordered by text address ascending).
+static void add_entry_to_list(entry_t* e, entry_t** start) {
+  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.
-  size_t buf_size = 4096;
-  char* loadquery_buf = AllocateHeap(buf_size, mtInternal);
+// Rebuild the internal module table. If an error occurs, old table remains
+// unchanged.
+static bool reload_table() {
 
-  while(loadquery(L_GETINFO, loadquery_buf, buf_size) == -1) {
-    if (errno == ENOMEM) {
-      buf_size *= 2;
-      loadquery_buf = ReallocateHeap(loadquery_buf, buf_size, mtInternal);
+  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) {
+        buflen *= 2;
+      } else {
+        trcVerbose("loadquery failed (%d)", errno);
+        goto cleanup;
+      }
     } else {
-      FreeHeap(loadquery_buf);
-      // Ensure that the uintptr_t pointer is valid
-      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 {
-      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;
     }
   }
 
-  FreeHeap(loadquery_buf);
+  trcVerbose("loadquery buffer size is %llu.", buflen);
 
-  // Ensure we have all loaded libs
-  assert(all_loaded, "loadquery returned more entries then expected. Please increase MAX_MODULES");
+  // Iterate over the loadquery result. For details see sys/ldr.h on AIX.
+  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()
 
 
-// output loaded libraries table
-//static
-void LoadedLibraries::print(outputStream* os) {
+///////////////////////////////////////////////////////////////////////////////
+// Externals
 
-  for (int i = 0; i < num_loaded; i++) {
-    tab[i].print(os);
-  }
+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) {
+  MiscUtils::AutoCritSect lck(&g_cs);
+  if (!g_first) {
+    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;
+}
+
--- a/src/os/aix/vm/loadlib_aix.hpp	Mon Nov 02 09:13:39 2015 +0100
+++ b/src/os/aix/vm/loadlib_aix.hpp	Fri Oct 30 12:36:54 2015 +0100
@@ -26,73 +26,47 @@
 // Loadlib_aix.cpp contains support code for analysing the memory
 // layout of loaded binaries in ones own process space.
 //
-// It is needed, among other things, to provide a  dladdr() emulation, because
-// that one is not provided by AIX
+// It is needed, among other things, to provide dladdr(3), which is
+// missing on AIX.
 
 #ifndef OS_AIX_VM_LOADLIB_AIX_HPP
 #define OS_AIX_VM_LOADLIB_AIX_HPP
 
+#include <stddef.h>
+
 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
-// 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).
-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
-    char shortname[30];  // eg libC.a
-    char membername[30]; // eg shrcore_64.o
-    const unsigned char* text_from;
-    const unsigned char* text_to;
-    const unsigned char* data_from;
-    const unsigned char* data_to;
+  // Points to the full path of the lodaed module, e.g.
+  // "/usr/lib/libC.a".
+  const char* path;
 
-  public:
+  // Host library name without path
+  const char* shortname;
 
-    const char* get_fullpath() const {
-      return fullpath;
-    }
-    const char* get_shortname() const {
-      return shortname;
-    }
-    const char* get_membername() const {
-      return membername;
-    }
+  // Points to the object file (AIX specific stuff)
+  // e.g "shrcore_64.o".
+  const char* member;
 
-    // text_from, text_to: returns the range of the text (code)
-    // segment for that module
-    const unsigned char* get_text_from() const {
-      return text_from;
-    }
-    const unsigned char* get_text_to() const {
-      return text_to;
-    }
+  // Text area from, to
+  const void* text;
+  size_t text_len;
 
-    // data_from/data_to: returns the range of the data
-    // segment for that module
-    const unsigned char* get_data_from() const {
-      return data_from;
-    }
-    const unsigned char* get_data_to() const {
-      return data_to;
-    }
+  // Data area from, to
+  const void* data;
+  size_t data_len;
 
-    // returns true if the
-    bool is_in_text(const unsigned char* p) const {
-      return p >= text_from && p < text_to ? true : false;
-    }
+  // True if this module is part of the vm.
+  bool is_in_vm;
 
-    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
 // in the AIX process space.
@@ -100,29 +74,31 @@
 // : AllStatic (including allocation.hpp just for AllStatic is overkill.)
 {
 
-  private:
-
-    enum {MAX_MODULES = 100};
-    static LoadedLibraryModule tab[MAX_MODULES];
-    static int num_loaded;
-
   public:
 
-    // rebuild the internal table of LoadedLibraryModule objects
-    static void reload();
+    // Rebuild the internal module table. If an error occurs, internal module
+    // table remains untouched.
+    static bool reload();
 
-    // 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* find_for_text_address(const  unsigned char* p);
+    // Check whether the given address points into the text segment of a
+    // loaded module. Return true if this is the case.
+    // 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.
-    // If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
-    static const LoadedLibraryModule* find_for_data_address(const  unsigned char* p);
+    // Check whether the given address points into the data segment of a
+    // loaded module. Return true if this is the case.
+    // 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);
 
-}; // end LoadedLibraries
-
+};
 
 #endif // OS_AIX_VM_LOADLIB_AIX_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/aix/vm/misc_aix.cpp	Fri Oct 30 12:36:54 2015 +0100
@@ -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);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/aix/vm/misc_aix.hpp	Fri Oct 30 12:36:54 2015 +0100
@@ -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
+
--- a/src/os/aix/vm/os_aix.cpp	Mon Nov 02 09:13:39 2015 +0100
+++ b/src/os/aix/vm/os_aix.cpp	Fri Oct 30 12:36:54 2015 +0100
@@ -40,6 +40,7 @@
 #include "loadlib_aix.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/filemap.hpp"
+#include "misc_aix.hpp"
 #include "mutex_aix.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "os_aix.inline.hpp"
@@ -159,23 +160,10 @@
 #define PV_8_Compat 0x308000   /* Power PC 8 */
 #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.
 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) {
   if (((uintptr_t)sp) & 0x7) {
     return false;
@@ -189,7 +177,7 @@
   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) {
   if (!p) {
     return false;
@@ -197,7 +185,7 @@
   if (((uintptr_t)p) & 0x3) {
     return false;
   }
-  if (LoadedLibraries::find_for_text_address((address)p) == NULL) {
+  if (!LoadedLibraries::find_for_text_address(p, NULL)) {
     return false;
   }
   return true;
@@ -1387,26 +1375,15 @@
 
   // 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.
-
-  const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(addr);
-  if (lib) {
-    if (strcmp(lib->get_shortname(), "libjvm.so") == 0) {
-      return true;
-    } else {
-      return false;
-    }
+  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 {
-    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;
-    }
-  }
+    return false;
+  }
+
 }
 
 // Resolve an AIX function descriptor literal to a code pointer.
@@ -1418,21 +1395,18 @@
 //   NULL is returned.
 static address resolve_function_descriptor_to_code_pointer(address p) {
 
-  const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(p);
-  if (lib) {
-    // its a real code pointer
+  if (LoadedLibraries::find_for_text_address(p, NULL) != NULL) {
+    // It is a real code pointer.
     return p;
-  } else {
-    lib = LoadedLibraries::find_for_data_address(p);
-    if (lib) {
-      // pointer to data segment, potential function descriptor
-      address code_entry = (address)(((FunctionDescriptor*)p)->entry());
-      if (LoadedLibraries::find_for_text_address(code_entry)) {
-        // Its a function descriptor
-        return code_entry;
-      }
+  } else if (LoadedLibraries::find_for_data_address(p, NULL) != NULL) {
+    // Pointer to data segment, potential function descriptor.
+    address code_entry = (address)(((FunctionDescriptor*)p)->entry());
+    if (LoadedLibraries::find_for_text_address(code_entry, NULL) != NULL) {
+      // It is a function descriptor.
+      return code_entry;
     }
   }
+
   return NULL;
 }
 
@@ -1461,7 +1435,6 @@
                          char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
                          ) {
 
-  // initialize output parameters
   if (p_name && namelen > 0) {
     *p_name = '\0';
   }
@@ -1469,16 +1442,15 @@
     *p_errmsg = '\0';
   }
 
-  const LoadedLibraryModule* const lib = LoadedLibraries::find_for_text_address((address)pc);
-  if (lib) {
-    if (p_name && namelen > 0) {
-      sprintf(p_name, "%.*s", namelen, lib->get_shortname());
+  if (p_name && namelen > 0) {
+    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;
   }
 
-  trcVerbose("pc outside any module");
-
   return -1;
 }
 
@@ -3781,18 +3753,11 @@
 
   st->print(PTR_FORMAT ": ", addr);
 
-  const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(addr);
-  if (lib) {
-    lib->print(st);
+  loaded_module_t lm;
+  if (LoadedLibraries::find_for_text_address(addr, &lm) != NULL ||
+      LoadedLibraries::find_for_data_address(addr, &lm) != NULL) {
+    st->print("%s", lm.path);
     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;
--- a/src/os/aix/vm/porting_aix.cpp	Mon Nov 02 09:13:39 2015 +0100
+++ b/src/os/aix/vm/porting_aix.cpp	Fri Oct 30 12:36:54 2015 +0100
@@ -23,11 +23,13 @@
  */
 
 #include "asm/assembler.hpp"
+#include "loadlib_aix.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
+// For CritSect
+#include "misc_aix.hpp"
+#include "porting_aix.hpp"
 #include "runtime/os.hpp"
-#include "loadlib_aix.hpp"
-#include "porting_aix.hpp"
 #include "utilities/debug.hpp"
 
 #include <demangle.h>
@@ -45,23 +47,6 @@
 
 #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
 // responsible for maintaining memory for function name/library
 // name. I guess this is because most OS's keep those values as part
@@ -139,18 +124,37 @@
     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;
 
-  // make sure the pointer is word aligned.
+  // Make sure the pointer is word aligned.
   pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
+  CHECK_POINTER_READABLE(pc2)
 
   // Find start of traceback table.
   // (starts after code, is marked by word-aligned (32bit) zeros)
   while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
+    CHECK_POINTER_READABLE(pc2)
     pc2++;
   }
   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
@@ -162,7 +166,7 @@
   if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
     // Language specifiers, go from 0 (C) to 14 (Objective C).
     // 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
@@ -173,6 +177,8 @@
   if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
     pc2++;
 
+  CHECK_POINTER_READABLE(pc2)
+
   if (tb->tb.has_tboff == TRUE) {
 
     // I want to know the displacement
@@ -182,7 +188,7 @@
 
     // Weed out the cases where we did find the wrong traceback table.
     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
@@ -204,15 +210,24 @@
   if (tb->tb.has_ctl == TRUE)
     pc2 += (*pc2) + 1; // don't care
 
+  CHECK_POINTER_READABLE(pc2)
+
   //
   // return function name if it exists.
   //
   if (p_name && namelen > 0) {
     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];
       const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
-      memcpy(buf, (char*)pc2 + sizeof(short), l);
-      buf[l] = '\0';
+      // Be very careful.
+      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';
 
@@ -275,7 +290,8 @@
   info->dli_saddr = NULL;
 
   address p = (address) addr;
-  const LoadedLibraryModule* lib = NULL;
+  loaded_module_t lm;
+  bool found = false;
 
   enum { noclue, code, data } type = noclue;
 
@@ -284,28 +300,28 @@
   // 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.
   // (see ppc64 ABI)
-  lib = LoadedLibraries::find_for_text_address(p);
-  if (lib) {
+  found = LoadedLibraries::find_for_text_address(p, &lm);
+  if (found) {
     type = code;
   }
 
-  if (!lib) {
+  if (!found) {
     // Not a pointer into any text segment. Is it a function descriptor?
     const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
     p = pfd->entry();
     if (p) {
-      lib = LoadedLibraries::find_for_text_address(p);
-      if (lib) {
+      found = LoadedLibraries::find_for_text_address(p, &lm);
+      if (found) {
         type = code;
       }
     }
   }
 
-  if (!lib) {
+  if (!found) {
     // Neither direct code pointer nor function descriptor. A data ptr?
     p = (address)addr;
-    lib = LoadedLibraries::find_for_data_address(p);
-    if (lib) {
+    found = LoadedLibraries::find_for_data_address(p, &lm);
+    if (found) {
       type = data;
     }
   }
@@ -313,12 +329,10 @@
   // If we did find the shared library this address belongs to (either
   // code or data segment) resolve library path and, if possible, the
   // symbol name.
-  if (lib) {
-    const char* const interned_libpath =
-      dladdr_fixed_strings.intern(lib->get_fullpath());
-    if (interned_libpath) {
-      info->dli_fname = interned_libpath;
-    }
+  if (found) {
+
+    // No need to intern the libpath, that one is already interned one layer below.
+    info->dli_fname = lm.path;
 
     if (type == code) {
 
@@ -328,7 +342,7 @@
       int displacement = 0;
 
       if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
-                      NULL, NULL, 0, true /* demangle */) == 0) {
+                      NULL, NULL, 0, false) == 0) {
         if (funcname[0] != '\0') {
           const char* const interned = dladdr_fixed_strings.intern(funcname);
           info->dli_sname = interned;
--- a/src/os/aix/vm/porting_aix.hpp	Mon Nov 02 09:13:39 2015 +0100
+++ b/src/os/aix/vm/porting_aix.hpp	Fri Oct 30 12:36:54 2015 +0100
@@ -27,13 +27,6 @@
 
 #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
 // home anywhere else and which can not go into os_<platform>.h because
 // that header is included inside the os class definition, hence all
@@ -68,13 +61,9 @@
 #endif
 int dladdr(void *addr, Dl_info *info);
 
+typedef unsigned int* codeptr_t;
 
-// 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;
+struct tbtable;
 
 // 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
@@ -87,65 +76,9 @@
       char* p_name, size_t namelen,    // [out] optional: user provided buffer for the function name
       int* p_displacement,             // [out] optional: displacement
       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
-      bool demangle = true             // [in] whether to demangle the name
+      char* p_errmsg, size_t errmsglen, // [out] optional: user provided buffer for error messages
+      bool demangle                    // [in] whether to demangle the name
     );
 
-// -------------------------------------------------------------------------
+#endif // OS_AIX_VM_PORTING_AIX_HPP
 
-// 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