import ghidra.app.script.GhidraScript; import ghidra.program.model.address.Address; import ghidra.program.model.listing.BookmarkManager; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; public class ImportMarkersAsBookmarks extends GhidraScript { @Override public void run() throws Exception { // Can't do this in headless mode // File input = askFile("Select CSV file", "Import"); String[] args = getScriptArgs(); if (args.length < 1) { throw new IllegalArgumentException( "Missing CSV file path.\nUsage: ImportMarkersAsBookmarks "); } File input = new File(args[0]); if (!input.isFile()) { throw new IllegalArgumentException( "CSV file does not exist or is not a regular file: " + input.getAbsolutePath()); } println("Importing bookmarks from: " + input.getAbsolutePath()); // https://ghidra.re/ghidra_docs/api/ghidra/program/model/listing/BookmarkManager.html BookmarkManager bm = currentProgram.getBookmarkManager(); int imported = 0; int skipped = 0; int lineNo = 0; // CSV columns: (benchmark, resulttype, faults, fault_address) // Example: (ip , OK_MARKER , 4311 , 0x10001B ) try (BufferedReader br = new BufferedReader(new FileReader(input))) { String line; while ((line = br.readLine()) != null) { lineNo++; line = line.trim(); if (line.isEmpty() || line.startsWith("#") || line.startsWith("benchmark")) { continue; } // Make sure to always use "," delimiter and never quotations String[] parts = line.split(","); if (parts.length != 4) { skipped++; printerr("Line " + lineNo + ": malformed"); continue; } String benchText = parts[0].trim(); String typeText = parts[1].trim(); String countText = parts[2].trim(); String addrText = parts[3].trim(); if (benchText.isEmpty() || typeText.isEmpty() || countText.isEmpty() || addrText.isEmpty()) { skipped++; printerr("Line " + lineNo + ": malformed"); continue; } Address addr = parseAddress(addrText); if (addr == null) { skipped++; printerr("Line " + lineNo + ": invalid address: " + addrText); continue; } println( "Adding bookmark at " + addr + " with type " + benchText + " with category " + benchText // ip, mem or regs + " - " + typeText + " description " + countText + "x"); // TYPE CATEGORY DESCRIPTION bm.setBookmark(addr, benchText, benchText + " - " + typeText, countText + "x"); imported++; } } println("Imported " + imported + " bookmarks."); if (skipped > 0) { println("Skipped " + skipped + " lines."); } } public Address parseAddress(String text) { text = text.trim(); if (text.startsWith("0x") || text.startsWith("0X")) { text = text.substring(2); } try { return toAddr(text); } catch (Exception e) { return null; } } }