In Delphi: How to skip sections of code while debugging?
Asked Answered
N

8

15

I often accidently step into code that I'm not interested in while debugging in Delphi.

Let's start by saying that I know that you can step over with F8, and that you can run to a certain line with f4.

Example:

function TMyClass.DoStuff():Integer;
begin
  // do some stuff
  bla();
end;

procedure TMyClass.Foo()
begin
  if DoStuff()=0 then // press F7 when entering this line
    beep;
end;

Example: I want to step into method DoStuff() by pressing F7, but instead of going there, I first end up in FastMM4.FastGetMem(), which is a massive blob of assembly code that obviously I'm not interested in at the moment.

There are several ways to go about this, and I don't like any of them:

  • Add a breakpoint on "bla" (almost useless if you only want to step into DoStuff on special occasions, like iteration 23498938);

  • Instead of pressing F7, manually move the cursor to "bla", and press F4 (Works for this simple example. In practice, it doesn't);

  • In case of FastMM: temporarily disable fastmm;

Is there any way to hint the IDE that I'm never interested into stepping into a certain block of code, or do I always have to set extra breakpoints or use F4 to try to avoid this?

I'm hoping for some magic compiler directive like {$NODEBUG BEGIN/END} or something like that.

In most cases being able to exclude entire units would be fine-grained enough for me, but being able to avoid certain methods or even lines of code would be even better.

Update: Maybe codegear should introduce something like skip-points (as opposed to break-points) :-)

Noakes answered 16/1, 2009 at 1:8 Comment(0)
F
25

There is a "magic nodebug switch". {$D-} will disable the generation of debug code. Place that at the top of your FastMM unit and you won't end up tracing into it. And if you do end up in a function you don't want to be in, SHIFT-F8 will get you out very quickly. (WARNING: Don't use SHIFT-F8 from inside an assembly-code routine that plays around with the stack. Unpredictable behavior can result. F4 to the bottom of it instead.)

Ferrocyanide answered 16/1, 2009 at 3:18 Comment(3)
Excellent! It works exactly the way I want: the debugger doesn't step into it anymore, while still getting code-completion and being able to see and modify the "debug-disabled" code if I want to.Noakes
As for FastMM4: leak-reporting still works, as long as you don't have {$define RequireDebugInfoForLeakReporting}, which is undefined by default.Noakes
You sir, as far as I'm concerned, have won the internet today. Worked beautifully. Many, many thanks.Krieger
D
7

If you're jumping into FastMM code, then there are memory operations occurring. The code you've shown doesn't have any memory operations, so your question is incomplete. I'll try to guess at what you meant.

When a subroutine has local variables of compiler-managed types (such as strings, interfaces, or dynamic arrays), the function prologue has non-trivial work to do. The prologue is also where reference counts of input parameters are adjusted. The debugger represents the prologue in the begin line of the function. If the current execution point is that line, and you "step into" it, you'll be taken to the RTL code for managing the special types. (I wouldn't expect FastMM to be involved there, either, but maybe things have changed from what I'm used to.) One easy thing to do in that situation is to "step over" the begin line instead of into it; use F8.

If you're really pressing F7 when entering your highlighted line, then you're doing it wrong. That's stepping into the begin line, not the line where DoStuff is called. So whether you get taken to the FastMM code has nothing to do with the implementation of DoStuff. To debug the call to DoStuff, the current execution point should already be the line with the call on it.

If you only want to debug DoStuff on iteration 23498938, then you can set a conditional breakpoint in that function. Click in the gutter to make a normal breakpoint, and then right-click it to display its properties. There you can define a condition that will be evaluated every time execution reaches that point. The debugger will only stop there when the condition is true. Press F8 to "step over" the DoStuff call, and if the condition is true, the debugger will stop there as though you'd pressed F7 instead.

You can toggle the "use debug DCUs" option to avoid stepping into most RTL and VCL units. I don't know whether FastMM is included in that set. The key difference is whether the DCUs you've linked to were compiled with debug information. The setting alters the library path to include or exclude the subdirectory where the debug DCUs are. I think you can configure the set of included or excluded debug directories so that a custom set of directories is added or removed based on the "debug DCUs" setting.

Back to breakpoints. You can set up breakpoint groups by assigning names to your breakpoints. You can use an advanced breakpoint to enable or disable a named group of breakpoints when you pass it. (Breakpoint groups can have just one breakpoint, if you want.) So, for example, if you only want to break at location X if you've also passed some other location Y in your program, you could set a disabled breakpoint at X and a non-breaking breakpoint at Y. Set the "enable groups" setting at Y to enable group X.

You can also take advantage of disabled breakpoints without automatic enabling and disabling. Your breakpoints appear in the "breakpoints" debugger window. If you're stepping through DoStuff and you decide you want to inspect bla this time, go to the breakpoint window and enable the breakpoint at bla. No need to navigate to bla's implementation to set the breakpoint there.

For more about advanced breakpoints, see Using Non-Breaking Breakpoints in Delphi, and article by Cary Jensen from a few years ago.

Dagley answered 16/1, 2009 at 3:52 Comment(2)
>>...so a customer set of directories is added or removed based on the "debug DCUs" setting.<< D'oh. That never occurred to me. I just added the DevEx sources to the Debug DCU path - et voilà: no more manual editing of the project search path.Damaging
You're right, the example is weak because the FastMM-specific problem wouldn't occur there. I was in doubt whether to accept this answer or Mason's. This answer is full of interesting information and tips, but Mason's answer immediately solves the problem.Noakes
A
7

I may have missed something with your post, but with FastMM4 you can edit the FastMM4Options.Inc include file and remove the '.' from the following define:


From FastMM4Options.inc ****

{Enable this option to suppress the generation of debug info for the FastMM4.pas unit. This will prevent the integrated debugger from stepping into the memory manager code.}

{$.define NoDebugInfo}


When recompiling (might need building) the debugger will (should) no longer debug the FastMM code.

Apeak answered 16/1, 2009 at 14:53 Comment(1)
(+1) Eventhough fastmm was used as an example only, I think your suggestion is the best way to take care of fastmm4.. It somehow felt wrong to modify fastmm4.pas;Noakes
M
4

Use a precompiled non-debug DCU of FasmMM

Madoc answered 16/1, 2009 at 2:12 Comment(0)
O
3

In the project dpr file, I use

uses
{$IFNDEF DEBUG} FastMM4, {$ENDIF}
  ... // other units

to exclude FastMM4 during debug mode. Requires no change in FastMM4 so I don't have to remember to add {$D-} in FastMM when I change to a different version.

Onepiece answered 13/10, 2011 at 13:27 Comment(0)
L
2

AFAIK, the debugger is only aware of the files in Browsing Path that you can modify in Options. So if you exclude the paths of modules you're not interested in debugging that will give the effect of what you want to do.

One caveat: code completion also relies on Browsing Path so you might run into occasions that code completion falls short when needed.

Linc answered 16/1, 2009 at 1:16 Comment(0)
S
2

Although it isn't a direct answer to your question, you could modify your first suggested solution by putting breakpoint at bla that is only enabled when a breakpoint at Foo is passed (or some other condition of your choose, such as iteration count). Then it will only break when you want it to.

As an aside, I am finding more and more that I am not halting execution at break points, but rather dumping variable values or stack dumps to the message log. This allows more careful analysis than on-the-fly inspection of variables, etc. FWIW.

Spittle answered 16/1, 2009 at 2:25 Comment(0)
I
0

No. I don't believe there is a way to tell the debugger to never stop in a certain section of code. There is no magic directive.

The best you can do when you get into a routine you don't want to be in is to use Shift+F8 which will Run until the Return. Then do a F7 or F8 to exit the procedure.


Hmmm. Now I see Mason's answer. Learned something. Thanks, Mason. +1

Increasing answered 16/1, 2009 at 1:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.