This bug cost me a couple of days a few years ago: a pointer bug caused the interrupt table to be modified, leading to a crash some time later, when the interrupt happened. (On ARMv5, the interrupt table is at address 0, so dereferencing a NULL pointer is legal, and puts you there.) That sort of problem is hard to find if you don't suspect it, because the program will crash at a random location (and usually always in the same place, if the timing remains the same), but that location has nothing to do with the actual bug. Plus, when you start debugging, the location will move. When you single step, the bug disappears altogether. It's a classical heisenbug.
After having finally found and fixed the problem, I felt motivated enough to read up on the ARM MMU unit and and figure out how to write-protect most of the address space. It cost me another two days to get that working because the docs were rather sparse, but I felt that eliminating a whole class of bugs was worth it.
Not strictly a bug, but painful nontheless: quite some time ago I was developing a custom printer driver for our application that would talk directly to the hardware. Apparently, the printer manufacturer wasn't a fan of error reporting. If you sent the printer invalid data, it would simply blink it's red LED 3 times and do nothing else. After pouring over a lot of hexdumps, and some guesswork, I did get it working in the end, so yay. But it's not a great feeling if you don't know whether you're 5 minutes or 5 days away from solving your problem.