Recent

Author Topic: Is there any way to name my threads for debugging?  (Read 23978 times)

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Is there any way to name my threads for debugging?
« Reply #15 on: January 09, 2018, 11:54:34 pm »
- It needs to be a member of a TThread derived class

Not necessary.  All you need is a Thread ID, or -1 for the current thread.

- You can't allocate nor define the record inside the procedure, it needs to be on the heap (global) and not on the stack (local) anyway

Not true.  Look at the MSDN example, it allocates on the stack.  So does Delphi.

- You should use stdcall

Not necessary.

- You should use PWideChar (the routine calls the widechar version anyway as per MSDN)

Wrong.  The name must be specified in ANSI, not in Unicode.  Look at the MSDN example again, it uses 'const char*', which is ANSI.

- You should copy in the Pwidechar, not assign the pointer.

Not necessary.  Copying the pointer is fine.

AND this need SEH enabled for your complete FPC build (*everything* full fpc build, full library build)

Is there a way to detect in app code whether SEH support is enabled at compile-time?

I seem to remember I also protected the WideChar with a critical section, although that should not be necessary.

Nope.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Is there any way to name my threads for debugging?
« Reply #16 on: January 10, 2018, 05:38:35 am »
According to GDB news page
June 4th, 2017 - GDB 8.0: "Support for thread names on MS-Windows"

I believe the version of GDB that ships with Lazarus is old (2014?), so I don't think it supports MS thread naming.

Recompiling everything just to get SEH support to set thread names seems a bit too much. I decided to do it in assembly. Someone already did something similar.

I used that code to do a quick test:
Code: Pascal  [Select][+][-]
  1. type
  2.   TThreadNameInfo =
  3.     record
  4.       RecType: DWord;
  5.       Name: pointer;//PAnsiChar;
  6.       ThreadID: DWord;
  7.       Flags: DWord;
  8.     end;
  9.  
  10. var
  11.   info: TThreadNameInfo;
  12.  
  13. procedure NameThreadForDebugging(const pName: pointer);
  14. begin
  15.     info.RecType := $1000;
  16.     info.Name := pName;
  17.     info.ThreadID := $FFFFFFFF;
  18.     info.Flags := 0;
  19.     //try
  20.         Windows.RaiseException($406D1388, 0, SizeOf(info) div SizeOf(DWord), Align(PDWord(@info),8));
  21.     //except
  22.     //end;
  23. end;
  24.  
  25. {$AsmMode intel}
  26.  
  27. function NameThread(vName:pointer):boolean;assembler;nostackframe;stdcall;
  28. label
  29. CLEANUP_label,next_instruction;
  30. asm
  31.   PUSH EBP //set up function's stack frame
  32.   MOV EBP, ESP
  33.  
  34.   CALL next_instruction //(next_instruction) //get EIP of next instruction (after 5-byte CALL) - MASM-syntax
  35. next_instruction:
  36.   POP EAX //EAX now equals whatever memory location THIS instruction is loaded at
  37.   ADD EAX, 01Ch //apply relative offset so EAX now points to our exception-handler entry point
  38.   PUSH EAX //build EXCEPTION_REGISTRATION structure on stack, first with our handler
  39.   PUSH DWORD PTR FS:[0] // followed by previous handler in chain
  40.   MOV DWORD PTR FS:[0], ESP //install our exception_frame to be first in chain
  41.  
  42.   MOV EAX, DWORD PTR SS:[EBP+8] //eax = pointer passed as argument #1
  43.   call NameThreadForDebugging
  44.   //MOV EAX, DWORD PTR DS:[EAX] //eax = *eax / dereference pointer - can we read DWORD memory?
  45.   XOR EAX, EAX //if we got here, no exception occurred, memory is readable, return zero (eax=0)
  46.  
  47.   //JMP SHORT CLEANUP_label (0000000Fh) //skip past exception_handler code
  48.   JMP SHORT CLEANUP_label //skip past exception_handler code
  49.  
  50.   XOR EAX, EAX //exception_handler entry point
  51.   INC EAX //return 1
  52.  
  53.   MOV ESP, DWORD PTR FS:[0] // **** SWALLOW EXCEPTION BY ****
  54.   MOV ESP, DWORD PTR SS:[ESP] // **** RESTORING ESP ****
  55. CLEANUP_label:
  56.   POP DWORD PTR FS:[0] //CLEANUP_label - restore previous exception handler
  57.   ADD ESP, 4 //remove our exception_handler from stack
  58.   POP EBP //restore caller's stack frame
  59.   RETN 4 //remove STDCALL argument and return from function
  60. end;

I don't know if it works, as I don't have a debugger that supports it.  Calling NameThread(@s[1]); supposed to change the name of the current thread.

Edit:
OllyDbg 2.0 supports "Thread names (MS_VC_EXCEPTION)". Tested the code and it showed the name of the thread. Check attached image.
« Last Edit: January 10, 2018, 06:24:49 am by engkin »

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: Is there any way to name my threads for debugging?
« Reply #17 on: January 10, 2018, 06:30:28 am »
I use gdb 8.0.1 for x86_64. Can't find an executable for i386 atm.
@remy: Can you provide a sample implemantation for x86_64?
@engkin: How to adapt the assembly code to work on x86_64?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Is there any way to name my threads for debugging?
« Reply #18 on: January 10, 2018, 06:38:10 am »
@engkin: How to adapt the assembly code to work on x86_64?
Maybe this helps as a starting point?

It seems that MS added a new function for Windows 10 SetThreadDescription

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: Is there any way to name my threads for debugging?
« Reply #19 on: January 10, 2018, 08:06:44 am »
It seems that MS added a new function for Windows 10 SetThreadDescription

Yes, i know from 1607 on, but then gdb or at least Lazarus has to call GetThreadDescription for thread window.
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: Is there any way to name my threads for debugging?
« Reply #20 on: January 10, 2018, 02:05:49 pm »
Does anyone have working code for x86_64 to name threads for debugging?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

balazsszekely

  • Guest
Re: Is there any way to name my threads for debugging?
« Reply #21 on: January 10, 2018, 05:07:21 pm »
Quote
@Pascal
Does anyone have working code for x86_64 to name threads for debugging?
I just noticed that while debugging a specific thread,  the gdb sends back the ThreadID(see screenshot). This can be used to add unique names to each thread created from your application. The name is virtual, but it will show up in Debug Windows-->Threads dialog. All you have to do is add a TList/TObjectList to TDebuggerIntf class(components/debuggerintf/dbgintfdebuggerbase.pp), the list will hold the name and ID of every thread you wish to monitor. When the gdb sends the notify message, you compare the ids with the internal list and assign the name accordingly. I'm not saying it's easy to implement but it can be done. As a second screenshot I attach all the relevant units.

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Is there any way to name my threads for debugging?
« Reply #22 on: January 10, 2018, 05:51:26 pm »
Tnx Remy. Appreciated.
Specialize a type, not a var.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: Is there any way to name my threads for debugging?
« Reply #23 on: January 10, 2018, 08:08:25 pm »
Quote
@Pascal
Does anyone have working code for x86_64 to name threads for debugging?
I just noticed that while debugging a specific thread,  the gdb sends back the ThreadID(see screenshot). This can be used to add unique names to each thread created from your application. The name is virtual, but it will show up in Debug Windows-->Threads dialog. All you have to do is add a TList/TObjectList to TDebuggerIntf class(components/debuggerintf/dbgintfdebuggerbase.pp), the list will hold the name and ID of every thread you wish to monitor. When the gdb sends the notify message, you compare the ids with the internal list and assign the name accordingly. I'm not saying it's easy to implement but it can be done. As a second screenshot I attach all the relevant units.

I also had this idea. But will it need IPC to share the information or is there an object which is accessible from Lazarus and my app?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

balazsszekely

  • Guest
Re: Is there any way to name my threads for debugging?
« Reply #24 on: January 10, 2018, 08:38:04 pm »
Quote
I also had this idea. But will it need IPC to share the information
The communication between Lazarus and gdb is already implemented. Gdb sends the information about each thread as a long string. The IDE splits the string and display the values in ThreadDlg dialog.  Unfortunately the name of the thread is eaten by gdb, the only link is the threadid. 

Quote
is there an object which is accessible from Lazarus and my app?
In order to be accessible from your application, you have to implement it through debuggerintf interface. When you create a thread you must pass the name and the id to a function which stores the values in a TList(or something else). The values in the list will be compared to the strings received from gdb.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: Is there any way to name my threads for debugging?
« Reply #25 on: January 10, 2018, 08:47:31 pm »
I've understand that so far. The question is:
How do i get a reference to the debuggerintf interface in my app?
I need the same as in Lazarus which handles the messages from gdb. Or do i have to setup some
kind of IPC to send the information from my app to Lazarus or to receive the reference to the interface
from Lazarus?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

balazsszekely

  • Guest
Re: Is there any way to name my threads for debugging?
« Reply #26 on: January 10, 2018, 08:54:37 pm »
By adding DebuggerIntf package to the "Required Packages", or by creating a package(IDE add-on) similar to LazProfiler. Please note the DebuggerIntf most likely must be extended.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: Is there any way to name my threads for debugging?
« Reply #27 on: January 10, 2018, 08:59:44 pm »
And that is really the same instance, not an app local interface with no connection to Lazarus?
In a package like LazProfiler it is obvious, it's linked into Lazarus. But in an standalone app i do not see the
connection to Lazarus.

Edit:
If i add DebuggerIntf package to my app DebugBossManager is not instantiated, so no link to Lazarus!
« Last Edit: January 10, 2018, 09:04:32 pm by Pascal »
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

balazsszekely

  • Guest
Re: Is there any way to name my threads for debugging?
« Reply #28 on: January 10, 2018, 09:08:51 pm »
Your application is debugged by lazarus, there is a connection. Just open lazarus.lpi, then but a break point to Threaddlg.pp(line 102) and debug it step by step.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: Is there any way to name my threads for debugging?
« Reply #29 on: January 10, 2018, 09:15:42 pm »
GetMem, many thanks  for your help so far. I'll try to implement it the next days, even though i am skeptical it'll work
with debugging apps other than Lazarus itself.
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

 

TinyPortal © 2005-2018