bool ElfDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* filepath) { assert(filepath, "null file path"); assert(buf != NULL && buflen > 0, "Invalid buffer"); if (has_error()) return false; ElfFile* file = get_elf_file(filepath); if (file == NULL) { return false; } if (!file->decode(addr, buf, buflen, offset)) { return false; } if (buf[0] != '\0') { demangle(buf, buf, buflen); } return true; }
ElfFile* ElfDecoder::get_elf_file(const char* filepath) { ElfFile* file; file = _opened_elf_files; while (file != NULL) { if (file->same_elf_file(filepath)) { return file; } file = file->next(); } file = new (std::nothrow)ElfFile(filepath); if (file != NULL) { if (_opened_elf_files != NULL) { file->set_next(_opened_elf_files); } _opened_elf_files = file; } return file; }
ElfFile* Decoder::get_elf_file(const char* filepath) { if (_decoder_status != no_error) { return NULL; } ElfFile* file = _opened_elf_files; while (file != NULL) { if (file->same_elf_file(filepath)) { return file; } file = file->m_next; } file = new ElfFile(filepath); if (file == NULL) { _decoder_status = out_of_memory; } if (_opened_elf_files != NULL) { file->m_next = _opened_elf_files; } _opened_elf_files = file; return file; }
Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) { if (_decoder_status != no_error) { return _decoder_status; } ElfFile* file = get_elf_file(filepath); if (_decoder_status != no_error) { return _decoder_status; } const char* symbol = file->decode(addr, offset); if (file->get_status() == out_of_memory) { _decoder_status = out_of_memory; return _decoder_status; } else if (symbol != NULL) { if (!demangle(symbol, buf, buflen)) { jio_snprintf(buf, buflen, "%s", symbol); } return no_error; } else { return symbol_not_found; } }
void Symbolizer::symbolize(const uintptr_t* addresses, SymbolizedFrame* frames, size_t addressCount) { size_t remaining = 0; for (size_t i = 0; i < addressCount; ++i) { auto& frame = frames[i]; if (!frame.found) { ++remaining; frame.name.clear(); frame.location = Dwarf::LocationInfo(); } } if (remaining == 0) { // we're done return; } int fd = openNoInt("/proc/self/maps", O_RDONLY); if (fd == -1) { return; } char buf[PATH_MAX + 100]; // Long enough for any line LineReader reader(fd, buf, sizeof(buf)); char fileNameBuf[PATH_MAX]; while (remaining != 0) { StringPiece line; if (reader.readLine(line) != LineReader::kReading) { break; } // Parse line uintptr_t from; uintptr_t to; StringPiece fileName; if (!parseProcMapsLine(line, from, to, fileName)) { continue; } bool first = true; ElfFile* elfFile = nullptr; // See if any addresses are here for (size_t i = 0; i < addressCount; ++i) { auto& frame = frames[i]; if (frame.found) { continue; } uintptr_t address = addresses[i]; if (from > address || address >= to) { continue; } // Found frame.found = true; --remaining; // Open the file on first use if (first) { first = false; if (fileCount_ < kMaxFiles && !fileName.empty() && fileName.size() < sizeof(fileNameBuf)) { memcpy(fileNameBuf, fileName.data(), fileName.size()); fileNameBuf[fileName.size()] = '\0'; auto& f = files_[fileCount_++]; if (f.openNoThrow(fileNameBuf) != -1) { elfFile = &f; } } } if (!elfFile) { continue; } // Undo relocation uintptr_t fileAddress = address - from + elfFile->getBaseAddress(); auto sym = elfFile->getDefinitionByAddress(fileAddress); if (!sym.first) { continue; } auto name = elfFile->getSymbolName(sym); if (name) { frame.name = name; } Dwarf(elfFile).findAddress(fileAddress, frame.location); } } closeNoInt(fd); }
bool ElfRelocator::init(const std::wstring& inputName) { relocator = Arch->getElfRelocator(); if (relocator == NULL) { Logger::printError(Logger::Error,L"Object importing not supported for this architecture"); return false; } auto inputFiles = loadArArchive(inputName); if (inputFiles.size() == 0) { Logger::printError(Logger::Error,L"Could not load library"); return false; } for (ArFileEntry& entry: inputFiles) { ElfRelocatorFile file; ElfFile* elf = new ElfFile(); if (elf->load(entry.data,false) == false) { Logger::printError(Logger::Error,L"Could not load object file %s",entry.name); return false; } if (elf->getType() != 1) { Logger::printError(Logger::Error,L"Unexpected ELF type %d in object file %s",elf->getType(),entry.name); return false; } if (elf->getSegmentCount() != 0) { Logger::printError(Logger::Error,L"Unexpected segment count %d in object file %s",elf->getSegmentCount(),entry.name); return false; } // load all relevant sections of this file for (size_t s = 0; s < elf->getSegmentlessSectionCount(); s++) { ElfSection* sec = elf->getSegmentlessSection(s); if (!(sec->getFlags() & SHF_ALLOC)) continue; if (sec->getType() == SHT_PROGBITS || sec->getType() == SHT_NOBITS || sec->getType() == SHT_INIT_ARRAY) { ElfRelocatorSection sectionEntry; sectionEntry.section = sec; sectionEntry.index = s; sectionEntry.relSection = NULL; sectionEntry.label = NULL; // search relocation section for (size_t k = 0; k < elf->getSegmentlessSectionCount(); k++) { ElfSection* relSection = elf->getSegmentlessSection(k); if (relSection->getType() != SHT_REL) continue; if (relSection->getInfo() != s) continue; // got it sectionEntry.relSection = relSection; break; } // keep track of constructor sections if (sec->getName() == ".ctors" || sec->getName() == ".init_array") { ElfRelocatorCtor ctor; ctor.symbolName = Global.symbolTable.getUniqueLabelName(); ctor.size = sec->getSize(); sectionEntry.label = Global.symbolTable.getLabel(ctor.symbolName,-1,-1); sectionEntry.label->setDefined(true); ctors.push_back(ctor); } file.sections.push_back(sectionEntry); } } // init exportable symbols for (int i = 0; i < elf->getSymbolCount(); i++) { Elf32_Sym symbol; bool found = elf->getSymbol(symbol, i); if (ELF32_ST_BIND(symbol.st_info) == STB_GLOBAL && symbol.st_shndx != 0) { ElfRelocatorSymbol symEntry; symEntry.type = ELF32_ST_TYPE(symbol.st_info); symEntry.name = convertUtf8ToWString(elf->getStrTableString(symbol.st_name)); symEntry.relativeAddress = symbol.st_value; symEntry.section = symbol.st_shndx; symEntry.size = symbol.st_size; symEntry.label = NULL; file.symbols.push_back(symEntry); } } file.elf = elf; file.name = entry.name; files.push_back(file); } return true; }
bool ElfRelocator::relocateFile(ElfRelocatorFile& file, u64& relocationAddress) { ElfFile* elf = file.elf; u64 start = relocationAddress; // calculate address for each section std::map<u64,u64> relocationOffsets; for (ElfRelocatorSection& entry: file.sections) { ElfSection* section = entry.section; size_t index = entry.index; int size = section->getSize(); while (relocationAddress % section->getAlignment()) relocationAddress++; if (entry.label != NULL) entry.label->setValue(relocationAddress); relocationOffsets[index] = relocationAddress; relocationAddress += size; } size_t dataStart = outputData.size(); outputData.reserveBytes((size_t)(relocationAddress-start)); // load sections bool error = false; for (ElfRelocatorSection& entry: file.sections) { ElfSection* section = entry.section; size_t index = entry.index; if (section->getType() == SHT_NOBITS) { // reserveBytes initialized the data to 0 already continue; } ByteArray sectionData = section->getData(); // relocate if necessary ElfSection* relSection = entry.relSection; if (relSection != NULL) { for (unsigned int relOffset = 0; relOffset < relSection->getSize(); relOffset += sizeof(Elf32_Rel)) { Elf32_Rel rel; loadRelocation(rel, relSection->getData(), relOffset, elf->isBigEndian()); int pos = rel.r_offset; int symNum = rel.getSymbolNum(); if (symNum <= 0) { Logger::queueError(Logger::Warning,L"Invalid symbol num %06X",symNum); error = true; continue; } Elf32_Sym sym; auto found = elf->getSymbol(sym, symNum); int symSection = sym.st_shndx; RelocationData relData; relData.opcode = sectionData.getDoubleWord(pos, elf->isBigEndian()); relData.opcodeOffset = pos+relocationOffsets[index]; relocator->setSymbolAddress(relData,sym.st_value,sym.st_info & 0xF); // externs? if (relData.targetSymbolType == STT_NOTYPE && sym.st_shndx == 0) { std::wstring symName = toWLowercase(elf->getStrTableString(sym.st_name)); Label* label = Global.symbolTable.getLabel(symName,-1,-1); if (label == NULL) { Logger::queueError(Logger::Error,L"Invalid external symbol %s",symName); error = true; continue; } if (label->isDefined() == false) { Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",symName,file.name); error = true; continue; } relData.relocationBase = (unsigned int) label->getValue(); relData.targetSymbolType = label->isData() ? STT_OBJECT : STT_FUNC; relData.targetSymbolInfo = label->getInfo(); } else { relData.relocationBase = relocationOffsets[symSection]+relData.symbolAddress; } if (relocator->relocateOpcode(rel.getType(),relData) == false) { Logger::queueError(Logger::Error,relData.errorMessage); error = true; continue; } sectionData.replaceDoubleWord(pos,relData.opcode, elf->isBigEndian()); } } size_t arrayStart = (size_t) (dataStart+relocationOffsets[index]-start); memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size()); } // now update symbols for (ElfRelocatorSymbol& sym: file.symbols) { u64 oldAddress = sym.relocatedAddress; switch (sym.section) { case SHN_ABS: // address does not change sym.relocatedAddress = sym.relativeAddress; break; case SHN_COMMON: // needs to be allocated. relativeAddress gives alignment constraint { u64 start = relocationAddress; while (relocationAddress % sym.relativeAddress) relocationAddress++; sym.relocatedAddress = relocationAddress; relocationAddress += sym.size; outputData.reserveBytes((size_t)(relocationAddress-start)); } break; default: // normal relocated symbol sym.relocatedAddress = sym.relativeAddress+relocationOffsets[sym.section]; break; } if (sym.label != NULL) sym.label->setValue(sym.relocatedAddress); if (oldAddress != sym.relocatedAddress) dataChanged = true; } return !error; }
// convert an elf file to a dol file // // args: dol file object // elf filename // returns: true if successful bool convertElfFileToDol(DolFile& dolFile, const char *elfFilename) { // open elf input file ElfFile elfFile; if(!elfFile.open(elfFilename)) return false; if(!elfFile.isPpc()) printf("Elf file doesnt seem to be for PPC!\n"); // create a temp file to store section data during copy FILE* temp_fd = fopen("~temp.tmp", "w+b"); if(temp_fd == 0) { elfFile.close(); return false; } // check which sections to add to dol file for(u32 i=0; i<elfFile.getNumSections(); i++) { // check if section type is 'PROGBITS' // these are the sections required for the dol file if(elfFile.getSectionType(i) == SHT_PROGBITS) { // get section data from elf file fseek(temp_fd, 0, SEEK_SET); elfFile.extractSectionData(i, temp_fd); fseek(temp_fd, 0, SEEK_SET); // sections with 'EXEC' flags are program code, and so // should be added as a TEXT section in the dol file if(elfFile.getSectionFlags(i) & SHF_EXECINSTR) { // add section data to dol file dolFile.addTextSection(temp_fd, elfFile.getSectionAddress(i), elfFile.getSectionSize(i)); } else { // add section data to dol file if (elfFile.getSectionAddress(i) != 0 && elfFile.getSectionSize(i) != 0) dolFile.addDataSection(temp_fd, elfFile.getSectionAddress(i), elfFile.getSectionSize(i)); } } else { // check for bss section by checking section name for '.bss' char *name = 0; if(elfFile.getSectionName(i, name) != ERROR_RETURN) { if(strcasecmp(name, ".bss") == 0) { dolFile.setBssAddress(elfFile.getSectionAddress(i)); dolFile.setBssSize(elfFile.getSectionSize(i)); } delete[] name; } } } // set dol files entry point dolFile.setEntryPoint(elfFile.getEntryPoint()); // finish up fclose(temp_fd); remove("~temp.tmp"); elfFile.close(); printf( "\nConverted %s to %s\n", elfFilename, dolFile.getFilename()); return true; }
// dump dol file to an elf file // // args: dol file object // returns: true if successful bool dumpDolToElfFile(const DolFile& dolFile) { // work out filename to use for elf file char elfFilename[256]; strcpy(elfFilename, dolFile.getFilename()); ChangeFileExtension(elfFilename, "elf"); // create elf output file ElfFile elfFile; if(!elfFile.create(elfFilename, ELFDATA2MSB)) return false; // set elf file as PPC elfFile.setMachineType(EM_PPC); // set entry point in elf file elfFile.setEntryPoint(dolFile.getEntryPoint()); // create a temp file to store section data during copy FILE* temp_fd = fopen("~temp.tmp", "w+b"); if(temp_fd == 0) { elfFile.close(); return false; } char name[32]; // add dol text sections to elf file for(u32 i=0; i<dolFile.getNumTextSections(); i++) { // get section data from dol file fseek(temp_fd, 0, SEEK_SET); dolFile.extractTextSection(i, temp_fd); sprintf(name, ".text%d", i); // add section data to elf file fseek(temp_fd, 0, SEEK_SET); elfFile.addSection(temp_fd, dolFile.getTextAddress(i), dolFile.getTextSize(i), name, SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 32); // add a program header for the section just added // the section just added, was added as the last section // u32 offset = elfFile.getSectionOffset(elfFile.getNumSections() - 1); // elfFile.addProgramHeader(dolFile.getTextAddress(i), dolFile.getTextSize(i), offset, PT_LOAD, PF_EXEC|PF_READ, 32); } // add dol data sections to elf file for(u32 i=0; i<dolFile.getNumDataSections(); i++) { // get section data from dol file fseek(temp_fd, 0, SEEK_SET); dolFile.extractDataSection(i, temp_fd); sprintf(name, ".data%d", i); // add section data to elf file fseek(temp_fd, 0, SEEK_SET); elfFile.addSection(temp_fd, dolFile.getDataAddress(i), dolFile.getDataSize(i), name, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, 32); // add a program header for the section just added // the section just added, was added as the last section // u32 offset = elfFile.getSectionOffset(elfFile.getNumSections() - 1); // elfFile.addProgramHeader(dolFile.getDataAddress(i), dolFile.getDataSize(i), offset, PT_LOAD, PF_WRITE|PF_READ, 32); } // add bss section to elf file elfFile.addSectionHeader(dolFile.getBssAddress(), dolFile.getBssSize(), ".bss", 0, SHT_NOBITS, SHF_WRITE|SHF_ALLOC, 1); // add a program header for the section just added // the section just added, was added as the last section // u32 index = elfFile.getNumSections() - 1; // elfFile.addProgramHeader(elfFile.getSectionAddress(index), elfFile.getSectionSize(index), elfFile.getSectionOffset(index), PT_LOAD, PF_WRITE|PF_READ, 32); // finish up fclose(temp_fd); remove("~temp.tmp"); elfFile.close(); printf( "\nConverted %s to to %s\n", dolFile.getFilename(), elfFilename); return true; }