Jump to content
dummzeuch

GExperts supports even more laziness

Recommended Posts

13 minutes ago, dummzeuch said:

I managed to fix the problem with Delphi 2005. It was totally unrelated: Some code when loading the code formatter configuration raised an external exception C000001D ((Illegal Instruction) for an inlined function when optimization was enabled. In the process I added the same exception handling to the editor experts that was already in place for regular experts, so now one faulty editor expert can no longer prevent all others from being loaded and initialized. Also the user gets a better error message in that case.

Very good. Just wondering does this behavior occur only on D2005? Or all older versions too? 

Share this post


Link to post
1 hour ago, Mahdi Safsafi said:

Very good. Just wondering does this behavior occur only on D2005? Or all older versions too? 

This particular problem was Delphi 2005 specific.

 

It resulted in an error message on every start of the IDE, when the GExperts DLL was compiled with optimization on. That's why I never encountered it in my tests before, because all my test builds are compiled with optimization turned off. I don't remember why I changed that this time. Maybe I just forgot to uncheck that option. Delphi 2005 did not have separate configurations for Release and Debug builds, that came with Delphi 2007.

 

As for older versions: Those did not support the inline keyword.

Edited by dummzeuch
  • Like 1

Share this post


Link to post
1 hour ago, dummzeuch said:

As for older versions: Those did not support the inline keyword.

Almost forget that information. Thanks. 

Share this post


Link to post

I am really missing a "don't bother me at all about any exception during the current debug session" button.

Share this post


Link to post
7 minutes ago, Stefan Glienke said:

I am really missing a "don't bother me at all about any exception during the current debug session" button.

Filtering is based on regex ... does using '.*' counts ?  

Edited by Mahdi Safsafi

Share this post


Link to post
1 minute ago, Mahdi Safsafi said:

Filtering is based on regex ... does using '.*' counts ?  

The filters work on Exception class name and that does not support regex or does a sub type check

Share this post


Link to post
2 minutes ago, Stefan Glienke said:

The filters work on Exception class name and that does not support regex or does a sub type check

Yeah I missed that. 

Share this post


Link to post
9 hours ago, Stefan Glienke said:

The filters work on Exception class name and that does not support regex or does a sub type check

Subclass checks would be very difficult to implement because all the expert knows is the exception name and the message. I know of no way to query the class inheritance in that context. But a regex for the name would be possible.

Share this post


Link to post

Probably possible using the debugger evaluation or something but being able to have an "any" option in the exception class field would be enough - and probably a button "ignore any" in the exception dialog.

Currently I am solving this by setting a non breaking breakpoint at the start of the unit tests with "ignore subsequent exceptions" but I forget to set that up often enough.

Share this post


Link to post

I'd like

"Disable break on exception this thread" 

"Disable break on exception in other threads" - limiting the breaks to the current thread or threads spawned in the current thread.

Share this post


Link to post
Guest
11 minutes ago, Lars Fosdal said:

"Disable break on exception this thread" 

"Disable break on exception in other threads" - limiting the breaks to the current thread or threads spawned in the current thread.

That is neat and pretty useful.

Share this post


Link to post
2 hours ago, Lars Fosdal said:

I'd like

"Disable break on exception this thread" 

"Disable break on exception in other threads" - limiting the breaks to the current thread or threads spawned in the current thread.

If you have got a suggestion on how that could be implemented, I'll give it a try. So far I don't see a way to get information about the thread in which the exception has been raised.

Share this post


Link to post
14 hours ago, dummzeuch said:

If you have got a suggestion on how that could be implemented, I'll give it a try. So far I don't see a way to get information about the thread in which the exception has been raised.

TBH, I am not sure that can be implemented without either digging into the debugger or using techniques like those in EurekaLog where it appears they inject their own exception class that is thread aware?
 

It was more of a wish list for the debugger team, than for GExperts.

Share this post


Link to post
16 minutes ago, Lars Fosdal said:

It was more of a wish list for the debugger team, than for GExperts.

In that case: Did you file a feature request with Embarcadero? I'm sure I'm not the only one who would vote on it.

Share this post


Link to post
Guest

Looking at IOTAProcess60 in OpenToolsApi and wondering if this can solve this, may be the logical thing for GetCurrentThread to return the thread raised the exception and a break issued on it, but why it is IUnkown ?

  IOTAProcess60 = interface(IUnknown)
    ['{34B2E2D2-E36F-11D1-AB0E-00C04FB16FB3}']
    { Adds an IOTAProcessNotifier }
    function AddNotifier(const Notifier: IOTAProcessNotifier): Integer;
    { Return the currently active thread }
    function GetCurrentThread: IOTAThread;
    { Return the number of Thread in this process }
    function GetThreadCount: Integer;
    { Return the index'd Thread }
    function GetThread(Index: Integer): IOTAThread;
    { Get the debugger's internal process ID }
    function GetProcessId: LongWord;
    { Stop/Pause the process }
    procedure Pause;
    { Read the process memory at the given address }
    function ReadProcessMemory(Address: LongWord; Count: Integer; var Buffer): Integer;
    { Removes the index'd IOTAProcessNotifier }
    procedure RemoveNotifier(Index: Integer);
    { Run the process with the specified run mode }
    procedure Run(RunMode: TOTARunMode);
    { Set a new current thread }
    procedure SetCurrentThread(Value: IOTAThread);
    { Reset/Terminate the process }
    procedure Terminate;
    { Write to the process memory at the given address }
    function WriteProcessMemory(Address: LongWord; Count: Integer; var Buffer): Integer;

    property CurrentThread: IOTAThread read GetCurrentThread write SetCurrentThread;
    property ProcessId: LongWord read GetProcessId;
    property ThreadCount: Integer read GetThreadCount;
    property Threads[Index: Integer]: IOTAThread read GetThread;
  end;

There is also IOTAProcessNotifier90 

  IOTAProcessNotifier90 = interface(IOTAProcessNotifier)
    ['{E2725B23-E67C-4CF1-B928-FA0F5B9C2C29}']
    { Called after a process' current thread is changed }
    procedure CurrentThreadChanged(const Thread: IOTAThread);
    { Called when a process' thread list changes.  This notification is purposely
      vague.  Things like thread creation, thread destruction, thread attribute
      changes (for now just thread name) are reported via this notification }
    procedure ThreadListChanged(const Process: IOTAProcess);
  end;

@dummzeuch Have you checked them?

Share this post


Link to post

From the description I gather that I would have to implement IOTAProcessNotifier90 and hope that CurrentThreadChanged is called often

and timely enough to provide the information on time. Might be worth a try.

Share this post


Link to post

You probably have to use an IOTADebuggerNotifier to detect ProcessCreated/ProcessDestroyed - there you have to add/remove IOTAProcessNotifier and get ThreadCreated/ThreadDestroyed and you can already guess it add/remove an IOTAThreadNotifier which has ThreadNotify where you are interested in TOTANotifyReason.nrException. The corresponding IOTAThread instance has all the required information like the OSThreadID or Handle properties

  • Thanks 1

Share this post


Link to post
Guest
3 hours ago, Stefan Glienke said:

there you have to add/remove IOTAProcessNotifier and get ThreadCreated/ThreadDestroyed and you can already guess it add/remove an IOTAThreadNotifier which has ThreadNotify where you are interested in TOTANotifyReason.nrException.

I think that part is not needed, once IOTAProcess is acquired then 

function GetCurrentThread: IOTAThread;

should return the current one in this case ( i mean break point on exception).

as you suggested IOTAThread90 does have 

property OSThreadID: LongWord read GetOSThreadID;

and this should do it .

 

The point is i don't think keep tracking/notified of all threads is necessary.

Share this post


Link to post

I was not sure what "current" means in the context of being called from the IDE from the hooked "break because of exception" method - but you could be right - that would make it easier.

Share this post


Link to post
Guest

I think this should clear that

IOTAThread.thumb.png.3e0c7619ac41925c5af5406d6e2c9eb9.png

Share this post


Link to post
1 hour ago, Kas Ob. said:

I think this should clear that

IOTAThread.thumb.png.3e0c7619ac41925c5af5406d6e2c9eb9.png

I'm definitely a bit slow today. I can't make out what the screenshot is supposed to tell me.

Share this post


Link to post

By popular request of a single gentleman (*) there is now a button "Ignore All this Session".

 

IgnoreAllThisSession.thumb.png.87db95dfc075f3d4ef61d6f7a55674fa.png

 

The exception class name is now also a regex. Empty matches any exception.

 

(* I'm not sure this really carries the meaning of the German joke "Auf vielfachen Wunsch eines einzelnen Herrn ..." )

  • Like 2
  • Haha 1

Share this post


Link to post
Guest
15 minutes ago, dummzeuch said:

I can't make out what the screenshot is supposed to tell me.

That was to clear the point Stefan pointed if Current is a thread in the debugged process or belongs to the debugger itself.

Screenshot shows how internally TProcess::GetCurrentThread is returning IOTAThread (same TGUID) which does have Evaluate means it belongs to the debugged process.

 

Now, how to use that, you already have in TBaseDebuggerNotifier 

ProcessCreated 

ProcessDestroyed

This is already solved this thing, i mean getting the IOTAProcess and save it.

all what is left i think, is to use IOTAProcess60.GetCurrentThread to get IOTAThread50.GetOSThreadID

 

I tried to get access to FBaseDebuggerNotifier from GX_FilterExceptionsNotification , but i don't see an easy or elegant way to do it without butchering your code, you design it you can redesign it.

 

 

Before click submit, i tried for last time and it is working !!

 

with such code just for testing , and it is ugly, there should be a better approach than global function, but that is up to you.

Function GetCurrentThread:TThreadID; // in unit GX_FilterExceptions
begin
  if Assigned(GlobalDebuggerNotifier) then
    begin
      result  := IOTAProcess60(GlobalDebuggerNotifier.GetCurrentProcess).CurrentThread.OSThreadID;
    end;
end;
  TBaseDebuggerNotifier = class(TNotifierObject, IOTADebuggerNotifier)
  private
    FNotifierIndex: Integer;
    FProcess: IOTAProcess;
  public
    constructor Create;
....
	Function GetCurrentProcess: IOTAProcess;
	end;
    
constructor TBaseDebuggerNotifier.Create;
begin
  inherited;
  FProcess := nil;
end;

procedure TBaseDebuggerNotifier.ProcessCreated({$IFDEF GX_VER170_up} const {$ENDIF} Process: IOTAProcess);
begin
  FProcess := Process;
end;

procedure TBaseDebuggerNotifier.ProcessDestroyed({$IFDEF GX_VER170_up} const {$ENDIF} Process: IOTAProcess);
begin
  FProcess := nil;
end;

function TBaseDebuggerNotifier.GetCurrentProcess: IOTAProcess;
begin
  Result := FProcess;
end;

and the result

IOTACurrentThread.thumb.png.8abca4826f55c168bf4b62181f2e5ead.png

Share this post


Link to post

@dummzeuch I made some debugging and was able to get much more information about the exception. On the attached file you will find a lot of useful stuff plus some comment for clarification.  

I hope, you will find it useful for GExperts.

ExceptionFilterImg.PNG

ExceptionFilter.pas

  • Like 1
  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×