1/* 2 * builtin-buildid-cache.c 3 * 4 * Builtin buildid-cache command: Manages build-id cache 5 * 6 * Copyright (C) 2010, Red Hat Inc. 7 * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com> 8 */ 9#include "builtin.h" 10#include "perf.h" 11#include "util/cache.h" 12#include "util/debug.h" 13#include "util/header.h" 14#include "util/parse-options.h" 15#include "util/strlist.h" 16#include "util/build-id.h" 17#include "util/session.h" 18#include "util/symbol.h" 19 20static int build_id_cache__add_file(const char *filename, const char *debugdir) 21{ 22 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 23 u8 build_id[BUILD_ID_SIZE]; 24 int err; 25 26 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { 27 pr_debug("Couldn't read a build-id in %s\n", filename); 28 return -1; 29 } 30 31 build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 32 err = build_id_cache__add_s(sbuild_id, debugdir, filename, 33 false, false); 34 if (verbose) 35 pr_info("Adding %s %s: %s\n", sbuild_id, filename, 36 err ? "FAIL" : "Ok"); 37 return err; 38} 39 40static int build_id_cache__remove_file(const char *filename, 41 const char *debugdir) 42{ 43 u8 build_id[BUILD_ID_SIZE]; 44 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 45 46 int err; 47 48 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { 49 pr_debug("Couldn't read a build-id in %s\n", filename); 50 return -1; 51 } 52 53 build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 54 err = build_id_cache__remove_s(sbuild_id, debugdir); 55 if (verbose) 56 pr_info("Removing %s %s: %s\n", sbuild_id, filename, 57 err ? "FAIL" : "Ok"); 58 59 return err; 60} 61 62static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused) 63{ 64 char filename[PATH_MAX]; 65 u8 build_id[BUILD_ID_SIZE]; 66 67 if (dso__build_id_filename(dso, filename, sizeof(filename)) && 68 filename__read_build_id(filename, build_id, 69 sizeof(build_id)) != sizeof(build_id)) { 70 if (errno == ENOENT) 71 return false; 72 73 pr_warning("Problems with %s file, consider removing it from the cache\n", 74 filename); 75 } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) { 76 pr_warning("Problems with %s file, consider removing it from the cache\n", 77 filename); 78 } 79 80 return true; 81} 82 83static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) 84{ 85 struct perf_session *session = perf_session__new(filename, O_RDONLY, 86 force, false, NULL); 87 if (session == NULL) 88 return -1; 89 90 perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0); 91 perf_session__delete(session); 92 93 return 0; 94} 95 96static int build_id_cache__update_file(const char *filename, 97 const char *debugdir) 98{ 99 u8 build_id[BUILD_ID_SIZE]; 100 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 101 102 int err; 103 104 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { 105 pr_debug("Couldn't read a build-id in %s\n", filename); 106 return -1; 107 } 108 109 build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 110 err = build_id_cache__remove_s(sbuild_id, debugdir); 111 if (!err) { 112 err = build_id_cache__add_s(sbuild_id, debugdir, filename, 113 false, false); 114 } 115 if (verbose) 116 pr_info("Updating %s %s: %s\n", sbuild_id, filename, 117 err ? "FAIL" : "Ok"); 118 119 return err; 120} 121 122int cmd_buildid_cache(int argc, const char **argv, 123 const char *prefix __maybe_unused) 124{ 125 struct strlist *list; 126 struct str_node *pos; 127 int ret = 0; 128 bool force = false; 129 char debugdir[PATH_MAX]; 130 char const *add_name_list_str = NULL, 131 *remove_name_list_str = NULL, 132 *missing_filename = NULL, 133 *update_name_list_str = NULL; 134 135 const struct option buildid_cache_options[] = { 136 OPT_STRING('a', "add", &add_name_list_str, 137 "file list", "file(s) to add"), 138 OPT_STRING('r', "remove", &remove_name_list_str, "file list", 139 "file(s) to remove"), 140 OPT_STRING('M', "missing", &missing_filename, "file", 141 "to find missing build ids in the cache"), 142 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 143 OPT_STRING('u', "update", &update_name_list_str, "file list", 144 "file(s) to update"), 145 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 146 OPT_END() 147 }; 148 const char * const buildid_cache_usage[] = { 149 "perf buildid-cache [<options>]", 150 NULL 151 }; 152 153 argc = parse_options(argc, argv, buildid_cache_options, 154 buildid_cache_usage, 0); 155 156 if (symbol__init() < 0) 157 return -1; 158 159 setup_pager(); 160 161 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); 162 163 if (add_name_list_str) { 164 list = strlist__new(true, add_name_list_str); 165 if (list) { 166 strlist__for_each(pos, list) 167 if (build_id_cache__add_file(pos->s, debugdir)) { 168 if (errno == EEXIST) { 169 pr_debug("%s already in the cache\n", 170 pos->s); 171 continue; 172 } 173 pr_warning("Couldn't add %s: %s\n", 174 pos->s, strerror(errno)); 175 } 176 177 strlist__delete(list); 178 } 179 } 180 181 if (remove_name_list_str) { 182 list = strlist__new(true, remove_name_list_str); 183 if (list) { 184 strlist__for_each(pos, list) 185 if (build_id_cache__remove_file(pos->s, debugdir)) { 186 if (errno == ENOENT) { 187 pr_debug("%s wasn't in the cache\n", 188 pos->s); 189 continue; 190 } 191 pr_warning("Couldn't remove %s: %s\n", 192 pos->s, strerror(errno)); 193 } 194 195 strlist__delete(list); 196 } 197 } 198 199 if (missing_filename) 200 ret = build_id_cache__fprintf_missing(missing_filename, force, stdout); 201 202 if (update_name_list_str) { 203 list = strlist__new(true, update_name_list_str); 204 if (list) { 205 strlist__for_each(pos, list) 206 if (build_id_cache__update_file(pos->s, debugdir)) { 207 if (errno == ENOENT) { 208 pr_debug("%s wasn't in the cache\n", 209 pos->s); 210 continue; 211 } 212 pr_warning("Couldn't update %s: %s\n", 213 pos->s, strerror(errno)); 214 } 215 216 strlist__delete(list); 217 } 218 } 219 220 return ret; 221} 222