From 62e8183d33ae159b9e984d2ef5b4a83656d56a16 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sat, 16 Jul 2016 22:59:28 +0200 Subject: 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. --- .editorconfig | 5 + CMakeLists.txt | 3 +- GnuLdLexer.g4 | 2 +- Ld.cpp | 252 +++++++++++++++++++++++++++++++++++++++ README.md | 27 ++++- elfinfo.cpp | 193 +++++++++++++++++------------- includes/trygvis/elfinfo/Ld.h | 70 +++++++++++ ld.cpp | 267 ------------------------------------------ ld.h | 11 -- 9 files changed, 467 insertions(+), 363 deletions(-) create mode 100644 .editorconfig create mode 100644 Ld.cpp create mode 100644 includes/trygvis/elfinfo/Ld.h delete mode 100644 ld.cpp delete mode 100644 ld.h 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 new file mode 100644 index 0000000..a60656c --- /dev/null +++ b/Ld.cpp @@ -0,0 +1,252 @@ +#include "Ld.h" +#include "GnuLdLexer.h" +#include "GnuLdParser.h" +#include "GnuLdParserBaseListener.h" + +namespace trygvis { +namespace elfinfo { + +using antlr4::ANTLRFileStream; +using namespace std; + +using ParseTree = antlr4::tree::ParseTree; + +static MemoryAttribute valueOf(char c) { + switch (c) { + case 'r': + case 'R': + return MemoryAttribute::R; + case 'w': + case 'W': + return MemoryAttribute::W; + case 'x': + case 'X': + return MemoryAttribute::X; + default: + throw std::domain_error("Invalid memory attribute: " + c); + } +} + +static bool endsWith(const string &a, const string &b) { + return b.length() <= a.length() && a.compare(a.length() - b.length(), b.length(), b) == 0; +} + +template +class ParseTreeProperty { +public: + virtual V get(Ref node) { + return get(node.get()); + } + + virtual V get(ParseTree *const node) { +// 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; +// } + } + + virtual void put(ParseTree *const node, V value) { + // cout << "put(" << node << ", " << value << ")" << endl; + _annotations[node] = value; + } + + virtual V removeFrom(ParseTree *const node) { + return _annotations.erase(node); + } + +protected: + std::map _annotations; + +private: +}; + +class ElfinfoGnuLdBaseListener : public GnuLdParserBaseListener { +private: +public: + vector memoryAreas; + ParseTreeProperty expr; + vector
sections; + MemoryAttribute attribute; + bool attributesInverted; + set 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 = s; + transform(begin(str), end(str), begin(str), ::tolower); + int base = 10; + if (str.compare(0, 2, "0x") == 0) { + base = 16; + str = str.substr(2); + } + + int factor = 1; + if (endsWith(str, "k")) { + factor = 1024; + str = str.substr(0, str.length() - 1); + } else if (endsWith(str, "m")) { + factor = 1024 * 1024; + str = str.substr(0, str.length() - 1); + } + + unsigned long long i = strtoull(str.c_str(), NULL, base); + + if (factor > 1) { + i = i * factor; + } + return i; + } + + 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 { + 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)); + 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)); + uint64_t b = expr.get(ctx->exp(1)); + uint64_t x = a + b; + expr.put(ctx, x); + } + + void exitExpName(GnuLdParser::ExpNameContext *ctx) override { + expr.put(ctx, 0); + } + + void exitExpAddr(GnuLdParser::ExpAddrContext *ctx) override { + expr.put(ctx, 0); + } + + void exitExpSizeof(GnuLdParser::ExpSizeofContext *ctx) override { + expr.put(ctx, 0); + } + + void exitExpLengthExp(GnuLdParser::ExpLengthExpContext *ctx) override { + MemoryArea ma = getMemoryArea(ctx->NAME()->getText()); + expr.put(ctx, ma.length); + } + + void exitExpOrigin(GnuLdParser::ExpOriginContext *ctx) override { + MemoryArea ma = getMemoryArea(ctx->NAME()->getText()); + expr.put(ctx, ma.origin); + } + + void exitMustbe_exp(GnuLdParser::Mustbe_expContext *ctx) override { + expr.put(ctx, expr.get(ctx->exp())); + } + + void exitExpLoadaddr(GnuLdParser::ExpLoadaddrContext *ctx) override { + auto §ion = getSection(ctx->NAME()->getText()); + expr.put(ctx, 0); + } + + void exitExpConstant(GnuLdParser::ExpConstantContext *ctx) override { + expr.put(ctx, expr.get(ctx->NAME())); + } + + void exitMemory_spec(GnuLdParser::Memory_specContext *ctx) override { + MemoryArea ma; + ma.name = ctx->NAME()->getText(); + ma.attributes = attributes; + ma.origin = expr.get(ctx->origin_spec()->mustbe_exp()); + ma.length = expr.get(ctx->length_spec()->mustbe_exp()); + memoryAreas.push_back(ma); + } + + void exitAttributes_opt(GnuLdParser::Attributes_optContext *ctx) override { + attributes.clear(); + } + + void enterAttributeInverted(GnuLdParser::AttributeInvertedContext *ctx) override { + 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)."); + } + + const string &name = ctx->NAME()->getText(); + + attributesInverted = true; + } + + void enterAttributeNormal(GnuLdParser::AttributeNormalContext *ctx) override { + + const string &name = ctx->NAME()->getText(); + for (int i = 0; i < name.length(); i++) { + attribute = valueOf(name[i]); + attributes.insert(attribute); + } + attributesInverted = false; + } +}; + +LdScriptLoader::LdScriptLoader() : debug_(false) { +} + +LdScript LdScriptLoader::load(std::string path) { + ANTLRFileStream input(path); + GnuLdLexer lexer(&input); + CommonTokenStream tokens(&lexer); + tokens.fill(); + + 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(); + + 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 #include #include +#include +#include +#include #include -#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
sections; +std::vector memoryAreas; +std::map> 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 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 §ion) { - 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->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 +#include +#include +#include + +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 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 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.cpp b/ld.cpp deleted file mode 100644 index 6118f3a..0000000 --- a/ld.cpp +++ /dev/null @@ -1,267 +0,0 @@ -#include "ld.h" -#include "GnuLdLexer.h" -#include "GnuLdParser.h" -#include "GnuLdParserBaseListener.h" -#include "antlr4-runtime.h" - -#include -#include -#include -#include -#include -#include -#include - -using antlr4::ANTLRFileStream; -using namespace std; - -enum class MemoryAttribute { - R, W, X -}; - -class MemoryArea { -public: - string name; - uint64_t origin; - uint64_t length; - set attributes; -}; - -static MemoryAttribute valueOf(char c) { - switch (c) { - case 'r': - case 'R': - return MemoryAttribute::R; - case 'w': - case 'W': - return MemoryAttribute::W; - case 'x': - case 'X': - return MemoryAttribute::X; - default: - throw std::domain_error("Invalid memory attribute: " + c); - } -} - -static bool endsWith(const string &a, const string &b) { - return b.length() <= a.length() && a.compare(a.length() - b.length(), b.length(), b); -} - -using ParseTree = antlr4::tree::ParseTree; - -template -class ParseTreeProperty { -public: - virtual V get(ParseTree *const node) { - 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; - } - } - - virtual void put(ParseTree *const node, V value) { - _annotations[node] = value; - } - - virtual V removeFrom(ParseTree *const node) { - return _annotations.erase(node); - } - -protected: - std::map _annotations; - -private: -}; - -class ElfinfoGnuLdBaseListener : public GnuLdParserBaseListener { -private: -public: - vector memoryAreas; - - ParseTreeProperty expr; -// map expr; - - static uint64_t parseInt(const string &s) { - string str; - transform(begin(s), end(s), begin(str), ::tolower); - int base = 10; - if (str.compare(0, 2, "0x")) { - base = 16; - str = str.substr(0, 2); - } - - int factor = 1; - if (endsWith(str, "k")) { - factor = 1024; - str = str.substr(0, str.length() - 1); - } else if (endsWith(str, "k")) { - factor = 1024 * 1024; - str = str.substr(0, str.length() - 1); - } - - unsigned long long i = strtoull(str.c_str(), NULL, base); - - if (factor > 1) { - i = i * factor; - } - return i; - } - - virtual 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 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 x = a + b; - expr.put(ctx, x); - } - - void exitExpName(GnuLdParser::ExpNameContext *ctx) override { - expr.put(ctx, 0); - } - - void exitExpAddr(GnuLdParser::ExpAddrContext *ctx) override { - expr.put(ctx, 0); - } - - void exitExpSizeof(GnuLdParser::ExpSizeofContext *ctx) override { - expr.put(ctx, 0); - } - - void exitExpLengthExp(GnuLdParser::ExpLengthExpContext *ctx) override { - MemoryArea - ma = getMemoryArea(ctx->NAME()->getText()); -// System.out.println("ma.length = " + ma.length); - 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); - 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())); - } - - - 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 enterMemory_spec(GnuLdParser::Memory_specContext *ctx) override { -// System.out.println("ElfinfoGnuLdListener.enterMemory_spec"); - } - - 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()); - memoryAreas.push_back(ma); - } - - MemoryAttribute attribute; - bool attributesInverted; - set 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)."); - } -// 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); - } - attributesInverted = false; - } -}; - -ld_file ld_file_loader::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; - } - - GnuLdParser parser(&tokens); - ElfinfoGnuLdBaseListener listener; - parser.addParseListener(&listener); - auto file = parser.file(); - std::cout << file->toStringTree(&parser) << std::endl << std::endl; - return {}; -} 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 - -class ld_file { -}; - -class ld_file_loader { -public: - static ld_file load(std::string path); -}; -- cgit v1.2.3