Did you fix all warnings the compiler throws in your own code? Ground zero.
Did you obtain a stacktrace? (my first thing to look, because I always fix all warnings in my own code... almost always
)
And did you use F7/F8/F9 and breakpoints?
See how far it runs trouble free and then add some watches on critical variables. Remove any breakpoints before that point that you know works, so it doesn't get cluttered.
Also compile with -glh, run. and see what that gives you. Or see screenshot for lazarus settings..
You can additionally enable valgrind - if you are familiar with it and your platform supports it.
Also if your application is multi-threaded, name your threads!! Really important for debugging them!!
Also, replace most of the showmessages with assertions and add assertions to the critical parts of your start up.
Complex code belongs in a version control system and the best are free...
Do you use a version control system like git or svn?
Then you can simply diff the code and examine the changes one by one.
Otherwise, try to remember what and where you made changes, revert them, compile again and when it finally works, use a version control system....
You may also want to apply some of
https://wiki.freepascal.org/Defensive_programming_techniques (note to self: I have to complete that still)
The screenshot shows my own - extreme - debug settings for hard to find cases. On Linux I sometimes also enable valgrind. (But valgrind tools are not very user friendly in my opinion, steep learning curve)
And maybe, if you tend to use FreeAndNil, that hides many bugs rather than solve them, use this one instead:
procedure FreeAndNil<T:class>(var obj:T); // just prefix with generic in mode objfpc.
var
temp: T;
begin
temp := obj;
obj := nil;
temp.free;
end;
That's because that version is type safe...It solves some of the issues related to FreeAndNil(var obj), which is untyped.....