| name | debugger |
| description | IDA debugger operations. Use when asked to set breakpoints, patch bytes, add conditions, or manage a patch inventory. |
| allowed-tools | ["Bash","Read","Glob","Grep"] |
Trigger Intents
Use this skill when user asks to:
- add/remove/modify breakpoints
- patch bytes or revert patches
- create patch inventories and debugging action plans
- instrument analysis-driven break/watch workflows
Route to:
analysis/xrefs for selecting meaningful targets first
disassembly for opcode-level patch context
annotations for documenting patch rationale and outcomes
Do This First (Warm-Start Sequence)
SELECT printf('0x%X', addr) AS addr, type_name, enabled
FROM breakpoints
ORDER BY addr;
SELECT printf('0x%X', addr) AS addr, original_value, value AS patched_value
FROM bytes WHERE is_patched = 1
ORDER BY addr
LIMIT 50;
SELECT addr, value, original_value, is_patched
FROM bytes
WHERE addr = 0x401000;
Interpretation guidance:
- Confirm existing instrumentation before adding more.
- Always snapshot current/original byte state before mutating.
Failure and Recovery
- Breakpoint insert/update failed:
- Validate address existence and hardware size/type compatibility.
- Patch verification mismatch:
- Re-read
bytes (and WHERE is_patched = 1), then retry with precise address.
- Unintended patch side effects:
- Revert with
DELETE FROM bytes WHERE addr = ... and reassess target instruction context.
Handoff Patterns
debugger -> disassembly to validate instruction semantics around patch site.
debugger -> xrefs to assess blast radius of patched/broken call paths.
debugger -> annotations to leave durable analyst breadcrumbs.
breakpoints
Debugger breakpoints. Supports full CRUD (SELECT, INSERT, UPDATE, DELETE). Breakpoints persist in the IDB even without an active debugger session. folder_path is the folder-oriented spelling of IDA's breakpoint group; updating either updates the same underlying breakpoint grouping.
| Column | Type | RW | Description |
|---|
addr | INT | R | Breakpoint address |
enabled | INT | RW | 1=enabled, 0=disabled |
type | INT | RW | Breakpoint type (1=hw_write, 2=hw_read, 3=hw_rdwr, 4=software, 8=hw_exec) |
type_name | TEXT | R | Type name (software, hardware_write, etc.) |
size | INT | RW | Breakpoint size (for hardware breakpoints) |
flags | INT | RW | Breakpoint flags |
pass_count | INT | RW | Pass count before trigger |
condition | TEXT | RW | Condition expression |
loc_type | INT | R | Location type code |
loc_type_name | TEXT | R | Location type (absolute, relative, symbolic, source) |
module | TEXT | R | Module path (relative breakpoints) |
symbol | TEXT | R | Symbol name (symbolic breakpoints) |
offset | INT | R | Offset (relative/symbolic) |
source_file | TEXT | R | Source file (source breakpoints) |
source_line | INT | R | Source line number |
is_hardware | INT | R | 1=hardware breakpoint |
is_active | INT | R | 1=currently active |
group | TEXT | RW | Breakpoint group name |
bptid | INT | R | Breakpoint ID |
folder_path | TEXT | RW | Alias for breakpoint group folder; NULL means root |
full_path | TEXT | R | Full breakpoint dirtree path when available |
SELECT printf('0x%08X', addr) as addr, type_name, enabled, condition
FROM breakpoints;
INSERT INTO breakpoints (addr) VALUES (0x401000);
INSERT INTO breakpoints (addr, type, size) VALUES (0x402000, 1, 4);
INSERT INTO breakpoints (addr, condition) VALUES (0x401330, 'eax == 0');
UPDATE breakpoints SET folder_path = 'idasql/breakpoints/network' WHERE addr = 0x401000;
UPDATE breakpoints SET folder_path = NULL WHERE addr = 0x401000;
UPDATE breakpoints SET enabled = 0 WHERE addr = 0x401000;
DELETE FROM breakpoints WHERE addr = 0x401000;
SELECT b.addr, f.name, b.type_name, b.enabled
FROM breakpoints b
JOIN funcs f ON b.addr >= f.addr AND b.addr < f.end_addr;
bytes (Byte Patching)
Pure mapped-byte program view with patch support. This table is one row per
mapped byte address; IDA item metadata such as size/type belongs to heads.
| Column | Type | RW | Description |
|---|
addr | INT | R | Byte address |
value | INT | RW | Current byte value (UPDATE patches 1 byte) |
word | INT | RW | 2-byte little-endian value (UPDATE patches 2 bytes) |
dword | INT | RW | 4-byte little-endian value (UPDATE patches 4 bytes) |
qword | INT | RW | 8-byte little-endian value (UPDATE patches 8 bytes) |
original_value | INT | R | Original byte value before patch |
is_patched | INT | R | 1 if byte differs from original (WHERE is_patched = 1 enumerates patches fast) |
fpos | INT | R | Physical/input file offset (NULL when unavailable) |
Revert a patch with DELETE FROM bytes WHERE addr = ... (or WHERE is_patched = 1).
SELECT addr, value, original_value, is_patched
FROM bytes WHERE addr = 0x401000;
SELECT addr, value
FROM bytes
WHERE addr >= 0x401000 AND addr < 0x401010
ORDER BY addr;
SELECT addr, size, type, flags, disasm
FROM heads
WHERE addr = 0x401000;
UPDATE bytes SET value = 0x90 WHERE addr = 0x401000;
UPDATE bytes SET dword = 0x90909090 WHERE addr = 0x401000;
SELECT printf('0x%X', addr) AS addr, original_value, value AS patched_value
FROM bytes WHERE is_patched = 1 ORDER BY addr LIMIT 20;
SELECT save_database();
bytes — Patching (write surface)
All byte patching is done through the writable bytes table.
| Column | RW | Meaning |
|---|
value | RW | Current byte; UPDATE patches 1 byte |
word / dword / qword | RW | UPDATE patches 2/4/8 bytes little-endian |
original_value | R | Original (pre-patch) byte |
is_patched | R | 1 if patched; WHERE is_patched = 1 enumerates patches fast |
SELECT printf('0x%X', addr) AS addr,
printf('0x%02X', original_value) AS old,
printf('0x%02X', value) AS new
FROM bytes WHERE is_patched = 1
ORDER BY addr;
Byte Access via the bytes Table
All byte reads and patches go through the bytes table. Bounded-read
shapes are documented in data; this skill focuses on the patching
workflow. load_file_bytes(...) writes a file's bytes into the IDB at
a given range; use it when the patch content already lives in a file.
| Function / Shape | Description |
|---|
SELECT hex(blob_concat(value)) FROM (SELECT value FROM bytes WHERE start_addr = X AND n = N ORDER BY addr) | Read N bytes as uppercase hex |
SELECT blob_concat(value) FROM (SELECT value FROM bytes WHERE start_addr = X AND n = N ORDER BY addr) | Read N bytes as BLOB |
load_file_bytes(path, file_offset, addr, size[, patchable]) | Write a file's bytes into the IDB at the target range |
SELECT hex(blob_concat(value))
FROM (SELECT value FROM bytes WHERE start_addr = 0x401000 AND n = 16 ORDER BY addr);
UPDATE bytes SET value = 0x90 WHERE addr = 0x401000;
UPDATE bytes SET dword = 0x90909090 WHERE addr = 0x401000;
SELECT value AS current, original_value AS original
FROM bytes WHERE addr = 0x401000;
DELETE FROM bytes WHERE addr = 0x401000;
DELETE FROM bytes WHERE is_patched = 1;
SELECT save_database();
Analysis-Driven Breakpoint Workflows
Set breakpoints on all callers of a security-sensitive API
Use disasm_calls to find every call site and batch-insert breakpoints:
INSERT INTO breakpoints (addr)
SELECT addr FROM disasm_calls WHERE callee_name LIKE '%VirtualAlloc%';
SELECT printf('0x%08X', addr) AS addr, type_name, enabled
FROM breakpoints;
Watchpoints on struct fields discovered via type analysis
After recovering a struct, set hardware watchpoints on specific field offsets:
INSERT INTO breakpoints (addr, type, size) VALUES (0x402010, 1, 4);
Conditional breakpoints from decompiler analysis
Set breakpoints that only trigger when specific conditions are met:
INSERT INTO breakpoints (addr, condition)
VALUES (0x401000, 'rcx == 3');
INSERT INTO breakpoints (addr, condition)
VALUES (0x401050, 'rax == 0xFFFFFFFF');
Patching Workflows
NOP out anti-debug checks
Find and neutralize IsDebuggerPresent checks:
SELECT dc.addr, (SELECT name FROM funcs WHERE dc.func_addr >= addr AND dc.func_addr < end_addr LIMIT 1) AS func_name,
disasm_at(dc.addr, 2) AS context
FROM disasm_calls dc
WHERE dc.callee_name LIKE '%IsDebuggerPresent%';
SELECT disasm_at(0x401030, 3);
UPDATE bytes SET value = 0x90 WHERE addr = 0x401035;
UPDATE bytes SET value = 0x90 WHERE addr = 0x401036;
Inventory all patches and generate report
SELECT printf('0x%X', addr) AS addr,
(SELECT name FROM funcs WHERE addr >= addr AND addr < end_addr LIMIT 1) AS func_name,
printf('0x%02X', original_value) AS original,
printf('0x%02X', value) AS patched,
disasm_at(addr) AS context
FROM bytes WHERE is_patched = 1
ORDER BY addr;
Performance Notes
| Table | Size | Constraint | Notes |
|---|
breakpoints | Small (<100 typical) | none needed | Always fast |
bytes | All mapped bytes | addr | Critical — constrain to one address or a tight range |
bytes WHERE is_patched = 1 | Small (patch count) | is_patched = 1 | Fast — iterates only patched locations via IDA's patch list |
breakpoints table is small — full scans are fine.
bytes table emits one row per mapped byte. Use WHERE addr = X or a tight addr range.
bytes WHERE is_patched = 1 iterates only patched locations — always fast.
See Also
disassembly — instruction context around a patch site (disasm_at, operand semantics).
annotations — record patch rationale via comments/bookmarks before mutating.
data — canonical owner of byte-read shapes (table vs. scalar disambiguation).