Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/agent/src/os/bsd/symtab.c
38833 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include <unistd.h>25#include <search.h>26#include <stdlib.h>27#include <string.h>28#include <db.h>29#include <fcntl.h>3031#include "libproc_impl.h"32#include "symtab.h"33#ifndef __APPLE__34#include "salibelf.h"35#endif // __APPLE__363738// ----------------------------------------------------39// functions for symbol lookups40// ----------------------------------------------------4142typedef struct symtab_symbol {43char *name; // name like __ZThread_...44uintptr_t offset; // to loaded address45uintptr_t size; // size strlen46} symtab_symbol;4748typedef struct symtab {49char *strs; // all symbols "__symbol1__'\0'__symbol2__...."50size_t num_symbols;51DB* hash_table;52symtab_symbol* symbols;53} symtab_t;5455#ifdef __APPLE__5657void build_search_table(symtab_t *symtab) {58int i;59for (i = 0; i < symtab->num_symbols; i++) {60DBT key, value;61key.data = symtab->symbols[i].name;62key.size = strlen(key.data) + 1;63value.data = &(symtab->symbols[i]);64value.size = sizeof(symtab_symbol);65(*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);6667// check result68if (is_debug()) {69DBT rkey, rvalue;70char* tmp = (char *)malloc(strlen(symtab->symbols[i].name) + 1);71strcpy(tmp, symtab->symbols[i].name);72rkey.data = tmp;73rkey.size = strlen(tmp) + 1;74(*symtab->hash_table->get)(symtab->hash_table, &rkey, &rvalue, 0);75// we may get a copy back so compare contents76symtab_symbol *res = (symtab_symbol *)rvalue.data;77if (strcmp(res->name, symtab->symbols[i].name) ||78res->offset != symtab->symbols[i].offset ||79res->size != symtab->symbols[i].size) {80print_debug("error to get hash_table value!\n");81}82free(tmp);83}84}85}8687// read symbol table from given fd.88struct symtab* build_symtab(int fd) {89symtab_t* symtab = NULL;90int i;91mach_header_64 header;92off_t image_start;9394if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) {95print_debug("failed in get fat header\n");96return NULL;97}98lseek(fd, image_start, SEEK_SET);99if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) {100print_debug("reading header failed!\n");101return NULL;102}103// header104if (header.magic != MH_MAGIC_64) {105print_debug("not a valid .dylib file\n");106return NULL;107}108109load_command lcmd;110symtab_command symtabcmd;111nlist_64 lentry;112113bool lcsymtab_exist = false;114115long filepos = ltell(fd);116for (i = 0; i < header.ncmds; i++) {117lseek(fd, filepos, SEEK_SET);118if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {119print_debug("read load_command failed for file\n");120return NULL;121}122filepos += lcmd.cmdsize; // next command position123if (lcmd.cmd == LC_SYMTAB) {124lseek(fd, -sizeof(load_command), SEEK_CUR);125lcsymtab_exist = true;126break;127}128}129if (!lcsymtab_exist) {130print_debug("No symtab command found!\n");131return NULL;132}133if (read(fd, (void *)&symtabcmd, sizeof(symtab_command)) != sizeof(symtab_command)) {134print_debug("read symtab_command failed for file");135return NULL;136}137symtab = (symtab_t *)malloc(sizeof(symtab_t));138if (symtab == NULL) {139print_debug("out of memory: allocating symtab\n");140return NULL;141}142143// create hash table, we use berkeley db to144// manipulate the hash table.145symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);146if (symtab->hash_table == NULL)147goto quit;148149symtab->num_symbols = symtabcmd.nsyms;150symtab->symbols = (symtab_symbol *)malloc(sizeof(symtab_symbol) * symtab->num_symbols);151symtab->strs = (char *)malloc(sizeof(char) * symtabcmd.strsize);152if (symtab->symbols == NULL || symtab->strs == NULL) {153print_debug("out of memory: allocating symtab.symbol or symtab.strs\n");154goto quit;155}156lseek(fd, image_start + symtabcmd.symoff, SEEK_SET);157for (i = 0; i < symtab->num_symbols; i++) {158if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) {159print_debug("read nlist_64 failed at %i\n", i);160goto quit;161}162symtab->symbols[i].offset = lentry.n_value;163symtab->symbols[i].size = lentry.n_un.n_strx; // index164}165166// string table167lseek(fd, image_start + symtabcmd.stroff, SEEK_SET);168int size = read(fd, (void *)(symtab->strs), symtabcmd.strsize * sizeof(char));169if (size != symtabcmd.strsize * sizeof(char)) {170print_debug("reading string table failed\n");171goto quit;172}173174for (i = 0; i < symtab->num_symbols; i++) {175symtab->symbols[i].name = symtab->strs + symtab->symbols[i].size;176if (i > 0) {177// fix size178symtab->symbols[i - 1].size = symtab->symbols[i].size - symtab->symbols[i - 1].size;179print_debug("%s size = %d\n", symtab->symbols[i - 1].name, symtab->symbols[i - 1].size);180181}182183if (i == symtab->num_symbols - 1) {184// last index185symtab->symbols[i].size =186symtabcmd.strsize - symtab->symbols[i].size;187print_debug("%s size = %d\n", symtab->symbols[i].name, symtab->symbols[i].size);188}189}190191// build a hashtable for fast query192build_search_table(symtab);193return symtab;194quit:195if (symtab) destroy_symtab(symtab);196return NULL;197}198199#else // __APPLE__200201struct elf_section {202ELF_SHDR *c_shdr;203void *c_data;204};205206// read symbol table from given fd.207struct symtab* build_symtab(int fd) {208ELF_EHDR ehdr;209struct symtab* symtab = NULL;210211// Reading of elf header212struct elf_section *scn_cache = NULL;213int cnt = 0;214ELF_SHDR* shbuf = NULL;215ELF_SHDR* cursct = NULL;216ELF_PHDR* phbuf = NULL;217int symtab_found = 0;218int dynsym_found = 0;219uint32_t symsection = SHT_SYMTAB;220221uintptr_t baseaddr = (uintptr_t)-1;222223lseek(fd, (off_t)0L, SEEK_SET);224if (! read_elf_header(fd, &ehdr)) {225// not an elf226return NULL;227}228229// read ELF header230if ((shbuf = read_section_header_table(fd, &ehdr)) == NULL) {231goto quit;232}233234baseaddr = find_base_address(fd, &ehdr);235236scn_cache = calloc(ehdr.e_shnum, sizeof(*scn_cache));237if (scn_cache == NULL) {238goto quit;239}240241for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) {242scn_cache[cnt].c_shdr = cursct;243if (cursct->sh_type == SHT_SYMTAB ||244cursct->sh_type == SHT_STRTAB ||245cursct->sh_type == SHT_DYNSYM) {246if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {247goto quit;248}249}250251if (cursct->sh_type == SHT_SYMTAB)252symtab_found++;253254if (cursct->sh_type == SHT_DYNSYM)255dynsym_found++;256257cursct++;258}259260if (!symtab_found && dynsym_found)261symsection = SHT_DYNSYM;262263for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {264ELF_SHDR *shdr = scn_cache[cnt].c_shdr;265266if (shdr->sh_type == symsection) {267ELF_SYM *syms;268int j, n;269size_t size;270271// FIXME: there could be multiple data buffers associated with the272// same ELF section. Here we can handle only one buffer. See man page273// for elf_getdata on Solaris.274275// guarantee(symtab == NULL, "multiple symtab");276symtab = calloc(1, sizeof(*symtab));277if (symtab == NULL) {278goto quit;279}280// the symbol table281syms = (ELF_SYM *)scn_cache[cnt].c_data;282283// number of symbols284n = shdr->sh_size / shdr->sh_entsize;285286// create hash table, we use berkeley db to287// manipulate the hash table.288symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);289// guarantee(symtab->hash_table, "unexpected failure: dbopen");290if (symtab->hash_table == NULL)291goto bad;292293// shdr->sh_link points to the section that contains the actual strings294// for symbol names. the st_name field in ELF_SYM is just the295// string table index. we make a copy of the string table so the296// strings will not be destroyed by elf_end.297size = scn_cache[shdr->sh_link].c_shdr->sh_size;298symtab->strs = malloc(size);299if (symtab->strs == NULL)300goto bad;301memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);302303// allocate memory for storing symbol offset and size;304symtab->num_symbols = n;305symtab->symbols = calloc(n , sizeof(*symtab->symbols));306if (symtab->symbols == NULL)307goto bad;308309// copy symbols info our symtab and enter them info the hash table310for (j = 0; j < n; j++, syms++) {311DBT key, value;312char *sym_name = symtab->strs + syms->st_name;313314// skip non-object and non-function symbols315int st_type = ELF_ST_TYPE(syms->st_info);316if ( st_type != STT_FUNC && st_type != STT_OBJECT)317continue;318// skip empty strings and undefined symbols319if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;320321symtab->symbols[j].name = sym_name;322symtab->symbols[j].offset = syms->st_value - baseaddr;323symtab->symbols[j].size = syms->st_size;324325key.data = sym_name;326key.size = strlen(sym_name) + 1;327value.data = &(symtab->symbols[j]);328value.size = sizeof(symtab_symbol);329(*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);330}331}332}333goto quit;334335bad:336destroy_symtab(symtab);337symtab = NULL;338339quit:340if (shbuf) free(shbuf);341if (phbuf) free(phbuf);342if (scn_cache) {343for (cnt = 0; cnt < ehdr.e_shnum; cnt++) {344if (scn_cache[cnt].c_data != NULL) {345free(scn_cache[cnt].c_data);346}347}348free(scn_cache);349}350return symtab;351}352353#endif // __APPLE__354355void destroy_symtab(symtab_t* symtab) {356if (!symtab) return;357free(symtab->strs);358free(symtab->symbols);359free(symtab);360}361362uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, const char *sym_name, int *sym_size) {363DBT key, value;364int ret;365366// library does not have symbol table367if (!symtab || !symtab->hash_table) {368return 0;369}370371key.data = (char*)(uintptr_t)sym_name;372key.size = strlen(sym_name) + 1;373ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0);374if (ret == 0) {375symtab_symbol *sym = value.data;376uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);377if (sym_size) *sym_size = sym->size;378return rslt;379}380381return 0;382}383384const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,385uintptr_t* poffset) {386int n = 0;387if (!symtab) return NULL;388for (; n < symtab->num_symbols; n++) {389symtab_symbol* sym = &(symtab->symbols[n]);390if (sym->name != NULL &&391offset >= sym->offset && offset < sym->offset + sym->size) {392if (poffset) *poffset = (offset - sym->offset);393return sym->name;394}395}396return NULL;397}398399400