diff --git a/INSTALL/INSTALL.vcxproj b/INSTALL/INSTALL.vcxproj
index adff494..46039ae 100644
--- a/INSTALL/INSTALL.vcxproj
+++ b/INSTALL/INSTALL.vcxproj
@@ -127,12 +127,12 @@
call %(identity) "$(OutDir)" "$(Configuration)" "$(SolutionDir)"
call %(identity) "$(OutDir)" "$(Configuration)" "$(SolutionDir)"
call %(identity) "$(OutDir)" "$(Configuration)" "$(SolutionDir)"
- $(SolutionDir)..\bdsx\bedrock_server\ChakraCore.dll;$(SolutionDir)..\bdsx\bedrock_server\Chakra.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.pdb;%(Outputs)
- $(SolutionDir)..\bdsx\bedrock_server\ChakraCore.dll;$(SolutionDir)..\bdsx\bedrock_server\Chakra.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.pdb;%(Outputs)
- $(SolutionDir)..\bdsx\bedrock_server\ChakraCore.dll;$(SolutionDir)..\bdsx\bedrock_server\Chakra.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.pdb;%(Outputs)
- $(OutDir)VCRUNTIME140_1.dll;$(OutDir)VCRUNTIME140_1.pdb;$(OutDir)ChakraCore.dll
- $(OutDir)VCRUNTIME140_1.dll;$(OutDir)VCRUNTIME140_1.pdb;$(OutDir)ChakraCore.dll
- $(OutDir)VCRUNTIME140_1.dll;$(OutDir)VCRUNTIME140_1.pdb;$(OutDir)ChakraCore.dll
+ $(SolutionDir)..\bdsx\bedrock_server\ChakraCore.dll;$(SolutionDir)..\bdsx\bedrock_server\Chakra.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.pdb;$(SolutionDir)..\bdsx\bedrock_server\pdbcachegen.exe;%(Outputs)
+ $(SolutionDir)..\bdsx\bedrock_server\ChakraCore.dll;$(SolutionDir)..\bdsx\bedrock_server\Chakra.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.pdb;$(SolutionDir)..\bdsx\bedrock_server\pdbcachegen.exe;%(Outputs)
+ $(SolutionDir)..\bdsx\bedrock_server\ChakraCore.dll;$(SolutionDir)..\bdsx\bedrock_server\Chakra.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.dll;$(SolutionDir)..\bdsx\bedrock_server\VCRUNTIME140_1.pdb;$(SolutionDir)..\bdsx\bedrock_server\pdbcachegen.exe;%(Outputs)
+ $(OutDir)VCRUNTIME140_1.dll;$(OutDir)VCRUNTIME140_1.pdb;$(OutDir)ChakraCore.dll;$(OutDir)pdbcachegen.exe
+ $(OutDir)VCRUNTIME140_1.dll;$(OutDir)VCRUNTIME140_1.pdb;$(OutDir)ChakraCore.dll;$(OutDir)pdbcachegen.exe
+ $(OutDir)VCRUNTIME140_1.dll;$(OutDir)VCRUNTIME140_1.pdb;$(OutDir)ChakraCore.dll;$(OutDir)pdbcachegen.exe
@@ -142,6 +142,9 @@
{77e07fd4-ed4b-4aaf-8b7a-d5751a742203}
+
+ {0db97edf-3343-4575-af19-0ef056d395b2}
+
diff --git a/INSTALL/install.bat b/INSTALL/install.bat
index 74e99ba..b075eb9 100644
--- a/INSTALL/install.bat
+++ b/INSTALL/install.bat
@@ -3,13 +3,19 @@ set config=%~2
set solutiondir=%~3
call "..\bdsx\version.bat"
+set /p BDS_VERSION=<"../../bdsx/bdsx/version-bds.json"
+set BDS_VERSION=%BDS_VERSION:"=%
if "%config%" == "Debug" (
set _debug=_debug
set d=d
)
+
call :copydll "%solutiondir%..\bdsx\bedrock_server"
-if "%config%" == "Release" call :zip
+if "%config%" == "Release" (
+ call :copydll "%solutiondir%release\bdsx-core-%BDSX_CORE_VERSION%"
+ call :zip "%solutiondir%release\bdsx-core-%BDSX_CORE_VERSION%"
+)
goto :eof
:copydll
@@ -18,11 +24,11 @@ copy "%outdir%Chakra.dll" "%~1\Chakra.dll"
copy "%outdir%VCRUNTIME140_1.dll" "%~1\VCRUNTIME140_1.dll"
copy "%outdir%VCRUNTIME140_1.pdb" "%~1\VCRUNTIME140_1.pdb"
copy "%outdir%ChakraCore.dll" "%~1\ChakraCore.dll"
+copy "%outdir%pdbcachegen.exe" "%~1\pdbcachegen.exe"
EXIT /B 0
:zip
-call :copydll "%solutiondir%release\bdsx-core-%BDSX_CORE_VERSION%"
echo Zipping...
-if exist "%solutiondir%release\bdsx-core-%BDSX_CORE_VERSION%.zip" del "%solutiondir%release\bdsx-core-%BDSX_CORE_VERSION%.zip"
-call zip "%solutiondir%release\bdsx-core-%BDSX_CORE_VERSION%" "%solutiondir%release\bdsx-core-%BDSX_CORE_VERSION%.zip"
+if exist "%~1.zip" del "%~1.zip"
+call zip "%~1" "%~1.zip"
EXIT /B 0
\ No newline at end of file
diff --git a/bdsx-core.sln b/bdsx-core.sln
index 900ad46..8f89b9c 100644
--- a/bdsx-core.sln
+++ b/bdsx-core.sln
@@ -38,6 +38,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "INSTALL", "INSTALL\INSTALL.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chakra2chakracore", "chakra2chakracore\chakra2chakracore.vcxproj", "{77E07FD4-ED4B-4AAF-8B7A-D5751A742203}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pdbcachegen", "pdbcachegen\pdbcachegen.vcxproj", "{0DB97EDF-3343-4575-AF19-0EF056D395B2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -123,6 +125,12 @@ Global
{77E07FD4-ED4B-4AAF-8B7A-D5751A742203}.Release|x64.Build.0 = Release|x64
{77E07FD4-ED4B-4AAF-8B7A-D5751A742203}.ReleaseTest|x64.ActiveCfg = Release|x64
{77E07FD4-ED4B-4AAF-8B7A-D5751A742203}.ReleaseTest|x64.Build.0 = Release|x64
+ {0DB97EDF-3343-4575-AF19-0EF056D395B2}.Debug|x64.ActiveCfg = Debug|x64
+ {0DB97EDF-3343-4575-AF19-0EF056D395B2}.Debug|x64.Build.0 = Debug|x64
+ {0DB97EDF-3343-4575-AF19-0EF056D395B2}.Release|x64.ActiveCfg = Release|x64
+ {0DB97EDF-3343-4575-AF19-0EF056D395B2}.Release|x64.Build.0 = Release|x64
+ {0DB97EDF-3343-4575-AF19-0EF056D395B2}.ReleaseTest|x64.ActiveCfg = Release|x64
+ {0DB97EDF-3343-4575-AF19-0EF056D395B2}.ReleaseTest|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/bdsx/cachedpdb.cpp b/bdsx/cachedpdb.cpp
index dacb8c8..3afaab3 100644
--- a/bdsx/cachedpdb.cpp
+++ b/bdsx/cachedpdb.cpp
@@ -13,839 +13,15 @@
using namespace kr;
-CachedPdb g_pdb;
-BText<32> g_md5;
-
-kr::BText16 CachedPdb::predefinedForCore;
-
-namespace
-{
- uint32_t getSelIndex(Text16 *text) noexcept
- {
- const char16* namepos = text->find_r(u'#');
- if (namepos != nullptr)
- {
- uint32_t value = text->subarr(namepos + 1).to_uint();
- text->cut_self(namepos);
- return value;
- }
- return 0;
- }
- void* getPointer(const JsValue& value) noexcept
- {
- VoidPointer* ptr = value.getNativeObject();
- if (ptr == nullptr) return nullptr;
- return ptr->getAddressRaw();
- }
- ATTR_NORETURN void throwAsJsException(FunctionError& err) throws(JsException)
- {
- TSZ16 tsz;
- tsz << (AnsiToUtf16)(Text)err.getFunctionName() << u": failed, ";
- err.getMessageTo(&tsz);
- tsz << u"(0x" << hexf(err.getErrorCode(), 8) << u")\n";
- throw JsException(tsz);
- }
-
- CriticalSection s_lock;
-
- enum class CacheState
- {
- Found,
- New,
- NotMatched
- };
- struct SymbolMaskInfo
- {
- uint32_t counter;
- uint32_t mask;
- };
-
- struct SymbolCache
- {
- byte* base;
- Keep> fos;
- Keep file;
- bool endWithLine = true;
-
- SymbolCache(pcstr16 filepath) noexcept
- :fos(nullptr)
- {
- base = (byte*)GetModuleHandleW(nullptr);
- if (filepath != nullptr)
- {
- try
- {
- file = File::openRW(filepath);
- }
- catch (Error&)
- {
- }
- }
- }
-
- void startWriting() noexcept
- {
- if (file != nullptr && fos == nullptr) fos = _new io::FOStream(file);
- }
-
- CacheState checkMd5(io::FIStream* fis, bool overwrite) noexcept
- {
- try
- {
- auto md5 = fis->readLine();
- if (md5.first.empty()) {
- file->toBegin();
- file->truncate();
- throw EofException();
- }
- if (md5.first != g_md5)
- {
- if (!overwrite) {
- cerr << "[BDSX] MD5 Hash does not Matched" << endl;
- cerr << "[BDSX] pdb.ini MD5 = " << md5.first << endl;
- cerr << "[BDSX] current MD5 = " << g_md5 << endl;
- cerr << "[BDSX] Please use 'npm i' to update it" << endl;
- return CacheState::NotMatched;
- }
- file->toBegin();
- file->truncate();
- throw EofException();
- }
- if (!md5.second)
- {
- endWithLine = false;
- }
- }
- catch (EofException&)
- {
- startWriting();
- *fos << g_md5 << "\r\n";
- return CacheState::New;
- }
- return CacheState::Found;
- }
- };
- struct SymbolMap:SymbolCache
- {
- Map targets;
-
- SymbolMap(pcstr16 filepath) noexcept
- :SymbolCache(filepath)
- {
- }
-
- void put(Text16 tx) noexcept
- {
- const char16* namepos = tx.find_r(u'#');
- uint32_t selbit = 1U << getSelIndex(&tx);
-
- auto res = targets.insert(tx, { 0, selbit });
- if (!res.second)
- {
- res.first->second.mask |= selbit;
- }
- }
-
- bool del(Text16 name) noexcept
- {
- uint32_t selbit = 1U << getSelIndex(&name);
- auto iter = targets.find(name);
- if (iter == targets.end()) return false;
-
- if ((iter->second.mask & selbit) == 0) return false;
- iter->second.mask &= ~selbit;
- if (iter->second.mask == 0)
- {
- targets.erase(iter);
- }
- return true;
- }
-
- bool test(Text16 name, void* address, TText16* line, Text16* nameWithIndex) noexcept
- {
- auto iter = targets.find(name);
- if (iter == targets.end()) return false;
- SymbolMaskInfo& selects = iter->second;
- uint32_t bit = (1 << selects.counter);
- uint32_t index = selects.counter++;
-
- if ((selects.mask & bit) == 0) return false;
- selects.mask &= ~bit;
- if (selects.mask == 0)
- {
- targets.erase(iter);
- }
-
- *line << name;
- if (index != 0)
- {
- *line << u'#' << index;
- }
- *nameWithIndex = *line;
-
- *line << u" = 0x" << hexf((byte*)address - base);
- if (fos != nullptr) *fos << (Utf16ToUtf8)*line << "\r\n";
- return true;
- }
-
- bool empty() noexcept
- {
- return targets.empty();
- }
-
- uintptr_t readOffset(io::FIStream* fis, TText16* name) throws(EofException)
- {
- for (;;)
- {
- auto line = fis->readLine();
- if (!line.second) endWithLine = false;
- pcstr equal = line.first.find_r('=');
- if (equal == nullptr) continue;
-
- *name = (Utf8ToUtf16)line.first.cut(equal).trim();
- if (!del(*name)) {
- name->truncate();
- continue;
- }
-
- Text value = line.first.subarr(equal + 1).trim();
-
- if (value.startsWith("0x"))
- {
- return value.subarr(2).to_uintp(16);
- }
- else
- {
- return value.to_uintp();
- }
- }
- }
-
- };
-
- struct __StreamWithPad
- {
- void* padForAntiCorruptingByVisualStudioBug; // https://developercommunity2.visualstudio.com/t/An-invalid-handle-was-specified-a-weird/1322604
- io::FIStream* const fis;
-
- __StreamWithPad(io::FIStream* fis) noexcept
- :fis(fis)
- {
- }
- ~__StreamWithPad() noexcept
- {
- delete fis;
- }
- operator io::FIStream*() noexcept
- {
- return fis;
- }
- io::FIStream* operator ->() noexcept
- {
- return fis;
- }
- };
-
- struct DeferField
- {
- bool inited = false;
- JsPropertyId typeIndex;
- JsPropertyId index;
- JsPropertyId size;
- JsPropertyId flags;
- JsPropertyId value;
- JsPropertyId address;
- JsPropertyId _register;
- JsPropertyId scope;
- JsPropertyId tag;
- JsPropertyId name;
- };
- Deferred s_field(JsRuntime::initpack);
-}
-
-CachedPdb::CachedPdb() noexcept
-{
-}
-CachedPdb::~CachedPdb() noexcept
-{
-}
-
-void CachedPdb::close() noexcept
-{
- if (s_lock.tryEnter())
- {
- m_pdb.close();
- s_lock.leave();
- }
-}
-int CachedPdb::setOptions(int options) throws(JsException)
-{
- if (!s_lock.tryEnter()) throw JsException(u"BUSY. It's using by async task");
- int out = PdbReader::setOptions(options);
- s_lock.leave();
- return out;
-}
-int CachedPdb::getOptions() throws(JsException)
-{
- if (!s_lock.tryEnter()) throw JsException(u"BUSY. It's using by async task");
- int out = PdbReader::getOptions();
- s_lock.leave();
- return out;
-}
-
-TText16 CachedPdb::undecorate(Text16 text, int flags) noexcept {
- TText16 undecorated;
- undecorated << PdbReader::undecorate(text.data(), flags);
- return move(undecorated);
-}
-
-autoptr CachedPdb::getProcAddress(pcstr16 predefined, pcstr name) noexcept
-{
- Text txname = (Text)name;
- CsLock __lock = s_lock;
-
- SymbolCache targets(predefined);
- void* foundptr = nullptr;
-
- if (predefined != nullptr)
- {
- try
- {
- Must> fis = _new io::FIStream((File*)targets.file);
- CacheState state = targets.checkMd5(fis, false);
- if (state == CacheState::New)
- {
- cout << "[BDSX] Generating " << (Utf16ToAnsi)(Text16)predefined << endl;
- }
- else if (state == CacheState::NotMatched)
- {
- return nullptr;
- }
- else
- {
- TText16 name;
- bool endWithLine = true;
- for (;;)
- {
- auto line = fis->readLine();
- if (!line.second) endWithLine = false;
- pcstr equal = line.first.find_r('=');
- if (equal == nullptr) continue;
- if (line.first.cut(equal).trim() != txname) continue;
- Text value = line.first.subarr(equal + 1).trim();
-
- if (value.startsWith("0x"))
- {
- return targets.base + value.subarr(2).to_uintp(16);
- }
- else
- {
- return targets.base + value.to_uintp();
- }
- }
- }
- }
- catch (EofException&)
- {
- if (!targets.endWithLine)
- {
- targets.startWriting();
- targets.fos->write("\r\n");
- }
- }
- }
-
- // load from pdb
- try
- {
- cout << "[BDSX] PdbReader: Search Symbols..." << endl;
- if (m_pdb.base() == nullptr)
- {
- m_pdb.load();
- }
-
- TText line;
- line << txname;
- foundptr = m_pdb.getFunctionAddress(line.c_str());
- if (foundptr != nullptr) {
- line << " = 0x" << hexf((byte*)foundptr - (byte*)m_pdb.base());
- cout << line << endl;
- targets.startWriting();
- *targets.fos << line << "\r\n";
- targets.fos->flush();
- }
- }
- catch (FunctionError& err)
- {
- cerr << err.getFunctionName() << ": failed, ";
- {
- TSZ tsz;
- err.getMessageTo(&tsz);
- cerr << tsz;
- }
- cerr << "(0x" << hexf(err.getErrorCode(), 8) << ')' << endl;
- }
-
- if (foundptr == nullptr)
- {
- cerr << txname << " not found" << endl;
- }
-
- return foundptr;
-}
-JsValue CachedPdb::getProcAddresses(pcstr16 predefined, JsValue out, JsValue array, bool quiet, uint32_t undecorateOpts) throws(kr::JsException)
-{
- int length = array.getArrayLength();
- if (length == 0) return out;
-
- if (!s_lock.tryEnter()) throw JsException(u"BUSY. It's using by the async task");
- finally { s_lock.leave(); };
-
- SymbolMap targets(predefined);
-
- for (int i = 0; i < length; i++)
- {
- targets.put(array.get(i).cast());
- }
-
- if (predefined != nullptr)
- {
- if (targets.file == nullptr)
- {
- throw JsException(TSZ16() << u"Failed to open " << predefined);
- }
- try
- {
- Must> fis = _new io::FIStream((File*)targets.file);
-
- CacheState state = targets.checkMd5(fis, true);
- if (state == CacheState::New)
- {
- if (!quiet) g_ctx->log(TSZ16() << u"[BDSX] Generating " << predefined);
- }
- else if (state == CacheState::NotMatched)
- {
- // does nothing
- }
- else
- {
- for (;;)
- {
- TText16 name;
- uintptr_t offset = targets.readOffset(fis, &name);
- NativePointer* ptr = NativePointer::newInstance();
- ptr->setAddressRaw(targets.base + offset);
- out.set(name, ptr);
- if (targets.empty()) return out;
- }
- }
- }
- catch (EofException&)
- {
- if (!targets.endWithLine)
- {
- targets.startWriting();
- targets.fos->write("\r\n");
- }
- }
- }
-
- // load from pdb
- try
- {
- if (!quiet)
- {
- size_t size = targets.targets.size();
- if (size > 5)
- {
- g_ctx->log(TSZ16() << u"[BDSX] PdbReader: Cache not found, " << size << u" symbols");
- }
- else
- {
- for (auto& pair : targets.targets)
- {
- g_ctx->log(TSZ16() << u"[BDSX] PdbReader: Cache not found, " << (Text16)pair.first);
- }
- }
- g_ctx->log(u"[BDSX] PdbReader: Search Symbols...");
- }
- if (m_pdb.base() == nullptr)
- {
- m_pdb.load();
- }
-
- struct Local
- {
- SymbolMap& targets;
- bool quiet;
- JsValue& out;
- uint32_t undecorateOpts;
- JsException exception;
- } local = {targets, quiet, out, undecorateOpts };
-
- targets.startWriting();
-
- m_pdb.search16(nullptr, [&local](Text16 name, void* address, uint32_t typeId) {
- TText16 undecorated;
- if (local.undecorateOpts != -1)
- {
- undecorated << PdbReader::undecorate(name.data(), local.undecorateOpts);
- name = undecorated;
- }
- Text16 nameWithIndex;
- TText16 line;
- if (!local.targets.test(name, address, &line, &nameWithIndex))
- {
- return true;
- }
- if (!local.quiet)
- {
- g_ctx->log(line);
- }
- NativePointer* ptr = NativePointer::newInstance();
- ptr->setAddressRaw(address);
- try
- {
- local.out.set(JsValue(nameWithIndex), ptr);
- return !local.targets.empty();
- }
- catch (JsException& ex)
- {
- local.exception = move(ex);
- return false;
- }
- });
- if (!local.exception.isEmpty())
- {
- throw move(local.exception);
- }
- if (targets.fos != nullptr) targets.fos->flush();
- }
- catch (FunctionError& err)
- {
- throwAsJsException(err);
- }
-
- if (!targets.empty())
- {
- for (auto& item : targets.targets)
- {
- Text name = item.first;
- if (!quiet) g_ctx->log(TSZ16() << Utf8ToUtf16(name) << u" not found");
- }
- }
-
- return out;
-}
-
-void CachedPdb::search(JsValue masks, JsValue cb) throws(kr::JsException)
-{
- try
- {
- if (m_pdb.base() == nullptr)
- {
- m_pdb.load();
- }
-
- TText filter;
- const char* filterstr = nullptr;
- switch (masks.getType())
- {
- case JsType::String:
- filter = masks.cast();
- filter << '\0';
- filterstr = filter.data();
- break;
- case JsType::Null:
- break;
- case JsType::Function:
- cb = move(masks);
- break;
- case JsType::Object: {
- // array
- Map finder;
- int length = masks.getArrayLength();
- finder.reserve((size_t)length * 2);
-
- for (int i = 0; i < length; i++)
- {
- TText text = masks.get(i).cast();
- finder.insert(text, i);
- }
-
- m_pdb.search(nullptr, [&](Text name, void* address, uint32_t typeId) {
- auto iter = finder.find(name);
- if (finder.end() == iter) return true;
-
- NativePointer* ptr = NativePointer::newInstance();
- ptr->setAddressRaw(address);
-
- int index = iter->second;
- return cb(masks.get(index), ptr, index).cast();
- });
- return;
- }
- }
- JsException exception;
- m_pdb.search(filterstr, [&](Text name, void* address, uint32_t typeId) {
- NativePointer* ptr = NativePointer::newInstance();
- ptr->setAddressRaw(address);
- try
- {
- return cb(TText16() << (Utf8ToUtf16)name, ptr).cast();
- }
- catch (JsException& ex)
- {
- exception = move(ex);
- return false;
- }
- });
- if (!exception.isEmpty())
- {
- throw move(exception);
- }
- }
- catch (FunctionError& err)
- {
- throwAsJsException(err);
- }
-}
-JsValue CachedPdb::getAll(JsValue onprogress) throws(kr::JsException)
-{
- try
- {
- bool callback = onprogress.getType() == JsType::Function;
- if (!callback) g_ctx->log(u"[BDSX] PdbReader: Search Symbols...");
-
- if (m_pdb.base() == nullptr)
- {
- m_pdb.load();
- }
-
- struct Local
- {
- JsValue out = JsNewObject;
- timepoint now;
- JsValue onprogress;
- uintptr_t totalcount;
- bool callback;
- JsException exception;
-
- bool report() noexcept
- {
- if (callback)
- {
- try
- {
- JsValue res = onprogress.call(totalcount);
- return res.getType() != JsType::Boolean || res.as();
- }
- catch (JsException& ex)
- {
- exception = move(ex);
- return false;
- }
- }
- else
- {
- TSZ16 tsz;
- tsz << u"[BDSX] PdbReader: Get symbols (" << totalcount << u')';
- g_ctx->log(tsz);
- }
- return true;
- }
- } local;
- local.now = timepoint::now();
- local.callback = callback;
- local.totalcount = 0;
- if (callback)
- {
- local.onprogress = onprogress;
- local.report();
- }
- m_pdb.getAll16([&local](Text16 name, autoptr address, int typeId) {
- ++local.totalcount;
- timepoint newnow = timepoint::now();
-
- NativePointer* ptr = NativePointer::newInstance();
- ptr->setAddressRaw(address);
- local.out.set(name, ptr);
- if (newnow - local.now > 500_ms)
- {
- local.now = newnow;
- return local.report();
- }
- return true;
- });
-
- local.report();
- if (!callback)
- {
- g_ctx->log(TSZ16() << u"[BDSX] PdbReader: done (" << local.totalcount << u")");
- }
- else if (!local.exception.isEmpty())
- {
- throw move(local.exception);
- }
- return local.out;
- }
- catch (FunctionError& err)
- {
- throwAsJsException(err);
- }
-}
-void CachedPdb::getAllEx(JsValue cb) throws(kr::JsException)
-{
- try
- {
- if (cb.getType() != JsType::Function) throw kr::JsException(u"function required");
- if (m_pdb.base() == nullptr)
- {
- m_pdb.load();
- }
-
- if (!s_field->inited)
- {
- s_field->inited = true;
- s_field->typeIndex = JsPropertyId(u"typeIndex");
- s_field->index = JsPropertyId(u"index");
- s_field->size = JsPropertyId(u"size");
- s_field->flags = JsPropertyId(u"flags");
- s_field->value = JsPropertyId(u"value");
- s_field->address = JsPropertyId(u"address");
- s_field->_register = JsPropertyId(u"register");
- s_field->scope = JsPropertyId(u"scope");
- s_field->tag = JsPropertyId(u"tag");
- s_field->name = JsPropertyId(u"name");
- }
-
- struct Local
- {
- JsValue out = JsNewArray();
- timepoint now;
- JsValue cb;
- JsException exception;
-
- bool callback;
- int counter = 0;
-
- bool flush() throws(JsException)
- {
- if (counter == 0) return true;
- bool res = cb(out) != false;
- out.setArrayLength(0);
- counter = 0;
- return res;
- }
- } local;
- local.now = timepoint::now();
- local.cb = cb;
- m_pdb.getAllEx([&local](Text name, SYMBOL_INFO* info) {
- size_t size = name.size();
- JsValue tuple = JsNewObject;
- tuple.set(s_field->typeIndex, (int)info->TypeIndex);
- tuple.set(s_field->index, (int)info->Index);
- tuple.set(s_field->size, (int)info->Size);
- tuple.set(s_field->flags, (int)info->Flags);
-
- NativePointer* value = NativePointer::newInstance();
- value->setAddressRaw((void*)info->Value);
- tuple.set(s_field->value, value);
-
- NativePointer* addr = NativePointer::newInstance();
- addr->setAddressRaw((void*)info->Address);
- tuple.set(s_field->address, addr);
-
- tuple.set(s_field->_register, (int)info->Register);
- tuple.set(s_field->scope, (int)info->Scope);
- tuple.set(s_field->tag, (int)info->Tag);
- tuple.set(s_field->name, TSZ16() << (NoneToUtf16)name);
- local.out.set(local.counter++, tuple);
-
- timepoint newnow = timepoint::now();
- if (newnow - local.now > 100_ms)
- {
- local.now = newnow;
- try
- {
- return local.flush();
- }
- catch (JsException& ex)
- {
- local.exception = move(ex);
- return false;
- }
- }
- return true;
- });
-
- if (!local.exception.isEmpty())
- {
- throw move(local.exception);
- }
- local.flush();
- }
- catch (FunctionError& err)
- {
- throwAsJsException(err);
- }
-}
JsValue getPdbNamespace() noexcept
{
JsValue pdb = JsNewObject;
- pdb.set(u"coreCachePath", (Text16)CachedPdb::predefinedForCore);
- pdb.setMethod(u"close", [] { return g_pdb.close(); });
- pdb.setMethod(u"setOptions", [](int options) { return g_pdb.setOptions(options); });
- pdb.setMethod(u"getOptions", []() { return g_pdb.getOptions(); });
- pdb.setMethod(u"undecorate", [](Text16 text, int flags)->TText16 { return g_pdb.undecorate(text, flags); });
- pdb.setMethod(u"search", [](JsValue masks, JsValue cb) { return g_pdb.search(masks, cb); });
- pdb.setMethod(u"getProcAddresses", [](JsValue out, JsValue array, bool quiet, bool undecorated) { return g_pdb.getProcAddresses(CachedPdb::predefinedForCore.data(), out, array, quiet, undecorated); });
-
- JsValue getList = JsFunction::makeT([](Text16 predefined, JsValue out, JsValue array, bool quiet, JsValue undecorateOpts) {
- return g_pdb.getProcAddresses(predefined.data(), out, array, quiet, undecorateOpts.abstractEquals(nullptr) ? -1 : undecorateOpts.as());
- });
- pdb.set(u"getList", getList);
- pdb.setMethod(u"getAll", [](JsValue onprogress) { return g_pdb.getAll(onprogress); });
- pdb.setMethod(u"getAllEx", [](JsValue onprogress) { return g_pdb.getAllEx(onprogress); });
+ pdb.setMethod(u"setOptions", [](int options) { return PdbReader::setOptions(options); });
+ pdb.setMethod(u"getOptions", []() { return PdbReader::getOptions(); });
+ pdb.setMethod(u"undecorate", [](Text16 text, int flags)->TText16 {
+ TText16 undecorated;
+ undecorated << PdbReader::undecorate(text.data(), flags);
+ return move(undecorated);
+ });
return pdb;
}
-
-// async pdb, not completed
-//getList.setMethod(u"async", [](Text16 predefined, JsValue out, JsValue array, bool quiet) {
-//
-// Array list;
-//
-// AText buffer;
-// buffer.reserve(1024);
-//
-// int32_t len = array.getArrayLength();
-// for (int i = 0; i < len; i++)
-// {
-// size_t front = buffer.size();
-// buffer << (Utf16ToUtf8)array.get(i).cast();
-// size_t back = buffer.size();
-// buffer << '\0';
-//
-// list.push(Text((pcstr)front, (pcstr)back));
-// }
-//
-// ThreadHandle::createLambda([predefined = AText16::concat(predefined, nullterm), quiet, buffer = move(buffer), list = move(list)]() mutable{
-// intptr_t off = (intptr_t)buffer.data();
-// for (Text& v : list)
-// {
-// v.addBegin(off);
-// v.addEnd(off);
-// }
-// struct Local
-// {
-// AText out;
-// } local;
-// local.out.reserve(1024);
-// g_pdb.getProcAddressesT(predefined.data(), list, [](Text name, void* fnptr, Local* param) {
-//
-// }, & local, quiet);
-// AsyncTask::post([predefined = move(predefined), quiet, buffer = move(buffer), list = move(list)]() mutable{
-//
-// });
-// });
-// });
\ No newline at end of file
diff --git a/bdsx/cachedpdb.h b/bdsx/cachedpdb.h
index cd2bc5a..9b2a3e9 100644
--- a/bdsx/cachedpdb.h
+++ b/bdsx/cachedpdb.h
@@ -3,36 +3,5 @@
#include
#include
-class CachedPdb
-{
-private:
- kr::PdbReader m_pdb;
-
-public:
- static kr::BText16 predefinedForCore;
- using Callback = void(*)(kr::Text16 name, void* fnptr, void* param);
-
- CachedPdb() noexcept;
- ~CachedPdb() noexcept;
- void close() noexcept;
- int setOptions(int options) throws(kr::JsException);
- int getOptions() throws(kr::JsException);
- kr::TText16 undecorate(kr::Text16 text, int flags) noexcept;
- kr::autoptr getProcAddress(kr::pcstr16 predefined, kr::pcstr name) noexcept;
- template
- bool getProcAddressesT(kr::pcstr16 predefined, kr::View text, void(*cb)(kr::Text16 name, void* fnptr, T* param), T* param, bool quiet) noexcept
- {
- static_assert(sizeof(T*) == sizeof(void*), "pointer size unmatched");
- return getProcAddresses(predefined, text, (Callback)cb, param, quiet);
- }
- kr::JsValue getProcAddresses(kr::pcstr16 predefined, kr::JsValue out, kr::JsValue array, bool quiet, uint32_t undecorateOpts) throws(kr::JsException);
- void search(kr::JsValue masks, kr::JsValue cb) throws(kr::JsException);
- kr::JsValue getAll(kr::JsValue onprogress) throws(kr::JsException);
- void getAllEx(kr::JsValue cb) throws(kr::JsException);
-};
-
-extern CachedPdb g_pdb;
-extern kr::BText<32> g_md5;
-
kr::JsValue getPdbNamespace() noexcept;
diff --git a/bdsx/netfilter.cpp b/bdsx/netfilter.cpp
index 4005990..7c89e30 100644
--- a/bdsx/netfilter.cpp
+++ b/bdsx/netfilter.cpp
@@ -490,7 +490,7 @@ JsValue getNetFilterNamespace() noexcept
if (iptext.empty()) return false;
return NetFilter::removeFilter(Ipv4Address(TSZ() << toNone(iptext)));
});
- ipfilter.setMethod(u"entires", NetFilter::entries);
+ ipfilter.setMethod(u"entries", NetFilter::entries);
ipfilter.setMethod(u"init", [](JsValue callbackOnExceeded) {
NetFilter::init(callbackOnExceeded);
});
diff --git a/bdsx/nodegate.cpp b/bdsx/nodegate.cpp
index 54abb29..8e5be3f 100644
--- a/bdsx/nodegate.cpp
+++ b/bdsx/nodegate.cpp
@@ -58,6 +58,7 @@ namespace
s_inited = true;
v8::Isolate* isolate = context->GetIsolate();
node::AddEnvironmentCleanupHook(isolate, [](void*) { clear(); }, nullptr);
+ node::AtExit([](void*) { clear(); });
nodegate::initNativeModule(*exports);
atexit(clear);
}
diff --git a/bdsx/sehandler.cpp b/bdsx/sehandler.cpp
index 0bfc6f0..289f29c 100644
--- a/bdsx/sehandler.cpp
+++ b/bdsx/sehandler.cpp
@@ -7,6 +7,7 @@
#include "unwind.h"
#include
+#include
#include
#include
#include
@@ -61,7 +62,7 @@ namespace
Array getStack(EXCEPTION_POINTERS* exptr, HANDLE thread) noexcept
{
- PdbReader::setOptions(0x00000002);
+ PdbReader::setOptions(SYMOPT_UNDNAME);
try {
for (int i = 0; i < 3; i++)
{
diff --git a/bdsx/version.bat b/bdsx/version.bat
index 2153782..2a2ba31 100644
--- a/bdsx/version.bat
+++ b/bdsx/version.bat
@@ -1,2 +1,2 @@
-set BDSX_CORE_VERSION=1.0.12.2
+set BDSX_CORE_VERSION=1.0.13.1
diff --git a/pdbcachegen/pdbcachegen.aps b/pdbcachegen/pdbcachegen.aps
new file mode 100644
index 0000000..0d7377d
Binary files /dev/null and b/pdbcachegen/pdbcachegen.aps differ
diff --git a/pdbcachegen/pdbcachegen.cpp b/pdbcachegen/pdbcachegen.cpp
new file mode 100644
index 0000000..b17833b
--- /dev/null
+++ b/pdbcachegen/pdbcachegen.cpp
@@ -0,0 +1,178 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "../bdsx/gen/version.h"
+#include "pdbcachegen.h"
+
+using namespace kr;
+
+uint32_t hashString(Text16 v) noexcept {
+ uint32_t out = 0;
+ uint32_t shift = 0;
+ uint32_t n = intact(v.size());
+ for (uint32_t i = 0; i < n;i++) {
+ uint32_t chr = v[i] + i;
+ out += (chr << shift) | (chr >> (32 - shift));
+ shift = (shift + 7) & 0x1f;
+ }
+ out += n;
+ return out;
+}
+
+struct Symbol {
+ AText16 name;
+ void* address;
+};
+
+struct OffsetEntry {
+ uint32_t hash;
+ uint32_t nameOffset;
+ uint32_t rva;
+};
+
+int wmain(int argn, const wchar_t** args) {
+ byte md5[encoder::Md5Context::SIZE];
+ filetime_t exeModifiedTime;
+
+ bool force = false;
+ int argi = 0;
+
+ pcstr16 exePath = nullptr, cachePath = nullptr;
+
+ for (;;) {
+ pcstr16 arg = unwide(*args++);
+ if (arg == nullptr) break;
+ Text16 argtx = (Text16)arg;
+ if (argtx == u"-f") {
+ force = true;
+ }
+ else {
+ switch (argi) {
+ case 0:
+ exePath = arg;
+ break;
+ case 1:
+ cachePath = arg;
+ break;
+ default:
+ cerr << "Too many arguments" << endl;
+ return EINVAL;
+ }
+ argi++;
+ }
+ }
+ if (argi < 2) {
+ cerr << "Need two arguments at least" << endl;
+ cerr << "ex) pdbcachegen.exe (exe) (cachefile)" << endl;
+ return EINVAL;
+ }
+ try {
+ Must exe = File::open(exePath);
+ exeModifiedTime = exe->getLastModifiedTime();
+ encoder::Md5Context ctx;
+ ctx.reset();
+ ctx.update((TBuffer)exe->readAll());
+ ctx.finish(md5);
+ }
+ catch (Error&) {
+ cerr << "exe file not found." << endl;
+ return ERROR_NOT_FOUND;
+ }
+ try {
+ Must cache = File::open(cachePath);
+ if (!force) {
+ if (exeModifiedTime < cache->getLastModifiedTime()) {
+ PdbCacheHeader header;
+ cache->read(&header, sizeof(header));
+ if (header.version == PdbCacheHeader::VERSION) {
+ if (memcmp(header.md5, md5, encoder::Md5Context::SIZE) == 0) {
+ cout << "pdbcache.bin: latest" << endl;
+ return S_OK;
+ }
+ }
+ }
+ }
+ }
+ catch (Error&) {
+ }
+ Array symbols;
+ symbols.reserve(100000);
+
+ cout << "pdbcache.bin: generating..." << endl;
+ cout.flush();
+
+ PdbReader pdb;
+ uint64_t base = 0x1000000;
+ pdb.load(base, exePath);
+ pdb.setOptions(SYMOPT_PUBLICS_ONLY);
+ pdb.getAll16([&symbols](Text16 name, autoptr64 address, uint32_t typeId) {
+ symbols.push({ name, address });
+ return true;
+ });
+ pdb.setOptions(SYMOPT_NO_PUBLICS);
+
+ pdb.getAll16([&symbols](Text16 name, autoptr64 address, uint32_t typeId) {
+ symbols.push({ name, address });
+ return true;
+ });
+
+ size_t capacity = symbols.size() * 2;
+
+ Array keyTable;
+ keyTable.resize(capacity);
+ keyTable.zero();
+
+ size_t offsetBegin = capacity * sizeof(OffsetEntry) + sizeof(PdbCacheHeader);
+ Array names;
+ names.reserve(capacity*5);
+
+ PdbCacheHeader header;
+ header.version = PdbCacheHeader::VERSION;
+ header.hashMapCapacity = intact(capacity);
+ memcpy(header.md5, md5, encoder::Md5Context::SIZE);
+
+ Text16 mainText = u"main";
+ uint32_t mainHash = hashString(mainText);
+
+ size_t dupMax = 0;
+ for (Symbol& sym : symbols) {
+ uint32_t hash = hashString(sym.name);
+ if (sym.name == u"vsnprintf") debug();
+ uint32_t rva = intact((uint64_t)sym.address - base);
+ if (hash == mainHash && sym.name == mainText) {
+ header.mainRva = rva;
+ }
+
+ uint32_t index = hash;
+ size_t dupCount = 0;
+ for (;;) {
+ index %= capacity;
+ OffsetEntry& entry = keyTable[index];
+ if (entry.nameOffset != 0) {
+ dupCount++;
+ index++;
+ continue;
+ }
+ entry.hash = hash;
+ entry.nameOffset = intact(names.size() + offsetBegin);
+ entry.rva = rva;
+ break;
+ }
+
+ names << (Utf16ToUtf8)(sym.name);
+ names.write('\0');
+ }
+
+ io::FileStream* file = File::create(cachePath)->stream();
+ file->writeas(header);
+ file->write((Buffer)keyTable);
+ file->write((Buffer)names);
+ delete file;
+
+ cout << "pdbcache.bin: generated" << endl;
+ return S_OK;
+}
diff --git a/pdbcachegen/pdbcachegen.h b/pdbcachegen/pdbcachegen.h
new file mode 100644
index 0000000..ecb46a7
--- /dev/null
+++ b/pdbcachegen/pdbcachegen.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+#include
+
+struct PdbCacheHeader {
+ static constexpr uint32_t VERSION = 1;
+
+ uint32_t version;
+ kr::byte md5[kr::encoder::Md5Context::SIZE];
+ uint32_t mainRva;
+ uint32_t hashMapCapacity;
+};
diff --git a/pdbcachegen/pdbcachegen.vcxproj b/pdbcachegen/pdbcachegen.vcxproj
new file mode 100644
index 0000000..906bc3b
--- /dev/null
+++ b/pdbcachegen/pdbcachegen.vcxproj
@@ -0,0 +1,163 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {0db97edf-3343-4575-af19-0ef056d395b2}
+ pdbcachegen
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+ {f5212e7b-4791-4488-a23a-57af3023e7d3}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pdbcachegen/pdbcachegen.vcxproj.filters b/pdbcachegen/pdbcachegen.vcxproj.filters
new file mode 100644
index 0000000..56f97a4
--- /dev/null
+++ b/pdbcachegen/pdbcachegen.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/pdbcachegen/pdbcachegen.vcxproj.user b/pdbcachegen/pdbcachegen.vcxproj.user
new file mode 100644
index 0000000..f8cfa17
--- /dev/null
+++ b/pdbcachegen/pdbcachegen.vcxproj.user
@@ -0,0 +1,22 @@
+
+
+
+ true
+
+
+ -f
+ WindowsLocalDebugger
+
+
+ -f
+ WindowsLocalDebugger
+
+
+ -f
+ WindowsLocalDebugger
+
+
+ -f
+ WindowsLocalDebugger
+
+
\ No newline at end of file