summaryrefslogtreecommitdiff
path: root/.github/calcrom/BuildAnalyzer.cpp
diff options
context:
space:
mode:
authorThomas <doodrabbit@hotmail.com>2021-12-17 20:57:03 -0500
committerGitHub <noreply@github.com>2021-12-17 20:57:03 -0500
commitaf67eaffa7ab1a347a6f0e59ed7f1e107749d15a (patch)
treeb9f90f7b047b3dc5a411dbf65117bf07b237a37d /.github/calcrom/BuildAnalyzer.cpp
parent3ab18655ca1311019212b3a2a9dbe32e5fbee55d (diff)
parent44cd7753b5dde323d1e8274b2dc8a5599729e83f (diff)
Merge pull request #463 from PikalaxALT/pikalax_workHEADmaster
Real-match math_util.c
Diffstat (limited to '.github/calcrom/BuildAnalyzer.cpp')
-rw-r--r--.github/calcrom/BuildAnalyzer.cpp143
1 files changed, 143 insertions, 0 deletions
diff --git a/.github/calcrom/BuildAnalyzer.cpp b/.github/calcrom/BuildAnalyzer.cpp
new file mode 100644
index 00000000..4fc36d81
--- /dev/null
+++ b/.github/calcrom/BuildAnalyzer.cpp
@@ -0,0 +1,143 @@
+#include <algorithm>
+#include <cstring>
+#include <iostream>
+#include "BuildAnalyzer.h"
+#include "Glob.h"
+#include "ElfFile.h"
+
+string default_version("");
+
+void BuildAnalyzer::AnalyzeObject(path fname_s) {
+#ifndef NDEBUG
+ cerr << fname_s << endl;
+#endif //NDEBUG
+ 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);
+
+ // 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);
+//#ifndef NDEBUG
+// unordered_set<unsigned> unique_addrs;
+//#endif
+ 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
+// unique_addrs.insert(word);
+//#endif
+ n_hardcoded++;
+ }
+ }
+//#ifndef NDEBUG
+// if (!version.empty()) {
+// for (const auto & word : unique_addrs) {
+// cerr << "hardcoded " << version << " pointer to " << hex << word << endl;
+// }
+// }
+//#endif
+ } else if (hdr.sh_type == SHT_RELA) {
+ n_relocations += elf.GetSectionElementCount<Elf32_Rela>(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;
+}
+
+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());
+ }
+
+ string elfpat = builddir + "/*.elf";
+ Glob globber(elfpat, GLOB_TILDE | GLOB_BRACE | GLOB_NOSORT);
+ if (globber.size() == 0) {
+ throw runtime_error("unable to find an ELF file with section data");
+ }
+ program.open(globber[0], Elf32File::sections | Elf32File::programs);
+}
+
+BuildAnalyzer &BuildAnalyzer::operator()() {
+ if (analyzed) {
+ reset();
+ }
+ string pattern = srcbase.string() + "/{src,asm,lib/{src,asm},lib/*/{src,asm},modules/*/{asm,src}}/*.{c,s,cpp}";
+ for (char const * & fname : Glob(pattern, GLOB_TILDE | GLOB_BRACE | GLOB_NOSORT)) {
+ if (string(fname).find("lib/syscall/") == string::npos) {
+ 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;
+}