Created
October 21, 2025 18:45
-
-
Save umanwizard/a9e055a7cc1b81248bbf17501c749481 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Compile with `clang++ -lclang main.cpp` | |
| // Important: | |
| // 1. The compile_commands.json in the node build dir should be generated with `bear`, NOT | |
| // with the (broken) ./configure -C option. | |
| // 2. the libclang must be from the same build as the clang that was used to build node | |
| // 3. You will have to tweak the /gnu/store/bzzn05rblq1hnds5zq1g4nsphry1cs60-profile/bin/clang++ | |
| // path to wherever clang lives on your system. | |
| #include <clang-c/CXCompilationDatabase.h> | |
| #include <clang-c/CXString.h> | |
| #include <clang-c/Index.h> | |
| #include <cstdlib> | |
| #include <cstring> | |
| #include <filesystem> | |
| #include <iostream> | |
| #include <memory> | |
| #include <type_traits> | |
| #include <vector> | |
| class DisposingCXString { | |
| CXString self_; | |
| public: | |
| CXString get() { return self_; } | |
| explicit DisposingCXString(CXString self) : self_(self) {} | |
| ~DisposingCXString() { clang_disposeString(self_); } | |
| }; | |
| int main() { | |
| const auto node_path = []{ | |
| if (const char* env_path = std::getenv("NODE_PATH")) { | |
| return std::string{env_path}; | |
| } | |
| return std::string{"/home/brennan/code/node"}; | |
| }(); | |
| std::filesystem::current_path(node_path + "/out"); | |
| CXIndex _index = clang_createIndex(0, 1); // Create index | |
| auto index = std::unique_ptr<void, decltype(&clang_disposeIndex)>( | |
| _index, clang_disposeIndex); | |
| CXCompilationDatabase_Error err; | |
| CXCompilationDatabase _cdb = clang_CompilationDatabase_fromDirectory( | |
| node_path.c_str(), &err); | |
| if (err) { | |
| std::cerr << "Unable to parse compdb. Quitting.\n"; | |
| return 1; | |
| } | |
| auto cdb = | |
| std::unique_ptr<void, decltype(&clang_CompilationDatabase_dispose)>( | |
| _cdb, clang_CompilationDatabase_dispose); | |
| CXCompileCommands _ccs = clang_CompilationDatabase_getCompileCommands( | |
| cdb.get(), (node_path + "/deps/v8/src/api/api.cc").c_str()); | |
| if (!_ccs) { | |
| std::cerr << "Failed to get CCs. Quitting.\n"; | |
| return 1; | |
| } | |
| auto ccs = std::unique_ptr<void, decltype(&clang_CompileCommands_dispose)>( | |
| _ccs, clang_CompileCommands_dispose); | |
| unsigned len = clang_CompileCommands_getSize(ccs.get()); | |
| if (!len) { | |
| std::cerr << "No commands\n"; | |
| return 1; | |
| } | |
| CXCompileCommand cmd = clang_CompileCommands_getCommand(ccs.get(), 0); | |
| if (!cmd) { | |
| std::cerr << "Failed to get command.\n"; | |
| return 1; | |
| } | |
| std::vector<DisposingCXString> backing; | |
| std::vector<const char *> c_strs{ | |
| "/gnu/store/bzzn05rblq1hnds5zq1g4nsphry1cs60-profile/bin/clang++", | |
| "-I./Release/obj/gen/generate-bytecode-output-root", | |
| "-I./Release/obj/gen"}; | |
| unsigned n_args = clang_CompileCommand_getNumArgs(cmd); | |
| for (unsigned i = 1; i < n_args; ++i) { | |
| backing.emplace_back(clang_CompileCommand_getArg(cmd, i)); | |
| c_strs.push_back(clang_getCString(backing.back().get())); | |
| } | |
| CXTranslationUnit _unit = nullptr; | |
| CXErrorCode ec = clang_parseTranslationUnit2FullArgv( | |
| index.get(), nullptr, c_strs.data(), c_strs.size(), nullptr, 0, | |
| CXTranslationUnit_None, &_unit); | |
| if (ec || !_unit) { | |
| std::cerr << "Failed to parse translation unit. Error: " << ec << "\n"; | |
| return 1; | |
| } | |
| auto unit = std::unique_ptr<std::remove_reference_t<decltype(*_unit)>, | |
| decltype(&clang_disposeTranslationUnit)>( | |
| _unit, clang_disposeTranslationUnit); | |
| CXCursor cur_unit = clang_getTranslationUnitCursor(unit.get()); | |
| int rv = 2; | |
| clang_visitChildren( | |
| cur_unit, | |
| [](CXCursor current, CXCursor parent, CXClientData client_data) { | |
| DisposingCXString s{clang_getCursorDisplayName(current)}; | |
| const char *c_str = clang_getCString(s.get()); | |
| if (!std::strcmp(c_str, "kJSAPIObjectWithEmbedderSlotsHeaderSize") | |
| || !std::strcmp(c_str, "kJSObjectHeaderSize")) { | |
| CXType type = clang_getCursorType(parent); | |
| auto kind = clang_getCursorKind(current); | |
| // std::cout << kind << std::endl; | |
| if (kind == CXCursor_VarDecl) { | |
| // CXCursor cur2 = clang_Cursor_getVarDeclInitializer(current); | |
| CXEvalResult er = clang_Cursor_Evaluate(current); | |
| CXEvalResultKind erk = clang_EvalResult_getKind(er); | |
| if (erk == CXEval_Int) { | |
| auto val = clang_EvalResult_getAsLongLong(er); | |
| std::cout << c_str << ": " << val << std::endl; | |
| *(int *)client_data = 0; | |
| } | |
| } | |
| } else if (!std::strcmp(c_str, "continuation_preserved_embedder_data_")) { | |
| auto kind = clang_getCursorKind(current); | |
| if (kind == CXCursor_FieldDecl) { | |
| long long off = clang_Cursor_getOffsetOfField(current); | |
| std::cout << c_str << " offset: "; | |
| if (off >= 0 && !(off % 8)) { | |
| std::cout << off / 8 << std::endl; | |
| *(int *)client_data = 0; | |
| } else { | |
| std::cout << "bit offset! " << off << std::endl; | |
| } | |
| } | |
| } | |
| return CXChildVisit_Recurse; | |
| }, | |
| &rv); | |
| return rv; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment