mirror of
https://github.com/wiiu-env/wut.git
synced 2025-01-23 22:41:12 +01:00
Add some .rpl verification to readrpl
This commit is contained in:
parent
8add0d0503
commit
55b2695eaf
@ -115,6 +115,13 @@ align_down(Type value, size_t alignment)
|
|||||||
return static_cast<Type>(static_cast<size_t>(value) & ~(alignment - 1));
|
return static_cast<Type>(static_cast<size_t>(value) & ~(alignment - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
constexpr bool
|
||||||
|
align_check(Type value, size_t alignment)
|
||||||
|
{
|
||||||
|
return (static_cast<size_t>(value) & (alignment - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_SIZE(Type, Size) \
|
#define CHECK_SIZE(Type, Size) \
|
||||||
static_assert(sizeof(Type) == Size, \
|
static_assert(sizeof(Type) == Size, \
|
||||||
#Type " must be " #Size " bytes")
|
#Type " must be " #Size " bytes")
|
||||||
|
@ -1,555 +1,44 @@
|
|||||||
|
#include "elf.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "verify.h"
|
||||||
|
|
||||||
#include <excmd.h>
|
#include <excmd.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include "elf.h"
|
|
||||||
|
|
||||||
struct Section
|
uint32_t
|
||||||
|
getSectionIndex(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
{
|
{
|
||||||
elf::SectionHeader header;
|
return static_cast<uint32_t>(§ion - &rpl.sections[0]);
|
||||||
std::vector<char> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatET(uint32_t type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case elf::ET_NONE:
|
|
||||||
return "ET_NONE";
|
|
||||||
case elf::ET_REL:
|
|
||||||
return "ET_REL";
|
|
||||||
case elf::ET_EXEC:
|
|
||||||
return "ET_EXEC";
|
|
||||||
case elf::ET_DYN:
|
|
||||||
return "ET_DYN";
|
|
||||||
case elf::ET_CORE:
|
|
||||||
return "ET_CORE";
|
|
||||||
case elf::ET_CAFE_RPL:
|
|
||||||
return "ET_CAFE_RPL";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string
|
bool
|
||||||
formatEM(uint32_t machine)
|
readSection(std::ifstream &fh,
|
||||||
{
|
Section §ion,
|
||||||
switch (machine) {
|
size_t i)
|
||||||
case elf::EM_PPC:
|
|
||||||
return "EM_PPC";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatEABI(uint32_t machine)
|
|
||||||
{
|
|
||||||
switch (machine) {
|
|
||||||
case elf::EABI_CAFE:
|
|
||||||
return "EABI_CAFE";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatSHF(uint32_t flags)
|
|
||||||
{
|
|
||||||
std::string result = "";
|
|
||||||
|
|
||||||
if (flags & elf::SHF_WRITE) {
|
|
||||||
result += "W";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & elf::SHF_ALLOC) {
|
|
||||||
result += "A";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & elf::SHF_EXECINSTR) {
|
|
||||||
result += "X";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & elf::SHF_DEFLATED) {
|
|
||||||
result += "Z";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatSHT(uint32_t type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case elf::SHT_NULL:
|
|
||||||
return "SHT_NULL";
|
|
||||||
case elf::SHT_PROGBITS:
|
|
||||||
return "SHT_PROGBITS";
|
|
||||||
case elf::SHT_SYMTAB:
|
|
||||||
return "SHT_SYMTAB";
|
|
||||||
case elf::SHT_STRTAB:
|
|
||||||
return "SHT_STRTAB";
|
|
||||||
case elf::SHT_RELA:
|
|
||||||
return "SHT_RELA";
|
|
||||||
case elf::SHT_HASH:
|
|
||||||
return "SHT_HASH";
|
|
||||||
case elf::SHT_DYNAMIC:
|
|
||||||
return "SHT_DYNAMIC";
|
|
||||||
case elf::SHT_NOTE:
|
|
||||||
return "SHT_NOTE";
|
|
||||||
case elf::SHT_NOBITS:
|
|
||||||
return "SHT_NOBITS";
|
|
||||||
case elf::SHT_REL:
|
|
||||||
return "SHT_REL";
|
|
||||||
case elf::SHT_SHLIB:
|
|
||||||
return "SHT_SHLIB";
|
|
||||||
case elf::SHT_DYNSYM:
|
|
||||||
return "SHT_DYNSYM";
|
|
||||||
case elf::SHT_INIT_ARRAY:
|
|
||||||
return "SHT_INIT_ARRAY";
|
|
||||||
case elf::SHT_FINI_ARRAY:
|
|
||||||
return "SHT_FINI_ARRAY";
|
|
||||||
case elf::SHT_PREINIT_ARRAY:
|
|
||||||
return "SHT_PREINIT_ARRAY";
|
|
||||||
case elf::SHT_GROUP:
|
|
||||||
return "SHT_GROUP";
|
|
||||||
case elf::SHT_SYMTAB_SHNDX:
|
|
||||||
return "SHT_SYMTAB_SHNDX";
|
|
||||||
case elf::SHT_LOPROC:
|
|
||||||
return "SHT_LOPROC";
|
|
||||||
case elf::SHT_HIPROC:
|
|
||||||
return "SHT_HIPROC";
|
|
||||||
case elf::SHT_LOUSER:
|
|
||||||
return "SHT_LOUSER";
|
|
||||||
case elf::SHT_RPL_EXPORTS:
|
|
||||||
return "SHT_RPL_EXPORTS";
|
|
||||||
case elf::SHT_RPL_IMPORTS:
|
|
||||||
return "SHT_RPL_IMPORTS";
|
|
||||||
case elf::SHT_RPL_CRCS:
|
|
||||||
return "SHT_RPL_CRCS";
|
|
||||||
case elf::SHT_RPL_FILEINFO:
|
|
||||||
return "SHT_RPL_FILEINFO";
|
|
||||||
case elf::SHT_HIUSER:
|
|
||||||
return "SHT_HIUSER";
|
|
||||||
default:
|
|
||||||
return fmt::format("{}", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printHeader(elf::Header &header)
|
|
||||||
{
|
|
||||||
fmt::print("ElfHeader\n");
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "magic", header.magic);
|
|
||||||
fmt::print(" {:<20} = {}\n", "fileClass", header.fileClass);
|
|
||||||
fmt::print(" {:<20} = {}\n", "encoding", header.encoding);
|
|
||||||
fmt::print(" {:<20} = {}\n", "elfVersion", header.elfVersion);
|
|
||||||
fmt::print(" {:<20} = {} 0x{:04x}\n", "abi", formatEABI(header.abi), header.abi);
|
|
||||||
fmt::print(" {:<20} = {} 0x{:04X}\n", "type", formatET(header.type), header.type);
|
|
||||||
fmt::print(" {:<20} = {} {}\n", "machine", formatEM(header.machine), header.machine);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "version", header.version);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "entry", header.entry);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "phoff", header.phoff);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "shoff", header.shoff);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "flags", header.flags);
|
|
||||||
fmt::print(" {:<20} = {}\n", "ehsize", header.ehsize);
|
|
||||||
fmt::print(" {:<20} = {}\n", "phentsize", header.phentsize);
|
|
||||||
fmt::print(" {:<20} = {}\n", "phnum", header.phnum);
|
|
||||||
fmt::print(" {:<20} = {}\n", "shentsize", header.shentsize);
|
|
||||||
fmt::print(" {:<20} = {}\n", "shnum", header.shnum);
|
|
||||||
fmt::print(" {:<20} = {}\n", "shstrndx", header.shstrndx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printSectionSummary(std::vector<Section> §ions,
|
|
||||||
const char *shStrTab)
|
|
||||||
{
|
|
||||||
fmt::print("Sections:\n");
|
|
||||||
fmt::print(
|
|
||||||
" {:<4} {:<20} {:<16} {:<8} {:<6} {:<6} {:<2} {:<4} {:<2} {:<4} {:<5}\n",
|
|
||||||
"[Nr]", "Name", "Type", "Addr", "Off", "Size", "ES", "Flag", "Lk", "Info", "Align");
|
|
||||||
|
|
||||||
for (auto i = 0u; i < sections.size(); ++i) {
|
|
||||||
auto §ion = sections[i];
|
|
||||||
auto name = shStrTab + section.header.name;
|
|
||||||
auto type = formatSHT(section.header.type);
|
|
||||||
auto flags = formatSHF(section.header.flags);
|
|
||||||
|
|
||||||
fmt::print(
|
|
||||||
" [{:>2}] {:<20} {:<16} {:08X} {:06X} {:06X} {:02X} {:>4} {:>2} {:>4} {:>5}\n",
|
|
||||||
i,
|
|
||||||
name,
|
|
||||||
type,
|
|
||||||
static_cast<uint32_t>(section.header.addr),
|
|
||||||
section.header.offset,
|
|
||||||
section.header.size,
|
|
||||||
section.header.entsize,
|
|
||||||
flags,
|
|
||||||
section.header.link,
|
|
||||||
section.header.info,
|
|
||||||
section.header.addralign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printFileInfo(Section §ion)
|
|
||||||
{
|
|
||||||
auto &info = *reinterpret_cast<elf::RplFileInfo *>(section.data.data());
|
|
||||||
auto filename = section.data.data() + info.filename;
|
|
||||||
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "version", info.version);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "textSize", info.textSize);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "textAlign", info.textAlign);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "dataSize", info.dataSize);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "dataAlign", info.dataAlign);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "loadSize", info.loadSize);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "loadAlign", info.loadAlign);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "tempSize", info.tempSize);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "trampAdjust", info.trampAdjust);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "trampAddition", info.trampAddition);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "sdaBase", info.sdaBase);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "sda2Base", info.sda2Base);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "stackSize", info.stackSize);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "heapSize", info.heapSize);
|
|
||||||
|
|
||||||
if (info.filename) {
|
|
||||||
fmt::print(" {:<20} = {}\n", "filename", filename);
|
|
||||||
} else {
|
|
||||||
fmt::print(" {:<20} = 0\n", "filename");
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "flags", info.flags);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "minSdkVersion", info.minVersion);
|
|
||||||
fmt::print(" {:<20} = {}\n", "compressionLevel", info.compressionLevel);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "fileInfoPad", info.fileInfoPad);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "sdkVersion", info.cafeSdkVersion);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "sdkRevision", info.cafeSdkRevision);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "tlsModuleIndex", info.tlsModuleIndex);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "tlsAlignShift", info.tlsAlignShift);
|
|
||||||
fmt::print(" {:<20} = 0x{:X}\n", "runtimeFileInfoSize", info.runtimeFileInfoSize);
|
|
||||||
|
|
||||||
if (info.tagOffset) {
|
|
||||||
const char *tags = section.data.data() + info.tagOffset;
|
|
||||||
fmt::print(" Tags:\n");
|
|
||||||
|
|
||||||
while (*tags) {
|
|
||||||
auto key = tags;
|
|
||||||
tags += strlen(tags) + 1;
|
|
||||||
auto value = tags;
|
|
||||||
tags += strlen(tags) + 1;
|
|
||||||
|
|
||||||
fmt::print(" \"{}\" = \"{}\"\n", key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatRelType(uint32_t type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case elf::R_PPC_NONE:
|
|
||||||
return "NONE";
|
|
||||||
case elf::R_PPC_ADDR32:
|
|
||||||
return "ADDR32";
|
|
||||||
case elf::R_PPC_ADDR16_LO:
|
|
||||||
return "ADDR16_LO";
|
|
||||||
case elf::R_PPC_ADDR16_HI:
|
|
||||||
return "ADDR16_HI";
|
|
||||||
case elf::R_PPC_ADDR16_HA:
|
|
||||||
return "ADDR16_HA";
|
|
||||||
case elf::R_PPC_REL24:
|
|
||||||
return "REL24";
|
|
||||||
case elf::R_PPC_REL14:
|
|
||||||
return "REL14";
|
|
||||||
case elf::R_PPC_DTPMOD32:
|
|
||||||
return "DTPMOD32";
|
|
||||||
case elf::R_PPC_DTPREL32:
|
|
||||||
return "DTPREL32";
|
|
||||||
case elf::R_PPC_EMB_SDA21:
|
|
||||||
return "EMB_SDA21";
|
|
||||||
case elf::R_PPC_EMB_RELSDA:
|
|
||||||
return "EMB_RELSDA";
|
|
||||||
case elf::R_PPC_DIAB_SDA21_LO:
|
|
||||||
return "DIAB_SDA21_LO";
|
|
||||||
case elf::R_PPC_DIAB_SDA21_HI:
|
|
||||||
return "DIAB_SDA21_HI";
|
|
||||||
case elf::R_PPC_DIAB_SDA21_HA:
|
|
||||||
return "DIAB_SDA21_HA";
|
|
||||||
case elf::R_PPC_DIAB_RELSDA_LO:
|
|
||||||
return "DIAB_RELSDA_LO";
|
|
||||||
case elf::R_PPC_DIAB_RELSDA_HI:
|
|
||||||
return "DIAB_RELSDA_HI";
|
|
||||||
case elf::R_PPC_DIAB_RELSDA_HA:
|
|
||||||
return "DIAB_RELSDA_HA";
|
|
||||||
case elf::R_PPC_GHS_REL16_HA:
|
|
||||||
return "GHS_REL16_HA";
|
|
||||||
case elf::R_PPC_GHS_REL16_HI:
|
|
||||||
return "GHS_REL16_HI";
|
|
||||||
case elf::R_PPC_GHS_REL16_LO:
|
|
||||||
return "GHS_REL16_LO";
|
|
||||||
default:
|
|
||||||
return fmt::format("{}", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatSymType(uint32_t type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case elf::STT_NOTYPE:
|
|
||||||
return "NOTYPE";
|
|
||||||
case elf::STT_OBJECT:
|
|
||||||
return "OBJECT";
|
|
||||||
case elf::STT_FUNC:
|
|
||||||
return "FUNC";
|
|
||||||
case elf::STT_SECTION:
|
|
||||||
return "SECTION";
|
|
||||||
case elf::STT_FILE:
|
|
||||||
return "FILE";
|
|
||||||
case elf::STT_COMMON:
|
|
||||||
return "COMMON";
|
|
||||||
case elf::STT_TLS:
|
|
||||||
return "TLS";
|
|
||||||
case elf::STT_LOOS:
|
|
||||||
return "LOOS";
|
|
||||||
case elf::STT_HIOS:
|
|
||||||
return "HIOS";
|
|
||||||
case elf::STT_GNU_IFUNC:
|
|
||||||
return "GNU_IFUNC";
|
|
||||||
default:
|
|
||||||
return fmt::format("{}", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatSymBinding(uint32_t type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case elf::STB_LOCAL:
|
|
||||||
return "LOCAL";
|
|
||||||
case elf::STB_GLOBAL:
|
|
||||||
return "GLOBAL";
|
|
||||||
case elf::STB_WEAK:
|
|
||||||
return "WEAK";
|
|
||||||
case elf::STB_GNU_UNIQUE:
|
|
||||||
return "UNIQUE";
|
|
||||||
default:
|
|
||||||
return fmt::format("{}", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string
|
|
||||||
formatSymShndx(uint32_t type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case elf::SHN_UNDEF:
|
|
||||||
return "UND";
|
|
||||||
case elf::SHN_ABS:
|
|
||||||
return "ABS";
|
|
||||||
case elf::SHN_COMMON:
|
|
||||||
return "CMN";
|
|
||||||
case elf::SHN_XINDEX:
|
|
||||||
return "UND";
|
|
||||||
default:
|
|
||||||
return fmt::format("{}", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printRela(std::vector<Section> §ions,
|
|
||||||
const char *shStrTab,
|
|
||||||
Section §ion)
|
|
||||||
{
|
|
||||||
fmt::print(
|
|
||||||
" {:<8} {:<8} {:<16} {:<8} {}\n", "Offset", "Info", "Type", "Value", "Name + Addend");
|
|
||||||
|
|
||||||
auto &symSec = sections[section.header.link];
|
|
||||||
auto symbols = reinterpret_cast<elf::Symbol *>(symSec.data.data());
|
|
||||||
auto &symStrTab = sections[symSec.header.link];
|
|
||||||
|
|
||||||
auto relas = reinterpret_cast<elf::Rela *>(section.data.data());
|
|
||||||
auto count = section.data.size() / sizeof(elf::Rela);
|
|
||||||
|
|
||||||
for (auto i = 0u; i < count; ++i) {
|
|
||||||
auto &rela = relas[i];
|
|
||||||
|
|
||||||
auto index = rela.info >> 8;
|
|
||||||
auto type = rela.info & 0xff;
|
|
||||||
auto typeName = formatRelType(type);
|
|
||||||
|
|
||||||
auto symbol = symbols[index];
|
|
||||||
auto name = reinterpret_cast<const char*>(symStrTab.data.data()) + symbol.name;
|
|
||||||
|
|
||||||
fmt::print(
|
|
||||||
" {:08X} {:08X} {:<16} {:08X} {} + {:X}\n",
|
|
||||||
rela.offset,
|
|
||||||
rela.info,
|
|
||||||
typeName,
|
|
||||||
symbol.value,
|
|
||||||
name,
|
|
||||||
rela.addend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printSymTab(std::vector<Section> §ions,
|
|
||||||
Section §ion)
|
|
||||||
{
|
|
||||||
auto strTab = reinterpret_cast<const char*>(sections[section.header.link].data.data());
|
|
||||||
|
|
||||||
fmt::print(
|
|
||||||
" {:<4} {:<8} {:<6} {:<8} {:<8} {:<3} {}\n",
|
|
||||||
"Num", "Value", "Size", "Type", "Bind", "Ndx", "Name");
|
|
||||||
|
|
||||||
auto id = 0u;
|
|
||||||
auto symbols = reinterpret_cast<elf::Symbol *>(section.data.data());
|
|
||||||
auto count = section.data.size() / sizeof(elf::Symbol);
|
|
||||||
|
|
||||||
for (auto i = 0u; i < count; ++i) {
|
|
||||||
auto &symbol = symbols[i];
|
|
||||||
|
|
||||||
auto name = strTab + symbol.name;
|
|
||||||
auto binding = symbol.info >> 4;
|
|
||||||
auto type = symbol.info & 0xf;
|
|
||||||
auto typeName = formatSymType(type);
|
|
||||||
auto bindingName = formatSymBinding(binding);
|
|
||||||
auto ndx = formatSymShndx(symbol.shndx);
|
|
||||||
|
|
||||||
fmt::print(
|
|
||||||
" {:>4} {:08X} {:>6} {:<8} {:<8} {:>3} {}\n",
|
|
||||||
id, symbol.value, symbol.size, typeName, bindingName, ndx, name);
|
|
||||||
|
|
||||||
++id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printRplImports(std::vector<Section> §ions,
|
|
||||||
uint32_t index,
|
|
||||||
Section §ion)
|
|
||||||
{
|
|
||||||
auto import = reinterpret_cast<elf::RplImport *>(section.data.data());
|
|
||||||
fmt::print(" {:<20} = {}\n", "name", import->name);
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "signature", import->signature);
|
|
||||||
fmt::print(" {:<20} = {}\n", "count", import->count);
|
|
||||||
|
|
||||||
if (import->count) {
|
|
||||||
for (auto &symSection : sections) {
|
|
||||||
if (symSection.header.type != elf::SHT_SYMTAB) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto symbols = reinterpret_cast<elf::Symbol *>(symSection.data.data());
|
|
||||||
auto count = symSection.data.size() / sizeof(elf::Symbol);
|
|
||||||
auto strTab = reinterpret_cast<const char*>(sections[symSection.header.link].data.data());
|
|
||||||
|
|
||||||
for (auto i = 0u; i < count; ++i) {
|
|
||||||
auto &symbol = symbols[i];
|
|
||||||
auto type = symbol.info & 0xf;
|
|
||||||
|
|
||||||
if (symbol.shndx == index &&
|
|
||||||
(type == elf::STT_FUNC || type == elf::STT_OBJECT)) {
|
|
||||||
fmt::print(" {}\n", strTab + symbol.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
checkRplCrcs(std::vector<Section> §ions)
|
|
||||||
{
|
|
||||||
elf::RplCrc *crcs = NULL;
|
|
||||||
auto crcSectionIndex = 0u;
|
|
||||||
|
|
||||||
for (auto i = 0u; i < sections.size(); ++i) {
|
|
||||||
auto §ion = sections[i];
|
|
||||||
if (section.header.type == elf::SHT_RPL_CRCS) {
|
|
||||||
crcs = reinterpret_cast<elf::RplCrc *>(section.data.data());
|
|
||||||
crcSectionIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!crcs) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto i = 0u; i < sections.size(); ++i) {
|
|
||||||
auto §ion = sections[i];
|
|
||||||
auto crc = uint32_t { 0u };
|
|
||||||
|
|
||||||
if (i == crcSectionIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section.data.size()) {
|
|
||||||
crc = crc32(0, Z_NULL, 0);
|
|
||||||
crc = crc32(crc, reinterpret_cast<Bytef *>(section.data.data()), section.data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crc != crcs[i].crc) {
|
|
||||||
fmt::print("Unexpected crc for section {}, read 0x{:08X} but calculated 0x{:08X}",
|
|
||||||
i, crcs[i].crc, crc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printRplCrcs(std::vector<Section> §ions,
|
|
||||||
const char *shStrTab,
|
|
||||||
Section §ion)
|
|
||||||
{
|
|
||||||
auto crcs = reinterpret_cast<elf::RplCrc *>(section.data.data());
|
|
||||||
auto count = section.data.size() / sizeof(elf::RplCrc);
|
|
||||||
|
|
||||||
for (auto i = 0u; i < count; ++i) {
|
|
||||||
auto name = shStrTab + sections[i].header.name;
|
|
||||||
fmt::print(" [{:>2}] 0x{:08X} {}\n", i, static_cast<uint32_t>(crcs[i].crc), name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
printRplExports(Section §ion)
|
|
||||||
{
|
|
||||||
auto exports = reinterpret_cast<elf::RplExport *>(section.data.data());
|
|
||||||
auto strTab = section.data.data();
|
|
||||||
fmt::print(" {:<20} = 0x{:08X}\n", "signature", exports->signature);
|
|
||||||
fmt::print(" {:<20} = {}\n", "count", exports->count);
|
|
||||||
|
|
||||||
for (auto i = 0u; i < exports->count; ++i) {
|
|
||||||
// TLS exports have the high bit set in name for some unknown reason...
|
|
||||||
auto name = strTab + (exports->exports[i].name & 0x7FFFFFFF);
|
|
||||||
auto value = exports->exports[i].value;
|
|
||||||
|
|
||||||
fmt::print(" 0x{:08X} {}\n", static_cast<uint32_t>(value), name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool readSection(std::ifstream &fh,
|
|
||||||
elf::SectionHeader &header,
|
|
||||||
std::vector<char> &data)
|
|
||||||
{
|
{
|
||||||
// Read section header
|
// Read section header
|
||||||
fh.read(reinterpret_cast<char*>(&header), sizeof(elf::SectionHeader));
|
fh.read(reinterpret_cast<char*>(§ion.header), sizeof(elf::SectionHeader));
|
||||||
|
|
||||||
if (header.type == elf::SHT_NOBITS || !header.size) {
|
if (section.header.type == elf::SHT_NOBITS || !section.header.size) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read section data
|
// Read section data
|
||||||
if (header.flags & elf::SHF_DEFLATED) {
|
if (section.header.flags & elf::SHF_DEFLATED) {
|
||||||
auto stream = z_stream {};
|
auto stream = z_stream {};
|
||||||
auto ret = Z_OK;
|
auto ret = Z_OK;
|
||||||
|
|
||||||
// Read the original size
|
// Read the original size
|
||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
fh.seekg(header.offset.value());
|
fh.seekg(section.header.offset.value());
|
||||||
fh.read(reinterpret_cast<char *>(&size), sizeof(uint32_t));
|
fh.read(reinterpret_cast<char *>(&size), sizeof(uint32_t));
|
||||||
size = byte_swap(size);
|
size = byte_swap(size);
|
||||||
data.resize(size);
|
section.data.resize(size);
|
||||||
|
|
||||||
// Inflate
|
// Inflate
|
||||||
memset(&stream, 0, sizeof(stream));
|
memset(&stream, 0, sizeof(stream));
|
||||||
@ -561,32 +50,32 @@ bool readSection(std::ifstream &fh,
|
|||||||
|
|
||||||
if (ret != Z_OK) {
|
if (ret != Z_OK) {
|
||||||
fmt::print("Couldn't decompress .rpx section because inflateInit returned {}\n", ret);
|
fmt::print("Couldn't decompress .rpx section because inflateInit returned {}\n", ret);
|
||||||
data.clear();
|
section.data.clear();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
std::vector<char> temp;
|
std::vector<char> temp;
|
||||||
temp.resize(header.size-sizeof(uint32_t));
|
temp.resize(section.header.size-sizeof(uint32_t));
|
||||||
fh.read(temp.data(), temp.size());
|
fh.read(temp.data(), temp.size());
|
||||||
|
|
||||||
stream.avail_in = header.size;
|
stream.avail_in = section.header.size;
|
||||||
stream.next_in = reinterpret_cast<Bytef*>(temp.data());
|
stream.next_in = reinterpret_cast<Bytef *>(temp.data());
|
||||||
stream.avail_out = static_cast<uInt>(data.size());
|
stream.avail_out = static_cast<uInt>(section.data.size());
|
||||||
stream.next_out = reinterpret_cast<Bytef*>(data.data());
|
stream.next_out = reinterpret_cast<Bytef *>(section.data.data());
|
||||||
|
|
||||||
ret = inflate(&stream, Z_FINISH);
|
ret = inflate(&stream, Z_FINISH);
|
||||||
|
|
||||||
if (ret != Z_OK && ret != Z_STREAM_END) {
|
if (ret != Z_OK && ret != Z_STREAM_END) {
|
||||||
fmt::print("Couldn't decompress .rpx section because inflate returned {}\n", ret);
|
fmt::print("Couldn't decompress .rpx section because inflate returned {}\n", ret);
|
||||||
data.clear();
|
section.data.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inflateEnd(&stream);
|
inflateEnd(&stream);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data.resize(header.size);
|
section.data.resize(section.header.size);
|
||||||
fh.seekg(header.offset.value());
|
fh.seekg(section.header.offset.value());
|
||||||
fh.read(data.data(), header.size);
|
fh.read(section.data.data(), section.header.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -660,57 +149,62 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
// Read file
|
// Read file
|
||||||
std::ifstream fh { path, std::ifstream::binary };
|
std::ifstream fh { path, std::ifstream::binary };
|
||||||
|
|
||||||
if (!fh.is_open()) {
|
if (!fh.is_open()) {
|
||||||
fmt::print("Could not open {} for reading\n", path);
|
fmt::print("Could not open {} for reading\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
elf::Header header;
|
Rpl rpl;
|
||||||
fh.read(reinterpret_cast<char*>(&header), sizeof(elf::Header));
|
fh.read(reinterpret_cast<char*>(&rpl.header), sizeof(elf::Header));
|
||||||
|
|
||||||
if (header.magic != elf::HeaderMagic) {
|
if (rpl.header.magic != elf::HeaderMagic) {
|
||||||
fmt::print("Invalid ELF magic header\n");
|
fmt::print("Invalid ELF magic header\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read sections
|
// Read sections
|
||||||
auto sections = std::vector<Section> {};
|
for (auto i = 0u; i < rpl.header.shnum; ++i) {
|
||||||
|
|
||||||
for (auto i = 0u; i < header.shnum; ++i) {
|
|
||||||
Section section;
|
Section section;
|
||||||
fh.seekg(header.shoff + header.shentsize * i);
|
fh.seekg(rpl.header.shoff + rpl.header.shentsize * i);
|
||||||
|
|
||||||
if (!readSection(fh, section.header, section.data)) {
|
if (!readSection(fh, section, i)) {
|
||||||
fmt::print("Error reading section {}", i);
|
fmt::print("Error reading section {}", i);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.push_back(section);
|
rpl.sections.push_back(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find strtab
|
// Set section names
|
||||||
auto shStrTab = reinterpret_cast<const char *>(sections[header.shstrndx].data.data());
|
auto shStrTab = reinterpret_cast<const char *>(rpl.sections[rpl.header.shstrndx].data.data());
|
||||||
|
for (auto §ion : rpl.sections) {
|
||||||
|
section.name = shStrTab + section.header.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify rpl format
|
||||||
|
verifyFile(rpl);
|
||||||
|
verifyCrcs(rpl);
|
||||||
|
verifyFileBounds(rpl);
|
||||||
|
verifyRelocationTypes(rpl);
|
||||||
|
verifySectionAlignment(rpl);
|
||||||
|
verifySectionOrder(rpl);
|
||||||
|
|
||||||
// Format shit
|
// Format shit
|
||||||
if (dumpElfHeader) {
|
if (dumpElfHeader) {
|
||||||
printHeader(header);
|
printHeader(rpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dumpSectionSummary) {
|
if (dumpSectionSummary) {
|
||||||
printSectionSummary(sections, shStrTab);
|
printSectionSummary(rpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkRplCrcs(sections);
|
|
||||||
|
|
||||||
// Print section data
|
// Print section data
|
||||||
for (auto i = 0u; i < sections.size(); ++i) {
|
for (auto i = 0u; i < rpl.sections.size(); ++i) {
|
||||||
auto §ion = sections[i];
|
auto §ion = rpl.sections[i];
|
||||||
auto name = shStrTab + section.header.name;
|
|
||||||
auto printSectionHeader = [&](){
|
auto printSectionHeader = [&](){
|
||||||
fmt::print(
|
fmt::print(
|
||||||
"Section {}: {}, {}, {} bytes\n",
|
"Section {}: {}, {}, {} bytes\n",
|
||||||
i, formatSHT(section.header.type), name, section.data.size());
|
i, formatSHT(section.header.type), section.name, section.data.size());
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (section.header.type) {
|
switch (section.header.type) {
|
||||||
@ -724,7 +218,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printSectionHeader();
|
printSectionHeader();
|
||||||
printRela(sections, shStrTab, section);
|
printRela(rpl, section);
|
||||||
break;
|
break;
|
||||||
case elf::SHT_SYMTAB:
|
case elf::SHT_SYMTAB:
|
||||||
if (!dumpSectionSymtab) {
|
if (!dumpSectionSymtab) {
|
||||||
@ -732,7 +226,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printSectionHeader();
|
printSectionHeader();
|
||||||
printSymTab(sections, section);
|
printSymTab(rpl, section);
|
||||||
break;
|
break;
|
||||||
case elf::SHT_STRTAB:
|
case elf::SHT_STRTAB:
|
||||||
break;
|
break;
|
||||||
@ -744,7 +238,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printSectionHeader();
|
printSectionHeader();
|
||||||
printRplExports(section);
|
printRplExports(rpl, section);
|
||||||
break;
|
break;
|
||||||
case elf::SHT_RPL_IMPORTS:
|
case elf::SHT_RPL_IMPORTS:
|
||||||
if (!dumpSectionRplImports) {
|
if (!dumpSectionRplImports) {
|
||||||
@ -752,7 +246,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printSectionHeader();
|
printSectionHeader();
|
||||||
printRplImports(sections, i, section);
|
printRplImports(rpl, section);
|
||||||
break;
|
break;
|
||||||
case elf::SHT_RPL_CRCS:
|
case elf::SHT_RPL_CRCS:
|
||||||
if (!dumpSectionRplCrcs) {
|
if (!dumpSectionRplCrcs) {
|
||||||
@ -760,7 +254,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printSectionHeader();
|
printSectionHeader();
|
||||||
printRplCrcs(sections, shStrTab, section);
|
printRplCrcs(rpl, section);
|
||||||
break;
|
break;
|
||||||
case elf::SHT_RPL_FILEINFO:
|
case elf::SHT_RPL_FILEINFO:
|
||||||
if (!dumpSectionRplFileinfo) {
|
if (!dumpSectionRplFileinfo) {
|
||||||
@ -768,7 +262,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printSectionHeader();
|
printSectionHeader();
|
||||||
printFileInfo(section);
|
printFileInfo(rpl, section);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
477
tools/readrpl/print.cpp
Normal file
477
tools/readrpl/print.cpp
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
#include "print.h"
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatET(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::ET_NONE:
|
||||||
|
return "ET_NONE";
|
||||||
|
case elf::ET_REL:
|
||||||
|
return "ET_REL";
|
||||||
|
case elf::ET_EXEC:
|
||||||
|
return "ET_EXEC";
|
||||||
|
case elf::ET_DYN:
|
||||||
|
return "ET_DYN";
|
||||||
|
case elf::ET_CORE:
|
||||||
|
return "ET_CORE";
|
||||||
|
case elf::ET_CAFE_RPL:
|
||||||
|
return "ET_CAFE_RPL";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatEM(uint32_t machine)
|
||||||
|
{
|
||||||
|
switch (machine) {
|
||||||
|
case elf::EM_PPC:
|
||||||
|
return "EM_PPC";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", machine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatEABI(uint32_t eabi)
|
||||||
|
{
|
||||||
|
switch (eabi) {
|
||||||
|
case elf::EABI_CAFE:
|
||||||
|
return "EABI_CAFE";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", eabi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSHF(uint32_t flags)
|
||||||
|
{
|
||||||
|
std::string result = "";
|
||||||
|
|
||||||
|
if (flags & elf::SHF_WRITE) {
|
||||||
|
result += "W";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & elf::SHF_ALLOC) {
|
||||||
|
result += "A";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & elf::SHF_EXECINSTR) {
|
||||||
|
result += "X";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & elf::SHF_DEFLATED) {
|
||||||
|
result += "Z";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
formatSHT(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::SHT_NULL:
|
||||||
|
return "SHT_NULL";
|
||||||
|
case elf::SHT_PROGBITS:
|
||||||
|
return "SHT_PROGBITS";
|
||||||
|
case elf::SHT_SYMTAB:
|
||||||
|
return "SHT_SYMTAB";
|
||||||
|
case elf::SHT_STRTAB:
|
||||||
|
return "SHT_STRTAB";
|
||||||
|
case elf::SHT_RELA:
|
||||||
|
return "SHT_RELA";
|
||||||
|
case elf::SHT_HASH:
|
||||||
|
return "SHT_HASH";
|
||||||
|
case elf::SHT_DYNAMIC:
|
||||||
|
return "SHT_DYNAMIC";
|
||||||
|
case elf::SHT_NOTE:
|
||||||
|
return "SHT_NOTE";
|
||||||
|
case elf::SHT_NOBITS:
|
||||||
|
return "SHT_NOBITS";
|
||||||
|
case elf::SHT_REL:
|
||||||
|
return "SHT_REL";
|
||||||
|
case elf::SHT_SHLIB:
|
||||||
|
return "SHT_SHLIB";
|
||||||
|
case elf::SHT_DYNSYM:
|
||||||
|
return "SHT_DYNSYM";
|
||||||
|
case elf::SHT_INIT_ARRAY:
|
||||||
|
return "SHT_INIT_ARRAY";
|
||||||
|
case elf::SHT_FINI_ARRAY:
|
||||||
|
return "SHT_FINI_ARRAY";
|
||||||
|
case elf::SHT_PREINIT_ARRAY:
|
||||||
|
return "SHT_PREINIT_ARRAY";
|
||||||
|
case elf::SHT_GROUP:
|
||||||
|
return "SHT_GROUP";
|
||||||
|
case elf::SHT_SYMTAB_SHNDX:
|
||||||
|
return "SHT_SYMTAB_SHNDX";
|
||||||
|
case elf::SHT_LOPROC:
|
||||||
|
return "SHT_LOPROC";
|
||||||
|
case elf::SHT_HIPROC:
|
||||||
|
return "SHT_HIPROC";
|
||||||
|
case elf::SHT_LOUSER:
|
||||||
|
return "SHT_LOUSER";
|
||||||
|
case elf::SHT_RPL_EXPORTS:
|
||||||
|
return "SHT_RPL_EXPORTS";
|
||||||
|
case elf::SHT_RPL_IMPORTS:
|
||||||
|
return "SHT_RPL_IMPORTS";
|
||||||
|
case elf::SHT_RPL_CRCS:
|
||||||
|
return "SHT_RPL_CRCS";
|
||||||
|
case elf::SHT_RPL_FILEINFO:
|
||||||
|
return "SHT_RPL_FILEINFO";
|
||||||
|
case elf::SHT_HIUSER:
|
||||||
|
return "SHT_HIUSER";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatRelType(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::R_PPC_NONE:
|
||||||
|
return "NONE";
|
||||||
|
case elf::R_PPC_ADDR32:
|
||||||
|
return "ADDR32";
|
||||||
|
case elf::R_PPC_ADDR16_LO:
|
||||||
|
return "ADDR16_LO";
|
||||||
|
case elf::R_PPC_ADDR16_HI:
|
||||||
|
return "ADDR16_HI";
|
||||||
|
case elf::R_PPC_ADDR16_HA:
|
||||||
|
return "ADDR16_HA";
|
||||||
|
case elf::R_PPC_REL24:
|
||||||
|
return "REL24";
|
||||||
|
case elf::R_PPC_REL14:
|
||||||
|
return "REL14";
|
||||||
|
case elf::R_PPC_DTPMOD32:
|
||||||
|
return "DTPMOD32";
|
||||||
|
case elf::R_PPC_DTPREL32:
|
||||||
|
return "DTPREL32";
|
||||||
|
case elf::R_PPC_EMB_SDA21:
|
||||||
|
return "EMB_SDA21";
|
||||||
|
case elf::R_PPC_EMB_RELSDA:
|
||||||
|
return "EMB_RELSDA";
|
||||||
|
case elf::R_PPC_DIAB_SDA21_LO:
|
||||||
|
return "DIAB_SDA21_LO";
|
||||||
|
case elf::R_PPC_DIAB_SDA21_HI:
|
||||||
|
return "DIAB_SDA21_HI";
|
||||||
|
case elf::R_PPC_DIAB_SDA21_HA:
|
||||||
|
return "DIAB_SDA21_HA";
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_LO:
|
||||||
|
return "DIAB_RELSDA_LO";
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_HI:
|
||||||
|
return "DIAB_RELSDA_HI";
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_HA:
|
||||||
|
return "DIAB_RELSDA_HA";
|
||||||
|
case elf::R_PPC_GHS_REL16_HA:
|
||||||
|
return "GHS_REL16_HA";
|
||||||
|
case elf::R_PPC_GHS_REL16_HI:
|
||||||
|
return "GHS_REL16_HI";
|
||||||
|
case elf::R_PPC_GHS_REL16_LO:
|
||||||
|
return "GHS_REL16_LO";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSymType(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::STT_NOTYPE:
|
||||||
|
return "NOTYPE";
|
||||||
|
case elf::STT_OBJECT:
|
||||||
|
return "OBJECT";
|
||||||
|
case elf::STT_FUNC:
|
||||||
|
return "FUNC";
|
||||||
|
case elf::STT_SECTION:
|
||||||
|
return "SECTION";
|
||||||
|
case elf::STT_FILE:
|
||||||
|
return "FILE";
|
||||||
|
case elf::STT_COMMON:
|
||||||
|
return "COMMON";
|
||||||
|
case elf::STT_TLS:
|
||||||
|
return "TLS";
|
||||||
|
case elf::STT_LOOS:
|
||||||
|
return "LOOS";
|
||||||
|
case elf::STT_HIOS:
|
||||||
|
return "HIOS";
|
||||||
|
case elf::STT_GNU_IFUNC:
|
||||||
|
return "GNU_IFUNC";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSymBinding(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::STB_LOCAL:
|
||||||
|
return "LOCAL";
|
||||||
|
case elf::STB_GLOBAL:
|
||||||
|
return "GLOBAL";
|
||||||
|
case elf::STB_WEAK:
|
||||||
|
return "WEAK";
|
||||||
|
case elf::STB_GNU_UNIQUE:
|
||||||
|
return "UNIQUE";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSymShndx(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::SHN_UNDEF:
|
||||||
|
return "UND";
|
||||||
|
case elf::SHN_ABS:
|
||||||
|
return "ABS";
|
||||||
|
case elf::SHN_COMMON:
|
||||||
|
return "CMN";
|
||||||
|
case elf::SHN_XINDEX:
|
||||||
|
return "UND";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printHeader(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
const auto &header = rpl.header;
|
||||||
|
fmt::print("ElfHeader\n");
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "magic", header.magic);
|
||||||
|
fmt::print(" {:<20} = {}\n", "fileClass", header.fileClass);
|
||||||
|
fmt::print(" {:<20} = {}\n", "encoding", header.encoding);
|
||||||
|
fmt::print(" {:<20} = {}\n", "elfVersion", header.elfVersion);
|
||||||
|
fmt::print(" {:<20} = {} 0x{:04x}\n", "abi", formatEABI(header.abi), header.abi);
|
||||||
|
fmt::print(" {:<20} = {} 0x{:04X}\n", "type", formatET(header.type), header.type);
|
||||||
|
fmt::print(" {:<20} = {} {}\n", "machine", formatEM(header.machine), header.machine);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "version", header.version);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "entry", header.entry);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "phoff", header.phoff);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "shoff", header.shoff);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "flags", header.flags);
|
||||||
|
fmt::print(" {:<20} = {}\n", "ehsize", header.ehsize);
|
||||||
|
fmt::print(" {:<20} = {}\n", "phentsize", header.phentsize);
|
||||||
|
fmt::print(" {:<20} = {}\n", "phnum", header.phnum);
|
||||||
|
fmt::print(" {:<20} = {}\n", "shentsize", header.shentsize);
|
||||||
|
fmt::print(" {:<20} = {}\n", "shnum", header.shnum);
|
||||||
|
fmt::print(" {:<20} = {}\n", "shstrndx", header.shstrndx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printSectionSummary(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
fmt::print("Sections:\n");
|
||||||
|
fmt::print(
|
||||||
|
" {:<4} {:<20} {:<16} {:<8} {:<6} {:<6} {:<2} {:<4} {:<2} {:<4} {:<5}\n",
|
||||||
|
"[Nr]", "Name", "Type", "Addr", "Off", "Size", "ES", "Flag", "Lk", "Info", "Align");
|
||||||
|
|
||||||
|
for (auto i = 0u; i < rpl.sections.size(); ++i) {
|
||||||
|
auto §ion = rpl.sections[i];
|
||||||
|
auto type = formatSHT(section.header.type);
|
||||||
|
auto flags = formatSHF(section.header.flags);
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" [{:>2}] {:<20} {:<16} {:08X} {:06X} {:06X} {:02X} {:>4} {:>2} {:>4} {:>5}\n",
|
||||||
|
i,
|
||||||
|
section.name,
|
||||||
|
type,
|
||||||
|
section.header.addr,
|
||||||
|
section.header.offset,
|
||||||
|
section.header.size,
|
||||||
|
section.header.entsize,
|
||||||
|
flags,
|
||||||
|
section.header.link,
|
||||||
|
section.header.info,
|
||||||
|
section.header.addralign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printFileInfo(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
auto &info = *reinterpret_cast<const elf::RplFileInfo *>(section.data.data());
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "version", info.version);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "textSize", info.textSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "textAlign", info.textAlign);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "dataSize", info.dataSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "dataAlign", info.dataAlign);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "loadSize", info.loadSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "loadAlign", info.loadAlign);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "tempSize", info.tempSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "trampAdjust", info.trampAdjust);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "trampAddition", info.trampAddition);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "sdaBase", info.sdaBase);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "sda2Base", info.sda2Base);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "stackSize", info.stackSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "heapSize", info.heapSize);
|
||||||
|
|
||||||
|
if (info.filename) {
|
||||||
|
auto filename = section.data.data() + info.filename;
|
||||||
|
fmt::print(" {:<20} = {}\n", "filename", filename);
|
||||||
|
} else {
|
||||||
|
fmt::print(" {:<20} = 0\n", "filename");
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "flags", info.flags);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "minSdkVersion", info.minVersion);
|
||||||
|
fmt::print(" {:<20} = {}\n", "compressionLevel", info.compressionLevel);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "fileInfoPad", info.fileInfoPad);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "sdkVersion", info.cafeSdkVersion);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "sdkRevision", info.cafeSdkRevision);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "tlsModuleIndex", info.tlsModuleIndex);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "tlsAlignShift", info.tlsAlignShift);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "runtimeFileInfoSize", info.runtimeFileInfoSize);
|
||||||
|
|
||||||
|
if (info.tagOffset) {
|
||||||
|
const char *tags = section.data.data() + info.tagOffset;
|
||||||
|
fmt::print(" Tags:\n");
|
||||||
|
|
||||||
|
while (*tags) {
|
||||||
|
auto key = tags;
|
||||||
|
tags += strlen(tags) + 1;
|
||||||
|
auto value = tags;
|
||||||
|
tags += strlen(tags) + 1;
|
||||||
|
|
||||||
|
fmt::print(" \"{}\" = \"{}\"\n", key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printRela(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
fmt::print(
|
||||||
|
" {:<8} {:<8} {:<16} {:<8} {}\n", "Offset", "Info", "Type", "Value", "Name + Addend");
|
||||||
|
|
||||||
|
auto &symSec = rpl.sections[section.header.link];
|
||||||
|
auto symbols = reinterpret_cast<const elf::Symbol *>(symSec.data.data());
|
||||||
|
auto &symStrTab = rpl.sections[symSec.header.link];
|
||||||
|
|
||||||
|
auto relas = reinterpret_cast<const elf::Rela *>(section.data.data());
|
||||||
|
auto count = section.data.size() / sizeof(elf::Rela);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
auto &rela = relas[i];
|
||||||
|
|
||||||
|
auto index = rela.info >> 8;
|
||||||
|
auto type = rela.info & 0xff;
|
||||||
|
auto typeName = formatRelType(type);
|
||||||
|
|
||||||
|
auto symbol = symbols[index];
|
||||||
|
auto name = reinterpret_cast<const char*>(symStrTab.data.data()) + symbol.name;
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" {:08X} {:08X} {:<16} {:08X} {} + {:X}\n",
|
||||||
|
rela.offset,
|
||||||
|
rela.info,
|
||||||
|
typeName,
|
||||||
|
symbol.value,
|
||||||
|
name,
|
||||||
|
rela.addend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printSymTab(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
auto strTab = reinterpret_cast<const char*>(rpl.sections[section.header.link].data.data());
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" {:<4} {:<8} {:<6} {:<8} {:<8} {:<3} {}\n",
|
||||||
|
"Num", "Value", "Size", "Type", "Bind", "Ndx", "Name");
|
||||||
|
|
||||||
|
auto id = 0u;
|
||||||
|
auto symbols = reinterpret_cast<const elf::Symbol *>(section.data.data());
|
||||||
|
auto count = section.data.size() / sizeof(elf::Symbol);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
auto &symbol = symbols[i];
|
||||||
|
|
||||||
|
auto name = strTab + symbol.name;
|
||||||
|
auto binding = symbol.info >> 4;
|
||||||
|
auto type = symbol.info & 0xf;
|
||||||
|
auto typeName = formatSymType(type);
|
||||||
|
auto bindingName = formatSymBinding(binding);
|
||||||
|
auto ndx = formatSymShndx(symbol.shndx);
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" {:>4} {:08X} {:>6} {:<8} {:<8} {:>3} {}\n",
|
||||||
|
id, symbol.value, symbol.size, typeName, bindingName, ndx, name);
|
||||||
|
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printRplImports(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
auto sectionIndex = getSectionIndex(rpl, section);
|
||||||
|
auto import = reinterpret_cast<const elf::RplImport *>(section.data.data());
|
||||||
|
fmt::print(" {:<20} = {}\n", "name", import->name);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "signature", import->signature);
|
||||||
|
fmt::print(" {:<20} = {}\n", "count", import->count);
|
||||||
|
|
||||||
|
if (import->count) {
|
||||||
|
for (auto &symSection : rpl.sections) {
|
||||||
|
if (symSection.header.type != elf::SHT_SYMTAB) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto symbols = reinterpret_cast<const elf::Symbol *>(symSection.data.data());
|
||||||
|
auto count = symSection.data.size() / sizeof(elf::Symbol);
|
||||||
|
auto strTab = reinterpret_cast<const char*>(rpl.sections[symSection.header.link].data.data());
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
auto &symbol = symbols[i];
|
||||||
|
auto type = symbol.info & 0xf;
|
||||||
|
|
||||||
|
if (symbol.shndx == sectionIndex &&
|
||||||
|
(type == elf::STT_FUNC || type == elf::STT_OBJECT)) {
|
||||||
|
fmt::print(" {}\n", strTab + symbol.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printRplCrcs(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
auto crcs = reinterpret_cast<const elf::RplCrc *>(section.data.data());
|
||||||
|
auto count = section.data.size() / sizeof(elf::RplCrc);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
fmt::print(" [{:>2}] 0x{:08X} {}\n", i, crcs[i].crc, section.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printRplExports(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
auto exports = reinterpret_cast<const elf::RplExport *>(section.data.data());
|
||||||
|
auto strTab = section.data.data();
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "signature", exports->signature);
|
||||||
|
fmt::print(" {:<20} = {}\n", "count", exports->count);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < exports->count; ++i) {
|
||||||
|
// TLS exports have the high bit set in name for some unknown reason...
|
||||||
|
auto name = strTab + (exports->exports[i].name & 0x7FFFFFFF);
|
||||||
|
auto value = exports->exports[i].value;
|
||||||
|
|
||||||
|
fmt::print(" 0x{:08X} {}\n", value, name);
|
||||||
|
}
|
||||||
|
}
|
35
tools/readrpl/print.h
Normal file
35
tools/readrpl/print.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "readrpl.h"
|
||||||
|
|
||||||
|
std::string
|
||||||
|
formatSHT(uint32_t type);
|
||||||
|
|
||||||
|
void
|
||||||
|
printHeader(const Rpl &rpl);
|
||||||
|
|
||||||
|
void
|
||||||
|
printSectionSummary(const Rpl &rpl);
|
||||||
|
|
||||||
|
void
|
||||||
|
printFileInfo(const Rpl &rpl,
|
||||||
|
const Section §ion);
|
||||||
|
|
||||||
|
void
|
||||||
|
printRela(const Rpl &rpl,
|
||||||
|
const Section §ion);
|
||||||
|
|
||||||
|
void
|
||||||
|
printSymTab(const Rpl &rpl,
|
||||||
|
const Section §ion);
|
||||||
|
|
||||||
|
void
|
||||||
|
printRplImports(const Rpl &rpl,
|
||||||
|
const Section §ion);
|
||||||
|
|
||||||
|
void
|
||||||
|
printRplCrcs(const Rpl &rpl,
|
||||||
|
const Section §ion);
|
||||||
|
|
||||||
|
void
|
||||||
|
printRplExports(const Rpl &rpl,
|
||||||
|
const Section §ion);
|
22
tools/readrpl/readrpl.h
Normal file
22
tools/readrpl/readrpl.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "elf.h"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct Section
|
||||||
|
{
|
||||||
|
elf::SectionHeader header;
|
||||||
|
std::string name;
|
||||||
|
std::vector<char> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Rpl
|
||||||
|
{
|
||||||
|
elf::Header header;
|
||||||
|
uint32_t fileSize;
|
||||||
|
std::vector<Section> sections;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
getSectionIndex(const Rpl &rpl,
|
||||||
|
const Section §ion);
|
585
tools/readrpl/verify.cpp
Normal file
585
tools/readrpl/verify.cpp
Normal file
@ -0,0 +1,585 @@
|
|||||||
|
#include "verify.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <set>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sValidateRelocsAddTable(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
const auto &header = section.header;
|
||||||
|
if (!header.size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entsize = static_cast<uint32_t>(header.entsize);
|
||||||
|
if (!entsize) {
|
||||||
|
entsize = static_cast<uint32_t>(sizeof(elf::Rela));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entsize < sizeof(elf::Rela)) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002E);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto numRelas = (header.size / entsize);
|
||||||
|
if (!numRelas) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000A);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!header.link || header.link >= rpl.header.shnum) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000B);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &symbolSection = rpl.sections[header.link];
|
||||||
|
if (symbolSection.header.type != elf::SHT_SYMTAB) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000C);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto symEntsize = symbolSection.header.entsize ?
|
||||||
|
static_cast<uint32_t>(symbolSection.header.entsize) :
|
||||||
|
static_cast<uint32_t>(sizeof(elf::Symbol));
|
||||||
|
if (symEntsize < sizeof(elf::Symbol)) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002F);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.info >= rpl.header.shnum) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000D);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &targetSection = rpl.sections[header.info];
|
||||||
|
if (targetSection.header.type != elf::SHT_NULL) {
|
||||||
|
auto numSymbols = symbolSection.data.size() / symEntsize;
|
||||||
|
for (auto i = 0u; i < numRelas; ++i) {
|
||||||
|
auto rela = reinterpret_cast<const elf::Rela *>(section.data.data() + i * entsize);
|
||||||
|
if (rela->info && (rela->info >> 8) >= numSymbols) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000F);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sValidateSymbolTable(const Rpl &rpl,
|
||||||
|
const Section §ion)
|
||||||
|
{
|
||||||
|
auto result = true;
|
||||||
|
const auto &header = section.header;
|
||||||
|
if (!header.size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Section *symStrTabSection = nullptr;
|
||||||
|
if (header.link) {
|
||||||
|
if (header.link >= rpl.header.shnum) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00001);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
symStrTabSection = &rpl.sections[header.link];
|
||||||
|
if (symStrTabSection->header.type != elf::SHT_STRTAB) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00002);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto entsize = header.entsize ?
|
||||||
|
static_cast<uint32_t>(header.entsize) :
|
||||||
|
static_cast<uint32_t>(sizeof(elf::Symbol));
|
||||||
|
if (entsize < sizeof(elf::Symbol)) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002D);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto numSymbols = header.size / entsize;
|
||||||
|
if (!numSymbols) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00003);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i = 0u; i < numSymbols; ++i) {
|
||||||
|
auto symbol = reinterpret_cast<const elf::Symbol *>(section.data.data() + i * entsize);
|
||||||
|
|
||||||
|
if (symStrTabSection &&
|
||||||
|
symbol->name > symStrTabSection->data.size()) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00004);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = symbol->info & 0xF;
|
||||||
|
if (symbol->shndx &&
|
||||||
|
symbol->shndx < elf::SHN_LORESERVE &&
|
||||||
|
type != elf::STT_SECTION &&
|
||||||
|
type != elf::STT_FILE) {
|
||||||
|
if (symbol->shndx >= rpl.header.shnum) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00005);
|
||||||
|
result = false;
|
||||||
|
} else if (type == elf::STT_OBJECT) {
|
||||||
|
const auto &targetSection = rpl.sections[symbol->shndx];
|
||||||
|
auto targetSectionSize = targetSection.data.size() ?
|
||||||
|
static_cast<uint32_t>(targetSection.data.size()) :
|
||||||
|
static_cast<uint32_t>(targetSection.header.size);
|
||||||
|
|
||||||
|
if (targetSectionSize &&
|
||||||
|
targetSection.header.flags & elf::SHF_ALLOC) {
|
||||||
|
if (targetSection.header.type == elf::SHT_NULL) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00006);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto position = symbol->value - targetSection.header.addr;
|
||||||
|
if (position > targetSectionSize || position + symbol->size > targetSectionSize) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00007);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == elf::STT_FUNC) {
|
||||||
|
const auto &targetSection = rpl.sections[symbol->shndx];
|
||||||
|
auto targetSectionSize = targetSection.data.size() ?
|
||||||
|
static_cast<uint32_t>(targetSection.data.size()) :
|
||||||
|
static_cast<uint32_t>(targetSection.header.size);
|
||||||
|
|
||||||
|
if (targetSectionSize &&
|
||||||
|
targetSection.header.flags & elf::SHF_ALLOC) {
|
||||||
|
if (targetSection.header.type == elf::SHT_NULL) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00008);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto position = symbol->value - targetSection.header.addr;
|
||||||
|
if (position > targetSectionSize || position + symbol->size > targetSectionSize) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00009);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to loader.elf ELFFILE_ValidateAndPrepare
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
verifyFile(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
const auto &header = rpl.header;
|
||||||
|
auto result = true;
|
||||||
|
|
||||||
|
if (rpl.fileSize < 0x104) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00018);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.magic != elf::HeaderMagic) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00019);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.fileClass != elf::ELFCLASS32) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001A);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.elfVersion > elf::EV_CURRENT) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001B);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!header.machine) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001C);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!header.version != 1) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001D);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ehsize = static_cast<uint32_t>(header.ehsize);
|
||||||
|
if (ehsize) {
|
||||||
|
if (header.ehsize < sizeof(elf::Header)) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001E);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ehsize = static_cast<uint32_t>(sizeof(elf::Header));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto phoff = header.phoff;
|
||||||
|
if (phoff && (phoff < ehsize || phoff >= rpl.fileSize)) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001F);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shoff = header.shoff;
|
||||||
|
if (shoff && (shoff < ehsize || shoff >= rpl.fileSize)) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00020);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.shstrndx && header.shstrndx >= header.shnum) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00021);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto phentsize = header.phentsize ?
|
||||||
|
static_cast<uint16_t>(header.phentsize) :
|
||||||
|
static_cast<uint16_t>(32);
|
||||||
|
if (header.phoff &&
|
||||||
|
(header.phoff + phentsize * header.phnum) > rpl.fileSize) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00022);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shentsize = header.shentsize ?
|
||||||
|
static_cast<uint32_t>(header.shentsize) :
|
||||||
|
static_cast<uint32_t>(sizeof(elf::SectionHeader));
|
||||||
|
if (header.shoff &&
|
||||||
|
(header.shoff + shentsize * header.shnum) > rpl.fileSize) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00023);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto §ion : rpl.sections) {
|
||||||
|
if (section.header.size &&
|
||||||
|
section.header.type != elf::SHT_NOBITS) {
|
||||||
|
if (section.header.offset < ehsize) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00024);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section.header.offset >= shoff &&
|
||||||
|
section.header.offset < (shoff + header.shnum * shentsize)) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00027);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.shstrndx) {
|
||||||
|
const auto &shStrTabSection = rpl.sections[header.shstrndx];
|
||||||
|
if (shStrTabSection.header.type != elf::SHT_STRTAB) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002A);
|
||||||
|
result = false;
|
||||||
|
} else {
|
||||||
|
for (auto §ion : rpl.sections) {
|
||||||
|
if (section.header.name >= shStrTabSection.data.size()) {
|
||||||
|
fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002B);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto §ion : rpl.sections) {
|
||||||
|
if (section.header.type == elf::SHT_RELA) {
|
||||||
|
result = sValidateRelocsAddTable(rpl, section) && result;
|
||||||
|
} else if (section.header.type == elf::SHT_SYMTAB) {
|
||||||
|
result = sValidateSymbolTable(rpl, section) && result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify values in SHT_RPL_CRCS
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
verifyCrcs(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
const elf::RplCrc *crcs = NULL;
|
||||||
|
auto result = true;
|
||||||
|
|
||||||
|
for (const auto §ion : rpl.sections) {
|
||||||
|
if (section.header.type == elf::SHT_RPL_CRCS) {
|
||||||
|
crcs = reinterpret_cast<const elf::RplCrc *>(section.data.data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crcs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sectionIndex = 0u;
|
||||||
|
for (const auto §ion : rpl.sections) {
|
||||||
|
auto crc = uint32_t { 0u };
|
||||||
|
if (section.header.type != elf::SHT_RPL_CRCS &&
|
||||||
|
section.data.size()) {
|
||||||
|
crc = crc32(0, Z_NULL, 0);
|
||||||
|
crc = crc32(crc, reinterpret_cast<const Bytef *>(section.data.data()), section.data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc != crcs[sectionIndex].crc) {
|
||||||
|
fmt::print("Unexpected crc for section {}, read 0x{:08X} but calculated 0x{:08X}",
|
||||||
|
sectionIndex, crcs[sectionIndex].crc, crc);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sectionIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to loader.elf LiCheckFileBounds
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
verifyFileBounds(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
auto result = true;
|
||||||
|
auto dataMin = -1;
|
||||||
|
auto dataMax = 0;
|
||||||
|
|
||||||
|
auto readMin = -1;
|
||||||
|
auto readMax = 0;
|
||||||
|
|
||||||
|
auto textMin = -1;
|
||||||
|
auto textMax = 0;
|
||||||
|
|
||||||
|
auto tempMin = -1;
|
||||||
|
auto tempMax = 0;
|
||||||
|
|
||||||
|
for (const auto §ion : rpl.sections) {
|
||||||
|
if (section.header.size == 0 ||
|
||||||
|
section.header.type == elf::SHT_RPL_FILEINFO ||
|
||||||
|
section.header.type == elf::SHT_RPL_CRCS ||
|
||||||
|
section.header.type == elf::SHT_NOBITS ||
|
||||||
|
section.header.type == elf::SHT_RPL_IMPORTS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((section.header.flags & elf::SHF_EXECINSTR) &&
|
||||||
|
section.header.type != elf::SHT_RPL_EXPORTS) {
|
||||||
|
textMin = std::min(textMin, static_cast<int32_t>(section.header.offset));
|
||||||
|
textMax = std::min(textMax, static_cast<int32_t>(section.header.offset + section.header.size));
|
||||||
|
} else {
|
||||||
|
if (section.header.flags & elf::SHF_ALLOC) {
|
||||||
|
if (section.header.flags & elf::SHF_WRITE) {
|
||||||
|
dataMin = std::min(dataMin, static_cast<int32_t>(section.header.offset));
|
||||||
|
dataMax = std::min(dataMax, static_cast<int32_t>(section.header.offset + section.header.size));
|
||||||
|
} else {
|
||||||
|
readMin = std::min(readMin, static_cast<int32_t>(section.header.offset));
|
||||||
|
readMax = std::min(readMax, static_cast<int32_t>(section.header.offset + section.header.size));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tempMin = std::min(tempMin, static_cast<int32_t>(section.header.offset));
|
||||||
|
tempMax = std::min(tempMax, static_cast<int32_t>(section.header.offset + section.header.size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataMin == -1) {
|
||||||
|
dataMax = (rpl.header.shnum * rpl.header.shentsize) + rpl.header.shoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readMin == -1) {
|
||||||
|
readMin = dataMax;
|
||||||
|
readMax = dataMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textMin == -1) {
|
||||||
|
textMin = readMax;
|
||||||
|
textMax = readMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tempMin == -1) {
|
||||||
|
tempMin = textMax;
|
||||||
|
tempMax = textMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataMin < rpl.header.shoff) {
|
||||||
|
fmt::print("*** SecHrs, FileInfo, or CRCs in bad spot in file. Return %d.\n", -470026);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data
|
||||||
|
if (dataMin > dataMax) {
|
||||||
|
fmt::print("*** DataMin > DataMax. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataMin > readMin) {
|
||||||
|
fmt::print("*** DataMin > ReadMin. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataMax > readMin) {
|
||||||
|
fmt::print("*** DataMax > ReadMin, break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read
|
||||||
|
if (readMin > readMax) {
|
||||||
|
fmt::print("*** ReadMin > ReadMax. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readMin > textMin) {
|
||||||
|
fmt::print("*** ReadMin > TextMin. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readMax > textMin) {
|
||||||
|
fmt::print("*** ReadMax > TextMin. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text
|
||||||
|
if (textMin > textMax) {
|
||||||
|
fmt::print("*** TextMin > TextMax. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textMin > tempMin) {
|
||||||
|
fmt::print("*** TextMin > TempMin. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textMax > tempMin) {
|
||||||
|
fmt::print("*** TextMax > TempMin. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temp
|
||||||
|
if (tempMin > tempMax) {
|
||||||
|
fmt::print("*** TempMin > TempMax. break.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
fmt::print("dataMin = 0x{:08X}\n", dataMin);
|
||||||
|
fmt::print("dataMax = 0x{:08X}\n", dataMax);
|
||||||
|
fmt::print("readMin = 0x{:08X}\n", readMin);
|
||||||
|
fmt::print("readMax = 0x{:08X}\n", readMax);
|
||||||
|
fmt::print("textMin = 0x{:08X}\n", textMin);
|
||||||
|
fmt::print("textMax = 0x{:08X}\n", textMax);
|
||||||
|
fmt::print("tempMin = 0x{:08X}\n", tempMin);
|
||||||
|
fmt::print("tempMax = 0x{:08X}\n", tempMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the rpl only uses relocation types which are supported by
|
||||||
|
* loader.elf
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
verifyRelocationTypes(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
std::set<unsigned int> unsupportedTypes;
|
||||||
|
|
||||||
|
for (auto §ion : rpl.sections) {
|
||||||
|
if (section.header.type != elf::SHT_RELA) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &symbolSection = rpl.sections[section.header.link];
|
||||||
|
auto &targetSection = rpl.sections[section.header.info];
|
||||||
|
auto rels = reinterpret_cast<const elf::Rela *>(section.data.data());
|
||||||
|
auto numRels = section.data.size() / sizeof(elf::Rela);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < numRels; ++i) {
|
||||||
|
auto info = rels[i].info;
|
||||||
|
auto addend = rels[i].addend;
|
||||||
|
auto offset = rels[i].offset;
|
||||||
|
auto index = info >> 8;
|
||||||
|
auto type = info & 0xFF;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case elf::R_PPC_NONE:
|
||||||
|
case elf::R_PPC_ADDR32:
|
||||||
|
case elf::R_PPC_ADDR16_LO:
|
||||||
|
case elf::R_PPC_ADDR16_HI:
|
||||||
|
case elf::R_PPC_ADDR16_HA:
|
||||||
|
case elf::R_PPC_REL24:
|
||||||
|
case elf::R_PPC_REL14:
|
||||||
|
case elf::R_PPC_DTPMOD32:
|
||||||
|
case elf::R_PPC_DTPREL32:
|
||||||
|
case elf::R_PPC_EMB_SDA21:
|
||||||
|
case elf::R_PPC_EMB_RELSDA:
|
||||||
|
case elf::R_PPC_DIAB_SDA21_LO:
|
||||||
|
case elf::R_PPC_DIAB_SDA21_HI:
|
||||||
|
case elf::R_PPC_DIAB_SDA21_HA:
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_LO:
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_HI:
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_HA:
|
||||||
|
case elf::R_PPC_GHS_REL16_HA:
|
||||||
|
case elf::R_PPC_GHS_REL16_HI:
|
||||||
|
case elf::R_PPC_GHS_REL16_LO:
|
||||||
|
// All valid relocations on Wii U, do nothing
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Only print error once per type
|
||||||
|
if (!unsupportedTypes.count(type)) {
|
||||||
|
fmt::print("Unsupported relocation type {}\n", type);
|
||||||
|
unsupportedTypes.insert(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return unsupportedTypes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that section.addr is aligned by section.addralign
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
verifySectionAlignment(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
auto result = true;
|
||||||
|
for (auto §ion : rpl.sections) {
|
||||||
|
if (!align_check(section.header.addr, section.header.addralign)) {
|
||||||
|
fmt::print("Unaligned section {}, addr {}, addralign {}",
|
||||||
|
getSectionIndex(rpl, section),
|
||||||
|
section.header.addr,
|
||||||
|
section.header.addralign);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
verifySectionOrder(const Rpl &rpl)
|
||||||
|
{
|
||||||
|
auto lastSection = rpl.sections[rpl.header.shnum - 1];
|
||||||
|
auto penultimateSection = rpl.sections[rpl.header.shnum - 2];
|
||||||
|
|
||||||
|
|
||||||
|
if (lastSection.header.type != elf::SHT_RPL_FILEINFO ||
|
||||||
|
(lastSection.header.flags & elf::SHF_DEFLATED)) {
|
||||||
|
fmt::print("***shnum-1 section type = 0x{:08X}, flags=0x{:08X}\n",
|
||||||
|
lastSection.header.type,
|
||||||
|
lastSection.header.flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (penultimateSection.header.type != elf::SHT_RPL_CRCS ||
|
||||||
|
(penultimateSection.header.flags & elf::SHF_DEFLATED)) {
|
||||||
|
fmt::print("***shnum-2 section type = 0x{:08X}, flags=0x{:08X}\n",
|
||||||
|
penultimateSection.header.type,
|
||||||
|
penultimateSection.header.flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
20
tools/readrpl/verify.h
Normal file
20
tools/readrpl/verify.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "readrpl.h"
|
||||||
|
|
||||||
|
bool
|
||||||
|
verifyFile(const Rpl &rpl);
|
||||||
|
|
||||||
|
bool
|
||||||
|
verifyCrcs(const Rpl &rpl);
|
||||||
|
|
||||||
|
bool
|
||||||
|
verifyFileBounds(const Rpl &rpl);
|
||||||
|
|
||||||
|
bool
|
||||||
|
verifyRelocationTypes(const Rpl &rpl);
|
||||||
|
|
||||||
|
bool
|
||||||
|
verifySectionAlignment(const Rpl &rpl);
|
||||||
|
|
||||||
|
bool
|
||||||
|
verifySectionOrder(const Rpl &rpl);
|
Loading…
x
Reference in New Issue
Block a user