Printing a string is luxury! When I was working on a Linux port to the Treo 650 ages ago, I had a single bit of output: an LED that I could turn on or off at certain parts of the boot sequence. That was good enough to get me to the point where the LCD could be initialized and I could do proper screen logging.
I've done this for a handful of other projects as well. My first step is always locating a processor GPIO that controls something obvious (camera flash, status LED, etc) that I can use to figure out where I am in the boot process.
One bit/pin can be more than enough if you can code some state behind it. On one embedded MCU job, I ended up with just one port pin free. I tied it to a piezo-oscillator and played short Morse strings through it; that was my printf. (It helps that I'm a ham, so I could head-copy those messages.)
Once I turned it over to production use, the techs found the difference in overall sound between "OK" and an error message useful enough that they kept it jumper-enabled. They did put tape over the oscillator's opening to cut down the amplitude, though.
Luxury. We used to _dream_ of printf debugging when we're doing embedded microcontroller systems! (at least the ones I work on).
There the debugging is toggling a port pin and examining with an oscilloscope. I typically toggle it different numbers of times at different places in the code to see where I've got to.
I grew fond of printing a char, after I spent some time snooping a uart. The o-scope in capture mode (I realize this wasn't always an option) grabs the char. Handy because I find char waveforms very easy to recognize at just a glance, and you don't have to measure periodicity or count toggles.
Even if you don't have a uart, you can write a little proc to bit-bang a pin.
When developing for microcontrollers and for example my leds aren't working, I like to define a place in memory where I write values to depending on the place in code. Then just read out that memory address with OpenOCD (jtag of swd).
I love ARM semihosting for this reason. It's obviously insanely slow, but unlike a UART it doesn't need any extra hardware and the target is halted while the slow bit is taking place.
I was once porting my OS to a new platform, and hadn't got the screen to work yet. What I did get to work was the screen's backlight, so I would have it blink to show debugging info. It was a huge pain in the ass.
I once had a university project where we were implementing low-level threading for a custom OS, and had some task manipulating the signal handlers. Needless to say, we ran in to a few issues with the code we wrote. At that time, I was pretty much a print-line debugger (still mostly am).
I failed that assignment, but in the process learned how to use gdb. I still do wish I had seen this post back* then though, just for the marks.
*Disc: I'm not knowledgeable enough to know 100% this would have helped
Apparently simply panning around that blog (while zoomed in on mobile) is a luxury, because it seems to send you to different blog entries when you do it.
Not as obnoxious as - on iOS - having my browser's focus stolen by an appstore link which switches me from browser to App Store.
This is particularly bad when visiting Pinterest. So bad that I stopped visiting Pinterest at all because I hate the behaviour. It is so obviously broken that I'm surprised they still do it.
A game that is popular at my school has these modal ads with a close button that is smaller than you can accurately tap. Every third time it opens I end up in the App Store. It drives me nuts. A confirmation would be nice.
My first commercial 8-bit games (Sinclair Spectrum and Amstrad CPC) were developed entirely with border color as the only debugging tool. Figuring out a particular stack corruption bug was a miracle, and there was at least another bug that went unfixed (just changed the level map and it stopped happening). Those were the days ahem.
I've done this for a handful of other projects as well. My first step is always locating a processor GPIO that controls something obvious (camera flash, status LED, etc) that I can use to figure out where I am in the boot process.