summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Ch. Eigler <fche@redhat.com>2022-09-02 12:41:38 -0400
committerFrank Ch. Eigler <fche@redhat.com>2022-09-06 16:46:42 -0400
commitaba6ae860566caad9f96ca19bd68a7e03a5249c6 (patch)
treeb93bbd3b681094d2fb4aa83718dd907542d35bd4
parentPR28284 - Debuginfod header functionality implemented (diff)
downloadelfutils-users/fche/try-pr28284h.tar.gz
elfutils-users/fche/try-pr28284h.tar.bz2
elfutils-users/fche/try-pr28284h.tar.xz
PR28284: add tweaks on previous debuginfod x-debuginfod* header forwarding workusers/fche/try-pr28284iusers/fche/try-pr28284h
Embrace case-independent headers, more fully document, handle HTTP \r. In addition to test case, hand-tested against fedora debuginfod instances, running federated servers under valgrind. Signed-off-by: Frank Ch. Eigler <fche@redhat.com>
-rw-r--r--debuginfod/ChangeLog14
-rw-r--r--debuginfod/debuginfod-client.c28
-rw-r--r--debuginfod/debuginfod-find.c3
-rw-r--r--debuginfod/debuginfod.cxx26
-rw-r--r--debuginfod/debuginfod.h.in4
-rw-r--r--debuginfod/libdebuginfod.map2
-rw-r--r--doc/ChangeLog5
-rw-r--r--doc/debuginfod_find_debuginfo.319
-rw-r--r--tests/ChangeLog6
-rwxr-xr-xtests/run-debuginfod-response-headers.sh49
-rwxr-xr-xtests/run-debuginfod-sizetime.sh4
11 files changed, 95 insertions, 65 deletions
diff --git a/debuginfod/ChangeLog b/debuginfod/ChangeLog
index 8c843f3a..bc6c11c9 100644
--- a/debuginfod/ChangeLog
+++ b/debuginfod/ChangeLog
@@ -1,11 +1,21 @@
12022-09-06 Frank Ch. Eigler <fche@redhat.com>
2
3 * debuginfod-client.c (header_callback): Don't copy \r in x-d headers.
4 Print all headers in verbose_fd mode.
5 * debuginfod-find.c (parse_opt): Set verbose_fd only at verbosity >= 2.
6 * debuginfod.cxx (handle_buildid): Clean up header forwarding
7 string processing.
8 * debuginfod.h.in: (debuginfod_get_headers): Tweak wording.
9 * libdebuginfod.map: Use ELFUTILS_0.188 for new function.
10
12022-07-15 Noah Sanci <nsanci@redhat.com> 112022-07-15 Noah Sanci <nsanci@redhat.com>
2 12
3 * debuginfod-client.c (header_callback): Handle headers without 13 * debuginfod-client.c (header_callback): Ignore headers without
4 X-DEBUGINFOD prefix. 14 X-DEBUGINFOD prefix.
5 (debuginfod_query_server): Removed verbose printing headers when 15 (debuginfod_query_server): Removed verbose printing headers when
6 undesired. 16 undesired.
7 (debuginfod_get_headers): Created. 17 (debuginfod_get_headers): Created.
8 * debuginfod-find.c (main): Verboes printing headers. 18 * debuginfod-find.c (main): Verbose printing headers.
9 * debuginfod.cxx (handle_buildid): Add headers prefixed with 19 * debuginfod.cxx (handle_buildid): Add headers prefixed with
10 X-DEBUGINFOD from federated servers to this server's response 20 X-DEBUGINFOD from federated servers to this server's response
11 headers. 21 headers.
diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c
index a3565f57..54dc3f2f 100644
--- a/debuginfod/debuginfod-client.c
+++ b/debuginfod/debuginfod-client.c
@@ -499,33 +499,37 @@ default_progressfn (debuginfod_client *c, long a, long b)
499static size_t 499static size_t
500header_callback (char * buffer, size_t size, size_t numitems, void * userdata) 500header_callback (char * buffer, size_t size, size_t numitems, void * userdata)
501{ 501{
502 struct handle_data *data = (struct handle_data *) userdata;
502 if (size != 1) 503 if (size != 1)
503 return 0; 504 return 0;
504 // X-DEBUGINFOD is 11 characters long. 505 if (data->client && data->client->verbose_fd >= 0)
506 dprintf (data->client->verbose_fd, "header %.*s", (int)numitems, buffer);
505 // Some basic checks to ensure the headers received are of the expected format 507 // Some basic checks to ensure the headers received are of the expected format
506 if ( strncmp(buffer, "X-DEBUGINFOD", 11) || buffer[numitems-1] != '\n' 508 if (strncasecmp(buffer, "X-DEBUGINFOD", 11)
507 || (buffer == strstr(buffer, ":")) ){ 509 || buffer[numitems-2] != '\r'
510 || buffer[numitems-1] != '\n'
511 || (buffer == strstr(buffer, ":")) ){
508 return numitems; 512 return numitems;
509 } 513 }
510 /* Temporary buffer for realloc */ 514 /* Temporary buffer for realloc */
511 char *temp = NULL; 515 char *temp = NULL;
512 struct handle_data *data = (struct handle_data *) userdata;
513 if (data->response_data == NULL) 516 if (data->response_data == NULL)
514 { 517 {
515 temp = malloc(numitems+1); 518 temp = malloc(numitems);
516 if (temp == NULL) 519 if (temp == NULL)
517 return 0; 520 return 0;
518 } 521 }
519 else 522 else
520 { 523 {
521 temp = realloc(data->response_data, data->response_data_size + numitems + 1); 524 temp = realloc(data->response_data, data->response_data_size + numitems);
522 if (temp == NULL) 525 if (temp == NULL)
523 return 0; 526 return 0;
524 } 527 }
525 528
526 memcpy(temp + data->response_data_size, buffer, numitems); 529 memcpy(temp + data->response_data_size, buffer, numitems-1);
527 data->response_data = temp; 530 data->response_data = temp;
528 data->response_data_size += numitems; 531 data->response_data_size += numitems-1;
532 data->response_data[data->response_data_size-1] = '\n';
529 data->response_data[data->response_data_size] = '\0'; 533 data->response_data[data->response_data_size] = '\0';
530 return numitems; 534 return numitems;
531} 535}
@@ -1072,11 +1076,9 @@ debuginfod_query_server (debuginfod_client *c,
1072 int committed_to = -1; 1076 int committed_to = -1;
1073 bool verbose_reported = false; 1077 bool verbose_reported = false;
1074 struct timespec start_time, cur_time; 1078 struct timespec start_time, cur_time;
1075 if (c->winning_headers != NULL) 1079
1076 { 1080 free (c->winning_headers);
1077 free (c->winning_headers); 1081 c->winning_headers = NULL;
1078 c->winning_headers = NULL;
1079 }
1080 if ( maxtime > 0 && clock_gettime(CLOCK_MONOTONIC_RAW, &start_time) == -1) 1082 if ( maxtime > 0 && clock_gettime(CLOCK_MONOTONIC_RAW, &start_time) == -1)
1081 { 1083 {
1082 rc = errno; 1084 rc = errno;
diff --git a/debuginfod/debuginfod-find.c b/debuginfod/debuginfod-find.c
index fb1f294c..778fb09b 100644
--- a/debuginfod/debuginfod-find.c
+++ b/debuginfod/debuginfod-find.c
@@ -99,7 +99,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
99 { 99 {
100 case 'v': verbose++; 100 case 'v': verbose++;
101 debuginfod_set_progressfn (client, & progressfn); 101 debuginfod_set_progressfn (client, & progressfn);
102 debuginfod_set_verbose_fd (client, STDERR_FILENO); 102 if (verbose > 1)
103 debuginfod_set_verbose_fd (client, STDERR_FILENO);
103 break; 104 break;
104 default: return ARGP_ERR_UNKNOWN; 105 default: return ARGP_ERR_UNKNOWN;
105 } 106 }
diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 27b671d3..000a41c4 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -2093,22 +2093,26 @@ and will not query the upstream servers");
2093 { 2093 {
2094 add_mhd_response_header (r, "Content-Type", 2094 add_mhd_response_header (r, "Content-Type",
2095 "application/octet-stream"); 2095 "application/octet-stream");
2096 // Copy the incoming headers
2096 const char * hdrs = debuginfod_get_headers(client); 2097 const char * hdrs = debuginfod_get_headers(client);
2097 string header_dup; 2098 string header_dup;
2098 if (hdrs) 2099 if (hdrs)
2099 header_dup = string(hdrs); 2100 header_dup = string(hdrs);
2100 size_t pos = 0; 2101 // Parse the "header: value\n" lines into (h,v) tuples and pass on
2101 // Clean winning headers to add all X-DEBUGINFOD lines to the package we'll send 2102 while(1)
2102 while( (pos = header_dup.find("X-DEBUGINFOD")) != string::npos)
2103 { 2103 {
2104 // Focus on where X-DEBUGINFOD- begins 2104 size_t newline = header_dup.find('\n');
2105 header_dup = header_dup.substr(pos); 2105 if (newline == string::npos) break;
2106 size_t newline = header_dup.find('\n'); 2106 size_t colon = header_dup.find(':');
2107 if (newline == string::npos) 2107 if (colon == string::npos) break;
2108 break; 2108 string header = header_dup.substr(0,colon);
2109 add_mhd_response_header(r, header_dup.substr(0,header_dup.find(':')).c_str(), 2109 string value = header_dup.substr(colon+1,newline-colon-1);
2110 header_dup.substr(header_dup.find(':')).c_str()); 2110 // strip leading spaces from value
2111 header_dup = header_dup.substr(newline); 2111 size_t nonspace = value.find_first_not_of(" ");
2112 if (nonspace != string::npos)
2113 value = value.substr(nonspace);
2114 add_mhd_response_header(r, header.c_str(), value.c_str());
2115 header_dup = header_dup.substr(newline+1);
2112 } 2116 }
2113 2117
2114 add_mhd_last_modified (r, s.st_mtime); 2118 add_mhd_last_modified (r, s.st_mtime);
diff --git a/debuginfod/debuginfod.h.in b/debuginfod/debuginfod.h.in
index 6ae8b91c..40b1ea00 100644
--- a/debuginfod/debuginfod.h.in
+++ b/debuginfod/debuginfod.h.in
@@ -93,8 +93,8 @@ void* debuginfod_get_user_data (debuginfod_client *client);
93/* Get the current or last active URL, if known. */ 93/* Get the current or last active URL, if known. */
94const char* debuginfod_get_url (debuginfod_client *client); 94const char* debuginfod_get_url (debuginfod_client *client);
95 95
96/* Returns all headers sent to this client which were prefixed 96/* Returns set of x-debuginfod* header lines received from current or
97 * with X-DEBUGINFOD */ 97 last active transfer, \n separated, if known. */
98const char* debuginfod_get_headers(debuginfod_client *client); 98const char* debuginfod_get_headers(debuginfod_client *client);
99 99
100/* Add an outgoing HTTP request "Header: Value". Copies string. */ 100/* Add an outgoing HTTP request "Header: Value". Copies string. */
diff --git a/debuginfod/libdebuginfod.map b/debuginfod/libdebuginfod.map
index f95b5b9a..93964167 100644
--- a/debuginfod/libdebuginfod.map
+++ b/debuginfod/libdebuginfod.map
@@ -18,6 +18,6 @@ ELFUTILS_0.179 {
18ELFUTILS_0.183 { 18ELFUTILS_0.183 {
19 debuginfod_set_verbose_fd; 19 debuginfod_set_verbose_fd;
20} ELFUTILS_0.179; 20} ELFUTILS_0.179;
21ELFUTILS_0.189 { 21ELFUTILS_0.188 {
22 debuginfod_get_headers; 22 debuginfod_get_headers;
23} ELFUTILS_0.183; 23} ELFUTILS_0.183;
diff --git a/doc/ChangeLog b/doc/ChangeLog
index c2a01a04..b2bb4890 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,4 +1,9 @@
12022-09-02 Frank Ch. Eigler <fche@redhat.com>
2
3 * debuginfod_find_debuginfo.3: Tweaked debuginfod_get_headers docs.
4
12022-07-15 Noah Sanci <nsanci@redhat.com> 52022-07-15 Noah Sanci <nsanci@redhat.com>
6
2 * debuginfod_find_debuginfo.3: Explained debuginfod_get_headers 7 * debuginfod_find_debuginfo.3: Explained debuginfod_get_headers
3 usage. 8 usage.
4 * debuginfod_get_headers.3: Created. 9 * debuginfod_get_headers.3: Created.
diff --git a/doc/debuginfod_find_debuginfo.3 b/doc/debuginfod_find_debuginfo.3
index 984fda12..aebbec3f 100644
--- a/doc/debuginfod_find_debuginfo.3
+++ b/doc/debuginfod_find_debuginfo.3
@@ -199,17 +199,18 @@ By default, the library adds a descriptive \fIUser-Agent:\fP
199header to outgoing requests. If the client application adds 199header to outgoing requests. If the client application adds
200a header with the same name, this default is suppressed. 200a header with the same name, this default is suppressed.
201 201
202During or after a lookup, a client application may call
202.BR \%debuginfod_get_headers () 203.BR \%debuginfod_get_headers ()
203may be called with a debuginfod client. This function will return the 204to gather the subset of HTTP response headers received from the
204http response headers prefixed with 205current or most recent debuginfod server. Only those headers prefixed
206with
205.BR X-DEBUGINFOD 207.BR X-DEBUGINFOD
206received from the first handle to get a response from a debuginfod server. 208(case-insensitive) are kept. They are returned as a single string,
207Note that all other http headers aren't stored in the libcurl header 209with each "header: value" terminated with a \\n (not \\r\\n as in
208callback function since they aren't of as much interest. The caller should 210HTTP). It may be NULL. The resulting string is owned by the library,
209copy the returned string if it is needed beyond the release of the client object. 211and must not be modified or freed. The caller should copy the
210The returned string may be NULL if no headers are prefixed with 212returned string if it is needed beyond the release of the client
211.BR X-DEBUGINFOD 213object.
212\.
213 214
214.SH "MACROS" 215.SH "MACROS"
215 216
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 659bfa19..ff24f8b2 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
12022-09-02 Frank Ch. Eigler <fche@redhat.com>
2
3 * run-debuginfod-response-headers: Use case-insensitive
4 header name matches. Use socat & sleep for greater
5 portability.
6
12022-07-15 Noah Sanci <nsanci@redhat.com> 72022-07-15 Noah Sanci <nsanci@redhat.com>
2 8
3 * run-debuginfod-response-headers.sh: Added test 9 * run-debuginfod-response-headers.sh: Added test
diff --git a/tests/run-debuginfod-response-headers.sh b/tests/run-debuginfod-response-headers.sh
index e5698cc9..63f2f241 100755
--- a/tests/run-debuginfod-response-headers.sh
+++ b/tests/run-debuginfod-response-headers.sh
@@ -1,6 +1,6 @@
1#!/usr/bin/env bash 1#!/usr/bin/env bash
2# 2#
3# Copyright (C) 2019-2021 Red Hat, Inc. 3# Copyright (C) 2022 Red Hat, Inc.
4# This file is part of elfutils. 4# This file is part of elfutils.
5# 5#
6# This file is free software; you can redistribute it and/or modify 6# This file is free software; you can redistribute it and/or modify
@@ -16,6 +16,8 @@
16# You should have received a copy of the GNU General Public License 16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>. 17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18 18
19type socat 2>/dev/null || exit 77
20
19. $srcdir/debuginfod-subr.sh # includes set -e 21. $srcdir/debuginfod-subr.sh # includes set -e
20 22
21# for test case debugging, uncomment: 23# for test case debugging, uncomment:
@@ -76,8 +78,8 @@ tempfiles vlog-find$PORT1.1
76errfiles vlog-find$PORT1.1 78errfiles vlog-find$PORT1.1
77cat vlog-find$PORT1.1 79cat vlog-find$PORT1.1
78grep 'Headers:' vlog-find$PORT1.1 80grep 'Headers:' vlog-find$PORT1.1
79grep 'X-DEBUGINFOD-FILE: prog' vlog-find$PORT1.1 81grep -i 'X-DEBUGINFOD-FILE: prog' vlog-find$PORT1.1
80grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.1 82grep -i 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.1
81 83
82# Check to see if an executable file located in an archive prints the file's description and archive 84# Check to see if an executable file located in an archive prints the file's description and archive
83env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ 85env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT1 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\
@@ -86,15 +88,15 @@ tempfiles vlog-find$PORT1.2
86errfiles vlog-find$PORT1.2 88errfiles vlog-find$PORT1.2
87cat vlog-find$PORT1.2 89cat vlog-find$PORT1.2
88grep 'Headers:' vlog-find$PORT1.2 90grep 'Headers:' vlog-find$PORT1.2
89grep 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.2 91grep -i 'X-DEBUGINFOD-FILE: ' vlog-find$PORT1.2
90grep 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.2 92grep -i 'X-DEBUGINFOD-SIZE: ' vlog-find$PORT1.2
91grep 'X-DEBUGINFOD-ARCHIVE: ' vlog-find$PORT1.2 93grep -i 'X-DEBUGINFOD-ARCHIVE: ' vlog-find$PORT1.2
92 94
93# Check that X-DEBUGINFOD-SIZE matches the size of each file 95# Check that X-DEBUGINFOD-SIZE matches the size of each file
94for file in vlog-find$PORT1.1 vlog-find$PORT1.2 96for file in vlog-find$PORT1.1 vlog-find$PORT1.2
95do 97do
96 st_size=$(stat -c%s $(tail -n 1 $file)) 98 st_size=$(stat -c%s $(tail -n 1 $file))
97 x_debuginfod_size=$(grep 'X-DEBUGINFOD-SIZE' $file | egrep -o '[0-9]+') 99 x_debuginfod_size=$(grep -i 'X-DEBUGINFOD-SIZE' $file | head -1 | egrep -o '[0-9]+')
98 test $st_size -eq $x_debuginfod_size 100 test $st_size -eq $x_debuginfod_size
99done 101done
100 102
@@ -106,31 +108,30 @@ mkdir -p ${PWD}/$netcat_dir
106cp F/prog ${PWD}/$netcat_dir/executable 108cp F/prog ${PWD}/$netcat_dir/executable
107tempfiles F/prog 109tempfiles F/prog
108 110
109# Netcat dies after answering the request 111# socat should after answering one request
110nc -l -p $PORT2 -c 'echo -e "HTTP/1.1 200 OK\nX-DEBUGINFOD-SIZE: ba:d_size\nX-DEBUGINFOD-\rFILE:\=\+ \r213\n\n $(date)"' & < ${PWD}/$netcat_dir"executable" & 112(echo -e "HTTP/1.1 200 OK\r\nX-DEBUGINFOD-SIZE: ba:d_size\nX-DEBUGINFOD-\rFILE:\=\+ \r213\n\n $(date)" | socat -u - tcp-listen:$PORT2) &
111# Wait until the netcat port is in use. Otherwise debuginfod-find can query 113PID2=$!
114# Wait a bit until the netcat port is in use. Otherwise debuginfod-find can query
112# before netcat is ready. 115# before netcat is ready.
113SECONDS=0 116sleep 5
114nc_start=$SECONDS
115while [ ! $(lsof -i -P -n | grep LISTEN | grep "nc.*$PORT2") ]
116do
117 # If it takes longer than 5 seconds for netcat to start up, then fail
118 duration=$(( SECONDS - nc_start ))
119 if [ $SECONDS -gt 5 ]
120 then
121 err
122 fi
123done
124 117
125env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT2 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\ 118touch vlog-find$PORT2
126 -vvv executable $BUILDID > vlog-find$PORT2 2>&1
127errfiles vlog-find$PORT2 119errfiles vlog-find$PORT2
128tempfiles vlog-find$PORT2 120tempfiles vlog-find$PORT2
129cat vlog-find$PORT2 | grep "X-DEBUGINFOD-" 121
122# calling out to valgrind deliberately, because this process will be forced to parse broken http headers
123${VALGRIND_CMD} env DEBUGINFOD_URLS="http://127.0.0.1:"$PORT2 LD_LIBRARY_PATH=$ldpath ${abs_top_builddir}/debuginfod/debuginfod-find\
124 -vvv executable $BUILDID > vlog-find$PORT2 2>&1 || true # permit curl rejection of the bad headers
125cat vlog-find$PORT2 # won't have any valid x-debuginfod* headers
130rm -f "$netcat_dir"executable 126rm -f "$netcat_dir"executable
131rmdir -p $netcat_dir 127rmdir -p $netcat_dir
132 128
129kill $PID2 || true
130wait $PID2 || true
131PID2=0
132
133kill $PID1 133kill $PID1
134wait $PID1 134wait $PID1
135PID1=0 135PID1=0
136
136exit 0 137exit 0
diff --git a/tests/run-debuginfod-sizetime.sh b/tests/run-debuginfod-sizetime.sh
index 2cf6f252..17307c02 100755
--- a/tests/run-debuginfod-sizetime.sh
+++ b/tests/run-debuginfod-sizetime.sh
@@ -51,7 +51,7 @@ wait_ready $PORT1 'thread_busy{role="scan"}' 0
51# Ensure DEBUGINFOD_MAXSIZE is functional and sends back the correct http 51# Ensure DEBUGINFOD_MAXSIZE is functional and sends back the correct http
52# code 52# code
53env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_RETRY_LIMIT=1 DEBUGINFOD_URLS="http://127.0.0.1:$PORT1/" DEBUGINFOD_MAXSIZE=1 \ 53env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_RETRY_LIMIT=1 DEBUGINFOD_URLS="http://127.0.0.1:$PORT1/" DEBUGINFOD_MAXSIZE=1 \
54 ${abs_top_builddir}/debuginfod/debuginfod-find -v executable ${PWD}/prog 2> find-vlog$PORT1 || true 54 ${abs_top_builddir}/debuginfod/debuginfod-find -v -v executable ${PWD}/prog 2> find-vlog$PORT1 || true
55tempfiles find-vlog$PORT1 55tempfiles find-vlog$PORT1
56errfiles find-vlog$PORT1 56errfiles find-vlog$PORT1
57echo "Checking maxsize" 57echo "Checking maxsize"
@@ -66,7 +66,7 @@ if [ -f ${DEBUGINFOD_CACHE_PATH}/${BUILDID} ]; then
66fi 66fi
67# Ensure no file is downloaded for longer than DEBUGINFOD_MAXTIME 67# Ensure no file is downloaded for longer than DEBUGINFOD_MAXTIME
68env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS="http://127.0.0.1:$PORT1/" DEBUGINFOD_MAXTIME=1 \ 68env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS="http://127.0.0.1:$PORT1/" DEBUGINFOD_MAXTIME=1 \
69 ${abs_top_builddir}/debuginfod/debuginfod-find -v debuginfo ${PWD}/prog.debug 2> find-vlog$PORT1 || true 69 ${abs_top_builddir}/debuginfod/debuginfod-find -v -v debuginfo ${PWD}/prog.debug 2> find-vlog$PORT1 || true
70tempfiles find-vlog$PORT1 70tempfiles find-vlog$PORT1
71grep 'using max time' find-vlog$PORT1 71grep 'using max time' find-vlog$PORT1
72# Ensure p+r%o\$g.debug is NOT cached 72# Ensure p+r%o\$g.debug is NOT cached