Skip to content

Commit

Permalink
Initialized base repo
Browse files Browse the repository at this point in the history
  • Loading branch information
AnonymousRandomPerson committed Jun 29, 2023
0 parents commit 608e361
Show file tree
Hide file tree
Showing 575 changed files with 403,116 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
root = true

[*]
end_of_line = lf
23 changes: 23 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
charmap.txt text eol=crlf

*.sh text eol=lf
*.s text eol=lf
Makefile text eol=lf
*.mk text eol=lf
*.c text eol=lf
*.h text eol=lf
*.inc text eol=lf
*.sha1 text eol=lf
*.json text eol=lf
*.cpp text eol=lf
*.hpp text eol=lf
.gitattributes text eol=lf
.gitignore text eol=lf
*.md text eol=lf
*.lsf text eol=lf
*.yml text eol=lf

*.bin binary

*.h linguist-language=C
*.inc linguist-language=Assembly
1 change: 1 addition & 0 deletions .github/calcrom/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
webhook.sh text eol=lf
2 changes: 2 additions & 0 deletions .github/calcrom/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
calcrom
*.exe
155 changes: 155 additions & 0 deletions .github/calcrom/BuildAnalyzer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#include <iostream>
#include <algorithm>
#include <cstring>
#include "BuildAnalyzer.h"
#include "Glob.h"

string default_version;

void BuildAnalyzer::AnalyzeObject(path fname_s) {
string ext = fname_s.extension();
SourceType sourceType = ext == ".s" ? SOURCE_ASM : SOURCE_C;
fname_s = builddir / relative(fname_s, srcbase);
fname_s = fname_s.replace_extension(".o");
if (!exists(fname_s)) {
throw runtime_error("No such file: " + fname_s.string());
}

Elf32File elf(fname_s);

path fname_b = fname_s.filename();

// Analyze sections
for (Elf32_Shdr & hdr : elf.GetSectionHeaders()) {
string shname = elf.GetSectionName(hdr);
SectionType sectionType = GetSectionType(shname);
if (sectionType != SECTION_OTHER) {
sizes[sectionType][sourceType] += (hdr.sh_size + 3) & ~3;
auto data = elf.ReadSectionData<unsigned>(hdr);
for (const auto & word : data) {
if (word == 0) {
continue; // might be a relocation
}
if (find_if(program.GetProgramHeaders().cbegin(), program.GetProgramHeaders().cend(), [&word](const auto & phdr) {
return phdr.p_vaddr <= word && word < phdr.p_vaddr + phdr.p_memsz;
}) != program.GetProgramHeaders().cend()) {
#ifndef NDEBUG
try {
unsigned addr = (&word - &*data.cbegin()) * 4 + xmap.at({fname_b.string(), shname});
fprintf(stderr, "%s\t%08X\t%08X\n", fname_b.c_str(), addr, word);
} catch (const out_of_range &e) {
fprintf(stderr, "Error: missing xmap reference to %s:%s\n", fname_b.c_str(), shname.c_str());
throw e;
}
#endif
n_hardcoded++;
}
}
} else if (hdr.sh_type == SHT_RELA) {
n_relocations += elf.GetSectionElementCount<Elf32_Rela>(hdr);
} else if (hdr.sh_type == SHT_REL) {
n_relocations += elf.GetSectionElementCount<Elf32_Rel>(hdr);
}
}
}

void BuildAnalyzer::reset() {
memset(sizes, 0, sizeof(sizes));
if (!version.empty()) {
sizes[SECTION_TEXT][SOURCE_ASM] = 0x800; // libsyscall.a
}
n_hardcoded = 0;
n_relocations = 0;
}

void BuildAnalyzer::LoadProgramElf() {
string elfpat = builddir + "/*.elf";
Glob globber(elfpat, GLOB_TILDE | GLOB_BRACE | GLOB_NOSORT);
if (globber.empty()) {
throw runtime_error("unable to find an ELF file with section data");
}
program.open(globber[0], Elf32File::sections | Elf32File::programs);
}

#ifndef NDEBUG
void BuildAnalyzer::LoadProgramXmap() {
string xmappat = builddir + "/*.xMAP";
Glob globber(xmappat, GLOB_TILDE | GLOB_BRACE | GLOB_NOSORT);
if (globber.empty()) {
throw runtime_error("unable to find an xMAP file with object load info");
}
xmap.open(globber[0]);
}
#endif

BuildAnalyzer::BuildAnalyzer(path &_basedir, path &_subdir, string &_version) :
basedir(_basedir),
subdir(_subdir),
version(_version)
{
reset();
srcbase = basedir / subdir;
builddir = srcbase / "build" / version;
if (!exists(srcbase)) {
throw runtime_error("No such directory: " + srcbase.string());
}

LoadProgramElf();
#ifndef NDEBUG
LoadProgramXmap();
#endif
}

BuildAnalyzer &BuildAnalyzer::operator()() {
if (analyzed) {
reset();
}
string pattern = srcbase.string() + "/{src,asm,lib/{src,asm},lib/{NitroSDK,NitroDWC}/{src,asm}}/{,*/,*/*/}*.{c,s,cpp}";
for (char const * & fname : Glob(pattern, GLOB_TILDE | GLOB_BRACE | GLOB_NOSORT)) {
AnalyzeObject(fname);
}
analyzed = true;
return *this;
}

ostream &operator<<(ostream &strm, BuildAnalyzer &_this) {
if (!_this.analyzed) {
strm << "Haven't analyzed this ROM, please call the BuildAnalyzer instance" << endl;
return strm;
}

strm << "Analysis of " << (_this.version.empty() ? _this.subdir.string() : _this.version) << " binary:" << endl;
// Report code
unsigned total_text = _this.sizes[SECTION_TEXT][SOURCE_C] + _this.sizes[SECTION_TEXT][SOURCE_ASM];
if (total_text != 0) {
double total_text_d = total_text;
double src_text_d = _this.sizes[SECTION_TEXT][SOURCE_C];
double asm_text_d = _this.sizes[SECTION_TEXT][SOURCE_ASM];
strm << " " << total_text << " total bytes of code" << endl;
strm << " " << _this.sizes[SECTION_TEXT][SOURCE_C] << " bytes of code in src (" << (src_text_d / total_text_d * 100.0) << "%)" << endl;
strm << " " << _this.sizes[SECTION_TEXT][SOURCE_ASM] << " bytes of code in asm (" << (asm_text_d / total_text_d * 100.0) << "%)" << endl;
}
strm << endl;
// Report data
unsigned total_data = _this.sizes[SECTION_DATA][SOURCE_C] + _this.sizes[SECTION_DATA][SOURCE_ASM];
if (total_data != 0) {
double total_data_d = total_data;
double src_data_d = _this.sizes[SECTION_DATA][SOURCE_C];
double asm_data_d = _this.sizes[SECTION_DATA][SOURCE_ASM];
strm << " " << total_data << " total bytes of data" << endl;
strm << " " << _this.sizes[SECTION_DATA][SOURCE_C] << " bytes of data in src (" << (src_data_d / total_data_d * 100.0) << "%)" << endl;
strm << " " << _this.sizes[SECTION_DATA][SOURCE_ASM] << " bytes of data in asm (" << (asm_data_d / total_data_d * 100.0) << "%)" << endl;
}
strm << endl;
// Report hardcoded pointers
unsigned total_pointers = _this.n_hardcoded + _this.n_relocations;
if (total_pointers != 0) {
double total_pointers_d = total_pointers;
double hardcoded_pointers_d = _this.n_hardcoded;
double relocated_pointers_d = _this.n_relocations;
strm << " " << total_pointers << " total pointers" << endl;
strm << " " << _this.n_relocations << " properly-linked pointers (" << (relocated_pointers_d / total_pointers_d * 100.0) << "%)" << endl;
strm << " " << _this.n_hardcoded << " hard-coded pointers (" << (hardcoded_pointers_d / total_pointers_d * 100.0) << "%)" << endl;
}
return strm;
}
76 changes: 76 additions & 0 deletions .github/calcrom/BuildAnalyzer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#ifndef CALCROM_BUILDANALYZER_H
#define CALCROM_BUILDANALYZER_H

#include "find_filesystem.h"
#include <utility>
#include <vector>
#include <unordered_set>
#include "ElfFile.h"
#ifndef NDEBUG
#include "MwerksXmapFile.h"
#endif

using namespace std;
using namespace fs;

extern string default_version;

enum SectionType {
SECTION_DATA,
SECTION_TEXT,
SECTION_MAX,
SECTION_OTHER = -1
};

enum SourceType {
SOURCE_C,
SOURCE_ASM,
SOURCE_MAX
};

static enum SourceType GetSourceType(const path &fname) {
string ext = fname.extension();
return ext == ".s" ? SOURCE_ASM : SOURCE_C;
}

static enum SectionType GetSectionType(const string &shname) {
if (shname == ".text" || shname == ".init" || shname == ".itcm") {
return SECTION_TEXT;
} else if (shname == ".data" || shname == ".rodata" || shname == ".sdata" || shname == ".dtcm") {
return SECTION_DATA;
} else {
return SECTION_OTHER;
}
}

class BuildAnalyzer {
bool analyzed = false;
path basedir;
path subdir;
string version;
path srcbase;
string builddir;
Elf32File program;
#ifndef NDEBUG
MwerksXmapFile xmap;
#endif

// Accumulate sizes
// src asm
// data _____|_____
// text |
unsigned sizes[SECTION_MAX][SOURCE_MAX] = {{0, 0}, {0, 0}};
unsigned n_hardcoded = 0;
unsigned n_relocations = 0;

void reset();
void AnalyzeObject(path fname_s);
void LoadProgramElf();
void LoadProgramXmap();
public:
BuildAnalyzer(path &_basedir, path &_subdir, string &_version = default_version);
BuildAnalyzer &operator()();
friend ostream &operator<<(ostream &strm, BuildAnalyzer &_this);
};

#endif //CALCROM_BUILDANALYZER_H
130 changes: 130 additions & 0 deletions .github/calcrom/ElfFile.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include <iostream>
#include <cassert>
#include <algorithm>
#include <cstring>
#include "ElfFile.h"

void Elf32File::ReadElfHeaderAndVerify() {
handle.seekg(0);
handle.read((char *)ehdr.e_ident, EI_NIDENT);
assert(memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0);
assert(ehdr.e_ident[EI_CLASS] == ELFCLASS32);
assert(ehdr.e_ident[EI_DATA] == ELFDATA2LSB);
assert(ehdr.e_ident[EI_VERSION] == EV_CURRENT);
handle.read((char*)&ehdr + EI_NIDENT, sizeof(ehdr) - EI_NIDENT);
assert(ehdr.e_shentsize == sizeof(Elf32_Shdr));
}

void Elf32File::ReadSectionHeaders() {
assert(shdr.empty());
shdr.resize(ehdr.e_shnum);
handle.seekg(ehdr.e_shoff);
handle.read((char*)shdr.data(), ehdr.e_shnum * ehdr.e_shentsize);
}

void Elf32File::ReadProgramHeaders() {
assert(phdr.empty());
phdr.resize(ehdr.e_phnum);
handle.seekg(ehdr.e_phoff);
handle.read((char*)phdr.data(), ehdr.e_phnum * ehdr.e_phentsize);
}

void Elf32File::ReadShstrtab() {
assert(shstrtab.empty());
shstrtab.resize(shdr[ehdr.e_shstrndx].sh_size);
handle.seekg(shdr[ehdr.e_shstrndx].sh_offset);
handle.read((char*)shstrtab.data(), shdr[ehdr.e_shstrndx].sh_size);
}

void Elf32File::ReadStrtab() {
assert(strtab.empty());
int i;
for (i = 1; i < ehdr.e_shnum; i++) {
if (i == ehdr.e_shstrndx) continue;
if (shdr[i].sh_type == SHT_STRTAB) break;
}
assert(i != ehdr.e_shnum);
strtab.resize(shdr[i].sh_size);
handle.seekg(shdr[i].sh_offset);
handle.read((char*)strtab.data(), shdr[i].sh_size);
}

void Elf32File::ReadSymtab() {
assert(symtab.empty());
auto sec = find_if(shdr.begin(), shdr.end(), [](Elf32_Shdr const& candidate) { return candidate.sh_type == SHT_SYMTAB; });
assert(sec != shdr.end());
symtab.resize(sec->sh_size);
handle.seekg(sec->sh_offset);
handle.read((char*)symtab.data(), sec->sh_size);
}

Elf32File::Elf32File(path const& filename, elfload load) {
open(filename, load);
}

void Elf32File::open(path const& filename, elfload load) {
assert(!is_open());
handle.open(filename, ios::binary);
assert(handle.good());
ReadElfHeaderAndVerify();
if (load & sections) {
ReadSectionHeaders();
ReadShstrtab();
}
if (load & programs) {
ReadProgramHeaders();
}
if (load & symbols) {
assert(load & sections);
ReadStrtab();
ReadSymtab();
}
}

void Elf32File::close() {
if (is_open()) {
handle.close();
}
memset(&ehdr, 0, sizeof(ehdr));
shdr.clear();
symtab.clear();
phdr.clear();
shstrtab.clear();
strtab.clear();
}

bool Elf32File::is_open() const {
return handle.is_open();
}

Elf32File::~Elf32File() {
close();
}

vector<Elf32_Shdr> &Elf32File::GetSectionHeaders() {
return shdr;
}

vector<Elf32_Phdr> &Elf32File::GetProgramHeaders() {
return phdr;
}

string Elf32File::GetSectionName(const Elf32_Shdr &section) const {
return {shstrtab.data() + section.sh_name};
}

string Elf32File::GetSymbolName(const Elf32_Sym &symbol) const {
return {strtab.data() + symbol.st_name};
}

Elf32_Sym &Elf32File::operator[](const string &name) {
return *find_if(symtab.begin(), symtab.end(), [&](Elf32_Sym const &sym) { return name == GetSymbolName(sym); });
}

Elf32_Sym &Elf32File::at(const string &name) {
auto ret = find_if(symtab.begin(), symtab.end(), [&](Elf32_Sym const &sym) { return name == GetSymbolName(sym); });
if (ret == symtab.end()) {
throw runtime_error("no symbol named " + name);
}
return *ret;
}
Loading

0 comments on commit 608e361

Please sign in to comment.