]>
Commit | Line | Data |
---|---|---|
1d506c26 | 1 | # Copyright 2023-2024 Free Software Foundation, Inc. |
a0b70d99 TT |
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 | ||
0b7de6d3 GA |
16 | import os |
17 | ||
a0b70d99 TT |
18 | import gdb |
19 | ||
20 | from .server import request, capability | |
2a89c950 | 21 | from .startup import in_gdb_thread, DAPException |
a0b70d99 TT |
22 | |
23 | ||
c64cba1b TT |
24 | # The next available source reference ID. Must be greater than 0. |
25 | _next_source = 1 | |
26 | ||
27 | # Map from full paths to Source dictionaries. | |
28 | _source_map = {} | |
29 | ||
30 | # Map from a source reference ID back to the same Source that is | |
31 | # stored in _source_map. | |
32 | _id_map = {} | |
33 | ||
34 | ||
35 | @in_gdb_thread | |
36 | def make_source(fullname, filename): | |
37 | """Return the Source for a given file name. | |
38 | ||
39 | FULLNAME is the full name. This is used as the key. | |
40 | FILENAME is the base name. | |
41 | """ | |
42 | global _source_map | |
43 | if fullname in _source_map: | |
44 | result = _source_map[fullname] | |
45 | else: | |
c64cba1b TT |
46 | result = { |
47 | "name": filename, | |
48 | "path": fullname, | |
c64cba1b | 49 | } |
0b7de6d3 GA |
50 | |
51 | if not os.path.exists(fullname): | |
52 | global _next_source | |
53 | result["sourceReference"] = _next_source | |
54 | ||
55 | global _id_map | |
56 | _id_map[_next_source] = result | |
57 | _next_source += 1 | |
58 | ||
c64cba1b | 59 | _source_map[fullname] = result |
c64cba1b TT |
60 | return result |
61 | ||
62 | ||
4b6521cf TT |
63 | @in_gdb_thread |
64 | def decode_source(source): | |
65 | """Decode a Source object. | |
66 | ||
67 | Finds and returns the filename of a given Source object.""" | |
68 | if "path" in source: | |
69 | return source["path"] | |
70 | if "sourceReference" not in source: | |
2a89c950 | 71 | raise DAPException("either 'path' or 'sourceReference' must appear in Source") |
4b6521cf TT |
72 | ref = source["sourceReference"] |
73 | global _id_map | |
74 | if ref not in _id_map: | |
2a89c950 | 75 | raise DAPException("no sourceReference " + str(ref)) |
4b6521cf TT |
76 | return _id_map[ref]["path"] |
77 | ||
78 | ||
c98921b2 TT |
79 | @request("loadedSources") |
80 | @capability("supportsLoadedSourcesRequest") | |
81 | def loaded_sources(**extra): | |
a0b70d99 TT |
82 | result = [] |
83 | for elt in gdb.execute_mi("-file-list-exec-source-files")["files"]: | |
c64cba1b | 84 | result.append(make_source(elt["fullname"], elt["file"])) |
a0b70d99 TT |
85 | return { |
86 | "sources": result, | |
87 | } | |
88 | ||
89 | ||
13bd1a91 TT |
90 | @request("source") |
91 | def source(*, source=None, sourceReference: int, **extra): | |
92 | # The 'sourceReference' parameter is required by the spec, but is | |
93 | # for backward compatibility, which I take to mean that the | |
94 | # 'source' is preferred. | |
95 | if source is None: | |
96 | source = {"sourceReference": sourceReference} | |
c98921b2 TT |
97 | filename = decode_source(source) |
98 | with open(filename) as f: | |
99 | content = f.read() | |
100 | return { | |
101 | "content": content, | |
102 | } |