What do CPUs do when a program aborts with an error?
CPUs don't have a notion of “program aborting”. Some CPUs have features that help operating system manage separate programs, but the concept of separate programs exists primarily at the level of the operating system.

The specification of the CPU specifies what happens for each instruction for all data. For example, it might specify that div r1, r2, r3 divides the integer value stored in r2 by the integer value stored in r3, stores the result into r1, and then moves the instruction pointer to the next instruction. It might furthermore specify that in case r2 is zero, the CPU executes a trap — this is what most CPUs do on a division by zero. Typically, on a trap:


The CPU saves the current value of the program counter into a register assigned to this purpose.
The CPU sets the reason for the trap (a constant that means “division by zero”) into a register assigned to this purpose.
The CPU reads an address from somewhere and sets the program counter to this address. This address is called the trap vector. This “somewhere” is usually either a register, or a memory location which is calculated from a value in a register.
The CPU switches to a privileged mode (e.g. kernel mode, ring 0).


(Note that details vary from CPU to CPU, I am only describing typical behavior.) Traps are very similar to interrupts; the difference is that a trap is due to an event happening in the CPU whereas interrupts are triggered by external events.

The operating system decides what happens when a trap occurs by providing some code and setting the trap vector to its address. The trap handling code typically analyses the reason for the trap and decides what to do, which may or may not include terminating the current process. For example, some operating systems allow application code to react to trap (e.g. with signal handlers on Unix) — then the kernel's trap handler looks up the address of the application trap handler in some internal kernel data structure and jumps to that after setting the processor in the appropriate mode.

An example of a trap which often doesn't result in the death of the application is a memory fault, when the application tries to access a virtual address which is not mapped in the MMU. On operating systems that implement swap, the trap handler looks up the virtual address to see if there is actually data that is mapped there in the application but that is currently swapped out to disk. If that is the case, the trap handler loads the content of the page from disk and updates its memory management data structures. Then it jumps back to the application, arranging to cause the application to execute the memory access instruction again. This time the instruction will succeed, and the application is unaware that the first attempt fails (except via some indirect means such as timing).

If the trap handler decides to terminate the program, it does so in pretty much the same way as if the program had called the exit system call: it frees the resources allocated to the process, then invokes the scheduler to execute whatever other threads have something to do.