summaryrefslogtreecommitdiffstats
path: root/userspace/cuda/tools/ghidra/ApplyNameMap.java
blob: b8be68ffa01faf0ad06b1a1b64141aec88cf482a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// SPDX-License-Identifier: BSD-3-Clause
//
// ApplyNameMap.java - Ghidra post-script: apply a symbol name map to a
// program. This is the version-transfer hook of the Open-IOV CUDA tooling:
// once a name map exists for version N (derived from public documentation,
// decompiled behaviour or an earlier version), it can be applied to version
// N+1 in seconds, so analysis effort accumulates instead of restarting.
//
// Input format (TSV, no header required):
//   <hex-addr> <name> [<optional namespace>]
// Lines starting with '#' and empty lines are ignored. Addresses are file
// virtual addresses ("libcuda+0x..."), not Ghidra image-base offsets.
//
// Usage (analyzeHeadless):
//   -process <program> -noanalysis \
//     -postScript ApplyNameMap.java <namemap.tsv> [--dry-run]
//
// The script prints how many names were applied, and leaves a
// "cuda-names-applied" user property on the program with the map path and
// count so a later session can see it happened.

import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.symbol.SourceType;

import java.io.BufferedReader;
import java.io.FileReader;

public class ApplyNameMap extends GhidraScript {

    @Override
    public void run() throws Exception {
        String[] args = getScriptArgs();
        if (args.length < 1) {
            println("usage: ApplyNameMap.java <namemap.tsv> [--dry-run]");
            return;
        }
        boolean dryRun = args.length > 1 && args[1].equals("--dry-run");
        Listing listing = currentProgram.getListing();
        long imageBase = currentProgram.getImageBase().getOffset();
        int applied = 0, missing = 0, lines = 0;

        try (BufferedReader r = new BufferedReader(new FileReader(args[0]))) {
            String line;
            while ((line = r.readLine()) != null && !monitor.isCancelled()) {
                line = line.trim();
                if (line.isEmpty() || line.startsWith("#")) continue;
                lines++;
                String[] parts = line.split("[ \t]+");
                if (parts.length < 2) continue;
                long addr;
                try {
                    addr = Long.parseUnsignedLong(parts[0].replaceFirst("^0x", ""), 16);
                } catch (NumberFormatException e) {
                    continue;
                }
                String name = parts[1];
                // Map keys are file virtual addresses (libcuda+0x...).
                Address a = toAddr(addr + imageBase);
                Function f = listing.getFunctionAt(a);
                if (f == null) {
                    missing++;
                    continue;
                }
                if (!dryRun) {
                    try {
                        f.setName(name, SourceType.USER_DEFINED);
                    } catch (Exception e) {
                        println("  cannot rename 0x" + Long.toHexString(addr)
                                + " -> " + name + ": " + e.getMessage());
                        continue;
                    }
                }
                applied++;
            }
        }
        if (!dryRun) {
            currentProgram.getOptions("OpenIOV")
                    .setString("cuda-names-applied", args[0] + " (" + applied + " names)");
        }
        println(String.format("[ApplyNameMap] lines=%d applied=%s missing=%d%s",
                lines, String.valueOf(applied), missing, dryRun ? " (dry run)" : ""));
    }
}