Sign in Join
Wiki copytemporary

Lazarus Debugger Implementation: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-<div style="font-size:130%">
2-
31> **Note:** There is another page on this topic [[TDebuggerIntf]]
4-
5-</div>
62
73# Introduction
84
95This page provides an overview of how the debugger is implemented in the Lazarus IDE.
106
117The debugger comprises the following parts:
128
139Debugger-Frontend
1410The controls (run, step, stop buttons) and dialogs (watches, stack) in the IDE.
1511
1612Debugger-Interface
1713A set of base-classes defining the communication between the front-end and each back-end
1814
1915Debugger-Backend
2016Any code to control the debugged app, and retrieve/modify data from/in that app. The back-end may itself be split into an **IDE back-end** and an **external back-end** (e.g. gdb).
2117
2218# Debugger-Frontend
2319
2420The code for the debugger frontend belongs currently directly to the IDE (to the project ide/lazarus.lpi). It is not a package of it's own.
2521
2622Some of this code may one day be moved into a package. And maybe even introduce a package DebuggerFrontendIntf, to allow alternative 3rd party front-ends.
2723
2824### Files and Folders
2925
3026- package: IdeDebugger in /ide/packages/idedebugger (Lazarus 2.3 up)
3127- folder: /debugger
3228- folder: /ide, files: debugmanager.pas and basedebugmanager.pas
3329- folders: /ide/frames and /debugger/frames (for configuration settings)
3430
3531Most of the Frontend-Debugger code should eventually move to the package IdeDebugger. Some abstract type definitions may go into the IdeIntf package.
3632
3733###
3834
3935BaseDebugManager is currently based on components\debuggerintf\dbgintfdebuggerbase.pp
4036
4137# Debugger-Interface
4238
4339### Files and Folders
4440
4541- package: DebuggerIntf in /components/debuggerintf/ (old code)
4642- package: LazDebuggerIntf in /components/debuggerintf/lazdebuggerintf (new version of the Interface / work in progress / Lazarus 2.3 up)
4743
4844Code in "DebuggerIntf" will over time move into other locations. (Frontend, LazDebuggerIntf or individual Backends)
4945
5046###
5147
5248> **Note:** The debugger interface is still subject to change. It was created by just extracting code from the GdbMiDebuggers (gdb/server/ssh) - which were at the time the only debuggers. The IDE now having several other debuggers may in future warrant a redesign of this interface
5349
5450## TDebuggerIntf - main class
5551
5652TDebuggerIntf provides the communication between front ad back-end.
5753
5854### State
5955
6056Note: Currently State contains some value internal to the backend. (dsIdle/dsInit). Those may vary from back-end to back-end
6157
6258There are 2 pause states.
6359
6460- The proper pause (debugged app is paused) = dsPause.
6561- And dsInternalPause used for example for breakpoints that will automatically continue to run the debuggee.
6662
6763See documentation in source code.
6864
6965### RequestCommand
7066
7167The front-end can send asynchronous commands to the back-end. A result - if any - will be provided via an event.
7268
7369Commands are (some entries of the list are outdated)
7470
7571` TDBGCommand = (`\
7672`   dcRun, dcPause,  dcStop,`\
7773`   dcStepOver,  dcStepInto,  dcStepOut,  dcStepTo,`\
7874`   dcRunTo,  dcJumpto, dcAttach,  dcDetach,`\
7975`   dcBreak,  dcWatch,  dcLocal,  dcEvaluate,  dcModify,`\
8076`   dcEnvironment, dcSetStackFrame,  dcDisassemble,`\
8177`   dcStepOverInstr,  dcStepIntoInstr,`\
8278`   dcSendConsoleInput  //, dcSendSignal`\
8379`   );`
8480
8581The back-end does not need to implement all commands. (see procedure SupportedCommands) The availability of commands also depends on the **State**
8682
8783There are helpers like
8884
8985` procedure Run;`
9086
9187They will take additional care of calling **Init** if needed.
9288
9389### Events
9490
9591## TDebuggerDataMonitor and TDebuggerDataSupplier - stack, watches, ....
9692
9793The debugger can supply data like Threads, Stack, Locals, Watches... Any of this data is provided by a ___DataSupplier. On the IDE site to each Supplier, one ___DataMonitor is attached. The Supplier/Monitor concept was introduced to allow both sides to have their own, yet synchronized list of items for the list-entries.
9894
9995For an example: Watches.
10096
10197The IDE creates a Watch as "TIdeWatch". The Ide can stick any data to a watch that the IDE may require. For example watch-properties (display, enabled, ...) or streaming.
10298
10399The back-end may need different information, such as internal details retrieved from the external-backend (gdb). So the back-end uses "TGDBMIWatches = class(TWatchesSupplier)". And other back-ends have their own sub-classes.
104100
105101The supplier/monitor concept keeps the two lists synchronized. For Watches, the IDE side (the monitor) creates and deletes the entries. For Stack and locals, it is the back-end that creates/deletes entries.
106102
107103When the IDE needs a value then the request is forwarded to the data-supplier. A value in this context can be anything read from any of the involved objects. The count of thread/stackframes is a value, the frame itself is a value (which is an object with multiple data fields). And the evaluated result of a watch is a value too.
108104
109105All data is retrieved event driven. Asking for Stackcount, or watch-result will not return the value immediately. It will trigger its evaluation, and the data-supplier will sent an update event when the value (any value) becomes available.
110106
111107For this to work, each value has a validity "TDebuggerDataState".
112108
113109- AWatch.Values\[ThreadId, Stackframe\].Value and AWatch.Values\[ThreadId, Stackframe\].Validity
114110- In other cases validity is not exposed. Count may return 0, if it is not yet valid. (Maybe a TODO, to expose the validity? Just maybe.)
115111
116112There is no rule how many update-events may be triggered before some value becomes valid. Any code listening to events from the monitor simply has to start over when it gets an event. Events may occur nested, code must protect itself again re-entrance in such a case.
117113
118114The validity is internally also used to avoid duplicate triggers. The IDE can ask for a value as often as it wants. When it asks for the first time the validity changes to "requested", preventing further triggers to the back-end. Validity is usually reset, when the debugger leaves the dsPause state. (dsPause is a state related to the debuggers execution of the debuggee).
119115
120116# Debugger-Backend
121117
122118"Command Queue"
123119
124120This is an item most/all backends have in common. Commands are received via **RequestCommand** and may take any amount of time to execute. Other work for the backend comes from the DataMonitor/Suppliers. And Backends may also schedule work of there own (for example retrieving the current location when an app enters pause). All this work is usually serialized in the backend (though backends are free to process multiple items paralel). For this backends have (at least) one CommandQueue. Usually this queue supports some sort of priority, so items in response to a user action (e.g. evaluating an expression for source editor hint) can be executed first. This means the user does not need to wait unnecessary long for this.
125121
126122## GDB / GDBMI based
127123
128124` Location: components/lazdebuggergdbmi`
129125
130126## LLDB
131127
132128` Location: components/lazdebuggers/LazDebuggerLldb`\
133129`           components/lazdebuggers/LazDebuggerFpLldb`
134130
135131## FpDebug
136132
137133` Location: components\lazdebuggers\LazDebuggerFp`
138134
139135# Testcases (Backend)
140136
141137Most/all backends come with a testcase, located in the subdirectory **test**
142138
143139The testcase are designed to test the backend against a set of "test apps". The results of the test may depend on:
144140
145141- the version of fpc used to compile the "test apps"
146142- the version of the external debugger, if any (gdb, lldb)
147143
148144Therefore there are some config files which should be set up before running the testcase. Those are fpclist.txt, and in case of gdb/lld based debuggers gdblist.txt or lldblist.txt. There are sample files included. Note that the specification of the version in those files may affect which tests are run. (i.e. not all version may support all features). If they do not exist, the testcase will try to find the lazarus config, but it may not run correctly.
149145
150146Note, on Linux the "test/TestApps" dir is expected as "test/testapps". A symbolic link needs to be created.
151147
152148Optional a "test/logs" folder should be created. If detected logs will be filed there instead of directly under "tests/".
153149
154150When running tests, they will create files/folders in test/TestApps. Some of them are not correctly cleaned up, and need to occasionally be removed by the user. Also if a testcase is not properly exited, it leaves behind files in the test/TestApps/lib folder, which could cause the next test run to fail, so they also need to be removed in that case.
155151
156152When the test are run, they will show test-entries for each combination of fpc (each version configured), and each external debugger (if applicable). There is a control window, which allows to deselect tests by various criteria.
157153
158154Each entry in the list of tests (test tree), actually runs many individual tests. Therefore at least on-error a logfile should be written to see what exactly failed. The log also tells how many subtests did fail, for quick access this info is also embedded in the filename.
159155
160156---
161157*From the Free Pascal wiki, page "Lazarus Debugger Implementation", as it stood on 2022-01-10 after a change by Martin, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history