1# Copyright (C) 2002-2020 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, write to the Free Software
15# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
16
17# test debuginfod with readelf and objdump
18
19set test "debuginfod"
20
21if {[which debuginfod] == 0} {
22    unsupported "$test (not found)"
23    return
24}
25
26if {[which curl] == 0} {
27    unsupported "$test (curl not found)"
28    return
29}
30
31if { ![is_elf_format] } {
32    unsupported "$test (unsupported target)"
33}
34
35if { [which $OBJDUMP] == 0} {
36    perror "$test $OBJDUMP (does not exist)"
37    return
38}
39
40 if { [which $READELF] == 0} {
41    perror "$test $READELF (does not exist)"
42    return
43}
44
45# Compile testprog.c, move the debuginfo to a separate file and add .gnu_debuglink.
46if { [target_compile $srcdir/$subdir/testprog.c tmpdir/testprog executable debug] != ""} {
47    fail "$test (compilation failed)"
48    return
49}
50
51if { [binutils_run $OBJCOPY "--only-keep-debug tmpdir/testprog tmpdir/testprog.debug"] != "" } {
52    fail "$test (create separate debug info file)"
53    return
54}
55
56if { [binutils_run $OBJCOPY "--strip-debug tmpdir/testprog"] != "" } {
57    fail "$test (strip debug info)"
58    return
59}
60
61if { [binutils_run $OBJCOPY "--add-gnu-debuglink=tmpdir/testprog.debug tmpdir/testprog"] != "" } {
62    fail "$test (add debuglink)"
63    return
64}
65
66# Assemble an elf file with a debugaltlink
67if { ![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o] } {
68    fail "$test (assemble debuglink)"
69}
70
71if { ![binutils_assemble $srcdir/$subdir/linkdebug.s tmpdir/linkdebug.debug] } {
72    fail "$test (assemble linkdebug)"
73}
74
75set cache [file join [pwd] "tmpdir/.debuginfod_cache"]
76set db [file join [pwd] "tmpdir/.debuginfod.db"]
77
78setenv DEBUGINFOD_URLS ""
79setenv DEBUGINFOD_TIMEOUT 30
80setenv DEBUGINFOD_CACHE_PATH $cache
81
82# Move debug files into another directory so that readelf and objdump cannot
83# find them without debuginfod.
84file mkdir tmpdir/dbg
85file rename -force tmpdir/testprog.debug tmpdir/dbg
86file rename -force tmpdir/linkdebug.debug tmpdir/dbg
87
88# Remove old cache and database if they exist.
89file delete -force $cache
90file delete -force $db
91
92# Check whether objdump and readelf are configured with debuginfod.
93# To check this we attempt to follow a broken debuglink. If configured
94# with debuginfod the output will contain the debuginfod URLs that were
95# queried (these queries fail since the server is not yet running).
96set conf_objdump [binutils_run $OBJDUMP "-WK tmpdir/testprog"]
97set conf_readelf [binutils_run $READELF "-wK tmpdir/testprog"]
98
99# Find an unused port
100set port 7999
101set found 0
102while { ! $found } {
103  incr port
104  if { $port == 65536 } {
105    untested "$test (no available ports)"
106    return
107  }
108
109  spawn debuginfod -vvvv -d $db -p $port -F tmpdir/dbg
110  expect {
111    "started http server on IPv4 IPv6 port=$port" {
112      set found 1
113    }
114    "Failed to bind to port" {
115      exec kill -INT -[exp_pid]
116      catch {close}; catch {wait -i $spawn_id}
117    }
118    timeout {
119      fail "$test (find port timeout)"
120      return
121    }
122  }
123}
124
125set metrics [list "ready 1" \
126             "thread_work_total{role=\"traverse\"} 1" \
127             "thread_work_pending{role=\"scan\"} 0" \
128             "thread_busy{role=\"scan\"} 0"]
129
130# Check server metrics to confirm init has completed.
131foreach m $metrics {
132  set timelim 20
133  while { $timelim != 0 } {
134    sleep 0.5
135
136    catch {exec curl -s http://127.0.0.1:$port/metrics} got
137
138    if { [regexp $m $got] } {
139      break
140    }
141
142    incr timelim -1
143  }
144
145  if { $timelim == 0 } {
146    fail "$test (server init timeout)"
147    exec kill -INT -[exp_pid]
148    catch {close}; catch {wait -i $spawn_id}
149    return
150  }
151}
152
153setenv DEBUGINFOD_URLS http://127.0.0.1:$port
154
155# Test whether prog can fetch separate debuginfo using debuginfod
156# if it's configured to do so.
157proc test_fetch_debuglink { prog progargs } {
158    global test
159    global cache
160
161    set got [binutils_run $prog "$progargs tmpdir/testprog"]
162
163    if { [regexp ".*Found separate debug info file.*Contents\[^\n\]*loaded from\[^\n\]*$cache.*" $got] } {
164       pass "$test ($prog debuglink)"
165    } else {
166       fail "$test ($prog debuglink)"
167    }
168}
169
170# Test whether prog can fetch debugaltlink files using debuginfod
171# if it's configured to do so.
172proc test_fetch_debugaltlink { prog progargs } {
173    global test
174    global cache
175
176    set got [binutils_run $prog "$progargs tmpdir/debuglink.o"]
177    set buildid "00112233445566778899aabbccddeeff0123456789abcdef"
178
179    if { [regexp ".*Found separate debug info file\[^\n\]*$cache/$buildid" $got] } {
180        pass "$test ($prog debugaltlink)"
181    } else {
182        fail "$test ($prog debugaltlink)"
183    }
184}
185
186if { [regexp ".*DEBUGINFOD.*" $conf_objdump] } {
187    test_fetch_debuglink $OBJDUMP "-W"
188    test_fetch_debugaltlink $OBJDUMP "-WK"
189} else {
190    untested "$test (objdump not configured with debuginfod)"
191}
192
193if { [regexp ".*DEBUGINFOD.*" $conf_readelf] } {
194    test_fetch_debuglink $READELF "-w"
195    test_fetch_debugaltlink $READELF "-wK"
196} else {
197    untested "$test (readelf not configured with debuginfod)"
198}
199