summaryrefslogtreecommitdiffstats
path: root/userspace/cuda/tools/ghidra/DecompileAt.java
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 12:11:04 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 12:11:04 -0400
commitf874d709e5a45d63c8ee9ab6b0300195aa5d20a5 (patch)
tree2d07208f789e402686ac960e5ad7456b6fd21cfd /userspace/cuda/tools/ghidra/DecompileAt.java
parentae18e08d02500579f084616874d8f2ae57f8281b (diff)
downloadopen-iov-f874d709e5a45d63c8ee9ab6b0300195aa5d20a5.tar.gz
open-iov-f874d709e5a45d63c8ee9ab6b0300195aa5d20a5.zip
userspace/cuda: add CUDA userspace driver analysis, tooling and name maps
Add the analysis of the NVIDIA CUDA userspace driver used by Open-IOV VMs: * docs/01-08: architecture (layers, object model, threads, sync, memory, channels, launch), build and execution model, the driver/kernel/GPU interface contract, virtualization approaches, the 570.144 decompilation map with the corrected libcuda crash path and the current engine-topology blocker, tooling, and a version-upgrade playbook. * tools/: version-agnostic toolchain - stdlib ELF/interface toolkit (exports, unwind-table function map, wrapper resolution, version delta, crash address decode), callgraph walker, corpus annotator, and Ghidra analysis/decompilation/name-map scripts with resumable parallel drivers. * 570.144/annotations/: our name map (exports + resolved wrappers + verified internals) and subsystem index, tracked so naming work accumulates. * READ-ME-FIRST.md: reading guide with the fast lookup recipes. The full decompiled corpus and annotated corpus stay untracked (vendor- derived, gitignored under the version run/ tree).
Diffstat (limited to 'userspace/cuda/tools/ghidra/DecompileAt.java')
-rw-r--r--userspace/cuda/tools/ghidra/DecompileAt.java86
1 files changed, 86 insertions, 0 deletions
diff --git a/userspace/cuda/tools/ghidra/DecompileAt.java b/userspace/cuda/tools/ghidra/DecompileAt.java
new file mode 100644
index 0000000..ed8cf5d
--- /dev/null
+++ b/userspace/cuda/tools/ghidra/DecompileAt.java
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//
+// DecompileAt.java - Ghidra post-script: decompile the function containing a
+// given file virtual address. Version-agnostic copy of the per-version
+// helper used with ghidra_decompile_at.sh.
+//
+// Usage:
+// analyzeHeadless <proj> <name> -process <program> -readOnly -noanalysis \
+// -postScript DecompileAt.java <hex-vaddr> [outfile]
+//
+// If the address does not fall inside a known function, the script tries to
+// disassemble at the address; if the target is outside any function body it
+// prints a comment with the nearest preceding function instead of failing.
+
+import ghidra.app.script.GhidraScript;
+import ghidra.app.decompiler.DecompInterface;
+import ghidra.app.decompiler.DecompileResults;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.FunctionIterator;
+import ghidra.program.model.listing.Listing;
+
+import java.io.FileWriter;
+
+public class DecompileAt extends GhidraScript {
+ @Override
+ public void run() throws Exception {
+ String[] args = getScriptArgs();
+ if (args.length < 1) {
+ println("usage: DecompileAt.java <hex-vaddr> [outfile]");
+ return;
+ }
+ long fileAddr = Long.parseUnsignedLong(args[0].replaceFirst("^0x", ""), 16);
+ // Arguments are FILE virtual addresses (libcuda+0x...). Ghidra may have
+ // loaded the program at a non-zero image base (0x100000 in this build),
+ // so translate before resolving. If image base is 0 this is a no-op.
+ long imageBase = currentProgram.getImageBase().getOffset();
+ Address addr = toAddr(fileAddr + imageBase);
+ long target = addr.getOffset();
+
+ Function f = getFunctionContaining(addr);
+ if (f == null) {
+ Listing listing = currentProgram.getListing();
+ FunctionIterator it = listing.getFunctions(addr, false);
+ if (it.hasNext()) f = it.next();
+ }
+ if (f == null) {
+ disassemble(addr);
+ f = createFunction(addr, null);
+ }
+ StringBuilder sb = new StringBuilder();
+ if (f == null) {
+ sb.append("// no function at 0x").append(Long.toHexString(target)).append("\n");
+ } else {
+ DecompInterface dif = new DecompInterface();
+ dif.toggleCCode(true);
+ dif.toggleSyntaxTree(true);
+ dif.openProgram(currentProgram);
+ DecompileResults res = dif.decompileFunction(f, 300, monitor);
+ sb.append("// function ").append(f.getName())
+ .append(" at libcuda+0x")
+ .append(Long.toHexString(f.getEntryPoint().getOffset() - imageBase))
+ .append(" (program 0x").append(Long.toHexString(f.getEntryPoint().getOffset()))
+ .append(", query file 0x").append(Long.toHexString(fileAddr)).append(")\n");
+ if (res != null && res.decompileCompleted()) {
+ sb.append("#include <stdint.h>\n")
+ .append("typedef unsigned char undefined1;\n")
+ .append("typedef unsigned short undefined2;\n")
+ .append("typedef unsigned int undefined4;\n")
+ .append("typedef unsigned long long undefined8;\n")
+ .append("typedef long long longlong;\n")
+ .append("typedef unsigned long long ulonglong;\n\n")
+ .append(res.getDecompiledFunction().getC());
+ } else {
+ sb.append("// decompilation failed\n");
+ }
+ }
+ String text = sb.toString();
+ if (args.length > 1) {
+ try (FileWriter w = new FileWriter(args[1])) {
+ w.write(text);
+ }
+ }
+ println(text);
+ }
+}