aboutsummaryrefslogtreecommitdiff
path: root/elfinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'elfinfo.cpp')
-rw-r--r--elfinfo.cpp193
1 files changed, 111 insertions, 82 deletions
diff --git a/elfinfo.cpp b/elfinfo.cpp
index a0138e2..5982dd1 100644
--- a/elfinfo.cpp
+++ b/elfinfo.cpp
@@ -10,46 +10,22 @@
#include <algorithm>
#include <getopt.h>
#include <inttypes.h>
+#include <sstream>
+#include <memory>
+#include <map>
#include <elf.h>
-#include "ld.h"
+#include "Ld.h"
-using std::vector;
+using namespace std;
+using namespace trygvis::elfinfo;
-enum class SectionType {
- TEXT, DATA
+struct Usage {
+ uint64_t maxAddress;
};
-const char *to_str(const SectionType &type) {
- switch (type) {
- case SectionType::TEXT:
- return "text";
- case SectionType::DATA:
- return "data";
- }
-}
-
-struct Section {
- SectionType type;
- const Elf64_Addr start;
- const Elf64_Addr end;
- const Elf64_Xword size;
- Elf64_Addr used;
-
- Section(SectionType type, Elf64_Addr start, Elf64_Xword size) : type(type), start(start), size(size),
- end(start + size), used(0) {
- }
-
- bool contains(Elf64_Addr address, Elf64_Xword size) const {
- return contains(address) && contains(address + size);
- }
-
- bool contains(Elf64_Addr address) const {
- return start <= address && address < end;
- }
-};
-
-vector<Section> sections;
+std::vector<MemoryArea> memoryAreas;
+std::map<string, shared_ptr<Usage>> usages;
char *filename = nullptr;
@@ -63,29 +39,29 @@ void usage(const char *reason = nullptr) {
fprintf(stderr, "%s\n", reason);
}
fprintf(stderr, "usage: %s -f file [-l ld] [-t start:size] [-d start:size]\n", program);
- fprintf(stderr, " -t/-d/-b: add text/data section\n");
- fprintf(stderr, "At least one section or a ld file has to be specified\n");
+ fprintf(stderr, " -t/-d/-b: add text/data area\n");
+ fprintf(stderr, "At least one area or a ld file has to be specified\n");
exit(EX_USAGE);
}
-void parse_start_size(char *input, Elf64_Addr &start, Elf64_Xword &size) {
+void parse_start_size(char *input, uint64_t &start, uint64_t &size) {
char *str_size = strchr(input, ':');
if (!str_size) {
- usage("bad section specification, missing ':'");
+ usage("bad area specification, missing ':'");
}
*str_size = '\0';
str_size++;
if (sscanf(input, "%" SCNi64, &start) != 1) {
- usage("bad section specification, could not parse start number");
+ usage("bad area specification, could not parse start number");
}
size_t str_size_len = strlen(str_size);
if (str_size_len < 1) {
- usage("bad section specification");
+ usage("bad area specification");
}
char suffix = str_size[str_size_len - 1];
@@ -101,15 +77,19 @@ void parse_start_size(char *input, Elf64_Addr &start, Elf64_Xword &size) {
case 'M':
modifier = 1024 * 1024;
break;
+ case 'g':
+ case 'G':
+ modifier = 1024 * 1024 * 1024;
+ break;
default:
- usage("bad size modifier, only 'k' and 'M' are allowed");
+ usage("bad size modifier, only 'k', 'M' and 'G' are allowed");
}
} else {
modifier = 1;
}
- if (sscanf(str_size, "%" SCNi64, &size) != 1) {
- usage("bad section specification, could not parse size number");
+ if (sscanf(str_size, "%" SCNu64, &size) != 1) {
+ usage("bad area specification, could not parse size number");
}
size = size * modifier;
}
@@ -118,6 +98,7 @@ bool debug = false;
void parse_args(int argc, char **argv) {
int c;
+ static int anonymousTextCounter = 0, anonymousDataCounter = 0;
while ((c = getopt(argc, argv, "Df:l:t:d:")) != -1) {
switch (c) {
@@ -129,8 +110,35 @@ void parse_args(int argc, char **argv) {
Elf64_Addr start;
Elf64_Xword size;
parse_start_size(optarg, start, size);
- SectionType type = c == 't' ? SectionType::TEXT : SectionType::DATA;
- sections.push_back(Section(type, start, size));
+
+ string name;
+ set<MemoryAttribute> attributes;
+ if (c == 't') {
+ attributes.insert(MemoryAttribute::R);
+ attributes.insert(MemoryAttribute::W);
+ attributes.insert(MemoryAttribute::X);
+
+ name = "text";
+ if (anonymousTextCounter > 0) {
+ name += anonymousTextCounter;
+ }
+ anonymousTextCounter++;
+ } else {
+ attributes.insert(MemoryAttribute::R);
+ attributes.insert(MemoryAttribute::W);
+
+ name = "data";
+ if (anonymousDataCounter > 0) {
+ name += anonymousDataCounter;
+ }
+ anonymousDataCounter++;
+ }
+ memoryAreas.push_back(MemoryArea {
+ .name = name,
+ .origin = start,
+ .length = size,
+ .attributes = attributes
+ });
break;
}
case 'f':
@@ -149,23 +157,28 @@ void parse_args(int argc, char **argv) {
}
}
- if (!filename || (sections.empty() && !ld_filename)) {
+ if (!filename || (memoryAreas.empty() && !ld_filename)) {
usage();
}
}
-void to_iso(Elf64_Addr i, char *buf) {
+string to_iso(uint64_t i) {
const char *suffix;
- if (i > 1024 * 1024) {
+ std::stringstream buf;
+ if (i >= 1024 * 1024 * 1024) {
+ i /= 1024 * 1024 * 1024;
+ suffix = "G";
+ } else if (i >= 1024 * 1024) {
i /= 1024 * 1024;
suffix = "M";
- } else if (i > 1024) {
+ } else if (i >= 1024) {
i /= 1024;
suffix = "k";
} else {
suffix = "";
}
- sprintf(buf, "%" PRIu64 "%s", i, suffix);
+ buf << i << suffix;
+ return buf.str();
}
int main(int argc, char **argv) {
@@ -173,7 +186,15 @@ int main(int argc, char **argv) {
parse_args(argc, argv);
if (ld_filename) {
- ld_file file = ld_file_loader::load(ld_filename);
+ try {
+ LdScriptLoader loader;
+ loader.setDebug(debug);
+ LdScript file = loader.load(ld_filename);
+
+ memoryAreas.insert(memoryAreas.end(), file.memoryAreas.begin(), file.memoryAreas.end());
+ } catch (...) {
+ errx(EX_DATAERR, "Unhandled exception when parsing LD script. The parser is new and fragile, so please file a bug and send me your LD script.");
+ }
}
if (elf_version(EV_CURRENT) == EV_NONE)
@@ -197,7 +218,6 @@ int main(int argc, char **argv) {
if (elf_getphdrnum(e, &program_header_count) != 0)
errx(EX_DATAERR, "elf_getphdrnum() failed: %s.", elf_errmsg(-1));
- size_t text_size = 0, data_size = 0, bss_size = 0;
for (int i = 0; i < program_header_count; i++) {
GElf_Phdr phdr;
@@ -205,67 +225,76 @@ int main(int argc, char **argv) {
errx(EX_SOFTWARE, "getphdr() failed: %s.", elf_errmsg(-1));
if (phdr.p_type == PT_LOAD) {
- SectionType expectedType;
- size_t *size;
-
if (phdr.p_flags == (PF_X | PF_W | PF_R) || phdr.p_flags == (PF_X | PF_R)) {
if (debug) {
printf("Adding PH #%d as text\n", i);
}
- expectedType = SectionType::TEXT;
- size = &text_size;
} else if (phdr.p_flags == (PF_R | PF_W)) {
- expectedType = SectionType::DATA;
if (phdr.p_filesz > 0) {
if (debug) {
printf("Adding PH #%d as data\n", i);
}
- size = &data_size;
}
else {
if (debug) {
printf("Adding PH #%d as bss\n", i);
}
- size = &bss_size;
}
} else {
warnx("Unknown flag combination: 0x%02x", phdr.p_flags);
- warnx("Unknown flag combination: 0x%02x", PF_X | PF_R);
continue;
}
- auto s = std::find_if(sections.begin(), sections.end(), [&](Section &section) {
- return section.type == expectedType && section.contains(phdr.p_vaddr, phdr.p_memsz);
+ auto ma = std::find_if(memoryAreas.begin(), memoryAreas.end(), [&](MemoryArea &memoryArea) {
+ return memoryArea.contains(phdr.p_vaddr);
});
- if (s == sections.end()) {
- fprintf(stderr,
- "Could not find a section for elf header #%d of type %s, at address 0x%08" PRIx64 " with size %" PRId64 "\n",
- i, to_str(expectedType), phdr.p_vaddr, phdr.p_memsz);
- }
- else {
- (*s).used += phdr.p_memsz;
+ if (ma == memoryAreas.end()) {
+ warnx(
+ "Could not find a area for elf header #%d of type %s, at address 0x%08" PRIx64 " with size %" PRId64 "\n",
+ i, ""/*to_str(expectedType)*/, phdr.p_vaddr, phdr.p_memsz);
+ } else {
+ if (debug && !ma->contains(phdr.p_vaddr + phdr.p_memsz)) {
+ warnx("Area overflow: %s", ma->name.c_str());
+ }
- *size += phdr.p_memsz;
+ auto &usage = usages[ma->name];
+
+ if (!usage) {
+ usage = usages[ma->name] = make_shared<Usage>();
+ }
+
+ usage->maxAddress = phdr.p_memsz;
}
} else {
// ignored
- };
+ if (debug) {
+ printf("Ignoring ELF section #%d\n", i);
+ }
+ }
}
- printf("Size by sections\n");
- printf("Type Start End Size Used\n");
- std::for_each(sections.begin(), sections.end(), [&](Section &s) {
- char size[100];
- to_iso(s.size, size);
- int used_pct = (int) (double(s.used) / double(s.size) * 100.0);
- printf("%4s %08" PRIx64 " %08" PRIx64 " %5s %8" PRId64 " %3d%%\n", to_str(s.type), s.start, s.end, size, s.used,
+ printf("Memory areas\n");
+ printf("Name Flags Start End Size Used\n");
+ std::for_each(memoryAreas.begin(), memoryAreas.end(), [&](const MemoryArea &s) {
+ auto &usage = usages[s.name];
+
+ int used_pct = 0;
+ if (usage) {
+ used_pct = (int) (double(usage->maxAddress) / double(s.length) * 100.0);
+ }
+ printf("%-10s %s %08" PRIx64 " %08" PRIx64 " %5s %3d%%\n",
+ s.name.c_str(),
+ s.attributes_string().c_str(),
+ s.origin,
+ s.origin + s.length,
+ to_iso(s.length).c_str(),
used_pct);
});
- printf("\n");
- printf("Size by type\n");
- printf("text=%zu, data=%zu, bss=%zu\n", text_size, data_size, bss_size);
+// printf("\n");
+// printf("Size by type\n");
+// printf("text=%zu, data=%zu, bss=%zu\n", text_size, data_size, bss_size);
return EXIT_SUCCESS;
}