// CSV format per line: // 0x401000, // // Creates NOTE bookmarks in category: FAIL_MARKER 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 { private static final String BOOKMARK_TYPE = "NOTE"; private static final String BOOKMARK_CATEGORY = "FAIL_MARKER"; @Override public void run() throws Exception { File input = askFile("Select CSV file", "Import"); BookmarkManager bm = currentProgram.getBookmarkManager(); int imported = 0; int skipped = 0; int lineNo = 0; try (BufferedReader br = new BufferedReader(new FileReader(input))) { String line; while ((line = br.readLine()) != null) { lineNo++; if (monitor.isCancelled()) { println("Cancelled."); break; } line = line.trim(); if (line.isEmpty() || line.startsWith("#")) { continue; } String[] parts = splitCsvLine(line); if (parts.length < 1) { skipped++; printerr("Line " + lineNo + ": missing address"); continue; } String addrText = parts[0].trim(); String description = parts.length >= 2 ? parts[1].trim() : ""; if (addrText.isEmpty()) { skipped++; printerr("Line " + lineNo + ": empty address"); continue; } Address addr = parseAddress(addrText); if (addr == null) { skipped++; printerr("Line " + lineNo + ": invalid address: " + addrText); continue; } println("Adding bookmark at " + addr + " with description " + description); bm.setBookmark(addr, BOOKMARK_TYPE, BOOKMARK_CATEGORY, description); imported++; } } println("Imported " + imported + " bookmarks."); if (skipped > 0) { println("Skipped " + skipped + " lines."); } } public Address parseAddress(String text) { text = text.trim(); if (text.startsWith("\"") && text.endsWith("\"") && text.length() >= 2) { text = text.substring(1, text.length() - 1).trim(); } if (text.startsWith("0x") || text.startsWith("0X")) { text = text.substring(2); } try { return toAddr(text); } catch (Exception e) { return null; } } private String[] splitCsvLine(String line) { java.util.ArrayList fields = new java.util.ArrayList<>(); StringBuilder current = new StringBuilder(); boolean inQuotes = false; for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (c == '"') { if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') { current.append('"'); i++; } else { inQuotes = !inQuotes; } } else if (c == ',' && !inQuotes) { fields.add(current.toString()); current.setLength(0); } else { current.append(c); } } fields.add(current.toString()); return fields.toArray(new String[0]); } }