In theory, debugging of the compiler is exactly the same as any other program (just like marcov already said). My experience is that in practice you need to know what behaviour you want to debug (e.g. procedure overload selection) and where to find it in the source to put a break point in approximately the right place. Just stepping through the compiler from the start hoping to find something specific requires an enormous amount of time and patience.
An easier situation is when you want to investigate what goes wrong when the compiler spits out an internal error code - in this case search for the error code in the source folder (I use rgrep a lot on Linux), then place a break point on the
internalerror call and look at the stack trace to see the call history leading up to this point.
Another situation could be when you want to analyze the compiler code that leads to an error/warning. In this case search for the error/warning code (or a short text snippet of the message) in the compiler/msg folder. The English messages will be in the errore.msg file. Locate the constant name of message (first part of message before "=") and search for this constant in the compiler source.
When using one of the existing ppcX.lpi projects in Lazarus, an executable called pp will be created in the target specific folder (X= target CPU). This executable can be used just like a normal compiler to perform simple testing with. You can also recompile the RTL using this compiler, it saves the time to bootstrap the new compiler (if you are working on the 64 bit version of the compiler):
make rtl PP=compiler/x86_64/pp
Just some random thoughts from my side. Please ask if there is anything more specific you would like to investigate.