Skip to content

Instantly share code, notes, and snippets.

@umanwizard
Created October 21, 2025 18:45
Show Gist options
  • Select an option

  • Save umanwizard/a9e055a7cc1b81248bbf17501c749481 to your computer and use it in GitHub Desktop.

Select an option

Save umanwizard/a9e055a7cc1b81248bbf17501c749481 to your computer and use it in GitHub Desktop.
// 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