hotspot/agent/src/os/bsd/symtab.c
changeset 10565 dc90c239f4ec
child 10739 91935236600e
equal deleted inserted replaced
10564:db5bf5438c0a 10565:dc90c239f4ec
       
     1 /*
       
     2  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. 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 #include <unistd.h>
       
    26 #include <search.h>
       
    27 #include <stdlib.h>
       
    28 #include <string.h>
       
    29 #include <db.h>
       
    30 #include <fcntl.h>
       
    31 #include "symtab.h"
       
    32 #include "salibelf.h"
       
    33 
       
    34 
       
    35 // ----------------------------------------------------
       
    36 // functions for symbol lookups
       
    37 // ----------------------------------------------------
       
    38 
       
    39 struct elf_section {
       
    40   ELF_SHDR   *c_shdr;
       
    41   void       *c_data;
       
    42 };
       
    43 
       
    44 struct elf_symbol {
       
    45   char *name;
       
    46   uintptr_t offset;
       
    47   uintptr_t size;
       
    48 };
       
    49 
       
    50 typedef struct symtab {
       
    51   char *strs;
       
    52   size_t num_symbols;
       
    53   struct elf_symbol *symbols;
       
    54   DB* hash_table;
       
    55 } symtab_t;
       
    56 
       
    57 // read symbol table from given fd.
       
    58 struct symtab* build_symtab(int fd) {
       
    59   ELF_EHDR ehdr;
       
    60   struct symtab* symtab = NULL;
       
    61 
       
    62   // Reading of elf header
       
    63   struct elf_section *scn_cache = NULL;
       
    64   int cnt = 0;
       
    65   ELF_SHDR* shbuf = NULL;
       
    66   ELF_SHDR* cursct = NULL;
       
    67   ELF_PHDR* phbuf = NULL;
       
    68   int symtab_found = 0;
       
    69   int dynsym_found = 0;
       
    70   uint32_t symsection = SHT_SYMTAB;
       
    71 
       
    72   uintptr_t baseaddr = (uintptr_t)-1;
       
    73 
       
    74   lseek(fd, (off_t)0L, SEEK_SET);
       
    75   if (! read_elf_header(fd, &ehdr)) {
       
    76     // not an elf
       
    77     return NULL;
       
    78   }
       
    79 
       
    80   // read ELF header
       
    81   if ((shbuf = read_section_header_table(fd, &ehdr)) == NULL) {
       
    82     goto quit;
       
    83   }
       
    84 
       
    85   baseaddr = find_base_address(fd, &ehdr);
       
    86 
       
    87   scn_cache = calloc(ehdr.e_shnum, sizeof(*scn_cache));
       
    88   if (scn_cache == NULL) {
       
    89     goto quit;
       
    90   }
       
    91 
       
    92   for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) {
       
    93     scn_cache[cnt].c_shdr = cursct;
       
    94     if (cursct->sh_type == SHT_SYMTAB ||
       
    95         cursct->sh_type == SHT_STRTAB ||
       
    96         cursct->sh_type == SHT_DYNSYM) {
       
    97       if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
       
    98          goto quit;
       
    99       }
       
   100     }
       
   101 
       
   102     if (cursct->sh_type == SHT_SYMTAB)
       
   103        symtab_found++;
       
   104 
       
   105     if (cursct->sh_type == SHT_DYNSYM)
       
   106        dynsym_found++;
       
   107 
       
   108     cursct++;
       
   109   }
       
   110 
       
   111   if (!symtab_found && dynsym_found)
       
   112      symsection = SHT_DYNSYM;
       
   113 
       
   114   for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
       
   115     ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
       
   116 
       
   117     if (shdr->sh_type == symsection) {
       
   118       ELF_SYM  *syms;
       
   119       int j, n, rslt;
       
   120       size_t size;
       
   121 
       
   122       // FIXME: there could be multiple data buffers associated with the
       
   123       // same ELF section. Here we can handle only one buffer. See man page
       
   124       // for elf_getdata on Solaris.
       
   125 
       
   126       // guarantee(symtab == NULL, "multiple symtab");
       
   127       symtab = calloc(1, sizeof(*symtab));
       
   128       if (symtab == NULL) {
       
   129          goto quit;
       
   130       }
       
   131       // the symbol table
       
   132       syms = (ELF_SYM *)scn_cache[cnt].c_data;
       
   133 
       
   134       // number of symbols
       
   135       n = shdr->sh_size / shdr->sh_entsize;
       
   136 
       
   137       // create hash table, we use berkeley db to
       
   138       // manipulate the hash table.
       
   139       symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);
       
   140       // guarantee(symtab->hash_table, "unexpected failure: dbopen");
       
   141 
       
   142       // shdr->sh_link points to the section that contains the actual strings
       
   143       // for symbol names. the st_name field in ELF_SYM is just the
       
   144       // string table index. we make a copy of the string table so the
       
   145       // strings will not be destroyed by elf_end.
       
   146       size = scn_cache[shdr->sh_link].c_shdr->sh_size;
       
   147       symtab->strs = malloc(size);
       
   148       memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);
       
   149 
       
   150       // allocate memory for storing symbol offset and size;
       
   151       symtab->num_symbols = n;
       
   152       symtab->symbols = calloc(n , sizeof(*symtab->symbols));
       
   153 
       
   154       // copy symbols info our symtab and enter them info the hash table
       
   155       for (j = 0; j < n; j++, syms++) {
       
   156         DBT key, value;
       
   157         char *sym_name = symtab->strs + syms->st_name;
       
   158 
       
   159         // skip non-object and non-function symbols
       
   160         int st_type = ELF_ST_TYPE(syms->st_info);
       
   161         if ( st_type != STT_FUNC && st_type != STT_OBJECT)
       
   162            continue;
       
   163         // skip empty strings and undefined symbols
       
   164         if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
       
   165 
       
   166         symtab->symbols[j].name   = sym_name;
       
   167         symtab->symbols[j].offset = syms->st_value - baseaddr;
       
   168         symtab->symbols[j].size   = syms->st_size;
       
   169 
       
   170         key.data = sym_name;
       
   171         key.size = strlen(sym_name) + 1;
       
   172         value.data = &(symtab->symbols[j]);
       
   173         value.size = sizeof(void *);
       
   174         (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
       
   175       }
       
   176     }
       
   177   }
       
   178 
       
   179 quit:
       
   180   if (shbuf) free(shbuf);
       
   181   if (phbuf) free(phbuf);
       
   182   if (scn_cache) {
       
   183     for (cnt = 0; cnt < ehdr.e_shnum; cnt++) {
       
   184       if (scn_cache[cnt].c_data != NULL) {
       
   185         free(scn_cache[cnt].c_data);
       
   186       }
       
   187     }
       
   188     free(scn_cache);
       
   189   }
       
   190   return symtab;
       
   191 }
       
   192 
       
   193 void destroy_symtab(struct symtab* symtab) {
       
   194   if (!symtab) return;
       
   195   if (symtab->strs) free(symtab->strs);
       
   196   if (symtab->symbols) free(symtab->symbols);
       
   197   if (symtab->hash_table) {
       
   198     symtab->hash_table->close(symtab->hash_table);
       
   199   }
       
   200   free(symtab);
       
   201 }
       
   202 
       
   203 uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
       
   204                       const char *sym_name, int *sym_size) {
       
   205   DBT key, value;
       
   206   int ret;
       
   207 
       
   208   // library does not have symbol table
       
   209   if (!symtab || !symtab->hash_table)
       
   210      return 0;
       
   211 
       
   212   key.data = (char*)(uintptr_t)sym_name;
       
   213   key.size = strlen(sym_name) + 1;
       
   214   ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0);
       
   215   if (ret == 0) {
       
   216     struct elf_symbol *sym = value.data;
       
   217     uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
       
   218     if (sym_size) *sym_size = sym->size;
       
   219     return rslt;
       
   220   }
       
   221 
       
   222 quit:
       
   223   return 0;
       
   224 }
       
   225 
       
   226 const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
       
   227                            uintptr_t* poffset) {
       
   228   int n = 0;
       
   229   if (!symtab) return NULL;
       
   230   for (; n < symtab->num_symbols; n++) {
       
   231      struct elf_symbol* sym = &(symtab->symbols[n]);
       
   232      if (sym->name != NULL &&
       
   233          offset >= sym->offset && offset < sym->offset + sym->size) {
       
   234         if (poffset) *poffset = (offset - sym->offset);
       
   235         return sym->name;
       
   236      }
       
   237   }
       
   238   return NULL;
       
   239 }