Spaces:
Running
Running
Edward J. Schwartz commited on
Commit ·
efc2358
1
Parent(s): abf836d
Route old-format CUDA ELF to nvdisasm 12.9 so CFGs work
Browse filesnvdisasm 13.x disables flow analysis on pre-CUDA 13 ELF (OSABI 0x33), so
control flow graphs fail. Fetch nvdisasm 12.9 from NVIDIA's redist site at
startup and use it for those files.
README.md
CHANGED
|
@@ -12,5 +12,7 @@ short_description: Disassemble CUDA cubins with cuobjdump and nvdisasm
|
|
| 12 |
|
| 13 |
Upload a CUDA cubin, fatbin or ELF object and run NVIDIA's `cuobjdump` or `nvdisasm` on it.
|
| 14 |
Both tools are installed from PyPI (`nvidia-cuda-cuobjdump`, `nvidia-cuda-nvdisasm`); no GPU required.
|
|
|
|
|
|
|
| 15 |
|
| 16 |
`examples/` holds two cubins assembled with `ptxas` from the included PTX sources.
|
|
|
|
| 12 |
|
| 13 |
Upload a CUDA cubin, fatbin or ELF object and run NVIDIA's `cuobjdump` or `nvdisasm` on it.
|
| 14 |
Both tools are installed from PyPI (`nvidia-cuda-cuobjdump`, `nvidia-cuda-nvdisasm`); no GPU required.
|
| 15 |
+
nvdisasm 13.x cannot build control flow graphs for old-format CUDA ELF (pre-CUDA 13, OSABI `0x33`), so those files are
|
| 16 |
+
routed to nvdisasm 12.9, downloaded from NVIDIA's redist site at startup.
|
| 17 |
|
| 18 |
`examples/` holds two cubins assembled with `ptxas` from the included PTX sources.
|
app.py
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
|
|
| 1 |
import shlex
|
| 2 |
import subprocess
|
|
|
|
|
|
|
|
|
|
| 3 |
from pathlib import Path
|
| 4 |
|
| 5 |
import gradio as gr
|
|
@@ -12,7 +16,23 @@ def find_tool(name):
|
|
| 12 |
return str(path)
|
| 13 |
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
TOOLS = {name: find_tool(name) for name in ("cuobjdump", "nvdisasm")}
|
|
|
|
|
|
|
| 16 |
OUTPUTS = {
|
| 17 |
"cuobjdump": ["--dump-sass", "--dump-ptx", "--dump-elf", "--dump-resource-usage", "--dump-elf-symbols",
|
| 18 |
"--list-elf", "--list-ptx"],
|
|
@@ -37,13 +57,23 @@ d3.select(graph).graphviz({useWorker: false, zoom: true}).renderDot(props.value,
|
|
| 37 |
EXAMPLES = sorted(str(p) for p in Path(__file__).with_name("examples").glob("*.cubin"))
|
| 38 |
|
| 39 |
|
| 40 |
-
def version(
|
| 41 |
-
return subprocess.run([
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
|
| 44 |
def run_one(tool, args, file):
|
| 45 |
try:
|
| 46 |
-
r = subprocess.run([
|
| 47 |
except subprocess.TimeoutExpired:
|
| 48 |
return "Timed out after 60s."
|
| 49 |
return (r.stdout + r.stderr or "(no output)") + (f"\n[exit code {r.returncode}]" if r.returncode else "")
|
|
@@ -65,8 +95,9 @@ def select_tool(tool):
|
|
| 65 |
|
| 66 |
with gr.Blocks(title="cuobjdump / nvdisasm") as demo:
|
| 67 |
gr.Markdown("# cuobjdump / nvdisasm\n"
|
| 68 |
-
"Disassemble CUDA cubins, fatbins and ELF objects with NVIDIA's tools
|
| 69 |
-
+ ", ".join(f"`{t}` {version(
|
|
|
|
| 70 |
with gr.Row(equal_height=True):
|
| 71 |
with gr.Column(scale=1):
|
| 72 |
file = gr.File(label="cubin / fatbin / CUDA ELF", type="filepath")
|
|
|
|
| 1 |
+
import platform
|
| 2 |
import shlex
|
| 3 |
import subprocess
|
| 4 |
+
import tarfile
|
| 5 |
+
import tempfile
|
| 6 |
+
import urllib.request
|
| 7 |
from pathlib import Path
|
| 8 |
|
| 9 |
import gradio as gr
|
|
|
|
| 16 |
return str(path)
|
| 17 |
|
| 18 |
|
| 19 |
+
def fetch_legacy_nvdisasm(version):
|
| 20 |
+
arch = "linux-sbsa" if platform.machine() == "aarch64" else "linux-x86_64"
|
| 21 |
+
name = f"cuda_nvdisasm-{arch}-{version}-archive"
|
| 22 |
+
path = Path(tempfile.gettempdir()) / name / "nvdisasm"
|
| 23 |
+
if not path.exists():
|
| 24 |
+
url = f"https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvdisasm/{arch}/{name}.tar.xz"
|
| 25 |
+
with urllib.request.urlopen(url) as r, tarfile.open(fileobj=r, mode="r|xz") as tar:
|
| 26 |
+
member = next(m for m in tar if m.name == f"{name}/bin/nvdisasm")
|
| 27 |
+
path.parent.mkdir(exist_ok=True)
|
| 28 |
+
path.write_bytes(tar.extractfile(member).read())
|
| 29 |
+
path.chmod(0o755)
|
| 30 |
+
return str(path)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
TOOLS = {name: find_tool(name) for name in ("cuobjdump", "nvdisasm")}
|
| 34 |
+
# nvdisasm 13.x can't run flow analysis (CFGs) on old-format CUDA ELF (OSABI 0x33, pre-CUDA 13); 12.9 can.
|
| 35 |
+
LEGACY_NVDISASM = fetch_legacy_nvdisasm("12.9.88")
|
| 36 |
OUTPUTS = {
|
| 37 |
"cuobjdump": ["--dump-sass", "--dump-ptx", "--dump-elf", "--dump-resource-usage", "--dump-elf-symbols",
|
| 38 |
"--list-elf", "--list-ptx"],
|
|
|
|
| 57 |
EXAMPLES = sorted(str(p) for p in Path(__file__).with_name("examples").glob("*.cubin"))
|
| 58 |
|
| 59 |
|
| 60 |
+
def version(exe):
|
| 61 |
+
return subprocess.run([exe, "--version"], capture_output=True, text=True).stdout.split("release ")[-1].splitlines()[0]
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def is_old_elf(file):
|
| 65 |
+
with open(file, "rb") as f:
|
| 66 |
+
head = f.read(8)
|
| 67 |
+
return head[:4] == b"\x7fELF" and head[7] == 0x33
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def executable(tool, file):
|
| 71 |
+
return LEGACY_NVDISASM if tool == "nvdisasm" and is_old_elf(file) else TOOLS[tool]
|
| 72 |
|
| 73 |
|
| 74 |
def run_one(tool, args, file):
|
| 75 |
try:
|
| 76 |
+
r = subprocess.run([executable(tool, file), *args, file], capture_output=True, text=True, timeout=60)
|
| 77 |
except subprocess.TimeoutExpired:
|
| 78 |
return "Timed out after 60s."
|
| 79 |
return (r.stdout + r.stderr or "(no output)") + (f"\n[exit code {r.returncode}]" if r.returncode else "")
|
|
|
|
| 95 |
|
| 96 |
with gr.Blocks(title="cuobjdump / nvdisasm") as demo:
|
| 97 |
gr.Markdown("# cuobjdump / nvdisasm\n"
|
| 98 |
+
"Disassemble CUDA cubins, fatbins and ELF objects with NVIDIA's tools ("
|
| 99 |
+
+ ", ".join(f"`{t}` {version(exe)}" for t, exe in TOOLS.items())
|
| 100 |
+
+ f"; old-format CUDA ELF goes to `nvdisasm` {version(LEGACY_NVDISASM)}).")
|
| 101 |
with gr.Row(equal_height=True):
|
| 102 |
with gr.Column(scale=1):
|
| 103 |
file = gr.File(label="cubin / fatbin / CUDA ELF", type="filepath")
|