summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoah Sanci <nsanci@redhat.com>2021-09-16 09:49:04 -0400
committerNoah Sanci <nsanci@redhat.com>2021-09-22 10:47:40 -0400
commit68e3b479949b4b9e44d46eb1877fa237aa3a0ca3 (patch)
tree170e9724434d923ab559456d31a186a7dc060135
parent28db5f16c44fa7bbd24b221b65aa4d133753355c (diff)
downloadelfutils-nsanci/pr28284.tar.gz
28284 firstnsanci/pr28284
Signed-off-by: Noah Sanci <nsanci@redhat.com>
-rw-r--r--debuginfod/debuginfod-client.c132
-rw-r--r--debuginfod/debuginfod-find.c43
-rw-r--r--debuginfod/debuginfod.cxx56
-rw-r--r--debuginfod/debuginfod.h.in16
4 files changed, 210 insertions, 37 deletions
diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c
index 88e45567..e01a11e1 100644
--- a/debuginfod/debuginfod-client.c
+++ b/debuginfod/debuginfod-client.c
@@ -128,6 +128,7 @@ struct debuginfod_client
handle data, etc. So those don't have to be reparsed and
recreated on each request. */
char * winning_headers;
+ size_t winning_size;
};
/* The cache_clean_interval_s file within the debuginfod cache specifies
@@ -187,6 +188,10 @@ struct handle_data
/* Response http headers for this client handle, sent from the server */
char *response_data;
size_t response_data_size;
+
+ /* synonymous with 'describe', but used in the context of the
+ * http response. */
+ char head_request;
};
static size_t
@@ -504,8 +509,7 @@ default_progressfn (debuginfod_client *c, long a, long b)
/* This is a callback function that receives http response headers in buffer for use
* in this program. https://curl.se/libcurl/c/CURLOPT_HEADERFUNCTION.html is the
- * online documentation.
- */
+ * online documentation. */
static size_t
header_callback (char * buffer, size_t size, size_t numitems, void * userdata)
{
@@ -514,6 +518,22 @@ header_callback (char * buffer, size_t size, size_t numitems, void * userdata)
/* Temporary buffer for realloc */
char *temp = NULL;
struct handle_data *data = (struct handle_data *) userdata;
+ curl_off_t resp;
+ curl_easy_getinfo(data->handle, CURLINFO_RESPONSE_CODE, &resp);
+ if (*data->target_handle == NULL &&
+ (resp == 200 || resp == 406) &&
+ data->head_request)
+ {
+ *data->target_handle = data->handle;
+ /* update the client object */
+ const char *url = NULL;
+ (void) curl_easy_getinfo (data->handle, CURLINFO_EFFECTIVE_URL, &url);
+ if (url)
+ {
+ free (data->client->url);
+ data->client->url = strdup(url); /* ok if fails */
+ }
+ }
if (data->response_data == NULL)
{
temp = malloc(numitems+1);
@@ -544,6 +564,7 @@ debuginfod_query_server (debuginfod_client *c,
const unsigned char *build_id,
int build_id_len,
const char *type,
+ const char describe,
const char *filename,
char **path)
{
@@ -748,7 +769,10 @@ debuginfod_query_server (debuginfod_client *c,
}
xalloc_str (target_cache_dir, "%s/%s", cache_path, build_id_bytes);
- xalloc_str (target_cache_path, "%s/%s%s", target_cache_dir, type, suffix);
+ if (describe)
+ xalloc_str (target_cache_path, "%s/%s_describe%s", target_cache_dir, type, suffix);
+ else
+ xalloc_str (target_cache_path, "%s/%s%s", target_cache_dir, type, suffix);
xalloc_str (target_cache_tmppath, "%s.XXXXXX", target_cache_path);
/* XXX combine these */
@@ -773,6 +797,26 @@ debuginfod_query_server (debuginfod_client *c,
/* Success!!!! */
if (path != NULL)
*path = strdup(target_cache_path);
+ if (describe)
+ {
+ FILE * cachefp = fopen(target_cache_path, "r");
+ if (cachefp == NULL)
+ fprintf(stderr, "Could not open cache: %s, for reading",target_cache_path);
+ else
+ {
+ fseek(cachefp, 0, SEEK_END);
+ size_t cachelen = ftell(cachefp);
+ fseek(cachefp, 0, SEEK_SET);
+ char *str = malloc(cachelen+1);
+ memset(str, '\0', cachelen+1);
+ size_t read = fread(str, 1, cachelen, cachefp);
+ if (read != cachelen)
+ fprintf(stderr, "Could not properly read file\n");
+ fclose(cachefp);
+ fprintf(stderr, "Describe cache content:\n%s \n", str);
+ free(str);
+ }
+ }
rc = fd;
goto out;
}
@@ -972,6 +1016,11 @@ debuginfod_query_server (debuginfod_client *c,
snprintf(data[i].url, PATH_MAX, "%s/%s/%s", server_url, build_id_bytes, type);
if (vfd >= 0)
dprintf (vfd, "url %d %s\n", i, data[i].url);
+ data[i].head_request = describe;
+ /* PR28284 when describing simply send HEAD request
+ * (done with CURLOPT_NOBODY) */
+ if (describe)
+ curl_easy_setopt(data[i].handle, CURLOPT_NOBODY, 1);
curl_easy_setopt(data[i].handle, CURLOPT_URL, data[i].url);
if (vfd >= 0)
@@ -1019,6 +1068,8 @@ debuginfod_query_server (debuginfod_client *c,
int committed_to = -1;
bool verbose_reported = false;
struct timespec start_time, cur_time;
+ /* PR28284 saved later if describing to remember what server has the file */
+ char *committed_url;
c->winning_headers = NULL;
if ( maxtime > 0 && clock_gettime(CLOCK_MONOTONIC_RAW, &start_time) == -1)
{
@@ -1048,6 +1099,7 @@ debuginfod_query_server (debuginfod_client *c,
curl_multi_wait(curlm, NULL, 0, 1000, NULL);
CURLMcode curlm_res = curl_multi_perform(curlm, &still_running);
+
/* If the target file has been found, abort the other queries. */
if (target_handle != NULL)
{
@@ -1058,15 +1110,18 @@ debuginfod_query_server (debuginfod_client *c,
{
committed_to = i;
if (c->winning_headers == NULL)
- {
- c->winning_headers = data[committed_to].response_data;
- if (vfd >= 0 && c->winning_headers != NULL)
- dprintf(vfd, "\n%s", c->winning_headers);
- data[committed_to].response_data = NULL;
+ {
+ c->winning_headers = data[i].response_data;
+ c->winning_size = data[i].response_data_size;
+ /* PR28284 if verbose or describing and winning headers exist
+ * print them. */
+ if ((vfd >= 0 || describe) && c->winning_headers != NULL)
+ dprintf(vfd, "%s\n", c->winning_headers);
+ data[i].response_data = NULL;
}
-
}
- }
+
+ }
if (vfd >= 0 && !verbose_reported && committed_to >= 0)
{
@@ -1077,6 +1132,8 @@ debuginfod_query_server (debuginfod_client *c,
c->default_progressfn_printed_p = 0;
verbose_reported = true;
}
+ if (committed_to >=0 && data[committed_to].url)
+ xalloc_str(committed_url, "Retrieved from: %s\n", data[committed_to].url);
if (curlm_res != CURLM_OK)
{
@@ -1347,7 +1404,23 @@ debuginfod_query_server (debuginfod_client *c,
goto out2;
/* Perhaps we need not give up right away; could retry or something ... */
}
-
+ if (describe)
+ {
+ /* PR28284 write info to cache file */
+ FILE *cache_file = fdopen(fd, "w");
+ if (cache_file == NULL)
+ {
+ rc = -errno;
+ goto out2;
+ }
+ if (c->winning_headers && c->winning_size)
+ fwrite(c->winning_headers, c->winning_size, 1, cache_file);
+ else dprintf(vfd, "Could not write headers to cache");
+ if (committed_url)
+ fwrite(committed_url, strlen(committed_url), 1, cache_file);
+ else dprintf(vfd, "Could not urls to cache");
+ fclose(cache_file);
+ }
/* remove all handles from multi */
for (int i = 0; i < num_urls; i++)
{
@@ -1380,6 +1453,7 @@ debuginfod_query_server (debuginfod_client *c,
free (data[i].response_data);
}
+ free(committed_url);
unlink (target_cache_tmppath);
close (fd); /* before the rmdir, otherwise it'll fail */
(void) rmdir (target_cache_dir); /* nop if not empty */
@@ -1407,7 +1481,7 @@ debuginfod_query_server (debuginfod_client *c,
if (c->default_progressfn_printed_p)
dprintf(STDERR_FILENO, "\n");
- if (vfd >= 0)
+ if (vfd >= 0 && !describe)
{
if (rc < 0)
dprintf (vfd, "not found %s (err=%d)\n", strerror (-rc), rc);
@@ -1500,7 +1574,7 @@ debuginfod_find_debuginfo (debuginfod_client *client,
char **path)
{
return debuginfod_query_server(client, build_id, build_id_len,
- "debuginfo", NULL, path);
+ "debuginfo", 0, NULL, path);
}
@@ -1511,7 +1585,7 @@ debuginfod_find_executable(debuginfod_client *client,
char **path)
{
return debuginfod_query_server(client, build_id, build_id_len,
- "executable", NULL, path);
+ "executable", 0, NULL, path);
}
/* See debuginfod.h */
@@ -1520,10 +1594,38 @@ int debuginfod_find_source(debuginfod_client *client,
const char *filename, char **path)
{
return debuginfod_query_server(client, build_id, build_id_len,
- "source", filename, path);
+ "source", 0, filename, path);
+}
+
+/* See debuginfod.h */
+int
+debuginfod_find_describe_debuginfo (debuginfod_client *client,
+ const unsigned char *build_id, int build_id_len,
+ char **path)
+{
+ return debuginfod_query_server(client, build_id, build_id_len,
+ "debuginfo", 1, NULL, path);
}
+/* See debuginfod.h */
+int
+debuginfod_find_describe_executable(debuginfod_client *client,
+ const unsigned char *build_id, int build_id_len,
+ char **path)
+{
+ return debuginfod_query_server(client, build_id, build_id_len,
+ "executable", 1, NULL, path);
+}
+
+/* See debuginfod.h */
+int debuginfod_find_describe_source(debuginfod_client *client,
+ const unsigned char *build_id, int build_id_len,
+ const char *filename, char **path)
+{
+ return debuginfod_query_server(client, build_id, build_id_len,
+ "source", 1, filename, path);
+}
/* Add an outgoing HTTP header. */
int debuginfod_add_http_header (debuginfod_client *client, const char* header)
{
diff --git a/debuginfod/debuginfod-find.c b/debuginfod/debuginfod-find.c
index 3e8ab203..cee8d689 100644
--- a/debuginfod/debuginfod-find.c
+++ b/debuginfod/debuginfod-find.c
@@ -48,7 +48,11 @@ static const char args_doc[] = N_("debuginfo BUILDID\n"
"executable BUILDID\n"
"executable PATH\n"
"source BUILDID /FILENAME\n"
- "source PATH /FILENAME\n");
+ "source PATH /FILENAME\n"
+ "describe BUILDID ARTIFACT\n"
+ "describe PATH ARTIFACT\n"
+ "describe BUILDID source /FILENAME\n"
+ "describe PATH source /FILENAME\n");
/* Definitions of arguments for argp functions. */
@@ -138,7 +142,6 @@ main(int argc, char** argv)
argp_help (&argp, stderr, ARGP_HELP_USAGE, argv[0]);
return 1;
}
-
/* If we were passed an ELF file name in the BUILDID slot, look in there. */
unsigned char* build_id = (unsigned char*) argv[remaining+1];
int build_id_len = 0; /* assume text */
@@ -182,7 +185,7 @@ main(int argc, char** argv)
fprintf (stderr, "Cannot extract build-id from %s: %s\n", build_id, elf_errmsg(-1));
}
- char *cache_name;
+ char *cache_name = NULL;
int rc = 0;
/* Check whether FILETYPE is valid and call the appropriate
@@ -207,6 +210,34 @@ main(int argc, char** argv)
build_id, build_id_len,
argv[remaining+2], &cache_name);
}
+ else if (strcmp(argv[remaining], "describe") == 0)
+ {
+ if (remaining+2 == argc)
+ {
+ fprintf(stderr, "Needs ARTIFACT. Options: executable, debuginfo, and source");
+ return 1;
+ }
+ /* Check the artifact slots of argv */
+ else if (strcmp(argv[remaining+2], "debuginfo") == 0)
+ rc = debuginfod_find_describe_debuginfo(client,
+ build_id, build_id_len,
+ &cache_name);
+ else if (strcmp(argv[remaining+2], "executable") == 0)
+ rc = debuginfod_find_describe_executable(client,
+ build_id, build_id_len,
+ &cache_name);
+ else if (strcmp(argv[remaining+2], "source") == 0)
+ {
+ if (remaining+3 == argc || argv[remaining+3][0] != '/')
+ {
+ fprintf(stderr, "If FILETYPE is \"source\" then absolute /FILENAME must be given\n");
+ return 1;
+ }
+ rc = debuginfod_find_describe_source(client,
+ build_id, build_id_len,
+ argv[remaining+3], &cache_name);
+ }
+ }
else
{
argp_help (&argp, stderr, ARGP_HELP_USAGE, argv[0]);
@@ -232,7 +263,11 @@ main(int argc, char** argv)
return 1;
}
- printf("%s\n", cache_name);
+ // PR28284 Previously, this could print junk. Now it only prints
+ // when the cache is present
+ if (cache_name)
+ printf("%s\n", cache_name);
+
free (cache_name);
return 0;
diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 2b9a1c41..88c56927 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -1047,6 +1047,7 @@ add_mhd_last_modified (struct MHD_Response *resp, time_t mtime)
static struct MHD_Response*
handle_buildid_f_match (bool internal_req_t,
+ bool describe,
int64_t b_mtime,
const string& b_source0,
int *result_fd)
@@ -1075,21 +1076,26 @@ handle_buildid_f_match (bool internal_req_t,
close(fd);
return 0;
}
-
+ struct MHD_Response* r;
+ if (describe)
+ r = MHD_create_response_from_buffer (0, (void*)"", MHD_RESPMEM_PERSISTENT);
+ /* create a response with the file's body */
+ else
+ r = MHD_create_response_from_fd ((uint64_t) s.st_size, fd);
inc_metric ("http_responses_total","result","file");
- struct MHD_Response* r = MHD_create_response_from_fd ((uint64_t) s.st_size, fd);
+
if (r == 0)
{
if (verbose)
- obatched(clog) << "cannot create fd-response for " << b_source0 << endl;
+ obatched(clog) << "cannot create response for " << b_source0 << endl;
close(fd);
}
else
{
MHD_add_response_header (r, "Content-Type", "application/octet-stream");
std::string file = b_source0.substr(b_source0.find_last_of("/")+1, b_source0.length());
+ MHD_add_response_header (r, "X-DEBUGINFOD-FILE", file.c_str());
MHD_add_response_header (r, "X-DEBUGINFOD-SIZE", to_string(s.st_size).c_str() );
- MHD_add_response_header (r, "X-DEBUGINFOD-FILE", file.c_str() );
add_mhd_last_modified (r, s.st_mtime);
if (verbose > 1)
obatched(clog) << "serving file " << b_source0 << endl;
@@ -1516,6 +1522,7 @@ string canonicalized_archive_entry_pathname(struct archive_entry *e)
static struct MHD_Response*
handle_buildid_r_match (bool internal_req_p,
+ bool describe,
int64_t b_mtime,
const string& b_source0,
const string& b_source1,
@@ -1546,12 +1553,15 @@ handle_buildid_r_match (bool internal_req_p,
fdcache.clear(b_source0, b_source1);
break; // branch out of if "loop", to try new libarchive fetch attempt
}
-
- struct MHD_Response* r = MHD_create_response_from_fd (fs.st_size, fd);
+ struct MHD_Response* r;
+ if (describe)
+ r = MHD_create_response_from_buffer (0, (void*)"", MHD_RESPMEM_PERSISTENT);
+ else
+ r = MHD_create_response_from_fd (fs.st_size, fd);
if (r == 0)
{
if (verbose)
- obatched(clog) << "cannot create fd-response for " << b_source0 << endl;
+ obatched(clog) << "cannot create response for " << b_source0 << endl;
close(fd);
break; // branch out of if "loop", to try new libarchive fetch attempt
}
@@ -1559,9 +1569,9 @@ handle_buildid_r_match (bool internal_req_p,
inc_metric ("http_responses_total","result","archive fdcache");
MHD_add_response_header (r, "Content-Type", "application/octet-stream");
+ MHD_add_response_header (r, "X-DEBUGINFOD-FILE", b_source1.c_str());
MHD_add_response_header (r, "X-DEBUGINFOD-SIZE", to_string(fs.st_size).c_str());
MHD_add_response_header (r, "X-DEBUGINFOD-ARCHIVE", b_source0.c_str());
- MHD_add_response_header (r, "X-DEBUGINFOD-FILE", b_source1.c_str());
add_mhd_last_modified (r, fs.st_mtime);
if (verbose > 1)
obatched(clog) << "serving fdcache archive " << b_source0 << " file " << b_source1 << endl;
@@ -1725,6 +1735,7 @@ handle_buildid_r_match (bool internal_req_p,
static struct MHD_Response*
handle_buildid_match (bool internal_req_p,
+ bool describe,
int64_t b_mtime,
const string& b_stype,
const string& b_source0,
@@ -1734,9 +1745,9 @@ handle_buildid_match (bool internal_req_p,
try
{
if (b_stype == "F")
- return handle_buildid_f_match(internal_req_p, b_mtime, b_source0, result_fd);
+ return handle_buildid_f_match(internal_req_p, describe, b_mtime, b_source0, result_fd);
else if (b_stype == "R")
- return handle_buildid_r_match(internal_req_p, b_mtime, b_source0, b_source1, result_fd);
+ return handle_buildid_r_match(internal_req_p, describe, b_mtime, b_source0, b_source1, result_fd);
}
catch (const reportable_exception &e)
{
@@ -1803,6 +1814,7 @@ static struct MHD_Response*
handle_buildid (MHD_Connection* conn,
const string& buildid /* unsafe */,
const string& artifacttype /* unsafe */,
+ const bool describe,
const string& suffix /* unsafe */,
int *result_fd)
{
@@ -1813,7 +1825,7 @@ handle_buildid (MHD_Connection* conn,
else if (artifacttype == "source") atype_code = "S";
else throw reportable_exception("invalid artifacttype");
- inc_metric("http_requests_total", "type", artifacttype);
+ inc_metric("http_requests_total", "type", artifacttype /*, "method", describe ? "HEAD" : "GET" */);
if (atype_code == "S" && suffix == "")
throw reportable_exception("invalid source suffix");
@@ -1883,11 +1895,11 @@ handle_buildid (MHD_Connection* conn,
if (verbose > 1)
obatched(clog) << "found mtime=" << b_mtime << " stype=" << b_stype
- << " source0=" << b_source0 << " source1=" << b_source1 << endl;
+ << " source0=" << b_source0 << " source1=" << b_source1 << " describe="<< describe << endl;
// Try accessing the located match.
// XXX: in case of multiple matches, attempt them in parallel?
- auto r = handle_buildid_match (conn ? false : true,
+ auto r = handle_buildid_match (conn ? false : true, describe,
b_mtime, b_stype, b_source0, b_source1, result_fd);
if (r)
return r;
@@ -1956,6 +1968,7 @@ and will not query the upstream servers");
(const unsigned char*) buildid.c_str(),
0, suffix.c_str(), NULL);
}
+
else
fd = -errno; /* Set by debuginfod_begin. */
debuginfod_pool_end (client);
@@ -1967,7 +1980,12 @@ and will not query the upstream servers");
int rc = fstat (fd, &s);
if (rc == 0)
{
- auto r = MHD_create_response_from_fd ((uint64_t) s.st_size, fd);
+ struct MHD_Response *r = 0;
+ if (describe)
+ r = MHD_create_response_from_buffer(0, (void*)"", MHD_RESPMEM_PERSISTENT);
+ else
+ r = MHD_create_response_from_fd ((uint64_t) s.st_size, fd);
+
if (r)
{
MHD_add_response_header (r, "Content-Type", "application/octet-stream");
@@ -2165,11 +2183,12 @@ handler_cb (void * /*cls*/,
struct timespec ts_start, ts_end;
clock_gettime (CLOCK_MONOTONIC, &ts_start);
double afteryou = 0.0;
+ bool describe = (string(method) == "HEAD");
try
{
- if (string(method) != "GET")
- throw reportable_exception(400, "we support GET only");
+ if (string(method) != "GET" && string(method) != "HEAD")
+ throw reportable_exception(400, "we only support GET and HEAD.");
/* Start decoding the URL. */
size_t slash1 = url_copy.find('/', 1);
@@ -2217,7 +2236,7 @@ handler_cb (void * /*cls*/,
// get the resulting fd so we can report its size
int fd;
- r = handle_buildid(connection, buildid, artifacttype, suffix, &fd);
+ r = handle_buildid(connection, buildid, artifacttype, describe, suffix, &fd);
if (r)
{
struct stat fs;
@@ -2250,6 +2269,7 @@ handler_cb (void * /*cls*/,
}
rc = MHD_queue_response (connection, MHD_HTTP_OK, r);
+ obatched(clog) << "describe" << describe<< "response "<<r<< " connection "<<connection<<endl;
http_code = MHD_HTTP_OK;
MHD_destroy_response (r);
}
@@ -2334,7 +2354,7 @@ dwarf_extract_source_paths (Elf *elf, set<string>& debug_sourcefiles)
struct MHD_Response *r = 0;
try
{
- r = handle_buildid (0, buildid, "debuginfo", "", &alt_fd);
+ r = handle_buildid (0, buildid, "debuginfo", false, "", &alt_fd);
}
catch (const reportable_exception& e)
{
diff --git a/debuginfod/debuginfod.h.in b/debuginfod/debuginfod.h.in
index c358df4d..4f57efff 100644
--- a/debuginfod/debuginfod.h.in
+++ b/debuginfod/debuginfod.h.in
@@ -78,6 +78,22 @@ int debuginfod_find_source (debuginfod_client *client,
const char *filename,
char **path);
+int debuginfod_find_describe_debuginfo (debuginfod_client *client,
+ const unsigned char *build_id,
+ int build_id_len,
+ char **path);
+
+int debuginfod_find_describe_executable (debuginfod_client *client,
+ const unsigned char *build_id,
+ int build_id_len,
+ char **path);
+
+int debuginfod_find_describe_source (debuginfod_client *client,
+ const unsigned char *build_id,
+ int build_id_len,
+ const char *filename,
+ char **path);
+
typedef int (*debuginfod_progressfn_t)(debuginfod_client *c, long a, long b);
void debuginfod_set_progressfn(debuginfod_client *c,
debuginfod_progressfn_t fn);