From 9bcf22e40f29dcb57d32190db047c30d032a5ea9 Mon Sep 17 00:00:00 2001 From: James Benton Date: Wed, 23 May 2018 12:35:24 +0100 Subject: [PATCH] Add tools readrpl, udplogserver. --- .gitmodules | 3 + .travis.yml | 2 +- CMakeLists.txt | 2 +- share/wut.toolchain.cmake | 2 +- tools/CMakeLists.txt | 2 + tools/common/be_val.h | 25 +- tools/elf2rpl/CMakeLists.txt | 16 +- tools/libraries/CMakeLists.txt | 5 + tools/libraries/excmd | 1 + tools/readrpl/CMakeLists.txt | 17 + tools/readrpl/main.cpp | 736 ++++++++++++++++++++++++++++++ tools/rplgen/CMakeLists.txt | 16 +- tools/udplogserver/CMakeLists.txt | 14 + tools/udplogserver/main.cpp | 106 +++++ 14 files changed, 912 insertions(+), 35 deletions(-) create mode 160000 tools/libraries/excmd create mode 100644 tools/readrpl/CMakeLists.txt create mode 100644 tools/readrpl/main.cpp create mode 100644 tools/udplogserver/CMakeLists.txt create mode 100644 tools/udplogserver/main.cpp diff --git a/.gitmodules b/.gitmodules index 28ebcdc..30d0af8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "tools/libraries/fmt"] path = tools/libraries/fmt url = https://github.com/fmtlib/fmt.git +[submodule "tools/libraries/excmd"] + path = tools/libraries/excmd + url = https://github.com/exjam/excmd.git diff --git a/.travis.yml b/.travis.yml index c3332a1..f009082 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,6 @@ script: - cd ../ - cd samples/helloworld - mkdir build && cd build - - chmod +x $WUT_ROOT/bin/wut-elf2rpl + - chmod +x $WUT_ROOT/bin/elf2rpl - cmake -DCMAKE_TOOLCHAIN_FILE=$WUT_ROOT/share/wut.toolchain.cmake -DCMAKE_INSTALL_PREFIX=$WUT_ROOT/samples ../ - make -j4 VERBOSE=TRUE install diff --git a/CMakeLists.txt b/CMakeLists.txt index 271a162..b1a88ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ externalproject_add(tools externalproject_get_property(tools BINARY_DIR) set(TOOLS_BINARY_DIR ${BINARY_DIR}) -set(WUT_RPLGEN "${TOOLS_BINARY_DIR}/bin/wut-rplgen") +set(WUT_RPLGEN "${TOOLS_BINARY_DIR}/bin/rplgen") externalproject_add(cafe SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cafe" diff --git a/share/wut.toolchain.cmake b/share/wut.toolchain.cmake index a1cf6fb..cb94723 100644 --- a/share/wut.toolchain.cmake +++ b/share/wut.toolchain.cmake @@ -35,7 +35,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # Tools -set(WUT_ELF2RPL "${WUT_ROOT}/bin/wut-elf2rpl${CMAKE_EXECUTABLE_SUFFIX}" CACHE PATH "") +set(WUT_ELF2RPL "${WUT_ROOT}/bin/elf2rpl${CMAKE_EXECUTABLE_SUFFIX}" CACHE PATH "") # Flags set(WUT TRUE) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5dc7668..35dc3f4 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -18,4 +18,6 @@ find_package(ZLIB REQUIRED) include_directories(common) add_subdirectory(elf2rpl) +add_subdirectory(readrpl) add_subdirectory(rplgen) +add_subdirectory(udplogserver) diff --git a/tools/common/be_val.h b/tools/common/be_val.h index 58262c0..ba2d17b 100644 --- a/tools/common/be_val.h +++ b/tools/common/be_val.h @@ -1,7 +1,7 @@ #pragma once #include "utils.h" #include "type_traits.h" -#include +#include template class be_val @@ -391,29 +391,6 @@ public: return value().operator ->(); } - // Helper to access FunctionPointer::getAddress - template - auto getAddress() - -> decltype(std::declval().getAddress()) const - { - return value().getAddress(); - } - - // Helper to access Pointer::getRawPointer - template - auto getRawPointer() - -> decltype(std::declval().getRawPointer()) const - { - return value().getRawPointer(); - } - - // Please use virt_addrof or phys_addrof instead - auto operator &() = delete; - - friend std::ostream &operator<<(std::ostream &os, const be_val &b) { - return os << b.value(); - } - private: value_type mStorage; }; diff --git a/tools/elf2rpl/CMakeLists.txt b/tools/elf2rpl/CMakeLists.txt index 51176bc..f7a46a6 100644 --- a/tools/elf2rpl/CMakeLists.txt +++ b/tools/elf2rpl/CMakeLists.txt @@ -1,8 +1,16 @@ -add_executable(wut-elf2rpl main.cpp) -target_include_directories(wut-elf2rpl PRIVATE +project(elf2rpl) + +file(GLOB_RECURSE SOURCE_FILES *.cpp) +file(GLOB_RECURSE HEADER_FILES *.h) + +add_executable(elf2rpl + ${SOURCE_FILES} ${HEADER_FILES}) + +target_include_directories(elf2rpl PRIVATE ${ZLIB_INCLUDE_DIR}) -target_link_libraries(wut-elf2rpl + +target_link_libraries(elf2rpl fmt ${ZLIB_LIBRARIES}) -install(TARGETS wut-elf2rpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") +install(TARGETS elf2rpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/libraries/CMakeLists.txt b/tools/libraries/CMakeLists.txt index 468fe7d..7d170a9 100644 --- a/tools/libraries/CMakeLists.txt +++ b/tools/libraries/CMakeLists.txt @@ -1 +1,6 @@ +# excmd +add_library(excmd INTERFACE) +target_include_directories(excmd INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/excmd/src") + +# fmt add_subdirectory(fmt) diff --git a/tools/libraries/excmd b/tools/libraries/excmd new file mode 160000 index 0000000..b48dab4 --- /dev/null +++ b/tools/libraries/excmd @@ -0,0 +1 @@ +Subproject commit b48dab4954bdc074d7768e38065171441aaff7ce diff --git a/tools/readrpl/CMakeLists.txt b/tools/readrpl/CMakeLists.txt new file mode 100644 index 0000000..9d2ade2 --- /dev/null +++ b/tools/readrpl/CMakeLists.txt @@ -0,0 +1,17 @@ +project(readrpl) + +file(GLOB_RECURSE SOURCE_FILES *.cpp) +file(GLOB_RECURSE HEADER_FILES *.h) + +add_executable(readrpl + ${SOURCE_FILES} ${HEADER_FILES}) + +target_include_directories(readrpl PRIVATE + ${ZLIB_INCLUDE_DIR}) + +target_link_libraries(readrpl + excmd + fmt + ${ZLIB_LIBRARIES}) + +install(TARGETS readrpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/readrpl/main.cpp b/tools/readrpl/main.cpp new file mode 100644 index 0000000..2741dfb --- /dev/null +++ b/tools/readrpl/main.cpp @@ -0,0 +1,736 @@ +#include +#include +#include +#include +#include +#include +#include "elf.h" + +struct Section +{ + elf::SectionHeader header; + std::vector data; +}; + +static std::string +formatET(uint32_t type) +{ + switch (type) { + case elf::ET_NONE: + return "ET_NONE"; + case elf::ET_REL: + return "ET_REL"; + case elf::ET_EXEC: + return "ET_EXEC"; + case elf::ET_DYN: + return "ET_DYN"; + case elf::ET_CORE: + return "ET_CORE"; + case elf::ET_CAFE_RPL: + return "ET_CAFE_RPL"; + default: + return ""; + } +} + +static std::string +formatEM(uint32_t machine) +{ + switch (machine) { + case elf::EM_PPC: + return "EM_PPC"; + default: + return ""; + } +} + +static std::string +formatEABI(uint32_t machine) +{ + switch (machine) { + case elf::EABI_CAFE: + return "EABI_CAFE"; + default: + return ""; + } +} + +static std::string +formatSHF(uint32_t flags) +{ + std::string result = ""; + + if (flags & elf::SHF_WRITE) { + result += "W"; + } + + if (flags & elf::SHF_ALLOC) { + result += "A"; + } + + if (flags & elf::SHF_EXECINSTR) { + result += "X"; + } + + if (flags & elf::SHF_DEFLATED) { + result += "Z"; + } + + return result; +} + +static std::string +formatSHT(uint32_t type) +{ + switch (type) { + case elf::SHT_NULL: + return "SHT_NULL"; + case elf::SHT_PROGBITS: + return "SHT_PROGBITS"; + case elf::SHT_SYMTAB: + return "SHT_SYMTAB"; + case elf::SHT_STRTAB: + return "SHT_STRTAB"; + case elf::SHT_RELA: + return "SHT_RELA"; + case elf::SHT_HASH: + return "SHT_HASH"; + case elf::SHT_DYNAMIC: + return "SHT_DYNAMIC"; + case elf::SHT_NOTE: + return "SHT_NOTE"; + case elf::SHT_NOBITS: + return "SHT_NOBITS"; + case elf::SHT_REL: + return "SHT_REL"; + case elf::SHT_SHLIB: + return "SHT_SHLIB"; + case elf::SHT_DYNSYM: + return "SHT_DYNSYM"; + case elf::SHT_INIT_ARRAY: + return "SHT_INIT_ARRAY"; + case elf::SHT_FINI_ARRAY: + return "SHT_FINI_ARRAY"; + case elf::SHT_PREINIT_ARRAY: + return "SHT_PREINIT_ARRAY"; + case elf::SHT_GROUP: + return "SHT_GROUP"; + case elf::SHT_SYMTAB_SHNDX: + return "SHT_SYMTAB_SHNDX"; + case elf::SHT_LOPROC: + return "SHT_LOPROC"; + case elf::SHT_HIPROC: + return "SHT_HIPROC"; + case elf::SHT_LOUSER: + return "SHT_LOUSER"; + case elf::SHT_RPL_EXPORTS: + return "SHT_RPL_EXPORTS"; + case elf::SHT_RPL_IMPORTS: + return "SHT_RPL_IMPORTS"; + case elf::SHT_RPL_CRCS: + return "SHT_RPL_CRCS"; + case elf::SHT_RPL_FILEINFO: + return "SHT_RPL_FILEINFO"; + case elf::SHT_HIUSER: + return "SHT_HIUSER"; + default: + return fmt::format("{}", type); + } +} + +static void +printHeader(elf::Header &header) +{ + fmt::print("ElfHeader\n"); + fmt::print(" {:<20} = 0x{:08X}\n", "magic", header.magic); + fmt::print(" {:<20} = {}\n", "fileClass", header.fileClass); + fmt::print(" {:<20} = {}\n", "encoding", header.encoding); + fmt::print(" {:<20} = {}\n", "elfVersion", header.elfVersion); + fmt::print(" {:<20} = {} 0x{:04x}\n", "abi", formatEABI(header.abi), header.abi); + fmt::print(" {:<20} = {} 0x{:04X}\n", "type", formatET(header.type), header.type); + fmt::print(" {:<20} = {} {}\n", "machine", formatEM(header.machine), header.machine); + fmt::print(" {:<20} = 0x{:X}\n", "version", header.version); + fmt::print(" {:<20} = 0x{:08X}\n", "entry", header.entry); + fmt::print(" {:<20} = 0x{:X}\n", "phoff", header.phoff); + fmt::print(" {:<20} = 0x{:X}\n", "shoff", header.shoff); + fmt::print(" {:<20} = 0x{:X}\n", "flags", header.flags); + fmt::print(" {:<20} = {}\n", "ehsize", header.ehsize); + fmt::print(" {:<20} = {}\n", "phentsize", header.phentsize); + fmt::print(" {:<20} = {}\n", "phnum", header.phnum); + fmt::print(" {:<20} = {}\n", "shentsize", header.shentsize); + fmt::print(" {:<20} = {}\n", "shnum", header.shnum); + fmt::print(" {:<20} = {}\n", "shstrndx", header.shstrndx); +} + +static void +printSectionSummary(std::vector
§ions, + const char *shStrTab) +{ + fmt::print("Sections:\n"); + fmt::print( + " {:<4} {:<20} {:<16} {:<8} {:<6} {:<6} {:<2} {:<4} {:<2} {:<4} {:<5}\n", + "[Nr]", "Name", "Type", "Addr", "Off", "Size", "ES", "Flag", "Lk", "Info", "Align"); + + for (auto i = 0u; i < sections.size(); ++i) { + auto §ion = sections[i]; + auto name = shStrTab + section.header.name; + auto type = formatSHT(section.header.type); + auto flags = formatSHF(section.header.flags); + + fmt::print( + " [{:>2}] {:<20} {:<16} {:08X} {:06X} {:06X} {:02X} {:>4} {:>2} {:>4} {:>5}\n", + i, + name, + type, + static_cast(section.header.addr), + section.header.offset, + section.header.size, + section.header.entsize, + flags, + section.header.link, + section.header.info, + section.header.addralign); + } +} + +static void +printFileInfo(Section §ion) +{ + auto &info = *reinterpret_cast(section.data.data()); + auto filename = section.data.data() + info.filename; + + fmt::print(" {:<20} = 0x{:08X}\n", "version", info.version); + fmt::print(" {:<20} = 0x{:08X}\n", "textSize", info.textSize); + fmt::print(" {:<20} = 0x{:X}\n", "textAlign", info.textAlign); + fmt::print(" {:<20} = 0x{:08X}\n", "dataSize", info.dataSize); + fmt::print(" {:<20} = 0x{:X}\n", "dataAlign", info.dataAlign); + fmt::print(" {:<20} = 0x{:08X}\n", "loadSize", info.loadSize); + fmt::print(" {:<20} = 0x{:X}\n", "loadAlign", info.loadAlign); + fmt::print(" {:<20} = 0x{:X}\n", "tempSize", info.tempSize); + fmt::print(" {:<20} = 0x{:X}\n", "trampAdjust", info.trampAdjust); + fmt::print(" {:<20} = 0x{:X}\n", "trampAddition", info.trampAddition); + fmt::print(" {:<20} = 0x{:08X}\n", "sdaBase", info.sdaBase); + fmt::print(" {:<20} = 0x{:08X}\n", "sda2Base", info.sda2Base); + fmt::print(" {:<20} = 0x{:08X}\n", "stackSize", info.stackSize); + fmt::print(" {:<20} = 0x{:08X}\n", "heapSize", info.heapSize); + + if (info.filename) { + fmt::print(" {:<20} = {}\n", "filename", filename); + } else { + fmt::print(" {:<20} = 0\n", "filename"); + } + + fmt::print(" {:<20} = 0x{:X}\n", "flags", info.flags); + fmt::print(" {:<20} = 0x{:08X}\n", "minSdkVersion", info.minVersion); + fmt::print(" {:<20} = {}\n", "compressionLevel", info.compressionLevel); + fmt::print(" {:<20} = 0x{:X}\n", "fileInfoPad", info.fileInfoPad); + fmt::print(" {:<20} = 0x{:X}\n", "sdkVersion", info.cafeSdkVersion); + fmt::print(" {:<20} = 0x{:X}\n", "sdkRevision", info.cafeSdkRevision); + fmt::print(" {:<20} = 0x{:X}\n", "tlsModuleIndex", info.tlsModuleIndex); + fmt::print(" {:<20} = 0x{:X}\n", "tlsAlignShift", info.tlsAlignShift); + fmt::print(" {:<20} = 0x{:X}\n", "runtimeFileInfoSize", info.runtimeFileInfoSize); + + if (info.tagOffset) { + const char *tags = section.data.data() + info.tagOffset; + fmt::print(" Tags:\n"); + + while (*tags) { + auto key = tags; + tags += strlen(tags) + 1; + auto value = tags; + tags += strlen(tags) + 1; + + fmt::print(" \"{}\" = \"{}\"\n", key, value); + } + } +} + +static std::string +formatRelType(uint32_t type) +{ + switch (type) { + case elf::R_PPC_NONE: + return "NONE"; + case elf::R_PPC_ADDR32: + return "ADDR32"; + case elf::R_PPC_ADDR16_LO: + return "ADDR16_LO"; + case elf::R_PPC_ADDR16_HI: + return "ADDR16_HI"; + case elf::R_PPC_ADDR16_HA: + return "ADDR16_HA"; + case elf::R_PPC_REL24: + return "REL24"; + case elf::R_PPC_REL14: + return "REL14"; + case elf::R_PPC_DTPMOD32: + return "DTPMOD32"; + case elf::R_PPC_DTPREL32: + return "DTPREL32"; + case elf::R_PPC_EMB_SDA21: + return "EMB_SDA21"; + case elf::R_PPC_EMB_RELSDA: + return "EMB_RELSDA"; + case elf::R_PPC_DIAB_SDA21_LO: + return "DIAB_SDA21_LO"; + case elf::R_PPC_DIAB_SDA21_HI: + return "DIAB_SDA21_HI"; + case elf::R_PPC_DIAB_SDA21_HA: + return "DIAB_SDA21_HA"; + case elf::R_PPC_DIAB_RELSDA_LO: + return "DIAB_RELSDA_LO"; + case elf::R_PPC_DIAB_RELSDA_HI: + return "DIAB_RELSDA_HI"; + case elf::R_PPC_DIAB_RELSDA_HA: + return "DIAB_RELSDA_HA"; + case elf::R_PPC_GHS_REL16_HA: + return "GHS_REL16_HA"; + case elf::R_PPC_GHS_REL16_HI: + return "GHS_REL16_HI"; + case elf::R_PPC_GHS_REL16_LO: + return "GHS_REL16_LO"; + default: + return fmt::format("{}", type); + } +} + +static std::string +formatSymType(uint32_t type) +{ + switch (type) { + case elf::STT_NOTYPE: + return "NOTYPE"; + case elf::STT_OBJECT: + return "OBJECT"; + case elf::STT_FUNC: + return "FUNC"; + case elf::STT_SECTION: + return "SECTION"; + case elf::STT_FILE: + return "FILE"; + case elf::STT_COMMON: + return "COMMON"; + case elf::STT_TLS: + return "TLS"; + case elf::STT_LOOS: + return "LOOS"; + case elf::STT_HIOS: + return "HIOS"; + case elf::STT_GNU_IFUNC: + return "GNU_IFUNC"; + default: + return fmt::format("{}", type); + } +} + +static std::string +formatSymBinding(uint32_t type) +{ + switch (type) { + case elf::STB_LOCAL: + return "LOCAL"; + case elf::STB_GLOBAL: + return "GLOBAL"; + case elf::STB_WEAK: + return "WEAK"; + case elf::STB_GNU_UNIQUE: + return "UNIQUE"; + default: + return fmt::format("{}", type); + } +} + +static std::string +formatSymShndx(uint32_t type) +{ + switch (type) { + case elf::SHN_UNDEF: + return "UND"; + case elf::SHN_ABS: + return "ABS"; + case elf::SHN_COMMON: + return "CMN"; + case elf::SHN_XINDEX: + return "UND"; + default: + return fmt::format("{}", type); + } +} + +static void +printRela(std::vector
§ions, + const char *shStrTab, + Section §ion) +{ + fmt::print( + " {:<8} {:<8} {:<16} {:<8} {}\n", "Offset", "Info", "Type", "Value", "Name + Addend"); + + auto &symSec = sections[section.header.link]; + auto symbols = reinterpret_cast(symSec.data.data()); + auto &symStrTab = sections[symSec.header.link]; + + auto relas = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Rela); + + for (auto i = 0u; i < count; ++i) { + auto &rela = relas[i]; + + auto index = rela.info >> 8; + auto type = rela.info & 0xff; + auto typeName = formatRelType(type); + + auto symbol = symbols[index]; + auto name = reinterpret_cast(symStrTab.data.data()) + symbol.name; + + fmt::print( + " {:08X} {:08X} {:<16} {:08X} {} + {:X}\n", + rela.offset, + rela.info, + typeName, + symbol.value, + name, + rela.addend); + } +} + +static void +printSymTab(std::vector
§ions, + Section §ion) +{ + auto strTab = reinterpret_cast(sections[section.header.link].data.data()); + + fmt::print( + " {:<4} {:<8} {:<6} {:<8} {:<8} {:<3} {}\n", + "Num", "Value", "Size", "Type", "Bind", "Ndx", "Name"); + + auto id = 0u; + auto symbols = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Symbol); + + for (auto i = 0u; i < count; ++i) { + auto &symbol = symbols[i]; + + auto name = strTab + symbol.name; + auto binding = symbol.info >> 4; + auto type = symbol.info & 0xf; + auto typeName = formatSymType(type); + auto bindingName = formatSymBinding(binding); + auto ndx = formatSymShndx(symbol.shndx); + + fmt::print( + " {:>4} {:08X} {:>6} {:<8} {:<8} {:>3} {}\n", + id, symbol.value, symbol.size, typeName, bindingName, ndx, name); + + ++id; + } +} + +static void +printRplImports(std::vector
§ions, + uint32_t index, + Section §ion) +{ + auto import = reinterpret_cast(section.data.data()); + fmt::print(" {:<20} = {}\n", "name", import->name); + fmt::print(" {:<20} = 0x{:08X}\n", "signature", import->signature); + fmt::print(" {:<20} = {}\n", "count", import->count); + + if (import->count) { + for (auto &symSection : sections) { + if (symSection.header.type != elf::SHT_SYMTAB) { + continue; + } + + auto symbols = reinterpret_cast(symSection.data.data()); + auto count = symSection.data.size() / sizeof(elf::Symbol); + auto strTab = reinterpret_cast(sections[symSection.header.link].data.data()); + + for (auto i = 0u; i < count; ++i) { + auto &symbol = symbols[i]; + auto type = symbol.info & 0xf; + + if (symbol.shndx == index && + (type == elf::STT_FUNC || type == elf::STT_OBJECT)) { + fmt::print(" {}\n", strTab + symbol.name); + } + } + } + } +} + +static void +printRplCrcs(std::vector
§ions, + const char *shStrTab, + Section §ion) +{ + auto crcs = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::RplCrc); + + for (auto i = 0u; i < count; ++i) { + auto name = shStrTab + sections[i].header.name; + fmt::print(" [{:>2}] 0x{:08X} {}\n", i, static_cast(crcs[i].crc), name); + } +} + +static void +printRplExports(Section §ion) +{ + auto exports = reinterpret_cast(section.data.data()); + auto strTab = section.data.data(); + fmt::print(" {:<20} = 0x{:08X}\n", "signature", exports->signature); + fmt::print(" {:<20} = {}\n", "count", exports->count); + + for (auto i = 0u; i < exports->count; ++i) { + // TLS exports have the high bit set in name for some unknown reason... + auto name = strTab + (exports->exports[i].name & 0x7FFFFFFF); + auto value = exports->exports[i].value; + + fmt::print(" 0x{:08X} {}\n", static_cast(value), name); + } +} + +bool readSection(std::ifstream &fh, + elf::SectionHeader &header, + std::vector &data) +{ + // Read section header + fh.read(reinterpret_cast(&header), sizeof(elf::SectionHeader)); + + if (header.type == elf::SHT_NOBITS || !header.size) { + return true; + } + + // Read section data + if (header.flags & elf::SHF_DEFLATED) { + auto stream = z_stream {}; + auto ret = Z_OK; + + // Read the original size + uint32_t size = 0; + fh.seekg(header.offset.value()); + fh.read(reinterpret_cast(&size), sizeof(uint32_t)); + size = byte_swap(size); + data.resize(size); + + // Inflate + memset(&stream, 0, sizeof(stream)); + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + ret = inflateInit(&stream); + + if (ret != Z_OK) { + fmt::print("Couldn't decompress .rpx section because inflateInit returned {}\n", ret); + data.clear(); + return false; + } else { + std::vector temp; + temp.resize(header.size-sizeof(uint32_t)); + fh.read(temp.data(), temp.size()); + + stream.avail_in = header.size; + stream.next_in = reinterpret_cast(temp.data()); + stream.avail_out = static_cast(data.size()); + stream.next_out = reinterpret_cast(data.data()); + + ret = inflate(&stream, Z_FINISH); + + if (ret != Z_OK && ret != Z_STREAM_END) { + fmt::print("Couldn't decompress .rpx section because inflate returned {}\n", ret); + data.clear(); + return false; + } + + inflateEnd(&stream); + } + } else { + data.resize(header.size); + fh.seekg(header.offset.value()); + fh.read(data.data(), header.size); + } + + return true; +} + +int main(int argc, char **argv) +{ + excmd::parser parser; + excmd::option_state options; + using excmd::description; + using excmd::value; + + try { + parser.global_options() + .add_option("H,help", + description { "Show help." }) + .add_option("a,all", + description { "Equivalent to: -h -S -s -r -i -x -c -f" }) + .add_option("h,file-header", + description { "Display the ELF file header" }) + .add_option("S,sections", + description { "Display the sections' header" }) + .add_option("s,symbols", + description { "Display the symbol table" }) + .add_option("r,relocs", + description { "Display the relocations" }) + .add_option("i,imports", + description { "Display the RPL imports" }) + .add_option("x,exports", + description { "Display the RPL exports" }) + .add_option("c,crc", + description { "Display the RPL crc" }) + .add_option("f,file-info", + description { "Display the RPL file info" }); + + parser.default_command() + .add_argument("path", + description { "Path to RPL file" }, + value {}); + + options = parser.parse(argc, argv); + } catch (excmd::exception ex) { + std::cout << "Error parsing options: " << ex.what() << std::endl; + return -1; + } + + if (options.empty() || options.has("help") || !options.has("path")) { + fmt::print("{} path\n", argv[0]); + fmt::print("{}\n", parser.format_help(argv[0])); + return 0; + } + + auto all = options.has("all"); + + auto dumpElfHeader = all || options.has("file-header"); + auto dumpSectionSummary = all || options.has("sections"); + auto dumpSectionRela = all || options.has("relocs"); + auto dumpSectionSymtab = all || options.has("symbols"); + auto dumpSectionRplExports = all || options.has("exports"); + auto dumpSectionRplImports = all || options.has("imports"); + auto dumpSectionRplCrcs = all || options.has("crc"); + auto dumpSectionRplFileinfo = all || options.has("file-info"); + auto path = options.get("path"); + + // If no options are set (other than "path"), let's default to a summary + if (options.set_options.size() == 1) { + dumpElfHeader = true; + dumpSectionSummary = true; + dumpSectionRplFileinfo = true; + } + + // Read file + std::ifstream fh { path, std::ifstream::binary }; + + if (!fh.is_open()) { + fmt::print("Could not open {} for reading\n", path); + return -1; + } + + elf::Header header; + fh.read(reinterpret_cast(&header), sizeof(elf::Header)); + + if (header.magic != elf::HeaderMagic) { + fmt::print("Invalid ELF magic header\n"); + return -1; + } + + // Read sections + auto sections = std::vector
{}; + + for (auto i = 0u; i < header.shnum; ++i) { + Section section; + fh.seekg(header.shoff + header.shentsize * i); + + if (!readSection(fh, section.header, section.data)) { + fmt::print("Error reading section {}", i); + return -1; + } + + sections.push_back(section); + } + + // Find strtab + auto shStrTab = reinterpret_cast(sections[header.shstrndx].data.data()); + + // Format shit + if (dumpElfHeader) { + printHeader(header); + } + + if (dumpSectionSummary) { + printSectionSummary(sections, shStrTab); + } + + // Print section data + for (auto i = 0u; i < sections.size(); ++i) { + auto §ion = sections[i]; + auto name = shStrTab + section.header.name; + auto printSectionHeader = [&](){ + fmt::print( + "Section {}: {}, {}, {} bytes\n", + i, formatSHT(section.header.type), name, section.data.size()); + }; + + switch (section.header.type) { + case elf::SHT_NULL: + case elf::SHT_NOBITS: + // Print nothing + break; + case elf::SHT_RELA: + if (!dumpSectionRela) { + continue; + } + + printSectionHeader(); + printRela(sections, shStrTab, section); + break; + case elf::SHT_SYMTAB: + if (!dumpSectionSymtab) { + continue; + } + + printSectionHeader(); + printSymTab(sections, section); + break; + case elf::SHT_STRTAB: + break; + case elf::SHT_PROGBITS: + break; + case elf::SHT_RPL_EXPORTS: + if (!dumpSectionRplExports) { + continue; + } + + printSectionHeader(); + printRplExports(section); + break; + case elf::SHT_RPL_IMPORTS: + if (!dumpSectionRplImports) { + continue; + } + + printSectionHeader(); + printRplImports(sections, i, section); + break; + case elf::SHT_RPL_CRCS: + if (!dumpSectionRplCrcs) { + continue; + } + + printSectionHeader(); + printRplCrcs(sections, shStrTab, section); + break; + case elf::SHT_RPL_FILEINFO: + if (!dumpSectionRplFileinfo) { + continue; + } + + printSectionHeader(); + printFileInfo(section); + break; + } + } + + return 0; +} diff --git a/tools/rplgen/CMakeLists.txt b/tools/rplgen/CMakeLists.txt index 4e4f5bf..3545b7f 100644 --- a/tools/rplgen/CMakeLists.txt +++ b/tools/rplgen/CMakeLists.txt @@ -1,7 +1,15 @@ -add_executable(wut-rplgen rplgen.cpp) -target_include_directories(wut-rplgen PRIVATE +project(rplgen) + +file(GLOB_RECURSE SOURCE_FILES *.cpp) +file(GLOB_RECURSE HEADER_FILES *.h) + +add_executable(rplgen + ${SOURCE_FILES} ${HEADER_FILES}) + +target_include_directories(rplgen PRIVATE ${ZLIB_INCLUDE_DIR}) -target_link_libraries(wut-rplgen + +target_link_libraries(rplgen ${ZLIB_LIBRARIES}) -install(TARGETS wut-rplgen RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") +install(TARGETS rplgen RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/udplogserver/CMakeLists.txt b/tools/udplogserver/CMakeLists.txt new file mode 100644 index 0000000..779bcb7 --- /dev/null +++ b/tools/udplogserver/CMakeLists.txt @@ -0,0 +1,14 @@ +project(udplogserver) + +file(GLOB_RECURSE SOURCE_FILES *.cpp) +file(GLOB_RECURSE HEADER_FILES *.h) + +add_executable(udplogserver + ${SOURCE_FILES} + ${HEADER_FILES}) + +if(MSVC) + target_link_libraries(udplogserver PRIVATE ws2_32) +endif() + +install(TARGETS udplogserver RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/udplogserver/main.cpp b/tools/udplogserver/main.cpp new file mode 100644 index 0000000..fdec456 --- /dev/null +++ b/tools/udplogserver/main.cpp @@ -0,0 +1,106 @@ +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#define SERVER_PORT 4405 + +int main(int argc, char **argv) +{ + struct sockaddr_in addr; + unsigned short port = SERVER_PORT; + + if (argc == 2) { + port = atoi(argv[1]); + } + +#ifdef _WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) == SOCKET_ERROR) { + return -1; + } +#endif + + // Create socket + auto fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); +#ifdef _WIN32 + if (fd == INVALID_SOCKET) { + WSACleanup(); +#else + if (fd < 0) { +#endif + return -1; + } + + // Set non blocking +#ifdef _WIN32 + u_long mode = 1; + ioctlsocket(fd, FIONBIO, &mode); +#else + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); +#endif + + // Bind socket + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +#ifdef _WIN32 + closesocket(fd); + WSACleanup(); +#else + close(fd); +#endif + return -1; + } + + // Receive data + char buffer[2048]; + bool running = true; + + while (running) { + fd_set fdsRead; + FD_ZERO(&fdsRead); + FD_SET(fd, &fdsRead); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 10000; + + if (select(fd + 1, &fdsRead, NULL, NULL, &tv) == 1) { + struct sockaddr_in from; +#ifdef _WIN32 + int fromLen = sizeof(from); +#else + socklen_t fromLen = sizeof(from); +#endif + int recvd = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &from, &fromLen); + + if (recvd > 0) { + buffer[recvd] = 0; + std::cout << buffer; + std::cout.flush(); + } + } + } + +#ifdef _WIN32 + closesocket(fd); + WSACleanup(); +#else + close(fd); +#endif + return 0; +}