Path: blob/master/src/hotspot/share/utilities/elfFile.cpp
40949 views
/*1* Copyright (c) 1997, 2018, 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 "precompiled.hpp"2526#if !defined(_WINDOWS) && !defined(__APPLE__)2728#include <string.h>29#include <stdio.h>30#include <limits.h>31#include <new>3233#include "logging/log.hpp"34#include "memory/allocation.inline.hpp"35#include "memory/resourceArea.hpp"36#include "utilities/decoder.hpp"37#include "utilities/elfFile.hpp"38#include "utilities/elfFuncDescTable.hpp"39#include "utilities/elfStringTable.hpp"40#include "utilities/elfSymbolTable.hpp"41#include "utilities/ostream.hpp"4243// For test only, disable elf section cache and force to read from file directly.44bool ElfFile::_do_not_cache_elf_section = false;4546ElfSection::ElfSection(FILE* fd, const Elf_Shdr& hdr) : _section_data(NULL) {47_stat = load_section(fd, hdr);48}4950ElfSection::~ElfSection() {51if (_section_data != NULL) {52os::free(_section_data);53}54}5556NullDecoder::decoder_status ElfSection::load_section(FILE* const fd, const Elf_Shdr& shdr) {57memcpy((void*)&_section_hdr, (const void*)&shdr, sizeof(shdr));5859if (ElfFile::_do_not_cache_elf_section) {60log_debug(decoder)("Elf section cache is disabled");61return NullDecoder::no_error;62}6364_section_data = os::malloc(shdr.sh_size, mtInternal);65// No enough memory for caching. It is okay, we can try to read from66// file instead.67if (_section_data == NULL) return NullDecoder::no_error;6869MarkedFileReader mfd(fd);70if (mfd.has_mark() &&71mfd.set_position(shdr.sh_offset) &&72mfd.read(_section_data, shdr.sh_size)) {73return NullDecoder::no_error;74} else {75os::free(_section_data);76_section_data = NULL;77return NullDecoder::file_invalid;78}79}8081bool FileReader::read(void* buf, size_t size) {82assert(buf != NULL, "no buffer");83assert(size > 0, "no space");84return fread(buf, size, 1, _fd) == 1;85}8687int FileReader::read_buffer(void* buf, size_t size) {88assert(buf != NULL, "no buffer");89assert(size > 0, "no space");90return fread(buf, 1, size, _fd);91}9293bool FileReader::set_position(long offset) {94return fseek(_fd, offset, SEEK_SET) == 0;95}9697MarkedFileReader::MarkedFileReader(FILE* fd) : FileReader(fd) {98_marked_pos = ftell(fd);99}100101MarkedFileReader::~MarkedFileReader() {102if (_marked_pos != -1) {103set_position(_marked_pos);104}105}106107ElfFile::ElfFile(const char* filepath) :108_next(NULL), _filepath(NULL), _file(NULL),109_symbol_tables(NULL), _string_tables(NULL), _shdr_string_table(NULL), _funcDesc_table(NULL),110_status(NullDecoder::no_error) {111memset(&_elfHdr, 0, sizeof(_elfHdr));112113int len = strlen(filepath) + 1;114_filepath = (char*)os::malloc(len * sizeof(char), mtInternal);115if (_filepath == NULL) {116_status = NullDecoder::out_of_memory;117return;118}119strcpy(_filepath, filepath);120121_status = parse_elf(filepath);122123// we no longer need section header string table124if (_shdr_string_table != NULL) {125delete _shdr_string_table;126_shdr_string_table = NULL;127}128}129130ElfFile::~ElfFile() {131if (_shdr_string_table != NULL) {132delete _shdr_string_table;133}134135cleanup_tables();136137if (_file != NULL) {138fclose(_file);139}140141if (_filepath != NULL) {142os::free((void*)_filepath);143}144145if (_next != NULL) {146delete _next;147}148}149150void ElfFile::cleanup_tables() {151if (_string_tables != NULL) {152delete _string_tables;153_string_tables = NULL;154}155156if (_symbol_tables != NULL) {157delete _symbol_tables;158_symbol_tables = NULL;159}160161if (_funcDesc_table != NULL) {162delete _funcDesc_table;163_funcDesc_table = NULL;164}165}166167NullDecoder::decoder_status ElfFile::parse_elf(const char* filepath) {168assert(filepath, "null file path");169170_file = fopen(filepath, "r");171if (_file != NULL) {172return load_tables();173} else {174return NullDecoder::file_not_found;175}176}177178//Check elf header to ensure the file is valid.179bool ElfFile::is_elf_file(Elf_Ehdr& hdr) {180return (ELFMAG0 == hdr.e_ident[EI_MAG0] &&181ELFMAG1 == hdr.e_ident[EI_MAG1] &&182ELFMAG2 == hdr.e_ident[EI_MAG2] &&183ELFMAG3 == hdr.e_ident[EI_MAG3] &&184ELFCLASSNONE != hdr.e_ident[EI_CLASS] &&185ELFDATANONE != hdr.e_ident[EI_DATA]);186}187188NullDecoder::decoder_status ElfFile::load_tables() {189assert(_file, "file not open");190assert(!NullDecoder::is_error(_status), "already in error");191192FileReader freader(fd());193// read elf file header194if (!freader.read(&_elfHdr, sizeof(_elfHdr))) {195return NullDecoder::file_invalid;196}197198// Check signature199if (!is_elf_file(_elfHdr)) {200return NullDecoder::file_invalid;201}202203// walk elf file's section headers, and load string tables204Elf_Shdr shdr;205if (!freader.set_position(_elfHdr.e_shoff)) {206return NullDecoder::file_invalid;207}208209for (int index = 0; index < _elfHdr.e_shnum; index ++) {210if (!freader.read(&shdr, sizeof(shdr))) {211return NullDecoder::file_invalid;212}213214if (shdr.sh_type == SHT_STRTAB) {215// string tables216ElfStringTable* table = new (std::nothrow) ElfStringTable(fd(), shdr, index);217if (table == NULL) {218return NullDecoder::out_of_memory;219}220if (index == _elfHdr.e_shstrndx) {221assert(_shdr_string_table == NULL, "Only set once");222_shdr_string_table = table;223} else {224add_string_table(table);225}226} else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {227// symbol tables228ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(fd(), shdr);229if (table == NULL) {230return NullDecoder::out_of_memory;231}232add_symbol_table(table);233}234}235#if defined(PPC64) && !defined(ABI_ELFv2)236// Now read the .opd section wich contains the PPC64 function descriptor table.237// The .opd section is only available on PPC64 (see for example:238// http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html)239// so this code should do no harm on other platforms but because of performance reasons we only240// execute it on PPC64 platforms.241// Notice that we can only find the .opd section after we have successfully read in the string242// tables in the previous loop, because we need to query the name of each section which is243// contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx).244245// Reset the file pointer246int sect_index = section_by_name(".opd", shdr);247248if (sect_index == -1) {249return NullDecoder::file_invalid;250}251252_funcDesc_table = new (std::nothrow) ElfFuncDescTable(_file, shdr, sect_index);253if (_funcDesc_table == NULL) {254return NullDecoder::out_of_memory;255}256#endif257return NullDecoder::no_error;258}259260int ElfFile::section_by_name(const char* name, Elf_Shdr& hdr) {261assert(name != NULL, "No section name");262size_t len = strlen(name) + 1;263ResourceMark rm;264char* buf = NEW_RESOURCE_ARRAY(char, len);265if (buf == NULL) {266return -1;267}268269assert(_shdr_string_table != NULL, "Section header string table should be loaded");270ElfStringTable* const table = _shdr_string_table;271MarkedFileReader mfd(fd());272if (!mfd.has_mark() || !mfd.set_position(_elfHdr.e_shoff)) return -1;273274int sect_index = -1;275for (int index = 0; index < _elfHdr.e_shnum; index ++) {276if (!mfd.read((void*)&hdr, sizeof(hdr))) {277break;278}279if (table->string_at(hdr.sh_name, buf, len)) {280if (strncmp(buf, name, len) == 0) {281sect_index = index;282break;283}284}285}286return sect_index;287}288289bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) {290// something already went wrong, just give up291if (NullDecoder::is_error(_status)) {292return false;293}294295int string_table_index;296int pos_in_string_table;297int off = INT_MAX;298bool found_symbol = false;299ElfSymbolTable* symbol_table = _symbol_tables;300301while (symbol_table != NULL) {302if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, _funcDesc_table)) {303found_symbol = true;304break;305}306symbol_table = symbol_table->next();307}308if (!found_symbol) {309return false;310}311312ElfStringTable* string_table = get_string_table(string_table_index);313314if (string_table == NULL) {315_status = NullDecoder::file_invalid;316return false;317}318if (offset) *offset = off;319320return string_table->string_at(pos_in_string_table, buf, buflen);321}322323void ElfFile::add_symbol_table(ElfSymbolTable* table) {324if (_symbol_tables == NULL) {325_symbol_tables = table;326} else {327table->set_next(_symbol_tables);328_symbol_tables = table;329}330}331332void ElfFile::add_string_table(ElfStringTable* table) {333if (_string_tables == NULL) {334_string_tables = table;335} else {336table->set_next(_string_tables);337_string_tables = table;338}339}340341ElfStringTable* ElfFile::get_string_table(int index) {342ElfStringTable* p = _string_tables;343while (p != NULL) {344if (p->index() == index) return p;345p = p->next();346}347return NULL;348}349350#endif // !_WINDOWS && !__APPLE__351352353