13#include "llvm/ADT/StringMap.h"
14#include "llvm/Support/FileSystem.h"
15#include "llvm/Support/ManagedStatic.h"
16#include "llvm/Support/Path.h"
17#include "llvm/Support/Process.h"
18#include "llvm/Support/raw_ostream.h"
22#include <system_error>
24#if defined(__linux__) || defined(__APPLE__)
31namespace DispatchRaw {
37 const Cpp::JitCall*,
void*,
unsigned long, int) =
nullptr;
39 const Cpp::JitCall*,
void*) =
nullptr;
50 static llvm::ManagedStatic<TraceInfo> TI;
65 static const llvm::StringMap<uint64_t> Map = {
66#define CPPINTEROP_API_FUNC(DN, CN, Ret, DA, CA, RT)
67#define CPPINTEROP_API_OUT(CN, OutMask) {#CN, OutMask},
68#include "CppInterOp/CppInterOpAPI.inc"
70 auto It = Map.find(Name);
82 explicit DumpScope(
TraceInfo& T) : TI(T) { TI.setDumping(
true); }
83 ~DumpScope() { TI.setDumping(
false); }
89 const std::string& Version) {
90 llvm::StringRef Ver(Version);
91 while (!Ver.empty()) {
92 auto [Line, Rest] = Ver.split(
'\n');
94 OS <<
"// " << Line <<
"\n";
104#if defined(__linux__) || defined(__APPLE__)
108 llvm::StringRef Name(info.dli_fname);
109 if (Name.contains(
".so") || Name.ends_with(
".dylib") ||
110 Name.ends_with(
".dll"))
111 return info.dli_fname;
119 OS <<
"// Build context (CppInterOp configure-time snapshot):\n";
123 llvm::StringRef Info(Snapshot);
124 while (!Info.empty()) {
125 auto [Line, Rest] = Info.split(
'\n');
127 OS <<
"//" << Line <<
"\n";
138 llvm::StringRef Title,
139 const std::string& Version,
140 llvm::StringRef Footnote) {
141 OS <<
"// CppInterOp " << Title <<
"\n";
143 if (!Footnote.empty())
144 OS <<
"// " << Footnote <<
"\n";
146 OS <<
"// Replay scope: re-runs recorded CppInterOp API calls. JIT\n";
147 OS <<
"// wrappers (Cpp::JitCall::Invoke) are not replayed -- their\n";
148 OS <<
"// pointer args reference the original process's memory. The\n";
149 OS <<
"// trailing `// JitCall::Invoke ...` comment, if present,\n";
150 OS <<
"// names the call active at the crash site.\n";
154 OS <<
"// Build (default, static link):\n";
155 OS <<
"// c++ -std=c++17 -I<CppInterOp-include-dir>"
156 " reproducer.cpp -lclangCppInterOp -o reproducer\n";
157 OS <<
"// Build (dlopen via Dispatch.h):\n";
158 OS <<
"// c++ -std=c++17 -DCPPINTEROP_USE_DISPATCH"
159 " -I<CppInterOp-include-dir>"
160 " reproducer.cpp -ldl -o reproducer\n";
162 OS <<
"// Run: ./reproducer";
164 OS <<
" (dispatch build: set "
165 "CPPINTEROP_LIBRARY_PATH=<libclangCppInterOp.so>)";
167 OS <<
" (dispatch build: CPPINTEROP_LIBRARY_PATH overrides the captured "
171 OS <<
"#ifdef CPPINTEROP_USE_DISPATCH\n";
172 OS <<
"#include <CppInterOp/Dispatch.h>\n\n";
174 OS <<
"using namespace Cpp;\n";
175 OS <<
"#define CPPINTEROP_API_FUNC(DN, CN, Ret, DeclArgs, CallArgs, "
177 " Ret(*CppInternal::DispatchRaw::DN) RawTypes = nullptr;\n"
178 "#include \"CppInterOp/CppInterOpAPI.inc\"\n\n";
180 OS <<
"static void initCppInterOpReproducer() {\n";
181 OS <<
" static bool inited = false;\n";
182 OS <<
" if (inited) return;\n";
183 OS <<
" const char* path = std::getenv(\"CPPINTEROP_LIBRARY_PATH\");\n";
184 if (!LibPath.empty())
185 OS <<
" if (!path) path = R\"PATH(" << LibPath <<
")PATH\";\n";
186 OS <<
" Cpp::LoadDispatchAPI(path);\n";
187 OS <<
" inited = true;\n";
190 OS <<
"#include <CppInterOp/CppInterOp.h>\n";
192 OS <<
"static void initCppInterOpReproducer() {}\n";
197 llvm::SmallString<128> TmpDir;
198 llvm::sys::path::system_temp_directory(
true, TmpDir);
199 llvm::SmallString<128> Path;
200 llvm::sys::path::append(Path, TmpDir,
"cppinterop-reproducer-%%%%%%.cpp");
203 std::error_code EC = llvm::sys::fs::createUniqueFile(Path, FD, Path);
207 llvm::raw_fd_ostream OS(FD,
true);
208 DumpScope Guard(*
this);
212 "Generated automatically — re-run to reproduce.");
213 OS <<
"void reproducer() {\n";
214 OS <<
" initCppInterOpReproducer();\n";
215 for (
const auto& Line : m_Log)
218 OS <<
"int main() { reproducer(); return 0; }\n";
220 return std::string(Path);
224 m_RegionStart = m_Log.size();
226 m_WriteOnStdErr = WriteOnStdErr;
230 m_RegionPath.clear();
234 llvm::SmallString<128> TmpDir;
235 llvm::sys::path::system_temp_directory(
true, TmpDir);
236 llvm::SmallString<128> Path;
237 llvm::sys::path::append(Path, TmpDir,
"cppinterop-reproducer-%%%%%%.cpp");
239 std::error_code EC = llvm::sys::fs::createUniqueFile(Path, FD, Path);
242 llvm::sys::Process::SafelyCloseFileDescriptor(FD);
243 m_RegionPath = std::string(Path);
257 llvm::raw_fd_ostream OS(m_RegionPath, EC);
261 DumpScope Guard(*
this);
264 OS <<
"void reproducer() {\n";
265 OS <<
" initCppInterOpReproducer();\n";
266 for (
size_t i = m_RegionStart; i < m_Log.size(); ++i)
267 OS << m_Log[i] <<
"\n";
269 OS <<
"int main() { reproducer(); return 0; }\n";
#define CPPINTEROP_TRACE_API
std::string writeToFile(const std::string &Version="")
Write the accumulated reproducer log to a file.
void StopRegion(const std::string &Version="")
End the traced region and write only the region's entries to the file.
std::string StartRegion(bool WriteOnStdErr=true)
Begin a traced region.
static std::optional< uint64_t > lookupOutMask(llvm::StringRef Name)
.td-declared OUT-arg bitmask for Name (matches CppName / func), or std::nullopt for non-public-API tr...
static std::string GetCppInterOpLibPath()
dladdr-based path to libclangCppInterOp, used as the dispatch-mode fallback.
static void WriteReproducerPrologue(llvm::raw_ostream &OS, llvm::StringRef Title, const std::string &Version, llvm::StringRef Footnote)
Emit a prologue compilable in two modes selected by -D: default <CppInterOp/CppInterOp....
void InitTracing()
Activate tracing.
static void WriteBuildContext(llvm::raw_ostream &OS)
Stream Cpp::GetBuildInfo() into the prologue as // comments.
static void WriteVersionComment(llvm::raw_ostream &OS, const std::string &Version)
Helper: emit version info as comment lines.
TraceInfo * TheTraceInfo
Process-global tracer pointer.
void(* CppInterOpTraceJitCallInvokeImpl)(const Cpp::JitCall *, void *, void **, std::size_t, void *)
void(* CppInterOpTraceJitCallInvokeReturnImpl)(const Cpp::JitCall *, void *)
void(* CppInterOpTraceJitCallInvokeDestructorImpl)(const Cpp::JitCall *, void *, unsigned long, int)
void CppInterOpTraceJitCallInvokeImpl(const JitCall *JC, void *result, void **args, std::size_t nargs, void *self)
void CppInterOpTraceJitCallInvokeReturnImpl(const JitCall *JC, void *result)
std::string GetBuildInfo()
void CppInterOpTraceJitCallInvokeDestructorImpl(const JitCall *JC, void *object, unsigned long nary, int withFree)