Brian W. Kernighan and Rob Pike wrote that stepping through a program less productive than thinking harder and adding output statements and self-checking code at critical places. Kernighan once wrote that the most effective debugging tool is still careful thought, coupled with judiciously placed print statements.
Just because two famous people didn't like step-debugging doesn't mean that there shouldn't be proper debugging tools beyond printf() ;) We need to be careful not falling into the cargo-culting trap (same as "Goto considered harmful").
But then again, Kernighan, Pike and Dijkstra became famous because of merit and not because of whatever made Kim Kardashian famous. So it seems reasonable to at least entertain the ideas people like them put forward, instead of dismissing the ideas outright, or dismissing the idea after only the most superficial thinking.
Dijkstra make an argument that proper control structures (if-then-else blocks, for-while loops) are better than simulating those with goto. Not that every last use of goto was bad. And if you look at what code looks like these days, seems he was right, or at least most people thought he was. People do not use goto anymore, except for a tiny set of special use cases where it makes sense. E.g. jumping into the "cleanup" end of a function in C, because there is no better way in C to do it, really (no RAII, no python-style with/C# style using, no go-style defer). But you'll hard pressed to find good code, or any code really, that uses goto to implement looping when there are language level loop structures available.
The idea here is not that "all and every use of side-stepping debuggers is considered harmful", and not even "just sprinkle some printf()", but to use a combination of good self-checking design (aka defensive programming) that allows to sprinkle printfs()/tracepoints/breakpoints at interesting places instead of blindly stepping through huge blobs of code in a debugger.
I like to do that myself, add some error checks and some "output" and it usually works great and is very productive, and having the additional error checks is useful not just then but also in the future... But when it does not work out (legacy code, code other people wrote and I am unfamiliar with) then a step debugger might be a viable alternative especially if the other remaining alternative is "nothing/ask magic eight ball".