{"record":{"id":"72fb123adb4812a8","repo":"NationalSecurityAgency/ghidra","slug":"must-save-breakpoint-to-program-before-naming-it","errorCode":null,"errorMessage":"Must save breakpoint to program before naming it","messagePattern":"Must save breakpoint to program before naming it","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/ProgramBreakpoint.java","lineNumber":248,"sourceCode":"\n\t/**\n\t * Get the user-defined name of the breakpoint\n\t * \n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\t/**\n\t * Set the name of the breakpoint\n\t * \n\t * @param name the name\n\t */\n\tpublic void setName(String name) {\n\t\tBookmark bookmark = getBookmark();\n\t\tif (bookmark == null) {\n\t\t\tthrow new IllegalStateException(\"Must save breakpoint to program before naming it\");\n\t\t}\n\t\tthis.name = name;\n\t\twriteProperties(bookmark);\n\t}\n\n\t/**\n\t * Get the sleigh injection for this breakpoint\n\t * \n\t * @return the sleigh injection\n\t */\n\tpublic String getEmuSleigh() {\n\t\treturn sleigh;\n\t}\n\n\t/***\n\t * Set the sleigh injection for this breakpoint\n\t * \n\t * @param sleigh the sleigh injection","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/ProgramBreakpoint.java#L230-L266","documentation":"ProgramBreakpoint stores its extrinsic properties (name, sleigh) inside the comment of a program Bookmark (the enabled or disabled bookmark). setName() calls getBookmark() and refuses to proceed when no bookmark exists, because there is nowhere to persist the name. A ProgramBreakpoint only has a backing bookmark once it has been written/saved into the program (i.e. toggled to an enabled or disabled state that creates the bookmark).","triggerScenarios":"Constructing a ProgramBreakpoint via new ProgramBreakpoint(program, address, length, kinds) and immediately calling setName(...) before ever creating a bookmark. Calling setName on a breakpoint whose bookmark was deleted (absent state). The check is getBookmark() == null -> throw IllegalStateException.","commonSituations":"Programmatic breakpoint management scripts that build a ProgramBreakpoint and try to label it without first enabling it. UI flows that rename a breakpoint that the user disabled-to-absent. Tests that construct breakpoints directly bypassing the bookmark creation path.","solutions":["Persist the breakpoint into the program first (set it to an enabled or disabled mode so getBookmark() returns a bookmark) before calling setName.","Guard setName with a null check on getBookmark(); if absent, create the bookmark via the breakpoint service or skip naming.","Use the logical breakpoint service APIs (DebuggerLogicalBreakpointServicePlugin) which create bookmarks and set names in the correct order.","If the bookmark was deleted, re-create the breakpoint before renaming."],"exampleFix":"// before\nProgramBreakpoint brk = new ProgramBreakpoint(program, addr, 1, kinds);\nbrk.setName(\"foo\"); // throws: no bookmark yet\n\n// after\nProgramBreakpoint brk = new ProgramBreakpoint(program, addr, 1, kinds);\n// write the breakpoint into the program so a bookmark exists first\nbrk.writeEnabled(...); // or use the breakpoint service to persist it\nif (brk.getBookmark() != null) {\n    brk.setName(\"foo\");\n}","handlingStrategy":"validation","validationCode":"// Run before setName(...)\npublic static boolean canName(ProgramBreakpoint brk) {\n    return brk.getBookmark() != null;\n}\n// usage:\nif (canName(brk)) {\n    brk.setName(name);\n} else {\n    // persist/enable the breakpoint first, then name it\n}","typeGuard":"// ProgramBreakpoint is not parameterized; guard on bookmark presence\npublic static boolean hasBackingBookmark(ProgramBreakpoint brk) {\n    return brk != null && brk.getBookmark() != null;\n}","tryCatchPattern":"try {\n    brk.setName(name);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Must save breakpoint\")) {\n        // persist breakpoint (enable/disable) to create bookmark, then retry setName\n    } else throw e;\n}","preventionTips":["Always persist a ProgramBreakpoint into the program (create its bookmark) before setting extrinsic properties like name/sleigh.","Prefer the logical breakpoint service which orders bookmark creation and property writes correctly.","In tests/UI flows, check getBookmark() before exposing rename actions."],"tags":["breakpoint","state-machine","ghidra-debugger","precondition"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}