aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.gdb/selftest.exp
blob: 969797ae31f10315702b03d87d2703abdfccb37f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
# Copyright 1988-2016 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# This file was written by Rob Savoye. (rob@cygnus.com)

load_lib selftest-support.exp

# are we on a target board
if { [is_remote target] || ![isnative] } then {
    return
}

# Not all of the lines of code near the start of main are executed for
# every machine.  Also, optimization may reorder some of the lines.
# So all we do is try to step or next over everything until we get
# to a line that we know is always executed.

proc do_steps_and_nexts {} {
    global gdb_prompt
    global srcdir
 
    gdb_reinitialize_dir $srcdir/..

    set unlikely_line 0
    for {set count 0} {$count < 32} {incr count} {
	# NOTE: carlton/2002-12-11: The "initial brace" and
	# "current_directory initialization" possibilities happen to
	# me with GCC 3.1 on i686-pc-linux-gnu when I compile with
	# optimization.
	gdb_test_multiple "list" "list" {
	    -re ".*context = \\(struct captured_main_args \\*\\) data.*$gdb_prompt $" {
		set description "step over context initialization"
		set command "step"
	    }
	    -re ".*argc = context->argc.*$gdb_prompt $" {
		set description "step over argc initialization"
		set command "step"
	    }
	    -re ".*argv = context->argv.*$gdb_prompt $" {
		set description "step over argv initialization"
		set command "step"
	    }
	    -re ".*quiet = 0.*$gdb_prompt $" {
		set description "step over quiet initialization"
		set command "step"
	    }
	    -re ".*batch = 0.*$gdb_prompt $" {
		set description "step over batch initialization"
		set command "step"
	    }
	    -re ".*symarg = NULL.*$gdb_prompt $" {
		set description "step over symarg initialization"
		set command "step"
	    }
	    -re ".*execarg = NULL.*$gdb_prompt $" {
		set description "step over execarg initialization"
		set command "step"
	    }
	    -re ".*pidarg = NULL.*$gdb_prompt $" {
		set description "step over pidarg initialization"
		set command "step"
	    }
	    -re ".*corearg = NULL.*$gdb_prompt $" {
		set description "step over corearg initialization"
		set command "step"
	    }
	    -re ".*pid_or_core_arg = NULL.*$gdb_prompt $" {
		set description "step over pid_or_core_arg initialization"
		set command "step"
	    }
	    -re ".*cdarg = NULL.*$gdb_prompt $" {
		set description "step over cdarg initialization"
		set command "step"
	    }
	    -re ".*ttyarg = NULL.*$gdb_prompt $" {
		set description "step over ttyarg initialization"
		set command "step"
	    }
	    -re ".*cmdarg_vec = NULL.*$gdb_prompt $" {
		set description "step over cmdarg_vec initialization"
		set command "step"
	    }
	    -re ".*pre_stat_chain = make_command_stats_cleanup.*$gdb_prompt $" {
		set description "next over make_command_stats_cleanup and everything it calls"
		set command "next"
	    }
	    -re ".*START_PROGRESS.*$gdb_prompt $" {
		# Note: ezannoni/2004/02/17: This check should be
		# removed, since as of today that source line is not
		# in gdb anymore.
		set description "next over START_PROGRESS and everything it calls"
		set command "next"
	    }
	    -re ".*mac_init.*$gdb_prompt $" {
		set description "next over mac_init and everything it calls"
		set command "next"
	    }
	    -re ".*init_malloc.*$gdb_prompt $" {
		# gdb 6.2.X is the last gdb which called init_malloc
		set description "next over init_malloc and everything it calls"
		set command "next"
	    }
	    -re ".*lim_at_start.*$gdb_prompt $" {
		set description "next over lim_at_start initialization"
		set command "next"
	    }
	    -re ".*count . 0x3.*$gdb_prompt $" {
		set description "next over conditional stack alignment code 1"
		set command "next"
	    }
	    -re ".*if .i != 0.*$gdb_prompt $" {
		set description "next over conditional stack alignment code 2"
		set command "next"
	    }
	    -re ".*alloca .i - 4.*$gdb_prompt $" {
		set description "next over conditional stack alignment alloca"
		set command "next"
	    }
	    -re ".*dirsize = 1.*$gdb_prompt $" {
		set description "next over dirsize initialization"
		set command "next"
	    }
	    -re ".*dirarg = .* xmalloc.*$gdb_prompt $" {
		return
	    }
	    -re ".*setlocale .LC_MESSAGES,.*$gdb_prompt $" {
		set description "next over setlocale LC_MESSAGES"
		set command "next"
	    }
	    -re ".*setlocale .LC_CTYPE,.*$gdb_prompt $" {
		set description "next over setlocale LC_CTYPE"
		set command "next"
	    }
	    -re ".*bindtextdomain .PACKAGE, LOCALEDIR.;.*$gdb_prompt $" {
		set description "next over bindtextdomain"
		set command "next"
	    }
	    -re ".*textdomain .PACKAGE.;.*$gdb_prompt $" {
		set description "next over textdomain PACKAGE"
		set command "next"
	    }
	    -re ".*bfd_init ..;.*$gdb_prompt $" {
		set description "next over bfd_init"
		set command "next"
	    }
	    -re ".*notice_open_fds ..;.*$gdb_prompt $" {
		set description "next over notice_open_fds"
		set command "next"
	    }
	    -re ".*VEC_cleanup .cmdarg_s.*$gdb_prompt $" {
		set description "next over cmdarg_s VEC_cleanup"
		set command "next"
	    }
	    -re "\[0-9\]+\[\t \]+\{\r\n$gdb_prompt $" {
		set description "step over initial brace"
		set command "step"
	    }
	    -re ".*current_directory = gdb_dirbuf.*$gdb_prompt $" {
		set description "step over current_directory initialization"
		set command "step"
	    }
	    -re ".*gdb_sysroot = .*$gdb_prompt $" {
		# NOTE: carlton/2003-01-15: More optimization reordering,
		# observed on GCC 3.1.
		set description "step over gdb_sysroot initialization"
		set command "step"
	    }
	    -re ".*ndir = 0.*$gdb_prompt $" {
		set description "step over ndir initialization"
		set command "step"
	    }
	    -re ".*instream = stdin.*$gdb_prompt $" {
		set description "step over instream initialization"
		set command "step"
	    }
	    -re ".*getcwd .gdb_dirbuf, sizeof .gdb_dirbuf.*$gdb_prompt $" {
		set description "next over getcwd"
		set command "next"
	    }
	    -re ".*gdb_program_name = xstrdup.*$gdb_prompt $" {
                set description "next over xstrdup"
                set command "next"
            } 
            -re ".*quit_flag = 0.*$gdb_prompt $" {
		set description "step over quit_flag initialization"
		set command "step"
	    }
	    -re ".*gdb_stdout = stdio_fileopen .stdout.;.*$gdb_prompt $" {
		set description "step over gdb_stdout initialization"
		set command "step"
	    }
	    -re ".*gdb_stderr = stdio_fileopen .stderr.;.*$gdb_prompt $" {
		set description "step over gdb_stderr initialization"
		set command "step"
	    }
	    -re ".*main.c.*No such file or directory.*$gdb_prompt $" {
		setup_xfail "rs6000-*-aix3*"
		fail "must be able to list source lines"
		return
	    }
	    -re ".*interpreter_p = xstrdup.*$gdb_prompt $" {
		if { $unlikely_line == 0 } {
		    # This is a GCC optimization bug; a constant has been
		    # associated with the wrong line number.
		    setup_xfail "*-*-*" gcc/26475
		    fail "$description (unlikely line from gcc)"
		    set unlikely_line 1
		}
		set description "next over xstrdup"
		set command "next"
	    }
	    -re ".*$gdb_prompt $" {
		# If $description hasn't been set yet, it's likely the file
		# has been edited but gdb hasn't been recompiled.
		if [info exists description] {
		    fail "unknown source line (after $description)"
		} else {
		    fail "unknown source line"
		}
		return
	    }
	    default {
		fail "unknown source line near main"
		return
	    }
	}
	gdb_test_multiple "$command" "$description" {
	    -re ".*No such file or directory.\r\n$gdb_prompt $" {
		fail "$description (no source available)"
	    }
	    -re ".*A file or directory .* does not exist..\r\n$gdb_prompt $" {
		fail "$description (no source available)"
	    }
	    -re ".*$gdb_prompt $" {
		pass "$description"
	    }
	}
    }
}

proc test_with_self { executable } {
    global gdb_prompt
    global tool
    global det_file
    global decimal
    global timeout
    global INTERNAL_GDBFLAGS
    global inferior_spawn_id gdb_spawn_id

    # load yourself into the debugger
    # This can take a relatively long time, particularly for testing where
    # the executable is being accessed over a network, or where gdb does not
    # support partial symbols for a particular target and has to load the
    # entire symbol table.  Set the timeout to 10 minutes, which should be
    # adequate for most environments (it *has* timed out with 5 min on a
    # SPARCstation SLC under moderate load, so this isn't unreasonable).
    # After gdb is started, set the timeout to 30 seconds for the duration
    # of this test, and then back to the original value.

    set oldtimeout $timeout
    set timeout 600
    verbose "Timeout is now $timeout seconds" 2

    global gdb_file_cmd_debug_info
    set gdb_file_cmd_debug_info "unset"

    set result [gdb_load $executable]
    set timeout $oldtimeout
    verbose "Timeout is now $timeout seconds" 2

    if { $result != 0 } then {
	return -1
    }

    if { $gdb_file_cmd_debug_info != "debug" } then {
	untested "No debug information, skipping testcase."
	return -1
    }

    # When GDB is built as a C++ program, disassemble shows the full
    # prototype.
    set cxx_main_args_re [string_to_regexp "(int, char**)"]

    # disassemble yourself
    gdb_test "x/10i main" \
	    "x/10i.*main.*main($cxx_main_args_re)?.$decimal.*main($cxx_main_args_re)?.$decimal.*" \
	    "Disassemble main"

    # Set a breakpoint at main
    gdb_test "break captured_main" \
	    "Breakpoint.*at.* file.*, line.*" \
	    "breakpoint in captured_main"

    # We'll need this when we send a ^C to GDB.  Need to do it before we
    # run the program and gdb starts saving and restoring tty states.
    gdb_test "shell stty intr '^C'" ".*" \
	"set interrupt character in test_with_self"

    # FIXME: If we put this after the run to main, the first list
    # command doesn't print the same line as the current line where
    # gdb is stopped.
    gdb_test_no_output "set listsize 1" "set listsize to 1"

    # run yourself
    # It may take a very long time for the inferior gdb to start (lynx),
    # so we bump it back up for the duration of this command.
    set timeout 600

    set description "run until breakpoint at captured_main"
    gdb_test_multiple "run $INTERNAL_GDBFLAGS" "$description" {
	-re "Starting program.*Breakpoint \[0-9\]+,.*captured_main .data.* at .*main.c:.*$gdb_prompt $" {
	    pass "$description"
	}
	-re "Starting program.*Breakpoint \[0-9\]+,.*captured_main .data.*$gdb_prompt $" {
	    xfail "$description (line numbers scrambled?)"
	}
	-re "vfork: No more processes.*$gdb_prompt $" {
	    fail "$description (out of virtual memory)"
	    set timeout $oldtimeout
	    verbose "Timeout is now $timeout seconds" 2
	    return -1
	}
	-re ".*$gdb_prompt $" {
	    fail "$description"
	    set timeout $oldtimeout
	    verbose "Timeout is now $timeout seconds" 2
	    return -1
	}
    }

    set timeout $oldtimeout
    verbose "Timeout is now $timeout seconds" 2

    # do we have a version number ?
    gdb_test_multiple "print version" "printed version" {
	-re ".\[0-9\]+ = .\[0-9.\]+.*$gdb_prompt $" {
	    pass "printed version as string"
	}
	-re ".\[0-9\]+ = +0x.*\[0-9.\]+.*$gdb_prompt $" {
	    pass "printed version as pointer"
	}
	-re ".\[0-9\]+ = +.+ +0x.*\[0-9.\]+.*$gdb_prompt $" {
	    pass "printed version with cast"
	}
    }

    do_steps_and_nexts

    gdb_test "print \"foo\"" ".\[0-9\]+ = \"foo\"" "print a string"

    # do_steps_and_nexts left us ready to execute an xmalloc call,
    # so give that a try.
    # If we don't actually enter the xmalloc call when we give a
    # step command that seems like a genuine bug.  It seems to happen
    # on most RISC processors.
    # NOTE drow/2003-06-22: However, if we step back to the preceding two
    # lines, just keep stepping until we enter.
    set stepped_back 0
    setup_xfail "alpha-*-*" "mips-*-*"
    set description "step into xmalloc call"
    gdb_test_multiple "step" "$description" {
	-re "ncmd = 0;.*$gdb_prompt $" {
	    set stepped_back 1
	    send_gdb "step\n"
	    exp_continue
	}
        -re ".*cmdarg = .* xmalloc.*$gdb_prompt $" {
	    set stepped_back 1
	    send_gdb "step\n"
	    exp_continue
        }
	-re "dirsize = 1;.*$gdb_prompt $" {
	    set stepped_back 1
	    send_gdb "step\n"
	    exp_continue
	}
	-re ".*dirarg = .* xmalloc.*$gdb_prompt $" {
	    if { $stepped_back == 1 } {
		send_gdb "step\n"
		exp_continue
	    } else {
		fail "$description"
	    }
	}
	-re "xmalloc.*size=.*at.*utils.c.*$gdb_prompt $" {
	    pass "$description"
	}
	-re ".*No such file or directory.\r\n$gdb_prompt $" {
	    pass "$description (no source available)"
	}
	-re "A file or directory .* does not exist..\r\n$gdb_prompt $" {
	    pass "$description (no source available)"
	}
    }

    # start the "xgdb" process
    if [target_info exists gdb,noinferiorio] {
	# With no way to interact with the inferior GDB, all we can do
	# is let it run.
	send_gdb "continue\n"
	# Wait a bit while the inferior gdb gets to its prompt.
	sleep 1
    } else {
	set test "xgdb is at prompt"
	gdb_test_multiple "continue" $test {
	    -i "$inferior_spawn_id"
	    -re "GNU gdb \[0-9\.\]*.*Copyright \\(C\\) \[0-9\]* Free Software Foundation, Inc.*License GPLv3\\+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.*This is free software: you are free to change and redistribute it.*There is NO WARRANTY, to the extent permitted by law.  Type \"show copying\".*and \"show warranty\" for details.*This GDB was configured as .*$gdb_prompt $" {
		pass $test
	    }
	}

	# set xgdb prompt so we can tell which is which
	send_inferior "set prompt (xgdb) \n"
	set msg "Set xgdb_prompt"
	gdb_test_multiple "" $msg {
	    -i "$inferior_spawn_id"
	    -re "\[(\]xgdb\[)\].*\[(\]xgdb\[)\] $" {
		pass $msg
	    }
	}
    }

    # kill the xgdb process
    if ![target_info exists gdb,nointerrupts] {
	set description "send ^C to child process"
	send_gdb "\003"
	# "Thread 1" is displayed iff Guile support is linked in.
	gdb_expect {
	    -re "(Thread .*|Program) received signal SIGINT.*$gdb_prompt $" {
		pass "$description"
	    }
	    -re ".*$gdb_prompt $" {
		fail "$description"
	    }
	    timeout {
		fail "$description (timeout)"
	    }
	}
    }
    
    set description "send SIGINT signal to child process"
    gdb_test "signal SIGINT" \
	"Continuing with signal SIGINT.*" \
	"$description"

    # Switch back to the GDB thread if Guile support is linked in.
    # "signal SIGINT" could also switch the current thread.
    gdb_test "thread 1" {\[Switching to thread 1 .*\].*}
    
    # get a stack trace
    #
    # This fails on some linux systems for unknown reasons.  On the
    # systems where it fails, sometimes it works fine when run manually.
    # The testsuite failures may not be limited to just aout systems.
    setup_xfail "i*86-pc-linuxaout-gnu"
    set description "backtrace through signal handler"
    gdb_test_multiple "backtrace" "$description" {
	-re "#0.*(read|poll).*in main \\(.*\\) at .*gdb\\.c.*$gdb_prompt $" {
	    pass "$description"
	}
    }


    # Set the timeout back to the value it had when we were called.
    set timeout $oldtimeout
    verbose "Timeout is now $timeout seconds" 2

    # Restart gdb in case next test expects it to be started already.
    return 0
}

# Run the test with self.
# Copy the file executable file in case this OS doesn't like to edit its own
# text space.

set GDB_FULLPATH [find_gdb $GDB]

if {[is_remote host]} {
    set xgdb x$tool
} else {
    set xgdb [standard_output_file x$tool]
}

# Remove any old copy lying around.
remote_file host delete $xgdb

gdb_start
set file [remote_download host $GDB_FULLPATH $xgdb]
set result [test_with_self $file]
gdb_exit
catch "remote_file host delete $file"

if {$result <0} then {
    warning "Couldn't test self"
    return -1
}