]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame_incremental - gdb/python/lib/gdb/dap/sources.py
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / dap / sources.py
... / ...
CommitLineData
1# Copyright 2023-2025 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import os
17
18from .server import capability, request
19from .startup import DAPException, exec_mi_and_log, in_gdb_thread
20
21# The next available source reference ID. Must be greater than 0.
22_next_source = 1
23
24# Map from full paths to Source dictionaries.
25_source_map = {}
26
27# Map from a source reference ID back to the same Source that is
28# stored in _source_map.
29_id_map = {}
30
31
32@in_gdb_thread
33def make_source(fullname, filename=None):
34 """Return the Source for a given file name.
35
36 FULLNAME is the full name. This is used as the key.
37 FILENAME is the base name; if None (the default), then it is
38 computed from FULLNAME.
39 """
40 if fullname in _source_map:
41 result = _source_map[fullname]
42 else:
43 if filename is None:
44 filename = os.path.basename(fullname)
45
46 result = {
47 "name": filename,
48 "path": fullname,
49 }
50
51 if not os.path.exists(fullname):
52 global _next_source
53 result["sourceReference"] = _next_source
54
55 _id_map[_next_source] = result
56 _next_source += 1
57
58 _source_map[fullname] = result
59 return result
60
61
62@in_gdb_thread
63def decode_source(source):
64 """Decode a Source object.
65
66 Finds and returns the filename of a given Source object."""
67 if "sourceReference" not in source or source["sourceReference"] <= 0:
68 if "path" in source:
69 return source["path"]
70 raise DAPException("either 'path' or 'sourceReference' must appear in Source")
71 ref = source["sourceReference"]
72 if ref not in _id_map:
73 raise DAPException("no sourceReference " + str(ref))
74 return _id_map[ref]["path"]
75
76
77@request("loadedSources")
78@capability("supportsLoadedSourcesRequest")
79def loaded_sources(**extra):
80 result = []
81 for elt in exec_mi_and_log("-file-list-exec-source-files")["files"]:
82 result.append(make_source(elt["fullname"], elt["file"]))
83 return {
84 "sources": result,
85 }
86
87
88@request("source")
89def source(*, source=None, sourceReference: int, **extra):
90 # The 'sourceReference' parameter is required by the spec, but is
91 # for backward compatibility, which I take to mean that the
92 # 'source' is preferred.
93 if source is None:
94 source = {"sourceReference": sourceReference}
95 filename = decode_source(source)
96 with open(filename) as f:
97 content = f.read()
98 return {
99 "content": content,
100 }