< prev index next >

src/os/aix/vm/loadlib_aix.cpp

Print this page
rev 9211 : 8140645: Recent Developments for AIX
Summary: Port recent developments from SAP for AIX to the OpenJDK


  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 
  26 // Implementation of LoadedLibraries and friends
  27 
  28 // Ultimately this just uses loadquery()
  29 // See:
  30 // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp
  31 //      ?topic=/com.ibm.aix.basetechref/doc/basetrf1/loadquery.htm
  32 
  33 #ifndef __STDC_FORMAT_MACROS
  34 #define __STDC_FORMAT_MACROS
  35 #endif
  36 // 'allocation.inline.hpp' triggers the inclusion of 'inttypes.h' which defines macros
  37 // required by the definitions in 'globalDefinitions.hpp'. But these macros in 'inttypes.h'
  38 // are only defined if '__STDC_FORMAT_MACROS' is defined!
  39 #include "memory/allocation.inline.hpp"
  40 #include "oops/oop.inline.hpp"
  41 #include "runtime/threadCritical.hpp"
  42 #include "utilities/debug.hpp"
  43 #include "utilities/ostream.hpp"
  44 #include "loadlib_aix.hpp"
  45 #include "porting_aix.hpp"


  46 
  47 // For loadquery()
  48 #include <sys/ldr.h>
  49 
  50 ///////////////////////////////////////////////////////////////////////////////
  51 // Implementation for LoadedLibraryModule























































  52 
  53 // output debug info
  54 void LoadedLibraryModule::print(outputStream* os) const {
  55   os->print("%15.15s: text: " INTPTR_FORMAT " - " INTPTR_FORMAT
  56                ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " ",
  57       shortname, text_from, text_to, data_from, data_to);
  58   os->print(" %s", fullpath);
  59   if (strlen(membername) > 0) {
  60     os->print("(%s)", membername);

  61   }
  62   os->cr();
  63 }
  64 

  65 
  66 ///////////////////////////////////////////////////////////////////////////////
  67 // Implementation for LoadedLibraries

  68 
  69 // class variables
  70 LoadedLibraryModule LoadedLibraries::tab[MAX_MODULES];
  71 int LoadedLibraries::num_loaded = 0;
  72 
  73 // Checks whether the address p points to any of the loaded code segments.
  74 // If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
  75 // static
  76 const LoadedLibraryModule* LoadedLibraries::find_for_text_address(const unsigned char* p) {
  77 
  78   if (num_loaded == 0) {
  79     reload();
  80   }
  81   for (int i = 0; i < num_loaded; i++) {
  82     if (tab[i].is_in_text(p)) {
  83       return &tab[i];
















  84     }
  85   }
  86   return NULL;
  87 }
  88 
  89 // Checks whether the address p points to any of the loaded data segments.
  90 // If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
  91 // static
  92 const LoadedLibraryModule* LoadedLibraries::find_for_data_address(const unsigned char* p) {
  93   if (num_loaded == 0) {
  94     reload();
  95   }
  96   for (int i = 0; i < num_loaded; i++) {
  97     if (tab[i].is_in_data(p)) {
  98       return &tab[i];
  99     }
 100   }
 101   return NULL;
 102 }
 103 
 104 // Rebuild the internal table of LoadedLibraryModule objects
 105 // static
 106 void LoadedLibraries::reload() {
 107 
 108   ThreadCritical cs;










 109 
 110   // discard old content
 111   num_loaded = 0;







 112 
 113   // Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX.
 114   size_t buf_size = 4096;
 115   char* loadquery_buf = AllocateHeap(buf_size, mtInternal);
 116 
 117   while(loadquery(L_GETINFO, loadquery_buf, buf_size) == -1) {






















 118     if (errno == ENOMEM) {
 119       buf_size *= 2;
 120       loadquery_buf = ReallocateHeap(loadquery_buf, buf_size, mtInternal);
 121     } else {
 122       FreeHeap(loadquery_buf);
 123       // Ensure that the uintptr_t pointer is valid
 124       assert(errno != EFAULT, "loadquery: Invalid uintptr_t in info buffer.");
 125       fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno));
 126       return;
 127     }
 128   }
 129 
 130   // Iterate over the loadquery result. For details see sys/ldr.h on AIX.
 131   const struct ld_info* p = (struct ld_info*) loadquery_buf;
 132 
 133   // Ensure we have all loaded libs.
 134   bool all_loaded = false;
 135   while(num_loaded < MAX_MODULES) {
 136     LoadedLibraryModule& mod = tab[num_loaded];
 137     mod.text_from = (const unsigned char*) p->ldinfo_textorg;
 138     mod.text_to   = (const unsigned char*) (((char*)p->ldinfo_textorg) + p->ldinfo_textsize);
 139     mod.data_from = (const unsigned char*) p->ldinfo_dataorg;
 140     mod.data_to   = (const unsigned char*) (((char*)p->ldinfo_dataorg) + p->ldinfo_datasize);
 141     sprintf(mod.fullpath, "%.*s", sizeof(mod.fullpath), p->ldinfo_filename);
 142     // do we have a member name as well (see ldr.h)?
 143     const char* p_mbr_name = p->ldinfo_filename + strlen(p->ldinfo_filename) + 1;
 144     if (*p_mbr_name) {
 145       sprintf(mod.membername, "%.*s", sizeof(mod.membername), p_mbr_name);
















 146     } else {
 147       mod.membername[0] = '\0';

 148     }
 149 
 150     // fill in the short name
 151     const char* p_slash = strrchr(mod.fullpath, '/');
 152     if (p_slash) {
 153       sprintf(mod.shortname, "%.*s", sizeof(mod.shortname), p_slash + 1);





 154     } else {
 155       sprintf(mod.shortname, "%.*s", sizeof(mod.shortname), mod.fullpath);
 156     }
 157     num_loaded ++;

















 158 
 159     // next entry...
 160     if (p->ldinfo_next) {
 161       p = (struct ld_info*)(((char*)p) + p->ldinfo_next);
 162     } else {
 163       all_loaded = true;
 164       break;
 165     }
 166   }
 167 
 168   FreeHeap(loadquery_buf);







 169 
 170   // Ensure we have all loaded libs
 171   assert(all_loaded, "loadquery returned more entries then expected. Please increase MAX_MODULES");







 172 
 173 } // end LoadedLibraries::reload()
 174 
 175 
 176 // output loaded libraries table
 177 //static










 178 void LoadedLibraries::print(outputStream* os) {









 179 
 180   for (int i = 0; i < num_loaded; i++) {
 181     tab[i].print(os);












 182   }



 183 
















 184 }
 185 


  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 
  26 // Implementation of LoadedLibraries and friends
  27 
  28 // Ultimately this just uses loadquery()
  29 // See:
  30 // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp
  31 //      ?topic=/com.ibm.aix.basetechref/doc/basetrf1/loadquery.htm
  32 
  33 #ifndef __STDC_FORMAT_MACROS
  34 #define __STDC_FORMAT_MACROS
  35 #endif
  36 
  37 #include "porting_aix.hpp"




  38 #include "utilities/debug.hpp"
  39 #include "utilities/ostream.hpp"
  40 #include "loadlib_aix.hpp"
  41 
  42 // for CritSect
  43 #include "misc_aix.hpp"
  44 
  45 // For loadquery()
  46 #include <sys/ldr.h>
  47 
  48 #define trcVerbose(...)
  49 //#define trcVerbose(...) { \
  50 //  if (Verbose) { \
  51 //    printf(__VA_ARGS__); \
  52 //    puts(""); \
  53 //    fflush(stdout); \
  54 //  } \
  55 //}
  56 
  57 // Use raw malloc instead of os::malloc - this code gets used for error reporting.
  58 
  59 // A class to "intern" eternal strings.
  60 // TODO: similar coding exists in AIX vcersion of dladdr and potentially elsewhere: consolidate!
  61 class StringList {
  62 
  63   char** _list;
  64   int _cap;
  65   int _num;
  66 
  67   // enlarge list. If oom, leave old list intact and return false.
  68   bool enlarge() {
  69     int cap2 = _cap + 64;
  70     char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2);
  71     if (!l2) {
  72       return false;
  73     }
  74     _list = l2;
  75     _cap = cap2;
  76     return true;
  77   }
  78 
  79   // append string to end of list
  80   // returns NULL if oom
  81   char* append(const char* s) {
  82     if (_cap == _num) {
  83       if (!enlarge()) {
  84         return NULL;
  85       }
  86     }
  87     assert0(_cap > _num);
  88     char* s2 = ::strdup(s);
  89     if (!s2) {
  90       return NULL;
  91     }
  92     _list[_num] = s2;
  93     trcVerbose("StringDir: added %s at pos %d", s2, _num);
  94     _num ++;
  95     return s2;
  96   }
  97 
  98 public:
  99 
 100   StringList()
 101     : _list(NULL)
 102     , _cap(0)
 103     , _num(0)
 104   {}
 105 
 106   // string is copied into the list; pointer to copy is returned.
 107   // returns NULL if oom.
 108   char* add (const char* s) {
 109     for (int i = 0; i < _num; i ++) {
 110       if (strcmp(_list[i], s) == 0) {
 111         return _list[i];
 112       }
 113     }
 114     return append(s);
 115   }


 116 
 117 };
 118 
 119 static StringList g_stringlist;
 120 
 121 //////////////////////
 122 
 123 // Entries are kept in a linked list ordered by text address. Entries are not
 124 // eternal - this list is rebuilt on every reload.
 125 // Note that we do not hand out those entries, but copies of them.
 126 
 127 struct entry_t {
 128   entry_t* next;
 129   loaded_module_t info;
 130 };
 131 
 132 static void print_entry(const entry_t* e, outputStream* os) {
 133   const loaded_module_t* const lm = &(e->info);
 134   os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT
 135             ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " "
 136             "%s",
 137       (lm->is_in_vm ? '*' : ' '),
 138       lm->text, (uintptr_t)lm->text + lm->text_len,
 139       lm->data, (uintptr_t)lm->data + lm->data_len,
 140       lm->path);
 141   if (lm->member) {
 142     os->print("(%s)", lm->member);
 143   }
 144 
 145 }
 146 
 147 static entry_t* g_first = NULL;
 148 
 149 static entry_t* find_entry_for_text_address(const void* p) {
 150   for (entry_t* e = g_first; e; e = e->next) {
 151     if ( (uintptr_t)p >= (uintptr_t)e->info.text &&
 152          (uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len) ) {
 153       return e;
 154     }
 155   }
 156   return NULL;
 157 }
 158 
 159 static entry_t* find_entry_for_data_address(const void* p) {
 160   for (entry_t* e = g_first; e; e = e->next) {
 161     if ( (uintptr_t)p >= (uintptr_t)e->info.data &&
 162          (uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len) ) {
 163       return e;





 164     }
 165   }
 166   return NULL;
 167 }
 168 
 169 // adds a new entry to the list (ordered by text address ascending)
 170 static void add_entry_to_list(entry_t* e, entry_t** start) {
 171   entry_t* last = NULL;
 172   entry_t* e2 = *start;
 173   while (e2 && e2->info.text < e->info.text) {
 174     last = e2;
 175     e2 = e2->next;
 176   }
 177   if (last) {
 178     last->next = e;
 179   } else {
 180     *start = e;
 181   }
 182   e->next = e2;
 183 }
 184 
 185 static void free_entry_list(entry_t** start) {
 186   entry_t* e = *start;
 187   while (e) {
 188     entry_t* const e2 = e->next;
 189     ::free(e);
 190     e = e2;
 191   }
 192   *start = NULL;
 193 }
 194 



 195 
 196 // rebuild the internal module table. If an error occurs, old table remains
 197 // unchanged.
 198 static bool reload_table() {
 199 
 200   bool rc = false;
 201 
 202   trcVerbose("reload module table...");
 203 
 204   entry_t* new_list = NULL;
 205   const struct ld_info* ldi = NULL;
 206 
 207   // call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery
 208   // requires a large enough buffer.
 209   uint8_t* buffer = NULL;
 210   size_t buflen =
 211 #ifdef ASSERT
 212     64;
 213 #else
 214     1024;
 215 #endif
 216   for (;;) {
 217     buffer = (uint8_t*) ::realloc(buffer, buflen);
 218     if (loadquery(L_GETINFO, buffer, buflen) == -1) {
 219       if (errno == ENOMEM) {
 220         buflen *= 2;

 221       } else {
 222         trcVerbose("loadquery failed (%d)", errno);
 223         goto cleanup;
 224       }
 225     } else {
 226       break;
 227     }
 228   }
 229 
 230   trcVerbose("loadquery buffer size is %llu.", buflen);
 231 
 232   // iterate over the loadquery result. For details see sys/ldr.h on AIX.
 233   ldi = (struct ld_info*) buffer;
 234 
 235   for (;;) {
 236 
 237     entry_t* e = (entry_t*) ::malloc(sizeof(entry_t));
 238     if (!e) {
 239       trcVerbose("OOM.");
 240       goto cleanup;
 241     }
 242 
 243     memset(e, 0, sizeof(entry_t));
 244 
 245     e->info.text = ldi->ldinfo_textorg;
 246     e->info.text_len = ldi->ldinfo_textsize;
 247     e->info.data = ldi->ldinfo_dataorg;
 248     e->info.data_len = ldi->ldinfo_datasize;
 249 
 250     e->info.path = g_stringlist.add(ldi->ldinfo_filename);
 251     if (!e->info.path) {
 252       trcVerbose("OOM.");
 253       goto cleanup;
 254     }
 255 
 256     // extract short name
 257     {
 258       const char* p = strrchr(e->info.path, '/');
 259       if (p) {
 260         p ++;
 261         e->info.shortname = p;
 262       } else {
 263         e->info.shortname = e->info.path;
 264       }
 265     }
 266 
 267     // do we have a member name as well (see ldr.h)?
 268     const char* p_mbr_name =
 269       ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1;
 270     if (*p_mbr_name) {
 271       e->info.member = g_stringlist.add(p_mbr_name);
 272       if (!e->info.member) {
 273         trcVerbose("OOM.");
 274         goto cleanup;
 275       }
 276     } else {
 277       e->info.member = NULL;
 278     }
 279 
 280     if (strcmp(e->info.shortname, "libjvm.so") == 0) {
 281       // note that this, theoretically, is fuzzy. We may accidentally contain
 282       // more than one libjvm.so. But that is improbable, so lets go with this
 283       // solution.
 284       e->info.is_in_vm = true;
 285     }
 286 
 287     trcVerbose("entry: %p %llu, %p %llu, %s %s %s, %d",
 288       e->info.text, e->info.text_len,
 289       e->info.data, e->info.data_len,
 290       e->info.path, e->info.shortname,
 291       (e->info.member ? e->info.member : "NULL"),
 292       e->info.is_in_vm
 293     );
 294 
 295     // add to list
 296     add_entry_to_list(e, &new_list);
 297 
 298     // next entry...
 299     if (ldi->ldinfo_next) {
 300       ldi = (struct ld_info*)(((char*)ldi) + ldi->ldinfo_next);
 301     } else {

 302       break;
 303     }
 304   }
 305 
 306   // we are done. All is well. Free old list and swap to new one.
 307   if (g_first) {
 308     free_entry_list(&g_first);
 309   }
 310   g_first = new_list;
 311   new_list = NULL;
 312 
 313   rc = true;
 314 
 315 cleanup:
 316 
 317   if (new_list) {
 318     free_entry_list(&new_list);
 319   }
 320 
 321   ::free(buffer);
 322 
 323   return rc;
 324 
 325 } // end LoadedLibraries::reload()
 326 
 327 
 328 ///////////////////////////////////////////////////////////////////////////////
 329 // Externals
 330 
 331 static MiscUtils::CritSect g_cs;
 332 
 333 // rebuild the internal module table. If an error occurs, old table remains
 334 // unchanged.
 335 bool LoadedLibraries::reload() {
 336   MiscUtils::AutoCritSect lck(&g_cs);
 337   return reload_table();
 338 }
 339 
 340 void LoadedLibraries::print(outputStream* os) {
 341   MiscUtils::AutoCritSect lck(&g_cs);
 342   if (!g_first) {
 343     reload_table();
 344   }
 345   for (entry_t* e = g_first; e; e = e->next) {
 346     print_entry(e, os);
 347     os->cr();
 348   }
 349 }
 350 
 351 
 352 bool LoadedLibraries::find_for_text_address (
 353   const void* p, loaded_module_t* info
 354 ) {
 355   MiscUtils::AutoCritSect lck(&g_cs);
 356   if (!g_first) {
 357     reload_table();
 358   }
 359   const entry_t* const e = find_entry_for_text_address(p);
 360   if (e) {
 361     if (info) {
 362       *info = e->info;
 363     }
 364     return true;
 365   }
 366   return false;
 367 }
 368 
 369 
 370 bool LoadedLibraries::find_for_data_address (
 371   const void* p,
 372   loaded_module_t* info // optional. can be NULL:
 373 ) {
 374   MiscUtils::AutoCritSect lck(&g_cs);
 375   if (!g_first) {
 376     reload_table();
 377   }
 378   const entry_t* const e = find_entry_for_data_address(p);
 379   if (e) {
 380     if (info) {
 381       *info = e->info;
 382     }
 383     return true;
 384   }
 385   return false;
 386 }
 387 
< prev index next >