diff options
author | Noah Sanci <nsanci@redhat.com> | 2021-09-16 09:49:04 -0400 |
---|---|---|
committer | Noah Sanci <nsanci@redhat.com> | 2021-09-22 10:47:40 -0400 |
commit | 68e3b479949b4b9e44d46eb1877fa237aa3a0ca3 (patch) | |
tree | 170e9724434d923ab559456d31a186a7dc060135 | |
parent | 28db5f16c44fa7bbd24b221b65aa4d133753355c (diff) | |
download | elfutils-nsanci/pr28284.tar.gz |
28284 firstnsanci/pr28284
Signed-off-by: Noah Sanci <nsanci@redhat.com>
-rw-r--r-- | debuginfod/debuginfod-client.c | 132 | ||||
-rw-r--r-- | debuginfod/debuginfod-find.c | 43 | ||||
-rw-r--r-- | debuginfod/debuginfod.cxx | 56 | ||||
-rw-r--r-- | debuginfod/debuginfod.h.in | 16 |
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); |