DF-5725 / fix.diff
--- a/sys/ddb/db_break.c 2026-06-29 12:51:18.000000000 +0000 +++ b/sys/ddb/db_break.c 2026-10-10 18:39:43.915899474 +0000 @@ -88,12 +88,26 @@ db_set_breakpoint(vm_map_t map, db_addr_t addr, int count) { db_breakpoint_t bkpt; + int inst; if (db_find_breakpoint(map, addr)) { db_printf("Already set.\n"); return; } + /* + * Save the original instruction byte NOW, at breakpoint-set time, + * while the console can still react to a bad address. If we + * defer the read to db_set_breakpoints() (resume time), a fault + * on one bad breakpoint aborts the whole insert pass mid-list + * via the DDB trap path: breakpoints earlier in the list stay + * patched with INT3 while db_breakpoints_inserted remains FALSE, + * and the next insert pass re-reads the patched INT3 byte as the + * "original" instruction, permanently corrupting kernel text + * when the breakpoint is later cleared. + */ + inst = db_get_value(addr, BKPT_SIZE, FALSE); + bkpt = db_breakpoint_alloc(); if (bkpt == 0) { db_printf("Too many breakpoints.\n"); @@ -105,6 +119,7 @@ bkpt->flags = 0; bkpt->init_count = count; bkpt->count = count; + bkpt->bkpt_inst = inst; bkpt->link = db_breakpoint_list; db_breakpoint_list = bkpt; @@ -168,9 +183,6 @@ bkpt != 0; bkpt = bkpt->link) if (db_map_current(bkpt->map)) { - bkpt->bkpt_inst = db_get_value(bkpt->address, - BKPT_SIZE, - FALSE); db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); |