You've got the process figured out :)
Reason through the code. Sometimes, reason through the output assembler (in case the C code is making invalid assumptions). Stare at oscilloscope traces. Think really hard about what's happening, come up with a hypothesis, and test that hypothesis.
The hypothesis testing part is key. I've worked with embedded developers who "fix" a bug by making a code change, but can't at all explain why the change is likely to fix the bug. In many cases, the reason it seems to fix the bug is that it changes the timing just enough so that the bug happens less frequently, but without having a really solid causal explanation, it likely just means that it's going to be even harder to find the bug when it pops back up again.