sym-info-cmds.exp revision 1.1.1.3 1 1.1.1.3 christos # Copyright 2019-2024 Free Software Foundation, Inc.
2 1.1 christos
3 1.1 christos # This program is free software; you can redistribute it and/or modify
4 1.1 christos # it under the terms of the GNU General Public License as published by
5 1.1 christos # the Free Software Foundation; either version 3 of the License, or
6 1.1 christos # (at your option) any later version.
7 1.1 christos #
8 1.1 christos # This program is distributed in the hope that it will be useful,
9 1.1 christos # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 1.1 christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 1.1 christos # GNU General Public License for more details.
12 1.1 christos #
13 1.1 christos # You should have received a copy of the GNU General Public License
14 1.1 christos # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 1.1 christos
16 1.1 christos # Make it easier to run the 'info modules' command (using
17 1.1 christos # GDBInfoModules), and the 'info module ...' commands (using
18 1.1 christos # GDBInfoModuleContents) and process the output.
19 1.1 christos #
20 1.1 christos # The difficulty we run into is that different versions of gFortran
21 1.1 christos # include different helper modules which show up in the results. The
22 1.1 christos # procedures in this library help process those parts of the output we
23 1.1 christos # actually want to check, while ignoring those parts that we don't
24 1.1 christos # care about.
25 1.1 christos #
26 1.1 christos # For each namespace GDBInfoModules and GDBInfoModuleContents, there's
27 1.1 christos # a run_command proc, use this to run a command and capture the
28 1.1 christos # output. Then make calls to check_header, check_entry, and
29 1.1 christos # check_no_entry to ensure the output was as expected.
30 1.1 christos
31 1.1 christos namespace eval GDBInfoSymbols {
32 1.1 christos
33 1.1 christos # A string that is the header printed by GDB immediately after the
34 1.1 christos # 'info [modules|types|functions|variables]' command has been issued.
35 1.1 christos variable _header
36 1.1 christos
37 1.1 christos # A list of entries extracted from the output of the command.
38 1.1 christos # Each entry is a filename, a line number, and the rest of the
39 1.1 christos # text describing the entry. If an entry has no line number then
40 1.1 christos # it is replaced with the text NONE.
41 1.1 christos variable _entries
42 1.1 christos
43 1.1 christos # The string that is the complete last command run.
44 1.1 christos variable _last_command
45 1.1 christos
46 1.1 christos # Add a new entry to the _entries list.
47 1.1 christos proc _add_entry { filename lineno text } {
48 1.1 christos variable _entries
49 1.1 christos
50 1.1 christos set entry [list $filename $lineno $text]
51 1.1 christos lappend _entries $entry
52 1.1 christos }
53 1.1 christos
54 1.1 christos # Run the 'info modules' command, passing ARGS as extra arguments
55 1.1 christos # to the command. Process the output storing the results within
56 1.1 christos # the variables in this namespace.
57 1.1 christos #
58 1.1 christos # The results of any previous call to run_command are discarded
59 1.1 christos # when this is called.
60 1.1 christos proc run_command { cmd { testname "" } } {
61 1.1 christos global gdb_prompt
62 1.1 christos
63 1.1 christos variable _header
64 1.1 christos variable _entries
65 1.1 christos variable _last_command
66 1.1 christos
67 1.1 christos if {![regexp -- "^info (modules|types|variables|functions)" $cmd]} {
68 1.1 christos perror "invalid command"
69 1.1 christos }
70 1.1 christos
71 1.1 christos set _header ""
72 1.1 christos set _entries [list]
73 1.1 christos set _last_command $cmd
74 1.1 christos
75 1.1 christos if { $testname == "" } {
76 1.1 christos set testname $cmd
77 1.1 christos }
78 1.1 christos
79 1.1 christos send_gdb "$cmd\n"
80 1.1 christos gdb_expect {
81 1.1 christos -re "^$cmd\r\n" {
82 1.1 christos # Match the original command echoed back to us.
83 1.1 christos }
84 1.1 christos timeout {
85 1.1 christos fail "$testname (timeout)"
86 1.1 christos return 0
87 1.1 christos }
88 1.1 christos }
89 1.1 christos
90 1.1 christos gdb_expect {
91 1.1 christos -re "^\r\n" {
92 1.1 christos # Found the blank line after the header, we're done
93 1.1 christos # parsing the header now.
94 1.1 christos }
95 1.1 christos -re "^\[ \t]*(\[^\r\n\]+)\r\n" {
96 1.1 christos set str $expect_out(1,string)
97 1.1 christos if { $_header == "" } {
98 1.1 christos set _header $str
99 1.1 christos } else {
100 1.1 christos set _header "$_header $str"
101 1.1 christos }
102 1.1 christos exp_continue
103 1.1 christos }
104 1.1 christos timeout {
105 1.1 christos fail "$testname (timeout)"
106 1.1 christos return 0
107 1.1 christos }
108 1.1 christos }
109 1.1 christos
110 1.1 christos set current_file ""
111 1.1 christos gdb_expect {
112 1.1 christos -re "^File (\[^\r\n\]+):\r\n" {
113 1.1 christos set current_file $expect_out(1,string)
114 1.1 christos exp_continue
115 1.1 christos }
116 1.1 christos -re "^(\[0-9\]+):\[ \t\]+(\[^\r\n\]+)\r\n" {
117 1.1 christos set lineno $expect_out(1,string)
118 1.1 christos set text $expect_out(2,string)
119 1.1 christos if { $current_file == "" } {
120 1.1 christos fail "$testname (missing filename)"
121 1.1 christos return 0
122 1.1 christos }
123 1.1 christos _add_entry $current_file $lineno $text
124 1.1 christos exp_continue
125 1.1 christos }
126 1.1 christos -re "^\[ \t\]+(\[^\r\n\]+)\r\n" {
127 1.1 christos set lineno "NONE"
128 1.1 christos set text $expect_out(1,string)
129 1.1 christos if { $current_file == "" } {
130 1.1 christos fail "$testname (missing filename)"
131 1.1 christos return 0
132 1.1 christos }
133 1.1 christos _add_entry $current_file $lineno $text
134 1.1 christos exp_continue
135 1.1 christos }
136 1.1 christos -re "^\r\n" {
137 1.1 christos exp_continue
138 1.1 christos }
139 1.1 christos -re "^$gdb_prompt $" {
140 1.1 christos # All done.
141 1.1 christos }
142 1.1 christos timeout {
143 1.1 christos fail "$testname (timeout)"
144 1.1 christos return 0
145 1.1 christos }
146 1.1 christos }
147 1.1 christos
148 1.1 christos pass $testname
149 1.1 christos return 1
150 1.1 christos }
151 1.1 christos
152 1.1 christos # Check that the header held in _header matches PATTERN. Use
153 1.1 christos # TESTNAME as the name of the test, or create a suitable default
154 1.1 christos # test name based on the last command.
155 1.1 christos proc check_header { pattern { testname "" } } {
156 1.1 christos variable _header
157 1.1 christos variable _last_command
158 1.1 christos
159 1.1 christos if { $testname == "" } {
160 1.1 christos set testname "$_last_command: check header"
161 1.1 christos }
162 1.1 christos
163 1.1 christos gdb_assert {[regexp -- $pattern $_header]} $testname
164 1.1 christos }
165 1.1 christos
166 1.1.1.2 christos # Call check_entry_1 with OPTIONAL == 0.
167 1.1.1.2 christos proc check_entry { filename lineno text { testname "" } } {
168 1.1.1.2 christos check_entry_1 $filename $lineno $text 0 $testname
169 1.1.1.2 christos }
170 1.1.1.2 christos
171 1.1.1.2 christos # Call check_entry_1 with OPTIONAL == 1.
172 1.1.1.2 christos proc check_optional_entry { filename lineno text { testname "" } } {
173 1.1.1.2 christos check_entry_1 $filename $lineno $text 1 $testname
174 1.1.1.2 christos }
175 1.1.1.2 christos
176 1.1 christos # Check that we have an entry in _entries matching FILENAME,
177 1.1 christos # LINENO, and TEXT. If LINENO is the empty string it is replaced
178 1.1 christos # with the string NONE in order to match a similarly missing line
179 1.1 christos # number in the output of the command.
180 1.1 christos #
181 1.1 christos # TESTNAME is the name of the test, or a default will be created
182 1.1 christos # based on the last command run and the arguments passed here.
183 1.1 christos #
184 1.1 christos # If a matching entry is found then it is removed from the
185 1.1 christos # _entries list, this allows us to check for duplicates using the
186 1.1 christos # check_no_entry call.
187 1.1.1.2 christos proc check_entry_1 { filename lineno text optional testname } {
188 1.1 christos variable _entries
189 1.1 christos variable _last_command
190 1.1 christos
191 1.1 christos if { $testname == "" } {
192 1.1 christos set testname \
193 1.1 christos "$_last_command: check for entry '$filename', '$lineno', '$text'"
194 1.1 christos }
195 1.1 christos
196 1.1 christos if { $lineno == "" } {
197 1.1 christos set lineno "NONE"
198 1.1 christos }
199 1.1 christos
200 1.1 christos set new_entries [list]
201 1.1 christos
202 1.1 christos set found_match 0
203 1.1 christos foreach entry $_entries {
204 1.1 christos
205 1.1 christos if {!$found_match} {
206 1.1 christos set f [lindex $entry 0]
207 1.1 christos set l [lindex $entry 1]
208 1.1 christos set t [lindex $entry 2]
209 1.1 christos if { [regexp -- $filename $f] \
210 1.1 christos && [regexp -- $lineno $l] \
211 1.1 christos && [regexp -- $text $t] } {
212 1.1 christos set found_match 1
213 1.1 christos } else {
214 1.1 christos lappend new_entries $entry
215 1.1 christos }
216 1.1 christos } else {
217 1.1 christos lappend new_entries $entry
218 1.1 christos }
219 1.1 christos }
220 1.1 christos
221 1.1 christos set _entries $new_entries
222 1.1.1.2 christos if { $optional && ! $found_match } {
223 1.1.1.2 christos unsupported $testname
224 1.1.1.2 christos } else {
225 1.1.1.2 christos gdb_assert { $found_match } $testname
226 1.1.1.2 christos }
227 1.1 christos }
228 1.1 christos
229 1.1 christos # Check that there is no entry in the _entries list matching
230 1.1 christos # FILENAME, LINENO, and TEXT. The LINENO and TEXT are optional,
231 1.1 christos # and will be replaced with '.*' if missing.
232 1.1 christos #
233 1.1 christos # If LINENO is the empty string then it will be replaced with the
234 1.1 christos # string NONE in order to match against missing line numbers in
235 1.1 christos # the output of the command.
236 1.1 christos #
237 1.1 christos # TESTNAME is the name of the test, or a default will be built
238 1.1 christos # from the last command run and the arguments passed here.
239 1.1 christos #
240 1.1 christos # This can be used after a call to check_entry to ensure that
241 1.1 christos # there are no further matches for a particular file in the
242 1.1 christos # output.
243 1.1 christos proc check_no_entry { filename { lineno ".*" } { text ".*" } \
244 1.1 christos { testname "" } } {
245 1.1 christos variable _entries
246 1.1 christos variable _last_command
247 1.1 christos
248 1.1 christos if { $testname == "" } {
249 1.1 christos set testname \
250 1.1 christos "$_last_command: check no matches for '$filename', '$lineno', and '$text'"
251 1.1 christos }
252 1.1 christos
253 1.1 christos if { $lineno == "" } {
254 1.1 christos set lineno "NONE"
255 1.1 christos }
256 1.1 christos
257 1.1 christos foreach entry $_entries {
258 1.1 christos set f [lindex $entry 0]
259 1.1 christos set l [lindex $entry 1]
260 1.1 christos set t [lindex $entry 2]
261 1.1 christos if { [regexp -- $filename $f] \
262 1.1 christos && [regexp -- $lineno $l] \
263 1.1 christos && [regexp -- $text $t] } {
264 1.1 christos fail $testname
265 1.1 christos }
266 1.1 christos }
267 1.1 christos
268 1.1 christos pass $testname
269 1.1 christos }
270 1.1 christos }
271 1.1 christos
272 1.1 christos
273 1.1 christos namespace eval GDBInfoModuleSymbols {
274 1.1 christos
275 1.1 christos # A string that is the header printed by GDB immediately after the
276 1.1 christos # 'info modules (variables|functions)' command has been issued.
277 1.1 christos variable _header
278 1.1 christos
279 1.1 christos # A list of entries extracted from the output of the command.
280 1.1 christos # Each entry is a filename, a module name, a line number, and the
281 1.1 christos # rest of the text describing the entry. If an entry has no line
282 1.1 christos # number then it is replaced with the text NONE.
283 1.1 christos variable _entries
284 1.1 christos
285 1.1 christos # The string that is the complete last command run.
286 1.1 christos variable _last_command
287 1.1 christos
288 1.1 christos # Add a new entry to the _entries list.
289 1.1 christos proc _add_entry { filename module lineno text } {
290 1.1 christos variable _entries
291 1.1 christos
292 1.1 christos set entry [list $filename $module $lineno $text]
293 1.1 christos lappend _entries $entry
294 1.1 christos }
295 1.1 christos
296 1.1 christos # Run the 'info module ....' command, passing ARGS as extra
297 1.1 christos # arguments to the command. Process the output storing the
298 1.1 christos # results within the variables in this namespace.
299 1.1 christos #
300 1.1 christos # The results of any previous call to run_command are discarded
301 1.1 christos # when this is called.
302 1.1 christos proc run_command { cmd { testname "" } } {
303 1.1 christos global gdb_prompt
304 1.1 christos
305 1.1 christos variable _header
306 1.1 christos variable _entries
307 1.1 christos variable _last_command
308 1.1 christos
309 1.1 christos if {![regexp -- "^info module (variables|functions)" $cmd]} {
310 1.1 christos perror "invalid command: '$cmd'"
311 1.1 christos }
312 1.1 christos
313 1.1 christos set _header ""
314 1.1 christos set _entries [list]
315 1.1 christos set _last_command $cmd
316 1.1 christos
317 1.1 christos if { $testname == "" } {
318 1.1 christos set testname $cmd
319 1.1 christos }
320 1.1 christos
321 1.1 christos send_gdb "$cmd\n"
322 1.1 christos gdb_expect {
323 1.1 christos -re "^$cmd\r\n" {
324 1.1 christos # Match the original command echoed back to us.
325 1.1 christos }
326 1.1 christos timeout {
327 1.1 christos fail "$testname (timeout)"
328 1.1 christos return 0
329 1.1 christos }
330 1.1 christos }
331 1.1 christos
332 1.1 christos gdb_expect {
333 1.1 christos -re "^\r\n" {
334 1.1 christos # Found the blank line after the header, we're done
335 1.1 christos # parsing the header now.
336 1.1 christos }
337 1.1 christos -re "^\[ \t\]*(\[^\r\n\]+)\r\n" {
338 1.1 christos set str $expect_out(1,string)
339 1.1 christos if { $_header == "" } {
340 1.1 christos set _header $str
341 1.1 christos } else {
342 1.1 christos set _header "$_header $str"
343 1.1 christos }
344 1.1 christos exp_continue
345 1.1 christos }
346 1.1 christos timeout {
347 1.1 christos fail "$testname (timeout)"
348 1.1 christos return 0
349 1.1 christos }
350 1.1 christos }
351 1.1 christos
352 1.1 christos set current_module ""
353 1.1 christos set current_file ""
354 1.1 christos gdb_expect {
355 1.1 christos -re "^Module \"(\[^\"\]+)\":\r\n" {
356 1.1 christos set current_module $expect_out(1,string)
357 1.1 christos exp_continue
358 1.1 christos }
359 1.1 christos -re "^File (\[^\r\n\]+):\r\n" {
360 1.1 christos if { $current_module == "" } {
361 1.1 christos fail "$testname (missing module)"
362 1.1 christos return 0
363 1.1 christos }
364 1.1 christos set current_file $expect_out(1,string)
365 1.1 christos exp_continue
366 1.1 christos }
367 1.1 christos -re "^(\[0-9\]+):\[ \t\]+(\[^\r\n\]+)\r\n" {
368 1.1 christos set lineno $expect_out(1,string)
369 1.1 christos set text $expect_out(2,string)
370 1.1 christos if { $current_module == "" } {
371 1.1 christos fail "$testname (missing module)"
372 1.1 christos return 0
373 1.1 christos }
374 1.1 christos if { $current_file == "" } {
375 1.1 christos fail "$testname (missing filename)"
376 1.1 christos return 0
377 1.1 christos }
378 1.1 christos _add_entry $current_file $current_module \
379 1.1 christos $lineno $text
380 1.1 christos exp_continue
381 1.1 christos }
382 1.1 christos -re "^\[ \t\]+(\[^\r\n\]+)\r\n" {
383 1.1 christos set lineno "NONE"
384 1.1 christos set text $expect_out(1,string)
385 1.1 christos if { $current_module == "" } {
386 1.1 christos fail "$testname (missing module)"
387 1.1 christos return 0
388 1.1 christos }
389 1.1 christos if { $current_file == "" } {
390 1.1 christos fail "$testname (missing filename)"
391 1.1 christos return 0
392 1.1 christos }
393 1.1 christos _add_entry $current_file $current_module \
394 1.1 christos $lineno $text
395 1.1 christos exp_continue
396 1.1 christos }
397 1.1 christos -re "^\r\n" {
398 1.1 christos exp_continue
399 1.1 christos }
400 1.1 christos -re "^$gdb_prompt $" {
401 1.1 christos # All done.
402 1.1 christos }
403 1.1 christos timeout {
404 1.1 christos fail "$testname (timeout)"
405 1.1 christos return 0
406 1.1 christos }
407 1.1 christos }
408 1.1 christos
409 1.1 christos pass $testname
410 1.1 christos return 1
411 1.1 christos }
412 1.1 christos
413 1.1 christos # Check that the header held in _header matches PATTERN. Use
414 1.1 christos # TESTNAME as the name of the test, or create a suitable default
415 1.1 christos # test name based on the last command.
416 1.1 christos proc check_header { pattern { testname "" } } {
417 1.1 christos variable _header
418 1.1 christos variable _last_command
419 1.1 christos
420 1.1 christos if { $testname == "" } {
421 1.1 christos set testname "$_last_command: check header"
422 1.1 christos }
423 1.1 christos
424 1.1 christos gdb_assert {[regexp -- $pattern $_header]} $testname
425 1.1 christos }
426 1.1 christos
427 1.1 christos # Check that we have an entry in _entries matching FILENAME,
428 1.1 christos # MODULE, LINENO, and TEXT. If LINENO is the empty string it is
429 1.1 christos # replaced with the string NONE in order to match a similarly
430 1.1 christos # missing line number in the output of the command.
431 1.1 christos #
432 1.1 christos # TESTNAME is the name of the test, or a default will be created
433 1.1 christos # based on the last command run and the arguments passed here.
434 1.1 christos #
435 1.1 christos # If a matching entry is found then it is removed from the
436 1.1 christos # _entries list, this allows us to check for duplicates using the
437 1.1 christos # check_no_entry call.
438 1.1 christos #
439 1.1 christos # If OPTIONAL, don't generate a FAIL for a mismatch, but use UNSUPPORTED
440 1.1 christos # instead.
441 1.1 christos proc check_entry_1 { filename module lineno text optional testname } {
442 1.1 christos variable _entries
443 1.1 christos variable _last_command
444 1.1 christos
445 1.1 christos if { $testname == "" } {
446 1.1 christos set testname \
447 1.1 christos "$_last_command: check for entry '$filename', '$lineno', '$text'"
448 1.1 christos }
449 1.1 christos
450 1.1 christos if { $lineno == "" } {
451 1.1 christos set lineno "NONE"
452 1.1 christos }
453 1.1 christos
454 1.1 christos set new_entries [list]
455 1.1 christos
456 1.1 christos set found_match 0
457 1.1 christos foreach entry $_entries {
458 1.1 christos
459 1.1 christos if {!$found_match} {
460 1.1 christos set f [lindex $entry 0]
461 1.1 christos set m [lindex $entry 1]
462 1.1 christos set l [lindex $entry 2]
463 1.1 christos set t [lindex $entry 3]
464 1.1 christos if { [regexp -- $filename $f] \
465 1.1 christos && [regexp -- $module $m] \
466 1.1 christos && [regexp -- $lineno $l] \
467 1.1 christos && [regexp -- $text $t] } {
468 1.1 christos set found_match 1
469 1.1 christos } else {
470 1.1 christos lappend new_entries $entry
471 1.1 christos }
472 1.1 christos } else {
473 1.1 christos lappend new_entries $entry
474 1.1 christos }
475 1.1 christos }
476 1.1 christos
477 1.1 christos set _entries $new_entries
478 1.1 christos if { $optional && ! $found_match } {
479 1.1 christos unsupported $testname
480 1.1 christos } else {
481 1.1 christos gdb_assert { $found_match } $testname
482 1.1 christos }
483 1.1 christos }
484 1.1 christos
485 1.1 christos # Call check_entry_1 with OPTIONAL == 0.
486 1.1 christos proc check_entry { filename module lineno text { testname "" } } {
487 1.1 christos check_entry_1 $filename $module $lineno $text 0 $testname
488 1.1 christos }
489 1.1 christos
490 1.1 christos # Call check_entry_1 with OPTIONAL == 1.
491 1.1 christos proc check_optional_entry { filename module lineno text { testname "" } } {
492 1.1 christos check_entry_1 $filename $module $lineno $text 1 $testname
493 1.1 christos }
494 1.1 christos
495 1.1 christos # Check that there is no entry in the _entries list matching
496 1.1 christos # FILENAME, MODULE, LINENO, and TEXT. The LINENO and TEXT are
497 1.1 christos # optional, and will be replaced with '.*' if missing.
498 1.1 christos #
499 1.1 christos # If LINENO is the empty string then it will be replaced with the
500 1.1 christos # string NONE in order to match against missing line numbers in
501 1.1 christos # the output of the command.
502 1.1 christos #
503 1.1 christos # TESTNAME is the name of the test, or a default will be built
504 1.1 christos # from the last command run and the arguments passed here.
505 1.1 christos #
506 1.1 christos # This can be used after a call to check_entry to ensure that
507 1.1 christos # there are no further matches for a particular file in the
508 1.1 christos # output.
509 1.1 christos proc check_no_entry { filename module { lineno ".*" } \
510 1.1 christos { text ".*" } { testname "" } } {
511 1.1 christos variable _entries
512 1.1 christos variable _last_command
513 1.1 christos
514 1.1 christos if { $testname == "" } {
515 1.1 christos set testname \
516 1.1 christos "$_last_command: check no matches for '$filename', '$lineno', and '$text'"
517 1.1 christos }
518 1.1 christos
519 1.1 christos if { $lineno == "" } {
520 1.1 christos set lineno "NONE"
521 1.1 christos }
522 1.1 christos
523 1.1 christos foreach entry $_entries {
524 1.1 christos set f [lindex $entry 0]
525 1.1 christos set m [lindex $entry 1]
526 1.1 christos set l [lindex $entry 2]
527 1.1 christos set t [lindex $entry 3]
528 1.1 christos if { [regexp -- $filename $f] \
529 1.1 christos && [regexp -- $module $m] \
530 1.1 christos && [regexp -- $lineno $l] \
531 1.1 christos && [regexp -- $text $t] } {
532 1.1 christos fail $testname
533 1.1 christos }
534 1.1 christos }
535 1.1 christos
536 1.1 christos pass $testname
537 1.1 christos }
538 1.1 christos }
539