#include "CrossLang.hpp" #include using namespace Tesses::CrossLang; void Ensure(Tesses::Framework::Streams::Stream& strm,uint8_t* buffer, size_t len) { if(strm.ReadBlock(buffer,len) != len) { throw VMException("Could not read " + std::to_string(len) + " byte(s)."); } } uint32_t EnsureInt(Tesses::Framework::Streams::Stream& strm) { uint8_t buff[4]; Ensure(strm,buff,sizeof(buff)); return BitConverter::ToUint32BE(buff[0]); } std::string EnsureString(Tesses::Framework::Streams::Stream& strm) { size_t len = (size_t)EnsureInt(strm); std::string myStr={}; myStr.resize(len); Ensure(strm,(uint8_t*)myStr.data(), len); return myStr; } void DumpFile(std::filesystem::path p) { if(std::filesystem::is_regular_file(p)) { try { std::cout << "File: " << p.string() << std::endl; Tesses::Framework::Streams::FileStream strm(p,"rb"); uint8_t main_header[18]; Ensure(strm,main_header,sizeof(main_header)); if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image."); TVMVersion version(main_header+8); if(version.CompareToRuntime() == 1) { throw VMException("Runtime is too old."); } TVMVersion v2(main_header+13); std::cout << "Version: " << v2.ToString() << std::endl; size_t _len = (size_t)EnsureInt(strm); std::cout << "SectionCount: " << _len << std::endl; std::vector strs; std::unordered_map> funs; std::vector> closures; char table_name[4]; for(size_t i = 0; i < _len; i++) { Ensure(strm,(uint8_t*)table_name,sizeof(table_name)); size_t tableLen = (size_t)EnsureInt(strm); std::string tableName(table_name,4); if(tableName == "STRS") { size_t strsLen = (size_t)EnsureInt(strm); for(size_t j = 0;j < strsLen;j++) { strs.push_back(EnsureString(strm)); } } else if(tableName == "DEPS") { std::string name = strs.at((size_t)EnsureInt(strm)); uint8_t version_bytes[5]; Ensure(strm,version_bytes,sizeof(version_bytes)); TVMVersion depVersion(version_bytes); std::cout << "Dependency: " << name << "-" << depVersion.ToString() << std::endl; } else if(tableName == "NAME") { std::cout << "Name: " << strs.at((size_t)EnsureInt(strm)) << std::endl; } else if(tableName == "CHKS") { size_t chunkCount = (size_t)EnsureInt(strm); for(size_t j = 0; j < chunkCount; j++) { std::vector args; size_t argCount = (size_t)EnsureInt(strm); for(size_t k = 0; k < argCount; k++) { args.push_back(strs.at(EnsureInt(strm))); } auto len = EnsureInt(strm); strm.Seek(len,Tesses::Framework::Streams::SeekOrigin::Current); closures.push_back(args); } } else if(tableName == "FUNS") { size_t funLength = (size_t)EnsureInt(strm); for(size_t j = 0; j < funLength;j++) { std::vector fnParts; uint32_t fnPartsC = EnsureInt(strm); for(uint32_t k = 0; k < fnPartsC; k++) { fnParts.push_back(strs.at(EnsureInt(strm))); } uint32_t fnNumber = EnsureInt(strm); funs[fnNumber] = fnParts; } } else if(tableName == "INFO") { std::cout << "Info: " << strs.at((size_t)EnsureInt(strm)) << std::endl; } else { strm.Seek((int64_t)tableLen,Tesses::Framework::Streams::SeekOrigin::Current); } } for(size_t i = 1; i < closures.size(); i++) { if(funs.contains((uint32_t)i)) { std::cout << "Func: "; auto res = funs[(uint32_t)i]; if(!res.empty()) { std::cout << "/^" << res[0] << "^/ "; } for(size_t i = 1; i < res.size(); i++) { if(i > 1) std::cout << "."; std::cout << res[i]; } } else { std::cout << "Closure: "; } std::cout << "("; bool first=true; for(auto arg : closures[i]) { if(!first) std::cout << ", "; std::cout << arg; if(first) first=false; } std::cout << ")" << std::endl; } std::cout << std::endl; std::cout << "String Table:" << std::endl; for(auto str : strs) { std::cout << EscapeString(str, true) << std::endl; } } catch(std::exception& ex) { std::cout << "Error when reading file \"" << p.string() << "\" " << ex.what() << std::endl; } } else { std::cout << "CrossVM file \"" << p.string() << "\" does not exist." << std::endl; } } int main(int argc, char** argv) { for(int i = 1; i < argc; i++) { DumpFile(argv[i]); } }