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) :-)
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.)
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.
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.
Use a precompiled non-debug DCU of FasmMM
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.
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.
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.
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
Related
I am trying to run a debug on my code, but somehow it stopped working. Here is a snippet and the green lines it is showing:
I have tried to right click on my project and clean it.
Tried
to delete temporary files, like .stat and .dcu.
Switching back and forth to Release and Debug modes, rebuilding, recompiling them.
The Debugging options under Project -> Options -> Delphi compilingare all set to true.
Checked if there are no duplicate files in the search paths.
Other projects are working correctly.
Also tried swearing.
What am I doing wrong?
It is a kind of normal compiler behaviour. It ever happens when the procedure (code line) is never called from anywhere inside your program. Compiler skips such procedures and functions (all the code lines within them).
See the picture.
You just need to check if the procedure (line) is really at least once called from anywhere inside your application.
Appended
This also takes place when the code line can never be called and this (the logic statement) can be evaluated at compilation (the result is known in advance and can not be affected at runtime). The compiler optimizes the code skipping such lines. That is why it does not accept breaks at them.
Here is a diassembly of the latter procedure. The if false then ... statement at lines 37 and 38 is omitted:
Adding to the answer from asd-tm, I include the following line in all my units:
unit SomeRandomUnit;
{$I ProjOptions.inc}
In the ProjOptions.inc file, I include the following code:
// Compiler switches:
// Debug Info Optimisation
// DEBUG On Off
// RELEASE Off On
{$IFDEF DBG}
{$D+}
{$O-}
{$ELSE}
{$D-}
{$O+}
{$ENDIF}
In this way, optimisation is off and debug information switched on when I am debugging without me worrying about accidentally toggling something in Project > Options. Manually deleting DCU files from the PROJECT\objects folder (combined with the above .inc file) should guarantee breakpoints working again (at least in DEBUG builds).
Is there a place where I can add code that will be executed before unit initialization?
The reason I want to do this is I need to change the DecimalSeparator, this has to be done before the initialization of some units. I have put it in the project source, before Application.Initialize but it is too late by then.
As I see it the only choice I have is to put it in the initialization of the unit that needs the DecimalSeparator to be changed, is this the case?
Thanks in advance for any advice.
Initialization order in Delphi is deterministic: units get initialized in the same order as the compiler compiled them, and finalized in the reverse order. The compiler starts at the top of the DPR's uses clause and works its way down, and for each unit it finds, it does the same thing recursively: start at the start of the uses clause, try to compile each used unit that isn't already compiled, then compile the current unit. So if you can get your unit in before any of the other ones get compiled, then it will get initialized first.
If you want to make sure it gets executed first, make a new unit, put your changes in that unit's initialization block, and then make sure it ends up in the DPR before any of the units that will depend on the changes. You might even want to make it the first unit, unless you have other "must be first" units there already, such as replacement memory managers.
Put it into the initialization section of the first unit in your project uses list, that way it will be executed prior to any other initialization code.
A word of warning here.
I've got an application running on the desktop of a logged in user and IN THE MIDDLE of testing the app the DecimalSeparator changed for me, without me restarting the application.
I used to set the
DecimalSeparator := '.';
once in the FormCreate() code, but that seems not the be enough. So now I set it once every time before I use my FormatFloat() function (used only in one place in my application).
I do not know WHY this happens, but probably there are some system-wide parameter changes happening, that reset the char to ',' on my system.
The best way to avoid this is probably to set the decimal separator in windows configuration to '.' to avoid strange problems...
When I'm debugging something that goes wrong inside a loop, say on the 600th iteration, it can be a pain to have to break for every one. So I tried setting a conditional breakpoint, to only break if I = 600. That works, but now it takes almost a full minute to reach that point, where before it was almost instantaneous. What's going on, and is there any way to fix it?
When you hit a breakpoint, Windows stops the process and notifies the debugger. It has to switch contexts, evaluate the condition, decide that no, you don't want to be notified about it, restart the process and switch back. That can take a lot of processor cycles. If you're doing it in a tight loop, it'll take a couple orders of magnitude more processor cycles than one iteration of the loop takes.
If you're willing to mess with your code a little, there's a way to do conditional breakpoints without incurring all this overhead.
if <condition here> then
asm int 3 end;
This is a simple assembly instruction that manually sends a breakpoint notification to the OS. Now you can evaluate your condition inside the program, without switching contexts. Just make sure to take it out again when you're done with it. If an int 3 goes off inside a program that's not connected to a debugger, it'll raise an exception.
It slows it down because every time you reach that point, it has to check your condition.
What I tend to do is to temporarily create another variable like this (in C but should be doable in Delphi).
int xyzzynum = 600;
while (true) {
doSomething();
if (--xyzzynum == 0)
xyzzynum = xyzzynum;
}
then I put a non-conditional breakpoint on the "xyzzynum = xyzzynum;" line.
The program runs at full speed until it's been through the loop 600 times, because the debugger is just doing a normal breakpoint interrupt rather than checking conditions every time.
You can make the condition as complicated as you want.
Further to Mason's answer, you could make the int 3 assember only be compiled in if the program is built with the debug conditional defined:
{$ifdef debug}
{$message warn 'debug breakpoint present in code'}
if <condition here> then
asm int 3 end;
{$endif}
So, when you are debugging in the ide, you have the debug conditional in the project options. When you build the final product for your customers (with your build script?), you wouldn't include that symbol, so it wont get compiled in.
I also included the $message compiler directive, so you will see a warning when you compile letting you know that the code is still there. If you do that everywhere you use int 3, you will then have a nice list of places which you can double click on to take you straight to the offending code.
N#
Mason's explanations are quite good.
His code could be made a bit more secure by testing that you run under the debugger:
if (DebugHook <> 0) and <your specific condition here> then
asm int 3 end;
This will not do anything when the application is running normally and will stop if it's running under the debugger (whether launched from the IDE or attached to the debugger).
And with boolean shortcut <your specific condition here> won't even be evaluated if you're not under the debugger.
Conditional breakpoints in any debugger (I'm just surmising here) require the process to flip back and forth every time between your program and the debugger every time the breakpoint is hit. This process is time consuming but I do not think there is anything you can do.
Normally condition breakpoints work by inserting the appropriate break instruction into the code and then checking for the conditions you have specified. It'll check at every iteration and it might well be that the way in which the check is implemented is responsible for the delay as it's unlikely that the debugger compiles and inserts the complete check and breakpoint code into the existing code.
A way that you might be able to accelerate this is if you put the condition followed by an op with no side effect into the code directly and break on that op. Just remember to remove the condition and the op when you're done.
I am trying to create a code coverage tool using Delphi 2007.
My general approach is to use the Win32 Debug API to insert breakpoints for each source line and then remove the breakpoints as I pass them - thus I would be able to track each executed source line.
Outline of my approach:
parse the detailed MAP file (as generated by Delphi 2007) to find all the addresses for each source line (only for .text segments)
open the application in debug mode using the OpenProcess API call
iterate over each source line and insert an Int3 instruction (one $cc byte using WriteProcessMemory + FlushInstructionCache) at the address of each line
continue executing and as each breakpoint is triggered, remove the corresponding breakpoint and mark the line as covered
After either each breakpoint is passed or program exists I generate a report on what lines were covered and which lines were not for each source module
Now on to my question:
Is each source line address in a detailed MAP file a valid address to insert an Int3 breakpoint?
While the approach was successful for some simple units, I run in to access violations for some larger applications where the violated address includes a $cc - which would lead me to think that my approach needs some modification to work.
Hints on better approaches also very welcome!
Well, in theory: yes. And practical, I think yes too. If Delphi can place a breakpoint on every line, so can you :-).
Probably you need some specific handling for some case (for example: first line of a procedure is initialization of local vars, setting EBP etc).
So can you find out in which case it fails?
Btw: nice project! Is it open source?
P.S. if you need some assembly code handling: look at koldetours.pas (use google search).
If I run a program and an exception is raised I am asked if I want to continue or break.
If I choose break I can see where the exception is coming from but if the break is in a library or system file not one of my source files (Say the exception is in System.pas or Controls.pas) I need to manually step the execution forward using F8 until it returns to one of my files, so I can see what part of my code caused the exception.
This can take a long time.
I know I should be catching lower level exceptions in my code but in this instance it's not hitting one of my exception handlers.
Is there a way to say
run forward with execution until you get to file X or
until you get back into a project specific file.
I'm also interested out of general curiosity on how other compilers / IDEs handle this.
Apologies if I haven't made this as clear as a I should.
You can resolve this by using the Stack View window.
Open the Stack View window (CTRL+ALT+S).
Double click on the method in the stack view where you wish to insert a breakpoint.
The unit, containing the caller method opens and the cursor is positioned on the caller method.
Set your breakpoint.
There's an even simpler way than Lieven's suggestion. Follow the first 3 steps as he laid them out, but don't place a breakpoint.
The problem with placing a breakpoint is that you have to clear it afterwards or you'll end up getting dropped into the debugger every time you pass that line. If you only want to run to a certain line and then drop to the debugger once, put the cursor on that line (the insertion point, not the mouse cursor) and press F4 (Run to Cursor). It's like a one-time breakpoint.
There are several ways:
Use the "Next source line" function (Shift+F7)
Use the call stack and double-click on the function you need, add a breakpoint there and hit "Run" (F9).
Use the "Step out" (Shift+F8) function until you are back into your own code.