I do not think debugging with serial or GPIO is slow.
So you suspect that register A doesn't have the right value. So you write a piece of code to print it on the serial window.
While the code is running, you suddenly realize that maybe the real problem is register B. What do you do then? You stop it and add a line to print register A.
With a debugger, you simply walk over to that register and read its value.
Cases like that are plenty.
Now, that's not to say that serial prints have no value - it allows (near) real time reporting which a hardware debugger doesn't do, until recently: swo, RTT and j-scope and the latest st-link v2-1 with integrated virtual comm ports for example are examples where debuggers are integrating some form of real-time reporting capabilities.
I agree there is no substitute for a good debugger for looking at registers or even the state of your code. But even then you have to be careful. A trap for young players I think is the term.
Just because you can read a register doesn't mean the value is the same as when the fault occured.
Example 1 Interrupt control registers.
Sometimnes reading them clears the flags so make sure what you are looking at is the first read and not the second.
printf or similar is good to avoid this one.
Example 2 Registers that do different things on reading to what they do on writes.
I currently have to use a register that returns chip status on read but sets up internal timing on a write.
As a result even though I own an electric drill in the form of a high end JTAG debugger I still use all of the hand drill tools,
including printf, stuffing individual bytes straight out of a UART, waggling IO pins, and even an on board software trace in the form a a quick and dirty array and index mechanism.
Basically what ever fits the problem at hand.