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

   1 /*
   2  * Copyright 2012, 2013 SAP AG. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  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 
--- EOF ---