src/hotspot/os/aix/loadlib_aix.cpp
changeset 47216 71c04702a3d5
parent 46535 fc2445cc0e3d
child 55683 b528b724b16d
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
       
     4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     5  *
       
     6  * This code is free software; you can redistribute it and/or modify it
       
     7  * under the terms of the GNU General Public License version 2 only, as
       
     8  * published by the Free Software Foundation.
       
     9  *
       
    10  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    13  * version 2 for more details (a copy is included in the LICENSE file that
       
    14  * accompanied this code).
       
    15  *
       
    16  * You should have received a copy of the GNU General Public License version
       
    17  * 2 along with this work; if not, write to the Free Software Foundation,
       
    18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    19  *
       
    20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    21  * or visit www.oracle.com if you need additional information or have any
       
    22  * questions.
       
    23  *
       
    24  */
       
    25 
       
    26 
       
    27 // Implementation of LoadedLibraries and friends
       
    28 
       
    29 // Ultimately this just uses loadquery()
       
    30 // See:
       
    31 // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp
       
    32 //      ?topic=/com.ibm.aix.basetechref/doc/basetrf1/loadquery.htm
       
    33 
       
    34 #include "loadlib_aix.hpp"
       
    35 #include "misc_aix.hpp"
       
    36 #include "porting_aix.hpp"
       
    37 #include "utilities/debug.hpp"
       
    38 #include "utilities/ostream.hpp"
       
    39 
       
    40 // For loadquery()
       
    41 #include <sys/ldr.h>
       
    42 
       
    43 // Use raw malloc instead of os::malloc - this code gets used for error reporting.
       
    44 
       
    45 // A class to "intern" eternal strings.
       
    46 // TODO: similar coding exists in AIX version of dladdr and potentially elsewhere: consolidate!
       
    47 class StringList {
       
    48 
       
    49   char** _list;
       
    50   int _cap;
       
    51   int _num;
       
    52 
       
    53   // Enlarge list. If oom, leave old list intact and return false.
       
    54   bool enlarge() {
       
    55     int cap2 = _cap + 64;
       
    56     char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2);
       
    57     if (!l2) {
       
    58       return false;
       
    59     }
       
    60     _list = l2;
       
    61     _cap = cap2;
       
    62     return true;
       
    63   }
       
    64 
       
    65   // Append string to end of list.
       
    66   // Returns NULL if oom.
       
    67   char* append(const char* s) {
       
    68     if (_cap == _num) {
       
    69       if (!enlarge()) {
       
    70         return NULL;
       
    71       }
       
    72     }
       
    73     assert0(_cap > _num);
       
    74     char* s2 = ::strdup(s);
       
    75     if (!s2) {
       
    76       return NULL;
       
    77     }
       
    78     _list[_num] = s2;
       
    79     trcVerbose("StringDir: added %s at pos %d", s2, _num);
       
    80     _num ++;
       
    81     return s2;
       
    82   }
       
    83 
       
    84 public:
       
    85 
       
    86   StringList()
       
    87     : _list(NULL)
       
    88     , _cap(0)
       
    89     , _num(0)
       
    90   {}
       
    91 
       
    92   // String is copied into the list; pointer to copy is returned.
       
    93   // Returns NULL if oom.
       
    94   char* add (const char* s) {
       
    95     for (int i = 0; i < _num; i++) {
       
    96       if (strcmp(_list[i], s) == 0) {
       
    97         return _list[i];
       
    98       }
       
    99     }
       
   100     return append(s);
       
   101   }
       
   102 
       
   103 };
       
   104 
       
   105 static StringList g_stringlist;
       
   106 
       
   107 //////////////////////
       
   108 
       
   109 // Entries are kept in a linked list ordered by text address. Entries are not
       
   110 // eternal - this list is rebuilt on every reload.
       
   111 // Note that we do not hand out those entries, but copies of them.
       
   112 
       
   113 struct entry_t {
       
   114   entry_t* next;
       
   115   loaded_module_t info;
       
   116 };
       
   117 
       
   118 static void print_entry(const entry_t* e, outputStream* os) {
       
   119   const loaded_module_t* const lm = &(e->info);
       
   120   os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT
       
   121             ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " "
       
   122             "%s",
       
   123       (lm->is_in_vm ? '*' : ' '),
       
   124       lm->text, (uintptr_t)lm->text + lm->text_len,
       
   125       lm->data, (uintptr_t)lm->data + lm->data_len,
       
   126       lm->path);
       
   127   if (lm->member) {
       
   128     os->print("(%s)", lm->member);
       
   129   }
       
   130 }
       
   131 
       
   132 static entry_t* g_first = NULL;
       
   133 
       
   134 static entry_t* find_entry_for_text_address(const void* p) {
       
   135   for (entry_t* e = g_first; e; e = e->next) {
       
   136     if ((uintptr_t)p >= (uintptr_t)e->info.text &&
       
   137         (uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len)) {
       
   138       return e;
       
   139     }
       
   140   }
       
   141   return NULL;
       
   142 }
       
   143 
       
   144 static entry_t* find_entry_for_data_address(const void* p) {
       
   145   for (entry_t* e = g_first; e; e = e->next) {
       
   146     if ((uintptr_t)p >= (uintptr_t)e->info.data &&
       
   147         (uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) {
       
   148       return e;
       
   149     }
       
   150   }
       
   151   return NULL;
       
   152 }
       
   153 
       
   154 // Adds a new entry to the list (ordered by text address ascending).
       
   155 static void add_entry_to_list(entry_t* e, entry_t** start) {
       
   156   entry_t* last = NULL;
       
   157   entry_t* e2 = *start;
       
   158   while (e2 && e2->info.text < e->info.text) {
       
   159     last = e2;
       
   160     e2 = e2->next;
       
   161   }
       
   162   if (last) {
       
   163     last->next = e;
       
   164   } else {
       
   165     *start = e;
       
   166   }
       
   167   e->next = e2;
       
   168 }
       
   169 
       
   170 static void free_entry_list(entry_t** start) {
       
   171   entry_t* e = *start;
       
   172   while (e) {
       
   173     entry_t* const e2 = e->next;
       
   174     ::free(e);
       
   175     e = e2;
       
   176   }
       
   177   *start = NULL;
       
   178 }
       
   179 
       
   180 
       
   181 // Rebuild the internal module table. If an error occurs, old table remains
       
   182 // unchanged.
       
   183 static bool reload_table() {
       
   184 
       
   185   bool rc = false;
       
   186 
       
   187   trcVerbose("reload module table...");
       
   188 
       
   189   entry_t* new_list = NULL;
       
   190   const struct ld_info* ldi = NULL;
       
   191 
       
   192   // Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery
       
   193   // requires a large enough buffer.
       
   194   uint8_t* buffer = NULL;
       
   195   size_t buflen = 1024;
       
   196   for (;;) {
       
   197     buffer = (uint8_t*) ::realloc(buffer, buflen);
       
   198     if (loadquery(L_GETINFO, buffer, buflen) == -1) {
       
   199       if (errno == ENOMEM) {
       
   200         buflen *= 2;
       
   201       } else {
       
   202         trcVerbose("loadquery failed (%d)", errno);
       
   203         goto cleanup;
       
   204       }
       
   205     } else {
       
   206       break;
       
   207     }
       
   208   }
       
   209 
       
   210   trcVerbose("loadquery buffer size is %llu.", buflen);
       
   211 
       
   212   // Iterate over the loadquery result. For details see sys/ldr.h on AIX.
       
   213   ldi = (struct ld_info*) buffer;
       
   214 
       
   215   for (;;) {
       
   216 
       
   217     entry_t* e = (entry_t*) ::malloc(sizeof(entry_t));
       
   218     if (!e) {
       
   219       trcVerbose("OOM.");
       
   220       goto cleanup;
       
   221     }
       
   222 
       
   223     memset(e, 0, sizeof(entry_t));
       
   224 
       
   225     e->info.text = ldi->ldinfo_textorg;
       
   226     e->info.text_len = ldi->ldinfo_textsize;
       
   227     e->info.data = ldi->ldinfo_dataorg;
       
   228     e->info.data_len = ldi->ldinfo_datasize;
       
   229 
       
   230     e->info.path = g_stringlist.add(ldi->ldinfo_filename);
       
   231     if (!e->info.path) {
       
   232       trcVerbose("OOM.");
       
   233       goto cleanup;
       
   234     }
       
   235 
       
   236     // Extract short name
       
   237     {
       
   238       const char* p = strrchr(e->info.path, '/');
       
   239       if (p) {
       
   240         p ++;
       
   241         e->info.shortname = p;
       
   242       } else {
       
   243         e->info.shortname = e->info.path;
       
   244       }
       
   245     }
       
   246 
       
   247     // Do we have a member name as well (see ldr.h)?
       
   248     const char* p_mbr_name =
       
   249       ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1;
       
   250     if (*p_mbr_name) {
       
   251       e->info.member = g_stringlist.add(p_mbr_name);
       
   252       if (!e->info.member) {
       
   253         trcVerbose("OOM.");
       
   254         goto cleanup;
       
   255       }
       
   256     } else {
       
   257       e->info.member = NULL;
       
   258     }
       
   259 
       
   260     if (strcmp(e->info.shortname, "libjvm.so") == 0) {
       
   261       // Note that this, theoretically, is fuzzy. We may accidentally contain
       
   262       // more than one libjvm.so. But that is improbable, so lets go with this
       
   263       // solution.
       
   264       e->info.is_in_vm = true;
       
   265     }
       
   266 
       
   267     trcVerbose("entry: %p %llu, %p %llu, %s %s %s, %d",
       
   268       e->info.text, e->info.text_len,
       
   269       e->info.data, e->info.data_len,
       
   270       e->info.path, e->info.shortname,
       
   271       (e->info.member ? e->info.member : "NULL"),
       
   272       e->info.is_in_vm
       
   273     );
       
   274 
       
   275     // Add to list.
       
   276     add_entry_to_list(e, &new_list);
       
   277 
       
   278     // Next entry...
       
   279     if (ldi->ldinfo_next) {
       
   280       ldi = (struct ld_info*)(((char*)ldi) + ldi->ldinfo_next);
       
   281     } else {
       
   282       break;
       
   283     }
       
   284   }
       
   285 
       
   286   // We are done. All is well. Free old list and swap to new one.
       
   287   if (g_first) {
       
   288     free_entry_list(&g_first);
       
   289   }
       
   290   g_first = new_list;
       
   291   new_list = NULL;
       
   292 
       
   293   rc = true;
       
   294 
       
   295 cleanup:
       
   296 
       
   297   if (new_list) {
       
   298     free_entry_list(&new_list);
       
   299   }
       
   300 
       
   301   ::free(buffer);
       
   302 
       
   303   return rc;
       
   304 
       
   305 } // end LoadedLibraries::reload()
       
   306 
       
   307 
       
   308 ///////////////////////////////////////////////////////////////////////////////
       
   309 // Externals
       
   310 
       
   311 static MiscUtils::CritSect g_cs;
       
   312 
       
   313 // Rebuild the internal module table. If an error occurs, old table remains
       
   314 // unchanged.
       
   315 bool LoadedLibraries::reload() {
       
   316   MiscUtils::AutoCritSect lck(&g_cs);
       
   317   return reload_table();
       
   318 }
       
   319 
       
   320 void LoadedLibraries::print(outputStream* os) {
       
   321   MiscUtils::AutoCritSect lck(&g_cs);
       
   322   if (!g_first) {
       
   323     reload_table();
       
   324   }
       
   325   for (entry_t* e = g_first; e; e = e->next) {
       
   326     print_entry(e, os);
       
   327     os->cr();
       
   328   }
       
   329 }
       
   330 
       
   331 bool LoadedLibraries::find_for_text_address(const void* p,
       
   332                                             loaded_module_t* info) {
       
   333   MiscUtils::AutoCritSect lck(&g_cs);
       
   334   if (!g_first) {
       
   335     reload_table();
       
   336   }
       
   337   const entry_t* const e = find_entry_for_text_address(p);
       
   338   if (e) {
       
   339     if (info) {
       
   340       *info = e->info;
       
   341     }
       
   342     return true;
       
   343   }
       
   344   return false;
       
   345 }
       
   346 
       
   347 
       
   348 bool LoadedLibraries::find_for_data_address (
       
   349   const void* p,
       
   350   loaded_module_t* info // optional. can be NULL:
       
   351 ) {
       
   352   MiscUtils::AutoCritSect lck(&g_cs);
       
   353   if (!g_first) {
       
   354     reload_table();
       
   355   }
       
   356   const entry_t* const e = find_entry_for_data_address(p);
       
   357   if (e) {
       
   358     if (info) {
       
   359       *info = e->info;
       
   360     }
       
   361     return true;
       
   362   }
       
   363   return false;
       
   364 }
       
   365