[Solved] Attach GDB to a TDaemon application lazarus / 12-Debugger ---------------------------------------------------------------------- ArminLinder · 2022-02-09 08:08 Hi, this question has been asked a while before (I found threads back until 2009), but IMHO never got a satisfactory answer. Is it possible to attach GDB and the Lazuarus IDE holding the source code to a running daemon (TDaemon) bullt with the debug configuration/switches, obviously to debug the daemon with the same level of functionality one is used to from "normal" applications? Thnx, Armin. ---------------------------------------------------------------------- Martin_fr · 2022-02-09 12:00 I haven't tried.... What happens if you use the attach feature of the IDE? (Run > Attach) If your daemon process runs as different user, you may have to start the entire IDE with sufficient rights. Note, if your daemon forks new processes (processes, not threads), only the process to which you attached will be debugged. So obviously at the time of attaching the process you are interested in has to be running already. ---------------------------------------------------------------------- Martin_fr · 2022-02-09 12:12 Or try gdbserver (search wiki). You may need to install the package LazDebuggerGdbmiServer. Then you can start the daemon using:   gdbserver [--host...]  your_daemon ---------------------------------------------------------------------- ArminLinder · 2022-02-09 14:23 Quote from: Martin_fr on February 09, 2022, 01:00:53 pmI haven't tried.... What happens if you use the attach feature of the IDE? (Run > Attach) If your daemon process runs as different user, you may have to start the entire IDE with sufficient rights. Note, if your daemon forks new processes (processes, not threads), only the process to which you attached will be debugged. So obviously at the time of attaching the process you are interested in has to be running already. IDE and Service are running under the same account. No forking involved. Nevertheless, attach to process fails. ---------------------------------------------------------------------- Martin_fr · 2022-02-09 15:17 What OS ? In order to comment on the gdb error, I would need a log / or the gdb "debug output": https://wiki.lazarus.freepascal.org/GDB_Debugger_Tips#Log_info_for_deb ug_session Have you tried FpDebug? Or is there a reason it has to be gdb? ---------------------------------------------------------------------- ArminLinder · 2022-02-09 18:05 Thanks very much for your support! My OS is Windows 11. I did some more testing. First of all, I updated Lazarus from 2.2.0RC2 to 2.2.0 Release. The message has changed, I get a readable "Access denied (Code 5)" message now. Tried: - User account is a member of the Administrators group - Lazarus and the affected Daemon are both running with this account - Started Lazarus with elevated privileges (got UAC confirmation dialog) Best regards, Armin. ---------------------------------------------------------------------- Martin_fr · 2022-02-09 19:19 OK, it looks like the logger got broken in 2.2 (The log you returned is empty, in the sense that the debug-log-msgs are not in it. And never mind where the debugging failed, there would be some of them). Anyway, with the error you get now, I am pretty sure that the log will contain the same error. That is the error comes from gdb, and not from the IDE. The latter could only be, if gdb could not be started). So the log is no longer needed. Testing on Win10, an elevated Lazarus process, does start gdb as elevated process too.  (Though I did not have a target that was running elevated) Anyway, it seems to fail due to restrictions from the OS. So other than googling, I don't have any recommendation. If you can successfully attach gdb (without the IDE), and know what was needed to do so, I can look if that can be achieved from inside the IDE. Btw, elevated. Faint memory of mine... If your TDaemon is some driver (hardware driver), then it may run as part of the kernel. Not sure if simple elevated, is enough for that. ---------------------------------------------------------------------- balazsszekely · 2022-02-09 20:22 It works fine at my side(see attached picture). I did the following: 1. Create a debug profile for my service 2. Run Lazarus elevated as SYSTEM with PSExec from SysInternals, like this(PSExec -sid c:\lazarus\lazarus.exe). 3. Run->Attach to Program.. ---------------------------------------------------------------------- Martin_fr · 2022-02-09 20:47 Great info. We should have a wiki page for stuff like this... ---------------------------------------------------------------------- 440bx · 2022-02-09 21:43 Quote from: Martin_fr on February 09, 2022, 09:47:49 pmGreat info. We should have a wiki page for stuff like this... I agree, that is really good stuff.  Thank you for sharing that GetMem. ---------------------------------------------------------------------- ArminLinder · 2022-02-10 13:00 Quote from: 440bx on February 09, 2022, 10:43:33 pmQuote from: Martin_fr on February 09, 2022, 09:47:49 pmGreat info. We should have a wiki page for stuff like this... I agree, that is really good stuff.  Thank you for sharing that GetMem. I think I can hijack this info and add a chapter about "daemon debugging" to "https://wiki.freepascal.org/Daemons_and_Services", as soon as I am done with the basics. For Windows I know what you did (I had a similar idea and tried to run the daemon and lazarus under the same Administrator account, which did not work), but I did not try to run Lazarus and the daemon under the "System" account. I'll check on Linux as well and see back to you in case my current Linux skills proove insufficient. Armin. ---------------------------------------------------------------------- ArminLinder · 2022-02-12 09:42 Unfortunately, I am stuck again. What worked quite well yesterday, doesn't work any longer today. I suspect I got a deadlock somewhere, and thus my breakpoints are never reached. What's happening is that I can start my service, get a PID, and attach the debugger using "run - attach to program", and then the debugger breaks in "ntdll!DbgBreakPoint", From there I can use "Run (F9)" to continue. Unfortunately this is where success ends, no further breakpoint is ever hit. I suspect that my daemon may hang somewhere, but I cannot find out where. At the core of the problem lies, the the PID gets known only after the daemon has been started, and there won't be any way to let it hit a breakpont on start, because I cannot find out the PID and attach the debugger before all the onStart code has already executed. Two possible soutions come to my mind, but each arises a bunch of further questions I do not yet have answers for: - there could probably be a construct DebuggerAttached.waitfor() to tell the code to wait, until the debugger is attached. I could put this into the onStart method, maybe. Does such a possibility exist? - I could try to run the code from normal lazarus in user context, I suspect the problem is not at all related to background operations, and then somehow trigger OnStart just like the OS service manager does. I did always suspect that this could be the functionality behind the -run command line parameter. So I put a breakpoint into onStart, and set the command line param string in Lazarus to -run. Nothing happened, the program started and ended immedately, without doing anything. Is there any way to achieve what I want? What is the functionality behind the -run parameter? Thnx, Armin. ---------------------------------------------------------------------- Martin_fr · 2022-02-12 10:03 Not sure if it works.... https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf- debugapi-isdebuggerpresent while not IsDebuggerPresent do sleep(10); If indeed it is hanging, hit pause. And then search through the thread window. On Windows, pausing a process (as well as attaching, afaik  / but not hitting a breakpoint) injects a thread. So you will be in the injected thread, which is meaningless to you. Btw, this means, your process must have finished the initialization in the system (and maybe sysutils) unit(s). Because the setup code and data, that is called/used when new threads are created (even if the thread is "injected", it's a callback, so it happens for every thread). If you manage to ask the OS to pause an fpc app, before that initialization => then the app will crash. ---------------------------------------------------------------------- Martin_fr · 2022-02-12 10:17 Also to find the "hang"... You can try https://docs.microsoft.com/en- us/windows/win32/api/debugapi/nf-debugapi-outputdebugstringw (both gdb and (afaik) fpdebug should show them / in the "debug event" window - if enabled in Tools > Options). Or open a regular file, and log to it (LazLogger sholud be able to do that). Then you can see, if certain points of your app are called. And (if you log, at locations where breakpoints will be) you can see if code with breakpoints is run, and therefore if the problem is indeed that they are not called, or if they do not work. Mind, there are some bugs with breakpoints, if your code contains subroutines that are "dead code". Fpc removes them, but it keeps some debug info (and/or messes up info of the code in front/behind). In rare cases this affects breakpoints set in live code, after a dead subroutine. (dead "if then" blocks are not known to be an issue). https://gitlab.com/freepascal.org/fpc/source/-/issues/39499  // This affects only gdb, not fpdebug  // fpdebug on the other hand does not handle methods of old style "type TFoo = object .... end;" ---------------------------------------------------------------------- ArminLinder · 2022-02-12 16:56 Quote from: Martin_fr on February 12, 2022, 11:03:49 amNot sure if it works.... https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf- debugapi-isdebuggerpresent Martin, u'r genius :-) The line worked like a charm, and now I got a really strong idea where the problem in my code stems from. I herewith promise to add all those extremely useful tips in the wikis about daemons, and probably general debugging within the enxt 1 or 2 weeks, I need to finish my daemon first, but afterwards I got some free time. It seems though, that IsDebuggerPresent is part of the Windows unit, so I suspect it won't work with Linux. Moreover I am mainly using Windows, and Linux only occasionally. Right now I'd test on Linux as good as I can, but some cross-checking with someone more familiar with debugging on Linux would be very welcome. Same applies to macOS, but since there is no requirement to run on macOS for my current project I hardly justify spending time on macOS, and I don't own any hardware Mac anyway, only VMs. nevertheless I consider Windows, Linux and macOS the "big three" we should always strive to support, so if anyone is willing to contribute the macOS part he'd be very welcome. Armin. ---------------------------------------------------------------------- Martin_fr · 2022-02-12 17:12 Quote from: Nimral on February 12, 2022, 05:56:25 pmIt seems though, that IsDebuggerPresent is part of the Windows unit, so I suspect it won't work with Linux. To be tested... A more generic approach Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var WaitForDbg: Ingeger; // Make this a GLOBAL varbegin  WaitForDbg := 0;  while WaitForDbg < 1 do    sleep(10); Once attached, while the app is paused, go to the debuggers "evaluate / modify" window. Enter WaitForDbg, and the modify it to "1" (need to press enter in the modify input field). ---------------------------------------------------------------------- ArminLinder · 2022-02-14 15:28 I did some more testing with this [new to me] functionality, and I need to correct myself in some respects. All tests done 2/2022 on Windows 11 with Lazarus 2.2.0/FPC 3.2.2. I could finally debug my daemon regardless of whether I ran it as system or under a specific service user account, and it is not necessary to  use the same account for Lazarus and the daemon. All I needed is to run Lazarus with elevated privilege. The handling of the debugger controls in Lazarus needs a bit of attention and practice when one does it the first time. And FPDebug didn't work, "Run - Attach to program" never got active, unless I changed the debugger in project options to GDB. PSExec has many options which may be handy in some scenarios, but is not specifically necessary, with one exception: Windows does AFAIK not allow one to "runas" Lazarus under the "system" account, so if anyone, for any reason, wants to run Lazarus under the system account, he needs to do that using PsExec. For my purposes "run as administrator" from the Lazarus.exe context menu did the job nicely. IsDebuggerPresent is a great aid for Windows, I still wonder whether there is an equivalent for Linux. Sure, there is that "change loop variable using the debugger" workaround mentioned above, but ... :-) Thanks again to Martin, whose initial post showed me the right way! Armin. ---------------------------------------------------------------------- Martin_fr · 2022-02-14 16:01 Quote from: Nimral on February 14, 2022, 04:28:09 pm And FPDebug didn't work, "Run - Attach to program" never got active, unless I changed the debugger in project options to GDB. Have you tried "Reset Debugger", before attaching? Should not be needed, but if the menu entry is grayed out.... The menu entry is enabled for me. I haven't attached to a service, but I did attach to other processes. However, unlike GDB the process will not be paused (so you don't notice it did attach) => you can pause it with the pause button. Maybe that should be changed.... ---------------------------------------------------------------------- ArminLinder · 2022-02-14 16:06 I tried, but the "Run" - "Attach to program" gets deactivated (grayed), as soon as I switch the debugger from GDB to fpDebug. ---------------------------------------------------------------------- Martin_fr · 2022-02-14 16:15 Sorry, didn't read your footer (in case the 2.0.12 applies). You need 2.2 for "attach" with FpDebug. ---------------------------------------------------------------------- ArminLinder · 2022-02-14 16:19 I am on latest 2.2.0/FPC 3.2.2 ---------------------------------------------------------------------- Martin_fr · 2022-02-14 16:27 Strange... No idea.