aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2016-07-16 22:59:28 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2016-07-16 22:59:28 +0200
commit62e8183d33ae159b9e984d2ef5b4a83656d56a16 (patch)
tree49eda06698ad2a11ad661386e6b1524a4ec11aba
parent4675ec55f6bdb8f826cc94a9585ff9229c277983 (diff)
downloadelfinfo-62e8183d33ae159b9e984d2ef5b4a83656d56a16.tar.gz
elfinfo-62e8183d33ae159b9e984d2ef5b4a83656d56a16.tar.bz2
elfinfo-62e8183d33ae159b9e984d2ef5b4a83656d56a16.tar.xz
elfinfo-62e8183d33ae159b9e984d2ef5b4a83656d56a16.zip
o Working version that can take the data from the LD script. Only tested with the Intel Quark D2000 LD script.
lexer: Allowing capital X in hex numbers too.
-rw-r--r--.editorconfig5
-rw-r--r--CMakeLists.txt3
-rw-r--r--GnuLdLexer.g42
-rw-r--r--Ld.cpp (renamed from ld.cpp)191
-rw-r--r--README.md27
-rw-r--r--elfinfo.cpp193
-rw-r--r--includes/trygvis/elfinfo/Ld.h70
-rw-r--r--ld.h11
8 files changed, 303 insertions, 199 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..ac070fd
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,5 @@
+[**]
+indent_style=space
+indent_size=4
+charset=utf-8
+trim_trailing_whitespace=true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2749ba8..ddbe243 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,9 +7,10 @@ find_package(Antlr4)
antlr4_add_target(TARGET GnuLd STATIC LEXER GnuLdLexer.g4 PARSER GnuLdParser.g4)
-add_executable(elfinfo elfinfo.cpp ld.cpp ld.h)
+add_executable(elfinfo elfinfo.cpp Ld.cpp includes/trygvis/elfinfo/Ld.h)
target_compile_options(elfinfo PUBLIC "--std=c++14")
target_link_libraries(elfinfo elf GnuLd Antlr4::antlr4_shared)
+target_include_directories(elfinfo PUBLIC includes/trygvis/elfinfo)
INSTALL(TARGETS elfinfo
RUNTIME DESTINATION bin
diff --git a/GnuLdLexer.g4 b/GnuLdLexer.g4
index fba488e..a02a8e4 100644
--- a/GnuLdLexer.g4
+++ b/GnuLdLexer.g4
@@ -147,7 +147,7 @@ fragment
INT_NUMBER : INT_HEX
| INT_DECIMAL;
fragment
-INT_HEX : '0x' [0-9a-fA-F]+;
+INT_HEX : '0' ('X' | 'x') [0-9a-fA-F]+;
fragment
INT_DECIMAL : [0-9]+;
fragment
diff --git a/ld.cpp b/Ld.cpp
index 6118f3a..a60656c 100644
--- a/ld.cpp
+++ b/Ld.cpp
@@ -1,31 +1,15 @@
-#include "ld.h"
+#include "Ld.h"
#include "GnuLdLexer.h"
#include "GnuLdParser.h"
#include "GnuLdParserBaseListener.h"
-#include "antlr4-runtime.h"
-#include <vector>
-#include <set>
-#include <map>
-#include <locale>
-#include <string>
-#include <algorithm>
-#include <iostream>
+namespace trygvis {
+namespace elfinfo {
using antlr4::ANTLRFileStream;
using namespace std;
-enum class MemoryAttribute {
- R, W, X
-};
-
-class MemoryArea {
-public:
- string name;
- uint64_t origin;
- uint64_t length;
- set<MemoryAttribute> attributes;
-};
+using ParseTree = antlr4::tree::ParseTree;
static MemoryAttribute valueOf(char c) {
switch (c) {
@@ -44,25 +28,28 @@ static MemoryAttribute valueOf(char c) {
}
static bool endsWith(const string &a, const string &b) {
- return b.length() <= a.length() && a.compare(a.length() - b.length(), b.length(), b);
+ return b.length() <= a.length() && a.compare(a.length() - b.length(), b.length(), b) == 0;
}
-using ParseTree = antlr4::tree::ParseTree;
-
template<typename V>
class ParseTreeProperty {
public:
+ virtual V get(Ref<ParseTree> node) {
+ return get(node.get());
+ }
+
virtual V get(ParseTree *const node) {
- try {
- cout << "node= " << node->getText() << endl;
+// try {
+// cout << "node = " << node->getText() << endl;
return _annotations.at(node);
- } catch (std::out_of_range &e) {
- cout << "out of range: " << node->getText() << endl;
- throw e;
- }
+// } catch (std::out_of_range &e) {
+// cout << "out of range: " << node->getText() << endl;
+// throw e;
+// }
}
virtual void put(ParseTree *const node, V value) {
+ // cout << "put(" << node << ", " << value << ")" << endl;
_annotations[node] = value;
}
@@ -80,24 +67,44 @@ class ElfinfoGnuLdBaseListener : public GnuLdParserBaseListener {
private:
public:
vector<MemoryArea> memoryAreas;
-
ParseTreeProperty<uint64_t> expr;
-// map<ParserRuleContext*, uint64_t> expr;
+ vector<Section> sections;
+ MemoryAttribute attribute;
+ bool attributesInverted;
+ set<MemoryAttribute> attributes;
+
+ MemoryArea getMemoryArea(const string &name) {
+ for (MemoryArea &ma : memoryAreas) {
+ if (ma.name == name) {
+ return ma;
+ }
+ }
+ throw out_of_range("No such memory area: " + name);
+ }
+
+ Section &getSection(const string &name) {
+ for (Section &s : sections) {
+ if (s.name == name) {
+ return s;
+ }
+ }
+ throw out_of_range("No such section: " + name);
+ }
static uint64_t parseInt(const string &s) {
- string str;
- transform(begin(s), end(s), begin(str), ::tolower);
+ string str = s;
+ transform(begin(str), end(str), begin(str), ::tolower);
int base = 10;
- if (str.compare(0, 2, "0x")) {
+ if (str.compare(0, 2, "0x") == 0) {
base = 16;
- str = str.substr(0, 2);
+ str = str.substr(2);
}
int factor = 1;
if (endsWith(str, "k")) {
factor = 1024;
str = str.substr(0, str.length() - 1);
- } else if (endsWith(str, "k")) {
+ } else if (endsWith(str, "m")) {
factor = 1024 * 1024;
str = str.substr(0, str.length() - 1);
}
@@ -110,26 +117,30 @@ public:
return i;
}
- virtual void exitExpAlign(GnuLdParser::ExpAlignContext *ctx) override {
+ void exitSection(GnuLdParser::SectionContext *ctx) override {
+ auto name = ctx->NAME()->getText();
+ sections.push_back(Section{.name = name});
+ }
+
+ void exitExpAlign(GnuLdParser::ExpAlignContext *ctx) override {
expr.put(ctx, 0);
}
void exitExpInt(GnuLdParser::ExpIntContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.exitExpInt: ctx->INT()->getText() = " + ctx->INT()->getText());
uint64_t i = parseInt(ctx->INT()->getText());
expr.put(ctx, i);
}
void exitExpSub(GnuLdParser::ExpSubContext *ctx) override {
- uint64_t a = expr.get(ctx->exp(0).get());
- uint64_t b = expr.get(ctx->exp(1).get());
+ uint64_t a = expr.get(ctx->exp(0));
+ uint64_t b = expr.get(ctx->exp(1));
uint64_t x = a - b;
expr.put(ctx, x);
}
void exitExpAdd(GnuLdParser::ExpAddContext *ctx) override {
- uint64_t a = expr.get(ctx->exp(0).get());
- uint64_t b = expr.get(ctx->exp(1).get());
+ uint64_t a = expr.get(ctx->exp(0));
+ uint64_t b = expr.get(ctx->exp(1));
uint64_t x = a + b;
expr.put(ctx, x);
}
@@ -147,99 +158,55 @@ public:
}
void exitExpLengthExp(GnuLdParser::ExpLengthExpContext *ctx) override {
- MemoryArea
- ma = getMemoryArea(ctx->NAME()->getText());
-// System.out.println("ma.length = " + ma.length);
+ MemoryArea ma = getMemoryArea(ctx->NAME()->getText());
expr.put(ctx, ma.length);
}
void exitExpOrigin(GnuLdParser::ExpOriginContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.exitExpOrigin: " + ctx->getText());
- MemoryArea
- ma = getMemoryArea(ctx->NAME()->getText());
-// System.out.println("ma.origin = " + ma.origin);
+ MemoryArea ma = getMemoryArea(ctx->NAME()->getText());
expr.put(ctx, ma.origin);
}
- MemoryArea getMemoryArea(const string &name) {
- for (MemoryArea &ma : memoryAreas) {
- if (ma.name == name) {
- return ma;
- }
- }
- throw new RuntimeException("No such memory area: " + name);
- }
-
- void enterMustbe_exp(GnuLdParser::Mustbe_expContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.enterMustbe_exp");
- }
-
void exitMustbe_exp(GnuLdParser::Mustbe_expContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.exitMustbe_exp");
-
- expr.put(ctx, expr.get(ctx->exp().get()));
+ expr.put(ctx, expr.get(ctx->exp()));
}
-
- void enterOrigin_spec(GnuLdParser::Origin_specContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.enterOrigin_spec");
- }
-
- void exitOrigin_spec(GnuLdParser::Origin_specContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.exitOrigin_spec");
- }
-
- void enterLength_spec(GnuLdParser::Length_specContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.enterLength_spec");
- }
-
- void exitLength_spec(GnuLdParser::Length_specContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.exitLength_spec");
+ void exitExpLoadaddr(GnuLdParser::ExpLoadaddrContext *ctx) override {
+ auto &section = getSection(ctx->NAME()->getText());
+ expr.put(ctx, 0);
}
- void enterMemory_spec(GnuLdParser::Memory_specContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.enterMemory_spec");
+ void exitExpConstant(GnuLdParser::ExpConstantContext *ctx) override {
+ expr.put(ctx, expr.get(ctx->NAME()));
}
void exitMemory_spec(GnuLdParser::Memory_specContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.exitMemory_spec");
MemoryArea ma;
ma.name = ctx->NAME()->getText();
ma.attributes = attributes;
-// System.out.println("ctx->origin_spec() = " + ctx->origin_spec());
- ma.origin = expr.get(ctx->origin_spec().get()->mustbe_exp().get());
- ma.length = expr.get(ctx->length_spec().get()->mustbe_exp().get());
+ ma.origin = expr.get(ctx->origin_spec()->mustbe_exp());
+ ma.length = expr.get(ctx->length_spec()->mustbe_exp());
memoryAreas.push_back(ma);
}
- MemoryAttribute attribute;
- bool attributesInverted;
- set<MemoryAttribute> attributes;
-
void exitAttributes_opt(GnuLdParser::Attributes_optContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.exitAttributes_opt");
attributes.clear();
}
void enterAttributeInverted(GnuLdParser::AttributeInvertedContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.enterAttributeInverted");
-
if (!attributes.empty()) {
throw new RuntimeException(
- "Attributes for memory areas can only be attributesInverted (with '!') as the first character in a specification; foo(!rw), not foo(x!rw).");
+ "Attributes for memory areas can only be attributesInverted (with '!') as the first character in a specification; foo(!rw), not foo(x!rw).");
}
-// const string& name = ctx->name()->getText();
+
const string &name = ctx->NAME()->getText();
-// System.out.println("ctx->ATTRIBUTE()->getText() = " + name);
attributesInverted = true;
}
void enterAttributeNormal(GnuLdParser::AttributeNormalContext *ctx) override {
-// System.out.println("ElfinfoGnuLdListener.enterAttributeNormal");
const string &name = ctx->NAME()->getText();
-// System.out.println("ctx->ATTRIBUTE()->getText() = " + name);
for (int i = 0; i < name.length(); i++) {
attribute = valueOf(name[i]);
attributes.insert(attribute);
@@ -248,20 +215,38 @@ public:
}
};
-ld_file ld_file_loader::load(std::string path) {
+LdScriptLoader::LdScriptLoader() : debug_(false) {
+}
+
+LdScript LdScriptLoader::load(std::string path) {
ANTLRFileStream input(path);
GnuLdLexer lexer(&input);
CommonTokenStream tokens(&lexer);
tokens.fill();
- for (auto token : tokens.getTokens()) {
- std::cout << token->toString() << std::endl;
+ if (debug_) {
+ for (auto token : tokens.getTokens()) {
+ std::cout << token->toString() << std::endl;
+ }
}
GnuLdParser parser(&tokens);
ElfinfoGnuLdBaseListener listener;
parser.addParseListener(&listener);
auto file = parser.file();
- std::cout << file->toStringTree(&parser) << std::endl << std::endl;
- return {};
+
+ if (debug_) {
+ std::cout << file->toStringTree(&parser) << std::endl << std::endl;
+ }
+
+ return {
+ .memoryAreas = listener.memoryAreas
+ };
}
+
+void LdScriptLoader::setDebug(bool debug) {
+ debug_ = debug;
+}
+
+} // namespace elfinfo
+} // namespace trygvis
diff --git a/README.md b/README.md
index 6744d1e..948b01e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,30 @@
# elfinfo - Extract info from ELF files
+Elfinfo shows you some nice stats about your ELF file, useful for microcontroller binaries if you want to keep an eye
+on how much flash and data you're using.
+
+Given this LD script (only significant parts shown, the rest is ignored):
+
+ MEMORY
+ {
+ flash(r) : ORIGIN = 0x00180000, LENGTH = 32K
+ data(rw) : ORIGIN = 0x00200000, LENGTH = 4K
+ /* Place IDT at the bottom of SRAM, 52 gate wide */
+ esram_idt (rw) : ORIGIN = 0x00280000, LENGTH = 0x1A0
+ esram(rw) : ORIGIN = 0x002801A0, LENGTH = 8K - 1K - 0x1A0
+ stack(rw) : ORIGIN = 0x00281C00, LENGTH = 1K
+ }
+
+this is a possible output:
+
+ Memory areas
+ Name Flags Start End Size Used
+ flash --- 00180000 00188000 32k 28%
+ data --- 00200000 00201000 4k 0%
+ esram_idt --- 00280000 002801a0 416 0%
+ esram --- 002801a0 00281c00 6k 3%
+ stack --- 00281c00 00282000 1k 0%
+
# Building
This code currently depend on experimental patches for Antlr4's C++ runtime which has to be build first. This should
@@ -18,6 +43,6 @@ This will build and install Antlr4 into $HOME/opt/antlr-cpp.
To build this code follow a similar approach:
mkdir build
- cmake .. -DAntlr4_DIR=$HOME/opt/antlr-cpp/lib/cmake/Antlr4
+ cmake .. -DAntlr4_DIR=$HOME/opt/antlr-cpp/lib/cmake/Antlr4 -DCMAKE_INSTALL_PREFIX=$HOME/opt/elfinfo
make
make install
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;
}
diff --git a/includes/trygvis/elfinfo/Ld.h b/includes/trygvis/elfinfo/Ld.h
new file mode 100644
index 0000000..cab466d
--- /dev/null
+++ b/includes/trygvis/elfinfo/Ld.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <string>
+#include <set>
+#include <vector>
+#include <sstream>
+
+namespace trygvis {
+namespace elfinfo {
+
+enum class MemoryAttribute {
+ R, W, X
+};
+
+static char to_str(const MemoryAttribute &type) {
+ switch (type) {
+ case MemoryAttribute::R:
+ return 'r';
+ case MemoryAttribute::W:
+ return 'w';
+ case MemoryAttribute::X:
+ return 'x';
+ }
+}
+
+struct Section {
+ std::string name;
+};
+
+struct MemoryArea {
+ std::string name;
+ uint64_t origin;
+ uint64_t length;
+ std::set<MemoryAttribute> attributes;
+
+ bool contains(uint64_t address, uint64_t size) const {
+ return contains(address) && contains(address + size);
+ }
+
+ bool contains(uint64_t address) const {
+ return origin <= address && address < origin + length;
+ }
+
+ std::string attributes_string() const {
+ char buf[4];
+ buf[0] = attributes.find(MemoryAttribute::R) == attributes.end() ? '-' : 'r';
+ buf[1] = attributes.find(MemoryAttribute::W) == attributes.end() ? '-' : 'w';
+ buf[2] = attributes.find(MemoryAttribute::X) == attributes.end() ? '-' : 'x';
+ buf[3] = '\0';
+ return std::string(buf);
+ }
+};
+
+struct LdScript {
+ std::vector<MemoryArea> memoryAreas;
+};
+
+class LdScriptLoader {
+public:
+ LdScriptLoader();
+
+ LdScript load(std::string path);
+
+ void setDebug(bool debug);
+private:
+ bool debug_;
+};
+
+} // namespace elfinfo
+} // namespace trygvis
diff --git a/ld.h b/ld.h
deleted file mode 100644
index b25a24c..0000000
--- a/ld.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-#include <string>
-
-class ld_file {
-};
-
-class ld_file_loader {
-public:
- static ld_file load(std::string path);
-};