rev 9449 : 8143125-Further Developments for AIX

   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 "loadlib_aix.hpp"
  38 // for CritSect
  39 #include "misc_aix.hpp"
  40 #include "porting_aix.hpp"
  41 #include "utilities/debug.hpp"
  42 #include "utilities/ostream.hpp"
  43 
  44 // For loadquery()
  45 #include <sys/ldr.h>
  46 
  47 // Use raw malloc instead of os::malloc - this code gets used for error reporting.
  48 
  49 // A class to "intern" eternal strings.
  50 // TODO: similar coding exists in AIX version of dladdr and potentially elsewhere: consolidate!
  51 class StringList {
  52 
  53   char** _list;
  54   int _cap;
  55   int _num;
  56 
  57   // Enlarge list. If oom, leave old list intact and return false.
  58   bool enlarge() {
  59     int cap2 = _cap + 64;
  60     char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2);
  61     if (!l2) {
  62       return false;
  63     }
  64     _list = l2;
  65     _cap = cap2;
  66     return true;
  67   }
  68 
  69   // Append string to end of list.
  70   // Returns NULL if oom.
  71   char* append(const char* s) {
  72     if (_cap == _num) {
  73       if (!enlarge()) {
  74         return NULL;
  75       }
  76     }
  77     assert0(_cap > _num);
  78     char* s2 = ::strdup(s);
  79     if (!s2) {
  80       return NULL;
  81     }
  82     _list[_num] = s2;
  83     trcVerbose("StringDir: added %s at pos %d", s2, _num);
  84     _num ++;
  85     return s2;
  86   }
  87 
  88 public:
  89 
  90   StringList()
  91     : _list(NULL)
  92     , _cap(0)
  93     , _num(0)
  94   {}
  95 
  96   // String is copied into the list; pointer to copy is returned.
  97   // Returns NULL if oom.
  98   char* add (const char* s) {
  99     for (int i = 0; i < _num; i++) {
 100       if (strcmp(_list[i], s) == 0) {
 101         return _list[i];
 102       }
 103     }
 104     return append(s);
 105   }
 106 
 107 };
 108 
 109 static StringList g_stringlist;
 110 
 111 //////////////////////
 112 
 113 // Entries are kept in a linked list ordered by text address. Entries are not
 114 // eternal - this list is rebuilt on every reload.
 115 // Note that we do not hand out those entries, but copies of them.
 116 
 117 struct entry_t {
 118   entry_t* next;
 119   loaded_module_t info;
 120 };
 121 
 122 static void print_entry(const entry_t* e, outputStream* os) {
 123   const loaded_module_t* const lm = &(e->info);
 124   os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT
 125             ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " "
 126             "%s",
 127       (lm->is_in_vm ? '*' : ' '),
 128       lm->text, (uintptr_t)lm->text + lm->text_len,
 129       lm->data, (uintptr_t)lm->data + lm->data_len,
 130       lm->path);
 131   if (lm->member) {
 132     os->print("(%s)", lm->member);
 133   }
 134 }
 135 
 136 static entry_t* g_first = NULL;
 137 
 138 static entry_t* find_entry_for_text_address(const void* p) {
 139   for (entry_t* e = g_first; e; e = e->next) {
 140     if ((uintptr_t)p >= (uintptr_t)e->info.text &&
 141         (uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len)) {
 142       return e;
 143     }
 144   }
 145   return NULL;
 146 }
 147 
 148 static entry_t* find_entry_for_data_address(const void* p) {
 149   for (entry_t* e = g_first; e; e = e->next) {
 150     if ((uintptr_t)p >= (uintptr_t)e->info.data &&
 151         (uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) {
 152       return e;
 153     }
 154   }
 155   return NULL;
 156 }
 157 
 158 // Adds a new entry to the list (ordered by text address ascending).
 159 static void add_entry_to_list(entry_t* e, entry_t** start) {
 160   entry_t* last = NULL;
 161   entry_t* e2 = *start;
 162   while (e2 && e2->info.text < e->info.text) {
 163     last = e2;
 164     e2 = e2->next;
 165   }
 166   if (last) {
 167     last->next = e;
 168   } else {
 169     *start = e;
 170   }
 171   e->next = e2;
 172 }
 173 
 174 static void free_entry_list(entry_t** start) {
 175   entry_t* e = *start;
 176   while (e) {
 177     entry_t* const e2 = e->next;
 178     ::free(e);
 179     e = e2;
 180   }
 181   *start = NULL;
 182 }
 183 
 184 
 185 // Rebuild the internal module table. If an error occurs, old table remains
 186 // unchanged.
 187 static bool reload_table() {
 188 
 189   bool rc = false;
 190 
 191   trcVerbose("reload module table...");
 192 
 193   entry_t* new_list = NULL;
 194   const struct ld_info* ldi = NULL;
 195 
 196   // Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery
 197   // requires a large enough buffer.
 198   uint8_t* buffer = NULL;
 199   size_t buflen = 1024;
 200   for (;;) {
 201     buffer = (uint8_t*) ::realloc(buffer, buflen);
 202     if (loadquery(L_GETINFO, buffer, buflen) == -1) {
 203       if (errno == ENOMEM) {
 204         buflen *= 2;
 205       } else {
 206         trcVerbose("loadquery failed (%d)", errno);
 207         goto cleanup;
 208       }
 209     } else {
 210       break;
 211     }
 212   }
 213 
 214   trcVerbose("loadquery buffer size is %llu.", buflen);
 215 
 216   // Iterate over the loadquery result. For details see sys/ldr.h on AIX.
 217   ldi = (struct ld_info*) buffer;
 218 
 219   for (;;) {
 220 
 221     entry_t* e = (entry_t*) ::malloc(sizeof(entry_t));
 222     if (!e) {
 223       trcVerbose("OOM.");
 224       goto cleanup;
 225     }
 226 
 227     memset(e, 0, sizeof(entry_t));
 228 
 229     e->info.text = ldi->ldinfo_textorg;
 230     e->info.text_len = ldi->ldinfo_textsize;
 231     e->info.data = ldi->ldinfo_dataorg;
 232     e->info.data_len = ldi->ldinfo_datasize;
 233 
 234     e->info.path = g_stringlist.add(ldi->ldinfo_filename);
 235     if (!e->info.path) {
 236       trcVerbose("OOM.");
 237       goto cleanup;
 238     }
 239 
 240     // Extract short name
 241     {
 242       const char* p = strrchr(e->info.path, '/');
 243       if (p) {
 244         p ++;
 245         e->info.shortname = p;
 246       } else {
 247         e->info.shortname = e->info.path;
 248       }
 249     }
 250 
 251     // Do we have a member name as well (see ldr.h)?
 252     const char* p_mbr_name =
 253       ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1;
 254     if (*p_mbr_name) {
 255       e->info.member = g_stringlist.add(p_mbr_name);
 256       if (!e->info.member) {
 257         trcVerbose("OOM.");
 258         goto cleanup;
 259       }
 260     } else {
 261       e->info.member = NULL;
 262     }
 263 
 264     if (strcmp(e->info.shortname, "libjvm.so") == 0) {
 265       // Note that this, theoretically, is fuzzy. We may accidentally contain
 266       // more than one libjvm.so. But that is improbable, so lets go with this
 267       // solution.
 268       e->info.is_in_vm = true;
 269     }
 270 
 271     trcVerbose("entry: %p %llu, %p %llu, %s %s %s, %d",
 272       e->info.text, e->info.text_len,
 273       e->info.data, e->info.data_len,
 274       e->info.path, e->info.shortname,
 275       (e->info.member ? e->info.member : "NULL"),
 276       e->info.is_in_vm
 277     );
 278 
 279     // Add to list.
 280     add_entry_to_list(e, &new_list);
 281 
 282     // Next entry...
 283     if (ldi->ldinfo_next) {
 284       ldi = (struct ld_info*)(((char*)ldi) + ldi->ldinfo_next);
 285     } else {
 286       break;
 287     }
 288   }
 289 
 290   // We are done. All is well. Free old list and swap to new one.
 291   if (g_first) {
 292     free_entry_list(&g_first);
 293   }
 294   g_first = new_list;
 295   new_list = NULL;
 296 
 297   rc = true;
 298 
 299 cleanup:
 300 
 301   if (new_list) {
 302     free_entry_list(&new_list);
 303   }
 304 
 305   ::free(buffer);
 306 
 307   return rc;
 308 
 309 } // end LoadedLibraries::reload()
 310 
 311 
 312 ///////////////////////////////////////////////////////////////////////////////
 313 // Externals
 314 
 315 static MiscUtils::CritSect g_cs;
 316 
 317 // Rebuild the internal module table. If an error occurs, old table remains
 318 // unchanged.
 319 bool LoadedLibraries::reload() {
 320   MiscUtils::AutoCritSect lck(&g_cs);
 321   return reload_table();
 322 }
 323 
 324 void LoadedLibraries::print(outputStream* os) {
 325   MiscUtils::AutoCritSect lck(&g_cs);
 326   if (!g_first) {
 327     reload_table();
 328   }
 329   for (entry_t* e = g_first; e; e = e->next) {
 330     print_entry(e, os);
 331     os->cr();
 332   }
 333 }
 334 
 335 bool LoadedLibraries::find_for_text_address(const void* p,
 336                                             loaded_module_t* info) {
 337   MiscUtils::AutoCritSect lck(&g_cs);
 338   if (!g_first) {
 339     reload_table();
 340   }
 341   const entry_t* const e = find_entry_for_text_address(p);
 342   if (e) {
 343     if (info) {
 344       *info = e->info;
 345     }
 346     return true;
 347   }
 348   return false;
 349 }
 350 
 351 
 352 bool LoadedLibraries::find_for_data_address (
 353   const void* p,
 354   loaded_module_t* info // optional. can be NULL:
 355 ) {
 356   MiscUtils::AutoCritSect lck(&g_cs);
 357   if (!g_first) {
 358     reload_table();
 359   }
 360   const entry_t* const e = find_entry_for_data_address(p);
 361   if (e) {
 362     if (info) {
 363       *info = e->info;
 364     }
 365     return true;
 366   }
 367   return false;
 368 }
 369 
--- EOF ---