1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2024-11-25 17:54:15 +00:00
oot/tools/fado/lib/fairy/fairy_print.c
Dragorn421 5834c335e6
git subrepo pull --force tools/fado (#1924)
subrepo:
  subdir:   "tools/fado"
  merged:   "7fad57f83"
upstream:
  origin:   "git@github.com:EllipticEllipsis/fado.git"
  branch:   "master"
  commit:   "7fad57f83"
git-subrepo:
  version:  "0.4.6"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "110b9eb"
2024-03-13 12:33:58 -04:00

463 lines
17 KiB
C

/**
* Functions for printing various sections of an N64 ELF file using the functions in Fairy, similarly to readelf
*/
/* Copyright (C) 2021 Elliptic Ellipsis */
/* SPDX-License-Identifier: AGPL-3.0-only */
#include "fairy.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fairy_data.inc"
void Fairy_PrintSymbolTable(FILE* inputFile) {
FairyFileHeader fileHeader;
FairySecHeader* sectionTable;
size_t shstrndx;
char* shstrtab;
FairySym* symbolTable = NULL;
size_t symbolTableNum = 0;
char* strtab = NULL;
Fairy_ReadFileHeader(&fileHeader, inputFile);
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
shstrndx = fileHeader.e_shstrndx;
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size);
{
size_t currentIndex;
size_t strtabndx = 0;
for (currentIndex = 0; currentIndex < fileHeader.e_shnum; currentIndex++) {
FairySecHeader currentHeader = sectionTable[currentIndex];
switch (currentHeader.sh_type) {
case SHT_SYMTAB:
if (strcmp(&shstrtab[currentHeader.sh_name], ".symtab") == 0) {
printf("symtab found\n");
symbolTableNum = Fairy_ReadSymbolTable(&symbolTable, inputFile, currentHeader.sh_offset,
currentHeader.sh_size);
}
break;
case SHT_STRTAB:
if (strcmp(&shstrtab[currentHeader.sh_name], ".strtab") == 0) {
strtabndx = currentIndex;
}
break;
default:
break;
}
}
if (symbolTable == NULL) {
puts("No symtab found.");
free(sectionTable);
return;
}
if (strtabndx != 0) {
printf("strtab found\n");
printf("Size: %X bytes\n", sectionTable[strtabndx].sh_size);
strtab = malloc(sectionTable[strtabndx].sh_size);
printf("and mallocked\n");
fseek(inputFile, sectionTable[strtabndx].sh_offset, SEEK_SET);
printf("file offset sought: %X\n", sectionTable[strtabndx].sh_offset);
assert(fread(strtab, sizeof(char), sectionTable[strtabndx].sh_size, inputFile) ==
sectionTable[strtabndx].sh_size);
printf("file read\n");
}
}
{
size_t currentIndex;
printf("Symbol table\n");
printf(" Num: Value Size Type Bind Vis Ndx Name\n");
for (currentIndex = 0; currentIndex < symbolTableNum; currentIndex++) {
FairySym currentSymbol = symbolTable[currentIndex];
printf("%4zd: ", currentIndex);
printf("%08X ", currentSymbol.st_value);
printf("%4X ", currentSymbol.st_size);
printf("%-11s ", Fairy_StringFromDefine(stTypes, ELF32_ST_TYPE(currentSymbol.st_info)));
printf("%-10s ", Fairy_StringFromDefine(stBinds, ELF32_ST_BIND(currentSymbol.st_info)));
printf("%-11s ", Fairy_StringFromDefine(stVisibilities, ELF32_ST_VISIBILITY(currentSymbol.st_other)));
if (currentSymbol.st_shndx != 0) {
printf("%3X ", currentSymbol.st_shndx);
} else {
printf("UND ");
}
if (strtab != NULL) {
printf("%s", &strtab[currentSymbol.st_name]);
} else {
printf("%4X ", currentSymbol.st_name);
}
putchar('\n');
}
}
free(sectionTable);
free(symbolTable);
if (strtab != NULL) {
free(strtab);
}
}
void Fairy_PrintRelocs(FILE* inputFile) {
FairyFileHeader fileHeader;
FairySecHeader* sectionTable;
FairyRela* relocs;
size_t shstrndx;
char* shstrtab;
size_t currentSection;
Fairy_ReadFileHeader(&fileHeader, inputFile);
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
shstrndx = fileHeader.e_shstrndx;
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size);
for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) {
size_t nRelocs;
if (sectionTable[currentSection].sh_type != SHT_REL || sectionTable[currentSection].sh_type != SHT_RELA) {
continue;
}
printf("Section size: %d\n", sectionTable[currentSection].sh_size);
nRelocs = Fairy_ReadRelocs(&relocs, inputFile, sectionTable[currentSection].sh_type,
sectionTable[currentSection].sh_offset, sectionTable[currentSection].sh_size);
// fseek(inputFile, sectionTable[currentSection].sh_offset, SEEK_SET);
// assert(fread(relocs, sizeof(char), sectionTable[currentSection].sh_size, inputFile) ==
// sectionTable[currentSection].sh_size);
printf("Relocs in section [%2zd]: %s:\n", currentSection, shstrtab + sectionTable[currentSection].sh_name);
printf("Offset Info Type Symbol\n");
{
size_t currentReloc;
for (currentReloc = 0; currentReloc < nRelocs; currentReloc++) {
printf("%08X,%08X ", relocs[currentReloc].r_offset, relocs[currentReloc].r_info);
switch (ELF32_R_TYPE(relocs[currentReloc].r_info)) {
case R_MIPS_NONE:
printf("%-15s", "R_MIPS_NONE");
break;
case R_MIPS_16:
printf("%-15s", "R_MIPS_16");
break;
case R_MIPS_32:
printf("%-15s", "R_MIPS_32");
break;
case R_MIPS_REL32:
printf("%-15s", "R_MIPS_REL32");
break;
case R_MIPS_26:
printf("%-15s", "R_MIPS_26");
break;
case R_MIPS_HI16:
printf("%-15s", "R_MIPS_HI16");
break;
case R_MIPS_LO16:
printf("%-15s", "R_MIPS_LO16");
break;
default:
break;
}
printf("%X", ELF32_R_SYM(relocs[currentReloc].r_info));
putchar('\n');
}
putchar('\n');
}
putchar('\n');
free(relocs);
}
free(sectionTable);
free(shstrtab);
}
void Fairy_PrintSectionTable(FILE* inputFile) {
FairyFileHeader fileHeader;
FairySecHeader* sectionTable;
size_t shstrndx;
char* shstrtab;
size_t currentSection;
Fairy_ReadFileHeader(&fileHeader, inputFile);
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
shstrndx = fileHeader.e_shstrndx;
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size);
printf("[Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n");
for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) {
FairySecHeader entry = sectionTable[currentSection];
printf("[%2zd] ", currentSection);
printf("%-15s", shstrtab + entry.sh_name);
printf("%-15s", Fairy_StringFromDefine(shTypes, entry.sh_type));
// printf("%08X ", entry.sh_type);
printf("%08X ", entry.sh_addr);
printf("%06X ", entry.sh_offset);
printf("%06X ", entry.sh_size);
printf("%02X ", entry.sh_entsize);
// printf("%08X ", entry.sh_flags);
{
char flagChars[] = { 'W', 'A', 'X', 'M', 'S', 'I', 'L', 'O', 'G', 'T', 'C', 'x', 'o', 'E', 'p' };
uint32_t flags = entry.sh_flags;
size_t shift;
int pad = 4;
for (shift = 0; shift < sizeof(flagChars); shift++) {
if ((flags >> shift) & 1) {
putchar(flagChars[shift]);
pad--;
}
}
if (pad > 0) {
printf("%*s", pad, "");
}
}
printf("%2X ", entry.sh_link);
printf("%3X ", entry.sh_info);
printf("%2X", entry.sh_addralign);
putchar('\n');
}
}
typedef enum { REL_SECTION_NONE, REL_SECTION_TEXT, REL_SECTION_DATA, REL_SECTION_RODATA } FairyOverlayRelSection;
const char* relSectionStrings[] = {
NULL,
".text",
".data",
".rodata",
};
static uint32_t Fairy_PackReloc(FairyOverlayRelSection sec, FairyRela rel) {
return (sec << 0x1E) | (ELF32_R_TYPE(rel.r_info) << 0x18) | rel.r_offset;
}
void Fairy_PrintSectionSizes(FairySecHeader* sectionTable, FILE* inputFile, size_t tableSize, char* shstrtab) {
size_t number = tableSize / sizeof(FairySecHeader);
FairySecHeader currentHeader;
char* sectionName;
size_t relocSectionsCount = 0;
size_t* relocSectionIndices;
int* relocSectionSection;
size_t currentRelocSection = 0;
FairySecHeader symtabHeader;
FairySym* symtab;
FairySecHeader strtabHeader;
char* strtab = NULL;
// size_t symtabSize;
uint32_t textSize = 0;
uint32_t dataSize = 0;
uint32_t rodataSize = 0;
uint32_t bssSize = 0;
uint32_t relocCount = 0;
size_t currentSection;
bool symtabFound = false;
bool strtabFound = false;
/* Count the reloc sections */
for (currentSection = 0; currentSection < number; currentSection++) {
if (sectionTable[currentSection].sh_type == SHT_REL || sectionTable[currentSection].sh_type == SHT_RELA) {
relocSectionsCount++;
}
}
printf("relocSectionsCount: %zd\n", relocSectionsCount);
relocSectionIndices = malloc(relocSectionsCount * sizeof(int));
relocSectionSection = malloc(relocSectionsCount * sizeof(int));
/* Find the section sizes and the reloc sections */
for (currentSection = 0; currentSection < number; currentSection++) {
size_t off = 0;
currentHeader = sectionTable[currentSection];
sectionName = &shstrtab[currentHeader.sh_name + 1]; /* ignore the initial '.' */
switch (currentHeader.sh_type) {
case SHT_PROGBITS:
if (Fairy_StartsWith(sectionName, "rodata")) {
printf("rodata\n");
rodataSize += currentHeader.sh_size;
break;
}
if (Fairy_StartsWith(sectionName, "data")) {
printf("data\n");
dataSize += currentHeader.sh_size;
break;
}
if (Fairy_StartsWith(sectionName, "text")) {
printf("text\n");
textSize += currentHeader.sh_size;
break;
}
break;
case SHT_NOBITS:
if (Fairy_StartsWith(sectionName, "bss")) {
printf("bss\n");
bssSize += currentHeader.sh_size;
}
break;
case SHT_RELA:
off += 1;
case SHT_REL:
relocSectionIndices[currentRelocSection] = currentSection;
off += 4; /* ignore the "rel."/"rela." part */
if (Fairy_StartsWith(&sectionName[off], "rodata")) {
printf("%s\n", sectionName);
relocSectionSection[currentRelocSection] = REL_SECTION_RODATA;
} else if (Fairy_StartsWith(&sectionName[off], "data")) {
printf("%s\n", sectionName);
relocSectionSection[currentRelocSection] = REL_SECTION_DATA;
} else if (Fairy_StartsWith(&sectionName[off], "text")) {
printf("%s\n", sectionName);
relocSectionSection[currentRelocSection] = REL_SECTION_TEXT;
}
currentRelocSection++;
break;
case SHT_SYMTAB:
if (Fairy_StartsWith(sectionName, "symtab")) {
symtabHeader = currentHeader;
symtabFound = true;
}
break;
case SHT_STRTAB:
if (Fairy_StartsWith(sectionName, "strtab")) {
strtabHeader = currentHeader;
strtabFound = true;
}
break;
default:
break;
}
}
/* Can use symbols here too */
puts(".section .ovl, \"a\"");
printf("# OverlayInfo\n");
printf(".word 0x%08X # .text size\n", textSize);
printf(".word 0x%08X # .data size\n", dataSize);
printf(".word 0x%08X # .rodata size\n", rodataSize);
printf(".word 0x%08X # .bss size\n\n", bssSize);
if (!symtabFound) {
fprintf(stderr, "Symbol table not found\n");
return;
}
/* Obtain the symbol table */
// TODO: Consider replacing this with a lighter-weight read: sufficient to get the name, shndx
Fairy_ReadSymbolTable(&symtab, inputFile, symtabHeader.sh_offset, symtabHeader.sh_size);
if (!strtabFound) {
fprintf(stderr, "String table not found\n");
} else {
/* Obtain the string table */
strtab = malloc(strtabHeader.sh_size);
fseek(inputFile, strtabHeader.sh_offset, SEEK_SET);
assert(fread(strtab, sizeof(char), strtabHeader.sh_size, inputFile) == strtabHeader.sh_size);
}
/* Do single-file relocs */
{
FairyRela* relocs;
for (currentSection = 0; currentSection < relocSectionsCount; currentSection++) {
size_t currentReloc;
size_t nRelocs;
currentHeader = sectionTable[relocSectionIndices[currentSection]];
nRelocs = Fairy_ReadRelocs(&relocs, inputFile, currentHeader.sh_type, currentHeader.sh_offset,
currentHeader.sh_size);
for (currentReloc = 0; currentReloc < nRelocs; currentReloc++) {
FairySym symbol = symtab[ELF32_R_SYM(relocs[currentReloc].r_info)];
if (symbol.st_shndx == SHN_UNDEF) {
continue; // TODO: this is where multifile has to look elsewhere
}
printf(".word 0x%08X", Fairy_PackReloc(relocSectionSection[currentSection], relocs[currentReloc]));
printf(" # %X (%s), %X, 0x%06X", relocSectionSection[currentSection], &shstrtab[currentHeader.sh_name],
ELF32_R_TYPE(relocs[currentReloc].r_info), relocs[currentReloc].r_offset);
if (strtab != NULL) {
printf(", %s", &strtab[symbol.st_name]);
}
putchar('\n');
relocCount++;
}
free(relocs);
}
}
printf(".word %d # relocCount\n", relocCount);
{
uint32_t ovlSectionSize = ((relocCount + 8) & ~0x03) * sizeof(uint32_t);
printf("\n.word 0x%08X # Overlay section size\n", ovlSectionSize);
}
free(relocSectionIndices);
free(relocSectionSection);
if (strtab != NULL) {
free(strtab);
}
}
void PrintZeldaReloc(FILE* inputFile) {
FairyFileHeader fileHeader;
FairySecHeader* sectionTable;
size_t shstrndx;
char* shstrtab;
Fairy_ReadFileHeader(&fileHeader, inputFile);
sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum);
shstrndx = fileHeader.e_shstrndx;
Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum);
shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char));
fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET);
assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size);
Fairy_PrintSectionSizes(sectionTable, inputFile, fileHeader.e_shentsize * fileHeader.e_shnum, shstrtab);
free(sectionTable);
free(shstrtab);
}