-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 608e361
Showing
575 changed files
with
403,116 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
root = true | ||
|
||
[*] | ||
end_of_line = lf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
webhook.sh text eol=lf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
calcrom | ||
*.exe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 §ion) 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; | ||
} |
Oops, something went wrong.