Sign in Join
Wiki copytemporary

Lazarus Debugger Implementation: what changed

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

OldNewLine
11> **Note:** There is another page on this topic [[TDebuggerIntf]]
22
33# Introduction
44
55This page provides an overview of how the debugger is implemented in the Lazarus IDE.
66
77The debugger comprises the following parts:
88
99Debugger-Frontend
1010The controls (run, step, stop buttons) and dialogs (watches, stack) in the IDE.
1111
1212Debugger-Interface
1313A set of base-classes defining the communication between the front-end and each back-end
1414
1515Debugger-Backend
1616Any 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).
1717
1818# Debugger-Frontend
1919
2020The 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.
2121
2222Some 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.
2323
2424### Files and Folders
2525
2626- package: IdeDebugger in /ide/packages/idedebugger (Lazarus 2.3 up)
2727- folder: /debugger
2828- folder: /ide, files: debugmanager.pas and basedebugmanager.pas
2929- folders: /ide/frames and /debugger/frames (for configuration settings)
3030
3131Most of the Frontend-Debugger code should eventually move to the package IdeDebugger. Some abstract type definitions may go into the IdeIntf package.
3232
3333###
3434
3535BaseDebugManager is currently based on components\debuggerintf\dbgintfdebuggerbase.pp
3636
3737# Debugger-Interface
3838
3939### Files and Folders
4040
4141- package: DebuggerIntf in /components/debuggerintf/ (old code)
4242- package: LazDebuggerIntf in /components/debuggerintf/lazdebuggerintf (new version of the Interface / work in progress / Lazarus 2.3 up)
4343
4444Code in "DebuggerIntf" will over time move into other locations. (Frontend, LazDebuggerIntf or individual Backends)
4545
4646###
4747
4848> **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
4949
5050## TDebuggerIntf - main class
5151
5252TDebuggerIntf provides the communication between front ad back-end.
5353
5454### State
5555
5656Note: Currently State contains some value internal to the backend. (dsIdle/dsInit). Those may vary from back-end to back-end
5757
5858There are 2 pause states.
5959
6060- The proper pause (debugged app is paused) = dsPause.
6161- And dsInternalPause used for example for breakpoints that will automatically continue to run the debuggee.
6262
6363See documentation in source code.
6464
6565### RequestCommand
6666
6767The front-end can send asynchronous commands to the back-end. A result - if any - will be provided via an event.
6868
6969Commands are (some entries of the list are outdated)
7070
71-` TDBGCommand = (`\
72-`   dcRun, dcPause,  dcStop,`\
73-`   dcStepOver,  dcStepInto,  dcStepOut,  dcStepTo,`\
74-`   dcRunTo,  dcJumpto, dcAttach,  dcDetach,`\
75-`   dcBreak,  dcWatch,  dcLocal,  dcEvaluate,  dcModify,`\
76-`   dcEnvironment, dcSetStackFrame,  dcDisassemble,`\
77-`   dcStepOverInstr,  dcStepIntoInstr,`\
78-`   dcSendConsoleInput  //, dcSendSignal`\
79-`   );`
71+```text
72+ TDBGCommand = (
73+ dcRun, dcPause, dcStop,
74+ dcStepOver, dcStepInto, dcStepOut, dcStepTo,
75+ dcRunTo, dcJumpto, dcAttach, dcDetach,
76+ dcBreak, dcWatch, dcLocal, dcEvaluate, dcModify,
77+ dcEnvironment, dcSetStackFrame, dcDisassemble,
78+ dcStepOverInstr, dcStepIntoInstr,
79+ dcSendConsoleInput //, dcSendSignal
80+ );
81+```
8082
8183The back-end does not need to implement all commands. (see procedure SupportedCommands) The availability of commands also depends on the **State**
8284
8385There are helpers like
8486
85-` procedure Run;`
87+``` pascal
88+ procedure Run;
89+```
8690
8791They will take additional care of calling **Init** if needed.
8892
8993### Events
9094
9195## TDebuggerDataMonitor and TDebuggerDataSupplier - stack, watches, ....
9296
9397The 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.
9498
9599For an example: Watches.
96100
97101The 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.
98102
99103The 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.
100104
101105The 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.
102106
103107When 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.
104108
105109All 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.
106110
107111For this to work, each value has a validity "TDebuggerDataState".
108112
109113- AWatch.Values\[ThreadId, Stackframe\].Value and AWatch.Values\[ThreadId, Stackframe\].Validity
110114- 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.)
111115
112116There 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.
113117
114118The 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).
115119
116120# Debugger-Backend
117121
118122"Command Queue"
119123
120124This 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.
121125
122126## GDB / GDBMI based
123127
124-` Location: components/lazdebuggergdbmi`
128+```text
129+ Location: components/lazdebuggergdbmi
130+```
125131
126132## LLDB
127133
128-` Location: components/lazdebuggers/LazDebuggerLldb`\
129-`           components/lazdebuggers/LazDebuggerFpLldb`
134+```text
135+ Location: components/lazdebuggers/LazDebuggerLldb
136+ components/lazdebuggers/LazDebuggerFpLldb
137+```
130138
131139## FpDebug
132140
133-` Location: components\lazdebuggers\LazDebuggerFp`
141+```text
142+ Location: components\lazdebuggers\LazDebuggerFp
143+```
134144
135145# Testcases (Backend)
136146
137147Most/all backends come with a testcase, located in the subdirectory **test**
138148
139149The testcase are designed to test the backend against a set of "test apps". The results of the test may depend on:
140150
141151- the version of fpc used to compile the "test apps"
142152- the version of the external debugger, if any (gdb, lldb)
143153
144154Therefore 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.
145155
146156Note, on Linux the "test/TestApps" dir is expected as "test/testapps". A symbolic link needs to be created.
147157
148158Optional a "test/logs" folder should be created. If detected logs will be filed there instead of directly under "tests/".
149159
150160When 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.
151161
152162When 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.
153163
154164Each 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.
155165
156166---
157167*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