I am sure it has been written about elsewhere, but here is the way in which I have been debugging timer jobs.
Add the PDB File to the GAC
The PDB file needs to be in the GAC for debugging in Visual Studio. You can add this file through a feature manifest file, but you are unlikely to want to deploy the PDB to the GAC on your production server, so a better way on the dev server is to directly place files in the GAC. To do this, map a drive in windows explorer to
\\[your server name]\c$\windows\assembly
This bypasses the windows explorer shell special handling for this folder, and allows you to copy and paste files as normal without using GACUTIL.
In the GAC_MSIL subfolder, find the subfolder corresponding to the name of your assembly. Below there will be one or more version subfolders. Find the latests version subfolder., and copy your timer job dll and pdb file (built in debug mode!) to this folder.
If this copy action is denied, open the Services administrative tool, and STOP the Windows SharePoint Services Timer service. Apply an IISRESET from the command line, and then attempt to copy the files again - resetting those two services should remove the lock on the dll. After copying the files, make sure to restart the SharePoint Timer service!
I did have one occasion where the Timer Service "hung" whilst attempting to restart. I found that ending OWSTIMER in the Windows Task Manager cleared this hiccup.
Debugging In Visual Studio
Set a breakpoint in your timer job code, and then open the "Attach to Process" dialog from the Debug menu. Check the box at the bottom of the dialog titled "Show Processes from All User", and select OWSTIMER.EXE from the list of available processes. Click the Attach button.... and hopefully your breakpoint should display as a nice fat filled dot!
An outlined breakpoint (an empty circle) rather than a filled breakpoint means VS cannot match your code against the running code, and so something in the above process has not worked for you. Worked for me, though! Perhaps you have copied your dll and PDB files to the wrong GAC subfolder?
Triggering the Job
Now you just need to trigger your timer job. One suggestion for this is to modify the schedule of the job to occur frequently - have a look at this post on blah!bLaH!BLOG!! for how to do that.
I have a design pattern in place where the schedule for custom timer jobs are configured in a configuration list in the WSS site. When the feature containing the timer job is activated, a feature receiver reads the configuration data from the list and sets the timer job accordingly. Works nicely when you want to manipulate schedules and other data relating to the timer job.
One Last Timer Job Tip...
If you need to persist data across executions of your timer job, here's how from James Mann.