diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 0848c6d..17a1a7e 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -10,9 +10,11 @@
"/usr/include",
"${workspaceRoot}",
"${workspaceRoot}/lib/libcrypto/include",
+ "${workspaceRoot}/lib/libcompress/include",
"${workspaceRoot}/lib/libes/include",
"${workspaceRoot}/lib/libfnd/include",
- "${workspaceRoot}/lib/libnx/include"
+ "${workspaceRoot}/lib/libnx/include",
+ "${workspaceRoot}/lib/libnx-hb/include"
],
"defines": [],
"intelliSenseMode": "clang-x64",
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/lib/libnx/nx.vcxproj b/lib/libnx/nx.vcxproj
index 832c709..c8becaa 100644
--- a/lib/libnx/nx.vcxproj
+++ b/lib/libnx/nx.vcxproj
@@ -28,7 +28,7 @@
-
+
diff --git a/lib/libnx/nx.vcxproj.filters b/lib/libnx/nx.vcxproj.filters
index 7ee9e40..065a177 100644
--- a/lib/libnx/nx.vcxproj.filters
+++ b/lib/libnx/nx.vcxproj.filters
@@ -162,9 +162,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -186,6 +183,9 @@
Header Files
+
+ Header Files
+
diff --git a/programs/nstool/nstool.vcxproj b/programs/nstool/nstool.vcxproj
index 8d63583..35b393f 100644
--- a/programs/nstool/nstool.vcxproj
+++ b/programs/nstool/nstool.vcxproj
@@ -171,7 +171,7 @@
-
+
@@ -182,6 +182,7 @@
+
@@ -192,7 +193,7 @@
-
+
@@ -203,6 +204,7 @@
+
diff --git a/programs/nstool/nstool.vcxproj.filters b/programs/nstool/nstool.vcxproj.filters
index a7c9d96..4d94f58 100644
--- a/programs/nstool/nstool.vcxproj.filters
+++ b/programs/nstool/nstool.vcxproj.filters
@@ -57,9 +57,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -72,6 +69,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
@@ -113,9 +116,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -128,6 +128,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
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