Blog
All Blog Posts | Next Post | Previous PostRun-time call-stack tracing with Delphi
Thursday, May 12, 2022
We are used to inspect a call-stack when something goes wrong in our application and it crashes. Delphi has excellent add-on tools that log detailed call-stack information when an application crashes.
But it is not always when an application crashes that call-stack information can be useful. We experience ourselves from time to time that having detailed call-stack information during a regular running application could help us trace undesired situations. Recently, it happened that in rare cases, a component property ended up with an unexpected value. In the application where the component was used, it was from many parts of the code and VCL framework itself that this property was set and it was mostly a matter of knowing from where exactly the unexpected value was set. Once we knew, we could understand and address the problem. The ability to just take at runtime a snapshot of the call-stack when a specific value was set was sufficient to find the culprit.
So, while this capability saved us already for several cases an enormous amount of time, we thought it was interesting to make it also available to you in TMS MemInsight.
While TMS MemInsight will also give you at run-time insight into the call-stack when exceptions occur, now there is a simple method GetCallStack(sl: TStrings) that you can call from anywhere and as many times as you want and it will return detailed call-stack information. Only requirement is that you link your application with a detailed map information (see Linker options under Project options)
How it works?
Imagine there is a class TMyClass with a property Text:
TMyClass = class(TPersistent) protected procedure SetText(const Value: string); public property Text: string read FText write SetText; end;
Now, we want to know from where exactly in our application, this class Text property would be set with an empty string value.
We can write the property setter in the following way:
uses TMS.MI.Core; interface type TMyClass = class(TPersistent) protected procedure SetText(const Value: string); public property Text: string read FText write SetText; end; implementation proceduer TMyClass.SetText(const Value: string); var sl: TStringList; begin FText := Value; if FText = '' then begin sl := TStringList.Create; try GetCallStack(sl); sl.SaveToFile('c:\temp\callstack.log'); finally sl.Free; end; end; end;
Now, at application level we can use this class for example like:
MyClass.Text := Edit1.Text;
and when the text property is being set with an empty string, we'll get a nice stack-trace report giving us the information we wanted.
For this example, we create at TForm class level the method to set the myClass.Text via:
TForm1 = class(TForm) private { Private declarations } procedure SetClassText(s: string); end; implementation procedure TForm1.SetClassText(s: string); begin myclass.Text := s; end;
and when we call this from both the an edit control's OnChange event and a form button OnClick event:
procedure TForm1.Button1Click(Sender: TObject); begin SetClassText(Edit1.Text); end; procedure TForm1.Edit1Change(Sender: TObject); begin SetClassText(Edit1.Text); end;
Now, we get a nice stack trace log when the class Text property is set with an empty string value:
TMyClass.SetText (57)
TForm1.SetClassText (77)
TForm1.Button1Click (43)
TControl.Click (7443)
TWinControl.WndProc (10162)
TButtonControl.WndProc (2617)
....
indicating this was called from the button OnClick.
Available now in TMS MemInsight v1.1
TMS MemInsight v1.1 is released and now includes this feature in addition to the many run-time memory usage inspection capabilities it already included. For active licensed users, this update is free and has some other performance optimizations as well. Check it out! It might be very valuable when you encounter your next challenge to debug a rare / difficult to find problem in your application.
Bruno Fierens
This blog post has received 3 comments.
2. Monday, July 4, 2022 at 3:54:59 PM
It is being researched to extend support to other platforms. Follow our announcements for news if we technically accomplished this and have added the support.
Bruno Fierens
3. Friday, September 15, 2023 at 5:07:00 AM
This is very usefull. Thanks again!
Koistinen Mika
All Blog Posts | Next Post | Previous Post
I am looking for exception stack tracer tool for android, it is an empty niche in the market, EurekaLog and madexcept does not support them, and I have seen the source code of TMS software units and this one doesn''t support it either.
Have you in mind any support for call stack tracer in android?.
Thank you.
Conde Manuel