The reason INT 3 is used is that it's the only interrupt that has a single byte opcode (0xCC). Other interrupts require two bytes: CD <interupt number>.
This makes setting a breakpoint really easy, as all you have to do is replace a single byte (and restore a single byte) where you want to place your breakpoint.
INT 3 being only one byte is also important when you're setting a breakpoint instead of a another single byte instruction - your newly set breakpoint won't override the consecutive instruction, which might be jumped to somewhere else in the code.
> The reason INT 3 is used is that it's the only interrupt that has a single byte opcode (0xCC). Other interrupts require two bytes: CD <interupt number>.
It's kind of the other way around. The reason it has a single byte opcode is because Intel wanted INT3 to be for break points, so they designated 0xCC for it. In fact, 0xCD 0x03 works, but just isn't used.
Because x86 instructions can cross 4/8/16 byte alignment boundaries, you can't safely set a multi-byte breakpoint in all cases. CPU might execute (bytes [0xCD, x] -> int x) instruction before the parameter becomes visible and trigger some other exception, whatever happened to be at that address before.
I agree with the first part, it's kind of a self reinforcing decision.
Intel wanted INT 3 to be for break points so they gave it a single byte instruction, and because INT 3 is a single byte instruction - it's the only one that makes sense for debug breakpoints.
Lets say you have a lot of single byte opcodes:
40 INC EAX
43 INC EBX
41 INC ECX
C3 RET
And you want to set a breakpoint on INC EAX.
If you replace "40" with "CD03" - you'll overwrite INC EBX as well.
That can cause your program to crash if there are control flows that end up jumping to INC EBX without going through INC EAX first.
One-byte opcodes won't save you when the code is jumping into the middle of instructions. The instruction you want to breakpoint might be in the middle of some other instruction that will run.
This makes setting a breakpoint really easy, as all you have to do is replace a single byte (and restore a single byte) where you want to place your breakpoint. INT 3 being only one byte is also important when you're setting a breakpoint instead of a another single byte instruction - your newly set breakpoint won't override the consecutive instruction, which might be jumped to somewhere else in the code.