1 /* 2 * Copyright (c) 1997, 2012, 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 "precompiled.hpp" 26 27 #if !defined(_WINDOWS) && !defined(__APPLE__) 28 29 #include "memory/allocation.inline.hpp" 30 #include "utilities/elfSymbolTable.hpp" 31 32 ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) { 33 assert(file, "null file handle"); 34 m_symbols = NULL; 35 m_next = NULL; 36 m_file = file; 37 m_status = NullDecoder::no_error; 38 39 // try to load the string table 40 long cur_offset = ftell(file); 41 if (cur_offset != -1) { 42 // call malloc so we can back up if memory allocation fails. 43 m_symbols = (Elf_Sym*)os::malloc(shdr.sh_size, mtInternal); 44 if (m_symbols) { 45 if (fseek(file, shdr.sh_offset, SEEK_SET) || 46 fread((void*)m_symbols, shdr.sh_size, 1, file) != 1 || 47 fseek(file, cur_offset, SEEK_SET)) { 48 m_status = NullDecoder::file_invalid; 49 os::free(m_symbols); 50 m_symbols = NULL; 51 } 52 } 53 if (!NullDecoder::is_error(m_status)) { 54 memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr)); 55 } 56 } else { 57 m_status = NullDecoder::file_invalid; 58 } 59 } 60 61 ElfSymbolTable::~ElfSymbolTable() { 62 if (m_symbols != NULL) { 63 os::free(m_symbols); 64 } 65 66 if (m_next != NULL) { 67 delete m_next; 68 } 69 } 70 71 #if defined(PPC64) 72 bool ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable) { 73 #else 74 bool ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) { 75 #endif 76 assert(stringtableIndex, "null string table index pointer"); 77 assert(posIndex, "null string table offset pointer"); 78 assert(offset, "null offset pointer"); 79 80 if (NullDecoder::is_error(m_status)) { 81 return false; 82 } 83 84 size_t sym_size = sizeof(Elf_Sym); 85 assert((m_shdr.sh_size % sym_size) == 0, "check size"); 86 int count = m_shdr.sh_size / sym_size; 87 if (m_symbols != NULL) { 88 for (int index = 0; index < count; index ++) { 89 if (STT_FUNC == ELF_ST_TYPE(m_symbols[index].st_info)) { 90 Elf_Word st_size = m_symbols[index].st_size; 91 #if defined(PPC64) 92 Elf_Word sym_fd = m_symbols[index].st_value; 93 address sym_addr = funcDescTable->lookup(sym_fd); 94 #else 95 address sym_addr = (address)m_symbols[index].st_value; 96 #endif 97 if (sym_addr <= addr && (Elf_Word)(addr - sym_addr) < st_size) { 98 *offset = (int)(addr - sym_addr); 99 *posIndex = m_symbols[index].st_name; 100 *stringtableIndex = m_shdr.sh_link; 101 return true; 102 } 103 } 104 } 105 } else { 106 long cur_pos; 107 if ((cur_pos = ftell(m_file)) == -1 || 108 fseek(m_file, m_shdr.sh_offset, SEEK_SET)) { 109 m_status = NullDecoder::file_invalid; 110 return false; 111 } 112 113 Elf_Sym sym; 114 for (int index = 0; index < count; index ++) { 115 if (fread(&sym, sym_size, 1, m_file) == 1) { 116 if (STT_FUNC == ELF_ST_TYPE(sym.st_info)) { 117 Elf_Word st_size = sym.st_size; 118 #if defined(PPC64) 119 Elf_Word sym_fd = sym.st_value; 120 address sym_addr = funcDescTable->lookup(sym_fd); 121 #else 122 address sym_addr = (address)sym.st_value; 123 #endif 124 if (sym_addr <= addr && (Elf_Word)(addr - sym_addr) < st_size) { 125 *offset = (int)(addr - sym_addr); 126 *posIndex = sym.st_name; 127 *stringtableIndex = m_shdr.sh_link; 128 return true; 129 } 130 } 131 } else { 132 m_status = NullDecoder::file_invalid; 133 return false; 134 } 135 } 136 fseek(m_file, cur_pos, SEEK_SET); 137 } 138 return true; 139 } 140 141 #if defined(PPC64) 142 143 ElfFuncDescTable::ElfFuncDescTable(FILE* file, Elf_Shdr shdr) { 144 assert(file, "null file handle"); 145 // The actual function address (i.e. function entry point) is always the 146 // first value in the function descriptor (on IA64 and PPC64 they look as follows): 147 // PPC64: [function entry point, TOC pointer, environment pointer] 148 // IA64 : [function entry point, GP (global pointer) value] 149 // Unfortunately 'shdr.sh_entsize' doesn't always seem to contain this size (it's zero on PPC64) so we can't assert 150 // assert(IA64_ONLY(2) PPC64_ONLY(3) * sizeof(address) == shdr.sh_entsize, "Size mismatch for '.opd' section entries"); 151 152 m_funcDescs = NULL; 153 m_file = file; 154 m_status = NullDecoder::no_error; 155 156 // try to load the function descriptor table 157 long cur_offset = ftell(file); 158 if (cur_offset != -1) { 159 // call malloc so we can back up if memory allocation fails. 160 m_funcDescs = (address*)os::malloc(shdr.sh_size, mtInternal); 161 if (m_funcDescs) { 162 if (fseek(file, shdr.sh_offset, SEEK_SET) || 163 fread((void*)m_funcDescs, shdr.sh_size, 1, file) != 1 || 164 fseek(file, cur_offset, SEEK_SET)) { 165 m_status = NullDecoder::file_invalid; 166 os::free(m_funcDescs); 167 m_funcDescs = NULL; 168 } 169 } 170 if (!NullDecoder::is_error(m_status)) { 171 memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr)); 172 } 173 } else { 174 m_status = NullDecoder::file_invalid; 175 } 176 } 177 178 ElfFuncDescTable::~ElfFuncDescTable() { 179 if (m_funcDescs != NULL) { 180 os::free(m_funcDescs); 181 } 182 } 183 184 address ElfFuncDescTable::lookup(Elf_Word index) { 185 if (NullDecoder::is_error(m_status)) { 186 return NULL; 187 } 188 189 if (m_funcDescs != NULL) { 190 if (m_shdr.sh_size > 0 && m_shdr.sh_addr <= index && index <= m_shdr.sh_addr + m_shdr.sh_size) { 191 // Notice that 'index' is a byte-offset into the function descriptor table. 192 return m_funcDescs[(index - m_shdr.sh_addr) / sizeof(address)]; 193 } 194 return NULL; 195 } 196 else { 197 long cur_pos; 198 address addr; 199 if (!(m_shdr.sh_size > 0 && m_shdr.sh_addr <= index && index <= m_shdr.sh_addr + m_shdr.sh_size)) { 200 // don't put the whole decoder in error mode if we just tried a wrong index 201 return NULL; 202 } 203 if ((cur_pos = ftell(m_file)) == -1 || 204 fseek(m_file, m_shdr.sh_offset + index - m_shdr.sh_addr, SEEK_SET) || 205 fread(&addr, sizeof(addr), 1, m_file) != 1 || 206 fseek(m_file, cur_pos, SEEK_SET)) { 207 m_status = NullDecoder::file_invalid; 208 return NULL; 209 } 210 return addr; 211 } 212 } 213 214 #endif 215 216 #endif // _WINDOWS