bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) { // something already went wrong, just give up if (NullDecoder::is_error(m_status)) { return false; } ElfSymbolTable* symbol_table = m_symbol_tables; int string_table_index; int pos_in_string_table; int off = INT_MAX; bool found_symbol = false; while (symbol_table != NULL) { if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off)) { found_symbol = true; } symbol_table = symbol_table->m_next; } if (!found_symbol) return false; ElfStringTable* string_table = get_string_table(string_table_index); if (string_table == NULL) { m_status = NullDecoder::file_invalid; return false; } if (offset) *offset = off; return string_table->string_at(pos_in_string_table, buf, buflen); }
bool ElfFile::load_tables() { assert(m_file, "file not open"); assert(!NullDecoder::is_error(m_status), "already in error"); // read elf file header if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { m_status = NullDecoder::file_invalid; return false; } if (!is_elf_file(m_elfHdr)) { m_status = NullDecoder::file_invalid; return false; } // walk elf file's section headers, and load string tables Elf_Shdr shdr; if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { if (NullDecoder::is_error(m_status)) return false; for (int index = 0; index < m_elfHdr.e_shnum; index ++) { if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { m_status = NullDecoder::file_invalid; return false; } if (shdr.sh_type == SHT_STRTAB) { // string tables ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index); if (table == NULL) { m_status = NullDecoder::out_of_memory; return false; } add_string_table(table); } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { // symbol tables ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); if (table == NULL) { m_status = NullDecoder::out_of_memory; return false; } add_symbol_table(table); } } #if defined(PPC64) && !defined(ABI_ELFv2) // Now read the .opd section wich contains the PPC64 function descriptor table. // The .opd section is only available on PPC64 (see for example: // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html) // so this code should do no harm on other platforms but because of performance reasons we only // execute it on PPC64 platforms. // Notice that we can only find the .opd section after we have successfully read in the string // tables in the previous loop, because we need to query the name of each section which is // contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx). // Reset the file pointer if (fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { m_status = NullDecoder::file_invalid; return false; } for (int index = 0; index < m_elfHdr.e_shnum; index ++) { if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { m_status = NullDecoder::file_invalid; return false; } if (m_elfHdr.e_shstrndx != SHN_UNDEF && shdr.sh_type == SHT_PROGBITS) { ElfStringTable* string_table = get_string_table(m_elfHdr.e_shstrndx); if (string_table == NULL) { m_status = NullDecoder::file_invalid; return false; } char buf[8]; // '8' is enough because we only want to read ".opd" if (string_table->string_at(shdr.sh_name, buf, sizeof(buf)) && !strncmp(".opd", buf, 4)) { m_funcDesc_table = new (std::nothrow) ElfFuncDescTable(m_file, shdr, index); if (m_funcDesc_table == NULL) { m_status = NullDecoder::out_of_memory; return false; } break; } } } #endif } return true; }