4

I am not sure how to track down the following crash:

  1. It happens when Unloading a Designtime Package that is used in-house at my company. It is our code, thus it is our bug to fix, not a third party component vendor problem.

  2. It apppears that a thread is involved, but since it happens in the Function ThreadProc in Classes.pas, I'm guessing it's a bare System/RTL thread without even a TThread class wrapper that I should be searching for in our code. (Question Part A: Is that so?)

  3. The call stack contains none of my code, only the IDE itself, and the base function in the call stack is ntdll.RtlInitializeExceptionChain.

call stack example of an access violation in some TThread.Execute method that shows that the debugger gives no details on WHICH thread is involved:

 :7599b9bc KERNELBASE.RaiseException + 0x58
 :516b4965 ; c:\program files (x86)\embarcadero\rad studio\8.0\bin\exceptiondiag150.bpl
 :5003b058 NotifyNonDelphiException + $1C
 :77be6a8b ; ntdll.dll
 :77bb0143 ntdll.KiUserExceptionDispatcher + 0xf
 rtl.Classes.ThreadProc($CB9ED70)
rtl.System.ThreadWrapper($403E910)
:75fb339a kernel32.BaseThreadInitThunk + 0x12
:77bd9ed2 ntdll.RtlInitializeExceptionChain + 0x63
:77bd9ea5 ntdll.RtlInitializeExceptionChain + 0x36

When I try to view thread info, the second Delphi IDE that is my target executable, itself crashes, but I am able to continue to view information in my delphi debug host instance.

I am aware of techniques for debugging designtime packages, and I am using said techniques. That is, I have a first copy of delphi (BDS.exe) launching a second copy, because the package project, has set in its Run Parameters, in the Host Application edit box the main bds.exe for Delphi XE. (C:\Program Files (x86)\Embarcadero\RAD Studio\8.0\bin\bds.exe). Thus when I run my package in debug mode, it loads itself into the Delphi IDE.

Question part B is: What is the best place to set a breakpoint so I can see non-TThread threads, as well as TThread-based threads being created? If there is no way to set a breakpoint, then how about an alternative means of finding what code is creating threads?

Update: I have found that setting a breakpoint in the line that reads Thread.Execute, in function ThreadProc, in Classes.pas, gets me a breakpoint hit on each TThread startup. That is enough to find threads started by a designtime or runtime package from its initialization section, but I'm hoping there exists an even lower level way to do this.

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • 2
    `Classes.ThreadProc()` is only used with the `TThread` class. There is no "bare thread" in the RTL that uses `ThreadProc()` directly (it would crash if it did because `ThreadProc()` looks for the caller's `TThread` object instance to call into). – Remy Lebeau Nov 29 '11 at 20:19
  • Have you tried placing a breakpoint inside the `TThread` constructor and then following the call stack to see what code is creating `TThread` objects to begin with? Placing a breakpoint inside of `ThreadProc()` will not tell you that. – Remy Lebeau Nov 29 '11 at 20:20
  • You're right REMY. I am looking for a way to set a breakpoint that will get called when a Non-TThread-based thread is activated. I already have a way to get breakpoints for TThread breakpoints. – Warren P Nov 30 '11 at 00:56
  • The only way to set a breakpoint for non-TThread threads would be to set a breakpoint inside of the Win32 API `CreateThread()` function directly. – Remy Lebeau Nov 30 '11 at 02:35
  • Remy, that's in fact what I did do, and since the technique might not be obvious to the world (I never knew you could do that until someone showed me that you could open windows.pas and set breakpoints) I've added it as an answer. – Warren P Dec 06 '11 at 15:46

1 Answers1

5

I debugged the designtime package crash in the following manner:

  1. As already noted above, set up Delphi to run itself, using Run Parameters, in the Host Application, the path is c:\path-to-delphi-install\bin\bds.exe.

  2. Set a breakpoint in the line in function ThreadProc in System.pas.

  3. Open windows.pas, and around line 30,000-33,000 there is a line like this:

    function CreateThread; external kernel32 name 'CreateThread';

Set a breakpoint on the line above with F8. Now when anything in the code being debugged invokes that Win32 function, whether via TThread or not, you'll get a breakpoint.

enter image description here

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • That is an interesting technique, I did not know the IDE supported that. My earlier suggestion was to put a breakpoint *inside* of the `CreateThread()` function, which you can do from within the debugger's Assembly view. – Remy Lebeau Dec 06 '11 at 19:04