A hardware debugger is no substitute for having good high-level debugging tools in your embedded device. Including printf().
High level debugging tools are no substitute for having a hardware debugger available, when you really need the latter.
Some of this depends on how much capability your hardware debugger has beyond that available via SW debugging. Accessing a 68k or x86 class machine via a software gdb stub, over serial, over a network, is frequently not much worse than accessing a machine via a gdb bridge to a hardware debugger. But other machines make a good software debug stub nearly impossibles, and newer chips have debugging capabilities that may not be available via "one-size-fits-all" debugging abstractions. (OTOH, such advanced features tend to be available to software debugging tools as well.)
A lot of serious debugging is done by instrumenting your software with additional software, and distilling events into human-readable form (whether that's a pin toggle, printf, or something else.) Conventional non-intrusive debugging, via either hardware or software, isn't close enough to 'real time' to be adequate.