On BPMs I use VS to code and the app server event viewer to get error messages or progress of the BPM.
The event viewer will give you the routine and sometimes the line number of the error.

If you don’t get line numbers add log entries to follow the process like below.
Ice.Diagnostics.Log.WriteEntry(" email from is good" + EMAIL_From);
DMRHead = Db.DMRHead.Where(DMRHead_Row => DMRHead_Row.Company == ttDMRActnRow.Company && DMRHead_Row.DMRNum == ttDMRActnRow.DMRNum).FirstOrDefault();
Ice.Diagnostics.Log.WriteEntry(" dmrhead is good");

When you do get a line number it is referencing the whole routine and not just your BPM, so you need to load the source file from the app server to find the number and it is not always the exact number. could be a line before or after. The number at the end is a directory that is generated with each BPM save. \c-e10app1\d$\Epicor\inetpub\wwwroot\Pilot\Server\BPM
For this Data Directive.
\c-e10app1\d$\Epicor\inetpub\wwwroot\Pilot\Server\BPM\Sources\DT\ERP.DMRActn.Triggers\13
if you have an entry in the event viewer that you are not sure what BPM wrote the entry you can use @hkeric.wci’s tip below on using grep in CMDER to find all routines that have a section of code in them. I have found this invaluable in the past month.
So @Banderson is correct that it is harder than stepping thru in VS, but with the right tools it is doable.