diff --git a/lib/libnx/include/nx/dynamic_symbol.h b/lib/libnx/include/nx/elf.h similarity index 78% rename from lib/libnx/include/nx/dynamic_symbol.h rename to lib/libnx/include/nx/elf.h index ca1944a..00356d6 100644 --- a/lib/libnx/include/nx/dynamic_symbol.h +++ b/lib/libnx/include/nx/elf.h @@ -3,12 +3,11 @@ namespace nx { - namespace dynsym + namespace elf { enum SpecialSectionIndex { SHN_UNDEF, - SHN_EXPORT = 1, SHN_LORESERVE = 0xFF00, SHN_LOPROC = 0xFF00, SHN_HIPROC = 0xFF1F, @@ -31,10 +30,21 @@ namespace nx STT_LOPROC, STT_HIPROC = 0xF }; + + enum SymbolBinding + { + STB_LOCAL, + STB_GLOBAL, + STB_WEAK, + STB_LOOS = 10, + STB_HIOS = 12, + STB_LOPROC, + STB_HIPROC = 0xF + }; } #pragma pack(push,1) - struct sDynSymbol32Bit + struct sElfSymbol32Bit { le_uint32_t name; le_uint32_t value; @@ -44,7 +54,7 @@ namespace nx le_uint32_t special_section_index; }; - struct sDynSymbol64Bit + struct sElfSymbol64Bit { le_uint32_t name; byte_t info; diff --git a/programs/nstool/source/DynamicSymbolParser.cpp b/programs/nstool/source/DynamicSymbolParser.cpp deleted file mode 100644 index 455173b..0000000 --- a/programs/nstool/source/DynamicSymbolParser.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "DynamicSymbolParser.h" - -DynamicSymbolParser::DynamicSymbolParser() -{ - mDynSymbolList.clear(); -} - -bool DynamicSymbolParser::operator==(const DynamicSymbolParser& other) const -{ - return isEqual(other); -} - -bool DynamicSymbolParser::operator!=(const DynamicSymbolParser& other) const -{ - return !isEqual(other); -} - -void DynamicSymbolParser::operator=(const DynamicSymbolParser& other) -{ - copyFrom(other); -} - -void DynamicSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit) -{ - //printf("DynamicSymbolParser::parseData()"); - size_t dynSymSize = is64Bit ? sizeof(nx::sDynSymbol64Bit) : sizeof(nx::sDynSymbol32Bit); - - sDynSymbol symbol; - for (size_t i = 0; i < dyn_sym_size; i += dynSymSize) - { - //printf("pos %x\n", i); - - uint32_t name_pos; - - if (is64Bit) - { - name_pos = ((nx::sDynSymbol64Bit*)(dyn_sym + i))->name.get(); - symbol.shn_index = (nx::dynsym::SpecialSectionIndex)((nx::sDynSymbol64Bit*)(dyn_sym + i))->special_section_index.get(); - symbol.symbol_type = (nx::dynsym::SymbolType)((((nx::sDynSymbol64Bit*)(dyn_sym + i))->info) & nx::dynsym::STT_HIPROC); - } - else - { - name_pos = ((nx::sDynSymbol64Bit*)(dyn_sym + i))->name.get(); - symbol.shn_index = (nx::dynsym::SpecialSectionIndex)((nx::sDynSymbol32Bit*)(dyn_sym + i))->special_section_index.get(); - symbol.symbol_type = (nx::dynsym::SymbolType)((((nx::sDynSymbol32Bit*)(dyn_sym + i))->info.get()) & nx::dynsym::STT_HIPROC); - } - - for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++); - - //printf("name_pos = 0x%x\n", name_pos); - symbol.name = std::string((char*)&dyn_str[name_pos]); - mDynSymbolList.addElement(symbol); - } - //printf("DynamicSymbolParser::parseData() end\n"); -} - -const fnd::List& DynamicSymbolParser::getDynamicSymbolList() const -{ - return mDynSymbolList; -} - -bool DynamicSymbolParser::isEqual(const DynamicSymbolParser& other) const -{ - return mDynSymbolList == other.mDynSymbolList; -} - -void DynamicSymbolParser::copyFrom(const DynamicSymbolParser& other) -{ - mDynSymbolList = other.mDynSymbolList; -} diff --git a/programs/nstool/source/DynamicSymbolParser.h b/programs/nstool/source/DynamicSymbolParser.h deleted file mode 100644 index 46a77e9..0000000 --- a/programs/nstool/source/DynamicSymbolParser.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include -#include -#include - -class DynamicSymbolParser -{ -public: - struct sDynSymbol - { - nx::dynsym::SpecialSectionIndex shn_index; - nx::dynsym::SymbolType symbol_type; - std::string name; - - void operator=(const sDynSymbol& other) - { - shn_index = other.shn_index; - symbol_type = other.symbol_type; - name = other.name; - } - - bool operator==(const sDynSymbol& other) const - { - return (shn_index == other.shn_index && symbol_type == other.symbol_type && name == other.name); - } - - bool operator!=(const sDynSymbol& other) const - { - return !(*this == other); - } - }; - - DynamicSymbolParser(); - - bool operator==(const DynamicSymbolParser& other) const; - bool operator!=(const DynamicSymbolParser& other) const; - void operator=(const DynamicSymbolParser& other); - - void parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit); - - const fnd::List& getDynamicSymbolList() const; -private: - - // data - fnd::List mDynSymbolList; - - bool isEqual(const DynamicSymbolParser& other) const; - void copyFrom(const DynamicSymbolParser& other); -}; \ No newline at end of file diff --git a/programs/nstool/source/ElfSymbolParser.cpp b/programs/nstool/source/ElfSymbolParser.cpp new file mode 100644 index 0000000..6ef477f --- /dev/null +++ b/programs/nstool/source/ElfSymbolParser.cpp @@ -0,0 +1,72 @@ +#include "ElfSymbolParser.h" + +ElfSymbolParser::ElfSymbolParser() +{ + mSymbolList.clear(); +} + +bool ElfSymbolParser::operator==(const ElfSymbolParser& other) const +{ + return isEqual(other); +} + +bool ElfSymbolParser::operator!=(const ElfSymbolParser& other) const +{ + return !isEqual(other); +} + +void ElfSymbolParser::operator=(const ElfSymbolParser& other) +{ + copyFrom(other); +} + +void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit) +{ + //printf("ElfSymbolParser::parseData()"); + size_t dynSymSize = is64Bit ? sizeof(nx::sElfSymbol64Bit) : sizeof(nx::sElfSymbol32Bit); + + sElfSymbol symbol; + for (size_t i = 0; i < dyn_sym_size; i += dynSymSize) + { + //printf("pos %x\n", i); + + uint32_t name_pos; + + if (is64Bit) + { + name_pos = ((nx::sElfSymbol64Bit*)(dyn_sym + i))->name.get(); + symbol.shn_index = (nx::elf::SpecialSectionIndex)((nx::sElfSymbol64Bit*)(dyn_sym + i))->special_section_index.get(); + symbol.symbol_type = (nx::elf::SymbolType)((((nx::sElfSymbol64Bit*)(dyn_sym + i))->info) & nx::elf::STT_HIPROC); + symbol.symbol_binding = (nx::elf::SymbolBinding)(((((nx::sElfSymbol64Bit*)(dyn_sym + i))->info) >> 4) & nx::elf::STB_HIPROC); + } + else + { + name_pos = ((nx::sElfSymbol64Bit*)(dyn_sym + i))->name.get(); + symbol.shn_index = (nx::elf::SpecialSectionIndex)((nx::sElfSymbol32Bit*)(dyn_sym + i))->special_section_index.get(); + symbol.symbol_type = (nx::elf::SymbolType)((((nx::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) & nx::elf::STT_HIPROC); + symbol.symbol_binding = (nx::elf::SymbolBinding)(((((nx::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) >> 4) & nx::elf::STB_HIPROC); + } + + for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++); + + //printf("name_pos = 0x%x\n", name_pos); + symbol.name = std::string((char*)&dyn_str[name_pos]); + mSymbolList.addElement(symbol); + } + //printf("ElfSymbolParser::parseData() end\n"); +} + +const fnd::List& ElfSymbolParser::getSymbolList() const +{ + return mSymbolList; +} + +bool ElfSymbolParser::isEqual(const ElfSymbolParser& other) const +{ + return mSymbolList == other.mSymbolList; +} + +void ElfSymbolParser::copyFrom(const ElfSymbolParser& other) +{ + mSymbolList = other.mSymbolList; +} diff --git a/programs/nstool/source/ElfSymbolParser.h b/programs/nstool/source/ElfSymbolParser.h new file mode 100644 index 0000000..a30a570 --- /dev/null +++ b/programs/nstool/source/ElfSymbolParser.h @@ -0,0 +1,51 @@ +#pragma once +#include +#include +#include + +class ElfSymbolParser +{ +public: + struct sElfSymbol + { + nx::elf::SpecialSectionIndex shn_index; + nx::elf::SymbolType symbol_type; + nx::elf::SymbolBinding symbol_binding; + std::string name; + + void operator=(const sElfSymbol& other) + { + shn_index = other.shn_index; + symbol_type = other.symbol_type; + symbol_binding = other.symbol_binding; + name = other.name; + } + + bool operator==(const sElfSymbol& other) const + { + return (shn_index == other.shn_index && symbol_type == other.symbol_type && symbol_binding == other.symbol_binding && name == other.name); + } + + bool operator!=(const sElfSymbol& other) const + { + return !(*this == other); + } + }; + + ElfSymbolParser(); + + bool operator==(const ElfSymbolParser& other) const; + bool operator!=(const ElfSymbolParser& other) const; + void operator=(const ElfSymbolParser& other); + + void parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit); + + const fnd::List& getSymbolList() const; +private: + + // data + fnd::List mSymbolList; + + bool isEqual(const ElfSymbolParser& other) const; + void copyFrom(const ElfSymbolParser& other); +}; \ No newline at end of file diff --git a/programs/nstool/source/NroProcess.cpp b/programs/nstool/source/NroProcess.cpp index 4a3baa8..0f56c02 100644 --- a/programs/nstool/source/NroProcess.cpp +++ b/programs/nstool/source/NroProcess.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -10,10 +9,7 @@ NroProcess::NroProcess(): mFile(nullptr), mOwnIFile(false), mCliOutputMode(_BIT(OUTPUT_BASIC)), - mVerify(false), - mInstructionType(nx::npdm::INSTR_64BIT), - mListApi(false), - mListSymbols(false) + mVerify(false) { } @@ -34,12 +30,12 @@ void NroProcess::process() importHeader(); importCodeSegments(); - importApiList(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - { displayHeader(); - displayRoMetaData(); - } + + processRoMeta(); + if (mIsHomebrewNro) mAssetProc.process(); } @@ -62,17 +58,17 @@ void NroProcess::setVerifyMode(bool verify) void NroProcess::setInstructionType(nx::npdm::InstructionType type) { - mInstructionType = type; + mRoMeta.setInstructionType(type); } void NroProcess::setListApi(bool listApi) { - mListApi = listApi; + mRoMeta.setListApi(listApi); } void NroProcess::setListSymbols(bool listSymbols) { - mListSymbols = listSymbols; + mRoMeta.setListSymbols(listSymbols); } void NroProcess::setAssetListFs(bool list) @@ -108,8 +104,8 @@ void NroProcess::importHeader() mHdr.importBinary(scratch.getBytes(), scratch.getSize()); + // setup homebrew extension nx::sNroHeader* raw_hdr = (nx::sNroHeader*)scratch.getBytes(); - if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nx::nro::kNroHomebrewSig && mFile->size() > mHdr.getNroSize()) { mIsHomebrewNro = true; @@ -119,7 +115,6 @@ void NroProcess::importHeader() } else mIsHomebrewNro = false; - } void NroProcess::importCodeSegments() @@ -132,38 +127,6 @@ void NroProcess::importCodeSegments() mFile->read(mDataBlob.getBytes(), mHdr.getDataInfo().memory_offset, mDataBlob.getSize()); } -void NroProcess::importApiList() -{ - struct sLayout { size_t offset; size_t size; } api_info, dyn_str, dyn_sym; - - api_info.offset = mHdr.getRoEmbeddedInfo().memory_offset; - api_info.size = mHdr.getRoEmbeddedInfo().size; - dyn_str.offset = mHdr.getRoDynStrInfo().memory_offset; - dyn_str.size = mHdr.getRoDynStrInfo().size; - dyn_sym.offset = mHdr.getRoDynSymInfo().memory_offset; - dyn_sym.size = mHdr.getRoDynSymInfo().size; - - if (api_info.size > 0) - { - std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + api_info.offset, api_info.size)); - std::string api; - - while(std::getline(list_stream, api, (char)0x00)) - { - mApiList.push_back(api); - } - } - else - { - mApiList.clear(); - } - - if (dyn_sym.size > 0) - { - mDynSymbolList.parseData(mRoBlob.getBytes() + dyn_sym.offset, dyn_sym.size, mRoBlob.getBytes() + dyn_str.offset, dyn_str.size, mInstructionType == nx::npdm::INSTR_64BIT); - } -} - void NroProcess::displayHeader() { #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) @@ -203,125 +166,16 @@ void NroProcess::displayHeader() #undef _HEXDUMP_L } -void NroProcess::displayRoMetaData() +void NroProcess::processRoMeta() { - if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) + if (mRoBlob.getSize()) { - printf("[SDK API List]\n"); - for (size_t i = 0; i < mApiList.size(); i++) - { - printf(" API %d:\n", (int)i); - printf(" Type: %s\n", getApiTypeStr(mApiList[i].getApiType())); - printf(" Vender: %s\n", mApiList[i].getVenderName().c_str()); - printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); - } + // setup ro metadata + mRoMeta.setApiInfo(mHdr.getRoEmbeddedInfo().memory_offset, mHdr.getRoEmbeddedInfo().size); + mRoMeta.setDynSym(mHdr.getRoDynSymInfo().memory_offset, mHdr.getRoDynSymInfo().size); + mRoMeta.setDynStr(mHdr.getRoDynStrInfo().memory_offset, mHdr.getRoDynStrInfo().size); + mRoMeta.setRoBinary(mRoBlob); + mRoMeta.setCliOutputMode(mCliOutputMode); + mRoMeta.process(); } - if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) - { - printf("[Symbol List]\n"); - for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++) - { - const DynamicSymbolParser::sDynSymbol& symbol = mDynSymbolList.getDynamicSymbolList()[i]; - printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type)); - } - } -} - -const char* NroProcess::getApiTypeStr(SdkApiString::ApiType type) const -{ - const char* str; - switch (type) - { - case (SdkApiString::API_MIDDLEWARE): - str = "Middleware"; - break; - case (SdkApiString::API_DEBUG): - str = "Debug"; - break; - case (SdkApiString::API_PRIVATE): - str = "Private"; - break; - case (SdkApiString::API_SDK_VERSION): - str = "SDK Version"; - break; - default: - str = "UNKNOWN"; - break; - } - return str; -} - -const char* NroProcess::getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const -{ - const char* str; - switch (shn_index) - { - case (nx::dynsym::SHN_UNDEF): - str = "UNDEF"; - break; - case (nx::dynsym::SHN_EXPORT): - str = "EXPORT"; - break; - case (nx::dynsym::SHN_LOPROC): - str = "LOPROC"; - break; - case (nx::dynsym::SHN_HIPROC): - str = "HIPROC"; - break; - case (nx::dynsym::SHN_LOOS): - str = "LOOS"; - break; - case (nx::dynsym::SHN_HIOS): - str = "HIOS"; - break; - case (nx::dynsym::SHN_ABS): - str = "ABS"; - break; - case (nx::dynsym::SHN_COMMON): - str = "COMMON"; - break; - default: - str = "UNKNOWN"; - break; - } - return str; -} - -const char* NroProcess::getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const -{ - const char* str; - switch (symbol_type) - { - case (nx::dynsym::STT_NOTYPE): - str = "NOTYPE"; - break; - case (nx::dynsym::STT_OBJECT): - str = "OBJECT"; - break; - case (nx::dynsym::STT_FUNC): - str = "FUNC"; - break; - case (nx::dynsym::STT_SECTION): - str = "SECTION"; - break; - case (nx::dynsym::STT_FILE): - str = "FILE"; - break; - case (nx::dynsym::STT_LOOS): - str = "LOOS"; - break; - case (nx::dynsym::STT_HIOS): - str = "HIOS"; - break; - case (nx::dynsym::STT_LOPROC): - str = "LOPROC"; - break; - case (nx::dynsym::STT_HIPROC): - str = "HIPROC"; - break; - default: - str = "UNKNOWN"; - break; - } - return str; } \ No newline at end of file diff --git a/programs/nstool/source/NroProcess.h b/programs/nstool/source/NroProcess.h index 0c123e6..5c68a21 100644 --- a/programs/nstool/source/NroProcess.h +++ b/programs/nstool/source/NroProcess.h @@ -8,8 +8,7 @@ #include "AssetProcess.h" #include "nstool.h" -#include "SdkApiString.h" -#include "DynamicSymbolParser.h" +#include "RoMetadataProcess.h" class NroProcess { @@ -40,24 +39,15 @@ private: CliOutputMode mCliOutputMode; bool mVerify; - nx::npdm::InstructionType mInstructionType; - bool mListApi; - bool mListSymbols; nx::NroHeader mHdr; + fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob; + RoMetadataProcess mRoMeta; bool mIsHomebrewNro; AssetProcess mAssetProc; - fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob; - std::vector mApiList; - DynamicSymbolParser mDynSymbolList; void importHeader(); void importCodeSegments(); - void importApiList(); void displayHeader(); - void displayRoMetaData(); - - const char* getApiTypeStr(SdkApiString::ApiType type) const; - const char* getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const; - const char* getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const; + void processRoMeta(); }; \ No newline at end of file diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp index 48d1771..ff8a9b9 100644 --- a/programs/nstool/source/NsoProcess.cpp +++ b/programs/nstool/source/NsoProcess.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -9,10 +8,7 @@ NsoProcess::NsoProcess(): mFile(nullptr), mOwnIFile(false), mCliOutputMode(_BIT(OUTPUT_BASIC)), - mVerify(false), - mInstructionType(nx::npdm::INSTR_64BIT), - mListApi(false), - mListSymbols(false) + mVerify(false) { } @@ -33,12 +29,10 @@ void NsoProcess::process() importHeader(); importCodeSegments(); - importApiList(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - { displayNsoHeader(); - displayRoMetaData(); - } + + processRoMeta(); } void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile) @@ -59,17 +53,17 @@ void NsoProcess::setVerifyMode(bool verify) void NsoProcess::setInstructionType(nx::npdm::InstructionType type) { - mInstructionType = type; + mRoMeta.setInstructionType(type); } void NsoProcess::setListApi(bool listApi) { - mListApi = listApi; + mRoMeta.setListApi(listApi); } void NsoProcess::setListSymbols(bool listSymbols) { - mListSymbols = listSymbols; + mRoMeta.setListSymbols(listSymbols); } void NsoProcess::importHeader() @@ -83,7 +77,7 @@ void NsoProcess::importHeader() scratch.alloc(sizeof(nx::sNsoHeader)); mFile->read(scratch.getBytes(), 0, scratch.getSize()); - mNsoHdr.importBinary(scratch.getBytes(), scratch.getSize()); + mHdr.importBinary(scratch.getBytes(), scratch.getSize()); } void NsoProcess::importCodeSegments() @@ -93,11 +87,11 @@ void NsoProcess::importCodeSegments() crypto::sha::sSha256Hash calc_hash; // process text segment - if (mNsoHdr.getTextSegmentInfo().is_compressed) + if (mHdr.getTextSegmentInfo().is_compressed) { - scratch.alloc(mNsoHdr.getTextSegmentInfo().file_layout.size); - mFile->read(scratch.getBytes(), mNsoHdr.getTextSegmentInfo().file_layout.offset, scratch.getSize()); - mTextBlob.alloc(mNsoHdr.getTextSegmentInfo().memory_layout.size); + scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size); + mFile->read(scratch.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.getSize()); + mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size); compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mTextBlob.getBytes(), (uint32_t)mTextBlob.getSize(), decompressed_len); if (decompressed_len != mTextBlob.getSize()) { @@ -106,24 +100,24 @@ void NsoProcess::importCodeSegments() } else { - mTextBlob.alloc(mNsoHdr.getTextSegmentInfo().file_layout.size); - mFile->read(mTextBlob.getBytes(), mNsoHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.getSize()); + mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size); + mFile->read(mTextBlob.getBytes(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.getSize()); } - if (mNsoHdr.getTextSegmentInfo().is_hashed) + if (mHdr.getTextSegmentInfo().is_hashed) { crypto::sha::Sha256(mTextBlob.getBytes(), mTextBlob.getSize(), calc_hash.bytes); - if (calc_hash != mNsoHdr.getTextSegmentInfo().hash) + if (calc_hash != mHdr.getTextSegmentInfo().hash) { throw fnd::Exception(kModuleName, "NSO text segment failed SHA256 verification"); } } // process ro segment - if (mNsoHdr.getRoSegmentInfo().is_compressed) + if (mHdr.getRoSegmentInfo().is_compressed) { - scratch.alloc(mNsoHdr.getRoSegmentInfo().file_layout.size); - mFile->read(scratch.getBytes(), mNsoHdr.getRoSegmentInfo().file_layout.offset, scratch.getSize()); - mRoBlob.alloc(mNsoHdr.getRoSegmentInfo().memory_layout.size); + scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size); + mFile->read(scratch.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.getSize()); + mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size); compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mRoBlob.getBytes(), (uint32_t)mRoBlob.getSize(), decompressed_len); if (decompressed_len != mRoBlob.getSize()) { @@ -132,24 +126,24 @@ void NsoProcess::importCodeSegments() } else { - mRoBlob.alloc(mNsoHdr.getRoSegmentInfo().file_layout.size); - mFile->read(mRoBlob.getBytes(), mNsoHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.getSize()); + mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size); + mFile->read(mRoBlob.getBytes(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.getSize()); } - if (mNsoHdr.getRoSegmentInfo().is_hashed) + if (mHdr.getRoSegmentInfo().is_hashed) { crypto::sha::Sha256(mRoBlob.getBytes(), mRoBlob.getSize(), calc_hash.bytes); - if (calc_hash != mNsoHdr.getRoSegmentInfo().hash) + if (calc_hash != mHdr.getRoSegmentInfo().hash) { throw fnd::Exception(kModuleName, "NSO ro segment failed SHA256 verification"); } } // process data segment - if (mNsoHdr.getDataSegmentInfo().is_compressed) + if (mHdr.getDataSegmentInfo().is_compressed) { - scratch.alloc(mNsoHdr.getDataSegmentInfo().file_layout.size); - mFile->read(scratch.getBytes(), mNsoHdr.getDataSegmentInfo().file_layout.offset, scratch.getSize()); - mDataBlob.alloc(mNsoHdr.getDataSegmentInfo().memory_layout.size); + scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size); + mFile->read(scratch.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.getSize()); + mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size); compress::lz4::decompressData(scratch.getBytes(), (uint32_t)scratch.getSize(), mDataBlob.getBytes(), (uint32_t)mDataBlob.getSize(), decompressed_len); if (decompressed_len != mDataBlob.getSize()) { @@ -158,239 +152,99 @@ void NsoProcess::importCodeSegments() } else { - mDataBlob.alloc(mNsoHdr.getDataSegmentInfo().file_layout.size); - mFile->read(mDataBlob.getBytes(), mNsoHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.getSize()); + mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size); + mFile->read(mDataBlob.getBytes(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.getSize()); } - if (mNsoHdr.getDataSegmentInfo().is_hashed) + if (mHdr.getDataSegmentInfo().is_hashed) { crypto::sha::Sha256(mDataBlob.getBytes(), mDataBlob.getSize(), calc_hash.bytes); - if (calc_hash != mNsoHdr.getDataSegmentInfo().hash) + if (calc_hash != mHdr.getDataSegmentInfo().hash) { throw fnd::Exception(kModuleName, "NSO data segment failed SHA256 verification"); } } } -void NsoProcess::importApiList() -{ - struct sLayout { size_t offset; size_t size; } api_info, dyn_str, dyn_sym; - - api_info.offset = mNsoHdr.getRoEmbeddedInfo().offset; - api_info.size = mNsoHdr.getRoEmbeddedInfo().size; - dyn_str.offset = mNsoHdr.getRoDynStrInfo().offset; - dyn_str.size = mNsoHdr.getRoDynStrInfo().size; - dyn_sym.offset = mNsoHdr.getRoDynSymInfo().offset; - dyn_sym.size = mNsoHdr.getRoDynSymInfo().size; - - if (api_info.size > 0) - { - std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + api_info.offset, api_info.size)); - std::string api; - - while(std::getline(list_stream, api, (char)0x00)) - { - mApiList.push_back(api); - } - } - else - { - mApiList.clear(); - } - - if (dyn_sym.size > 0) - { - mDynSymbolList.parseData(mRoBlob.getBytes() + dyn_sym.offset, dyn_sym.size, mRoBlob.getBytes() + dyn_str.offset, dyn_str.size, mInstructionType == nx::npdm::INSTR_64BIT); - } -} - void NsoProcess::displayNsoHeader() { #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) printf("[NSO Header]\n"); printf(" ModuleId: "); - _HEXDUMP_L(mNsoHdr.getModuleId().data, nx::nso::kModuleIdSize); + _HEXDUMP_L(mHdr.getModuleId().data, nx::nso::kModuleIdSize); printf("\n"); if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) - printf(" Program Segments:\n"); - printf(" .module_name:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().offset); - printf(" FileSize: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().size); - printf(" .text:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getTextSegmentInfo().file_layout.size, mNsoHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .ro:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getRoSegmentInfo().file_layout.size, mNsoHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .data:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getDataSegmentInfo().file_layout.size, mNsoHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + { + printf(" Program Segments:\n"); + printf(" .module_name:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().offset); + printf(" FileSize: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().size); + printf(" .text:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().file_layout.offset); + printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getTextSegmentInfo().file_layout.size, mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + printf(" .ro:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().file_layout.offset); + printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getRoSegmentInfo().file_layout.size, mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + printf(" .data:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().file_layout.offset); + printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getDataSegmentInfo().file_layout.size, mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + } printf(" Program Sections:\n"); printf(" .text:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.size); - if (mNsoHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.size); + if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" Hash: "); - _HEXDUMP_L(mNsoHdr.getTextSegmentInfo().hash.bytes, 32); + _HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32); printf("\n"); } printf(" .ro:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.size); - if (mNsoHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.size); + if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" Hash: "); - _HEXDUMP_L(mNsoHdr.getRoSegmentInfo().hash.bytes, 32); + _HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32); printf("\n"); } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" .api_info:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().size); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size); printf(" .dynstr:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().size); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size); printf(" .dynsym:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().size); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size); } printf(" .data:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.size); - if (mNsoHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.size); + if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" Hash: "); - _HEXDUMP_L(mNsoHdr.getDataSegmentInfo().hash.bytes, 32); + _HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32); printf("\n"); } printf(" .bss:\n"); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getBssSize()); + printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getBssSize()); #undef _HEXDUMP_L } -void NsoProcess::displayRoMetaData() +void NsoProcess::processRoMeta() { - if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) + if (mRoBlob.getSize()) { - printf("[SDK API List]\n"); - for (size_t i = 0; i < mApiList.size(); i++) - { - printf(" API %d:\n", (int)i); - printf(" Type: %s\n", getApiTypeStr(mApiList[i].getApiType())); - printf(" Vender: %s\n", mApiList[i].getVenderName().c_str()); - printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); - } + // setup ro metadata + mRoMeta.setApiInfo(mHdr.getRoEmbeddedInfo().offset, mHdr.getRoEmbeddedInfo().size); + mRoMeta.setDynSym(mHdr.getRoDynSymInfo().offset, mHdr.getRoDynSymInfo().size); + mRoMeta.setDynStr(mHdr.getRoDynStrInfo().offset, mHdr.getRoDynStrInfo().size); + mRoMeta.setRoBinary(mRoBlob); + mRoMeta.setCliOutputMode(mCliOutputMode); + mRoMeta.process(); } - if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) - { - printf("[Symbol List]\n"); - for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++) - { - const DynamicSymbolParser::sDynSymbol& symbol = mDynSymbolList.getDynamicSymbolList()[i]; - printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type)); - } - } -} - - -const char* NsoProcess::getApiTypeStr(SdkApiString::ApiType type) const -{ - const char* str; - switch (type) - { - case (SdkApiString::API_MIDDLEWARE): - str = "Middleware"; - break; - case (SdkApiString::API_DEBUG): - str = "Debug"; - break; - case (SdkApiString::API_PRIVATE): - str = "Private"; - break; - case (SdkApiString::API_SDK_VERSION): - str = "SDK Version"; - break; - default: - str = "UNKNOWN"; - break; - } - return str; -} - -const char* NsoProcess::getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const -{ - const char* str; - switch (shn_index) - { - case (nx::dynsym::SHN_UNDEF): - str = "UNDEF"; - break; - case (nx::dynsym::SHN_EXPORT): - str = "EXPORT"; - break; - case (nx::dynsym::SHN_LOPROC): - str = "LOPROC"; - break; - case (nx::dynsym::SHN_HIPROC): - str = "HIPROC"; - break; - case (nx::dynsym::SHN_LOOS): - str = "LOOS"; - break; - case (nx::dynsym::SHN_HIOS): - str = "HIOS"; - break; - case (nx::dynsym::SHN_ABS): - str = "ABS"; - break; - case (nx::dynsym::SHN_COMMON): - str = "COMMON"; - break; - default: - str = "UNKNOWN"; - break; - } - return str; -} - -const char* NsoProcess::getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const -{ - const char* str; - switch (symbol_type) - { - case (nx::dynsym::STT_NOTYPE): - str = "NOTYPE"; - break; - case (nx::dynsym::STT_OBJECT): - str = "OBJECT"; - break; - case (nx::dynsym::STT_FUNC): - str = "FUNC"; - break; - case (nx::dynsym::STT_SECTION): - str = "SECTION"; - break; - case (nx::dynsym::STT_FILE): - str = "FILE"; - break; - case (nx::dynsym::STT_LOOS): - str = "LOOS"; - break; - case (nx::dynsym::STT_HIOS): - str = "HIOS"; - break; - case (nx::dynsym::STT_LOPROC): - str = "LOPROC"; - break; - case (nx::dynsym::STT_HIPROC): - str = "HIPROC"; - break; - default: - str = "UNKNOWN"; - break; - } - return str; } \ No newline at end of file diff --git a/programs/nstool/source/NsoProcess.h b/programs/nstool/source/NsoProcess.h index fd4ce7a..5a24ba2 100644 --- a/programs/nstool/source/NsoProcess.h +++ b/programs/nstool/source/NsoProcess.h @@ -7,8 +7,7 @@ #include #include "nstool.h" -#include "SdkApiString.h" -#include "DynamicSymbolParser.h" +#include "RoMetadataProcess.h" class NsoProcess { @@ -37,18 +36,12 @@ private: bool mListApi; bool mListSymbols; - nx::NsoHeader mNsoHdr; + nx::NsoHeader mHdr; fnd::MemoryBlob mTextBlob, mRoBlob, mDataBlob; - std::vector mApiList; - DynamicSymbolParser mDynSymbolList; + RoMetadataProcess mRoMeta; void importHeader(); void importCodeSegments(); - void importApiList(); void displayNsoHeader(); - void displayRoMetaData(); - - const char* getApiTypeStr(SdkApiString::ApiType type) const; - const char* getSectionIndexStr(nx::dynsym::SpecialSectionIndex shn_index) const; - const char* getSymbolTypeStr(nx::dynsym::SymbolType symbol_type) const; + void processRoMeta(); }; \ No newline at end of file diff --git a/programs/nstool/source/RoMetadataProcess.cpp b/programs/nstool/source/RoMetadataProcess.cpp new file mode 100644 index 0000000..ceeb424 --- /dev/null +++ b/programs/nstool/source/RoMetadataProcess.cpp @@ -0,0 +1,255 @@ +#include +#include + +#include "RoMetadataProcess.h" + +RoMetadataProcess::RoMetadataProcess() : + mCliOutputMode(_BIT(OUTPUT_BASIC)), + mInstructionType(nx::npdm::INSTR_64BIT), + mListApi(false), + mListSymbols(false), + mApiInfo(), + mDynSym(), + mDynStr(), + mRoBlob(), + mSdkVerApiList(), + mPublicApiList(), + mDebugApiList(), + mPrivateApiList(), + mSymbolList() +{ + +} + +void RoMetadataProcess::process() +{ + if (mRoBlob.getSize() == 0) + { + throw fnd::Exception(kModuleName, "No ro binary set."); + } + + importApiList(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + displayRoMetaData(); +} + +void RoMetadataProcess::setRoBinary(const fnd::MemoryBlob& bin) +{ + mRoBlob = bin; +} + +void RoMetadataProcess::setApiInfo(size_t offset, size_t size) +{ + mApiInfo.offset = offset; + mApiInfo.size = size; +} +void RoMetadataProcess::setDynSym(size_t offset, size_t size) +{ + mDynSym.offset = offset; + mDynSym.size = size; +} +void RoMetadataProcess::setDynStr(size_t offset, size_t size) +{ + mDynStr.offset = offset; + mDynStr.size = size; +} + +void RoMetadataProcess::setCliOutputMode(CliOutputMode type) +{ + mCliOutputMode = type; +} + +void RoMetadataProcess::setInstructionType(nx::npdm::InstructionType type) +{ + mInstructionType = type; +} + +void RoMetadataProcess::setListApi(bool listApi) +{ + mListApi = listApi; +} + +void RoMetadataProcess::setListSymbols(bool listSymbols) +{ + mListSymbols = listSymbols; +} + +void RoMetadataProcess::importApiList() +{ + if (mApiInfo.size > 0) + { + std::stringstream list_stream(std::string((char*)mRoBlob.getBytes() + mApiInfo.offset, mApiInfo.size)); + std::string api_str; + + while(std::getline(list_stream, api_str, (char)0x00)) + { + SdkApiString api(api_str); + + if (api.getApiType() == SdkApiString::API_SDK_VERSION) + mSdkVerApiList.push_back(api); + else if (api.getApiType() == SdkApiString::API_MIDDLEWARE) + mPublicApiList.push_back(api); + else if (api.getApiType() == SdkApiString::API_DEBUG) + mDebugApiList.push_back(api); + else if (api.getApiType() == SdkApiString::API_PRIVATE) + mPrivateApiList.push_back(api); + } + } + + if (mDynSym.size > 0) + { + mSymbolList.parseData(mRoBlob.getBytes() + mDynSym.offset, mDynSym.size, mRoBlob.getBytes() + mDynStr.offset, mDynStr.size, mInstructionType == nx::npdm::INSTR_64BIT); + } +} + +void RoMetadataProcess::displayRoMetaData() +{ + size_t api_num = mSdkVerApiList.size() + mPublicApiList.size() + mDebugApiList.size() + mPrivateApiList.size(); + + if (api_num > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) + { + printf("[SDK API List]\n"); + if (mSdkVerApiList.size() > 0) + { + printf(" Sdk Revision: %s\n", mSdkVerApiList[0].getModuleName().c_str()); + } + if (mPublicApiList.size() > 0) + { + printf(" Public APIs:\n"); + for (size_t i = 0; i < mPublicApiList.size(); i++) + { + printf(" %s (vender: %s)\n", mPublicApiList[i].getModuleName().c_str(), mPublicApiList[i].getVenderName().c_str()); + } + } + if (mDebugApiList.size() > 0) + { + printf(" Debug APIs:\n"); + for (size_t i = 0; i < mDebugApiList.size(); i++) + { + printf(" %s (vender: %s)\n", mDebugApiList[i].getModuleName().c_str(), mDebugApiList[i].getVenderName().c_str()); + } + } + if (mPrivateApiList.size() > 0) + { + printf(" Private APIs:\n"); + for (size_t i = 0; i < mPrivateApiList.size(); i++) + { + printf(" %s (vender: %s)\n", mPrivateApiList[i].getModuleName().c_str(), mPrivateApiList[i].getVenderName().c_str()); + } + } + } + if (mSymbolList.getSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) + { + printf("[Symbol List]\n"); + for (size_t i = 0; i < mSymbolList.getSymbolList().getSize(); i++) + { + const ElfSymbolParser::sElfSymbol& symbol = mSymbolList.getSymbolList()[i]; + printf(" %s [SHN=%s (%04x)][STT=%s][STB=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type), getSymbolBindingStr(symbol.symbol_binding)); + } + } +} + +const char* RoMetadataProcess::getSectionIndexStr(nx::elf::SpecialSectionIndex shn_index) const +{ + const char* str; + switch (shn_index) + { + case (nx::elf::SHN_UNDEF): + str = "UNDEF"; + break; + case (nx::elf::SHN_LOPROC): + str = "LOPROC"; + break; + case (nx::elf::SHN_HIPROC): + str = "HIPROC"; + break; + case (nx::elf::SHN_LOOS): + str = "LOOS"; + break; + case (nx::elf::SHN_HIOS): + str = "HIOS"; + break; + case (nx::elf::SHN_ABS): + str = "ABS"; + break; + case (nx::elf::SHN_COMMON): + str = "COMMON"; + break; + default: + str = "UNKNOWN"; + break; + } + return str; +} + +const char* RoMetadataProcess::getSymbolTypeStr(nx::elf::SymbolType symbol_type) const +{ + const char* str; + switch (symbol_type) + { + case (nx::elf::STT_NOTYPE): + str = "NOTYPE"; + break; + case (nx::elf::STT_OBJECT): + str = "OBJECT"; + break; + case (nx::elf::STT_FUNC): + str = "FUNC"; + break; + case (nx::elf::STT_SECTION): + str = "SECTION"; + break; + case (nx::elf::STT_FILE): + str = "FILE"; + break; + case (nx::elf::STT_LOOS): + str = "LOOS"; + break; + case (nx::elf::STT_HIOS): + str = "HIOS"; + break; + case (nx::elf::STT_LOPROC): + str = "LOPROC"; + break; + case (nx::elf::STT_HIPROC): + str = "HIPROC"; + break; + default: + str = "UNKNOWN"; + break; + } + return str; +} + +const char* RoMetadataProcess::getSymbolBindingStr(nx::elf::SymbolBinding symbol_binding) const +{ + const char* str; + switch (symbol_binding) + { + case (nx::elf::STB_LOCAL): + str = "LOCAL"; + break; + case (nx::elf::STB_GLOBAL): + str = "GLOBAL"; + break; + case (nx::elf::STB_WEAK): + str = "WEAK"; + break; + case (nx::elf::STB_LOOS): + str = "LOOS"; + break; + case (nx::elf::STB_HIOS): + str = "HIOS"; + break; + case (nx::elf::STB_LOPROC): + str = "LOPROC"; + break; + case (nx::elf::STB_HIPROC): + str = "HIPROC"; + break; + default: + str = "UNKNOWN"; + break; + } + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/RoMetadataProcess.h b/programs/nstool/source/RoMetadataProcess.h new file mode 100644 index 0000000..cf58f7e --- /dev/null +++ b/programs/nstool/source/RoMetadataProcess.h @@ -0,0 +1,62 @@ +#pragma once +#include +#include +#include +#include + +#include + +#include "nstool.h" +#include "SdkApiString.h" +#include "ElfSymbolParser.h" + +class RoMetadataProcess +{ +public: + RoMetadataProcess(); + + void process(); + + void setRoBinary(const fnd::MemoryBlob& bin); + void setApiInfo(size_t offset, size_t size); + void setDynSym(size_t offset, size_t size); + void setDynStr(size_t offset, size_t size); + + void setCliOutputMode(CliOutputMode type); + + void setInstructionType(nx::npdm::InstructionType type); + void setListApi(bool listApi); + void setListSymbols(bool listSymbols); +private: + const std::string kModuleName = "RoMetadataProcess"; + + CliOutputMode mCliOutputMode; + nx::npdm::InstructionType mInstructionType; + bool mListApi; + bool mListSymbols; + + struct sLayout + { + sLayout() : offset(0), size(0) {} + size_t offset; + size_t size; + }; + + sLayout mApiInfo; + sLayout mDynSym; + sLayout mDynStr; + fnd::MemoryBlob mRoBlob; + std::vector mSdkVerApiList; + std::vector mPublicApiList; + std::vector mDebugApiList; + std::vector mPrivateApiList; + + ElfSymbolParser mSymbolList; + + void importApiList(); + void displayRoMetaData(); + + const char* getSectionIndexStr(nx::elf::SpecialSectionIndex shn_index) const; + const char* getSymbolTypeStr(nx::elf::SymbolType symbol_type) const; + const char* getSymbolBindingStr(nx::elf::SymbolBinding symbol_binding) const; +}; \ No newline at end of file