diff options
Diffstat (limited to 'tools/perf/util/srcline.c')
-rw-r--r-- | tools/perf/util/srcline.c | 72 |
1 files changed, 53 insertions, 19 deletions
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index d11aefbc4b8d..f3e4bc5fe5d2 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c | |||
@@ -129,7 +129,7 @@ static struct a2l_data *addr2line_init(const char *path) | |||
129 | 129 | ||
130 | out: | 130 | out: |
131 | if (a2l) { | 131 | if (a2l) { |
132 | free((void *)a2l->input); | 132 | zfree((char **)&a2l->input); |
133 | free(a2l); | 133 | free(a2l); |
134 | } | 134 | } |
135 | bfd_close(abfd); | 135 | bfd_close(abfd); |
@@ -140,24 +140,30 @@ static void addr2line_cleanup(struct a2l_data *a2l) | |||
140 | { | 140 | { |
141 | if (a2l->abfd) | 141 | if (a2l->abfd) |
142 | bfd_close(a2l->abfd); | 142 | bfd_close(a2l->abfd); |
143 | free((void *)a2l->input); | 143 | zfree((char **)&a2l->input); |
144 | free(a2l->syms); | 144 | zfree(&a2l->syms); |
145 | free(a2l); | 145 | free(a2l); |
146 | } | 146 | } |
147 | 147 | ||
148 | static int addr2line(const char *dso_name, unsigned long addr, | 148 | static int addr2line(const char *dso_name, unsigned long addr, |
149 | char **file, unsigned int *line) | 149 | char **file, unsigned int *line, struct dso *dso) |
150 | { | 150 | { |
151 | int ret = 0; | 151 | int ret = 0; |
152 | struct a2l_data *a2l; | 152 | struct a2l_data *a2l = dso->a2l; |
153 | |||
154 | if (!a2l) { | ||
155 | dso->a2l = addr2line_init(dso_name); | ||
156 | a2l = dso->a2l; | ||
157 | } | ||
153 | 158 | ||
154 | a2l = addr2line_init(dso_name); | ||
155 | if (a2l == NULL) { | 159 | if (a2l == NULL) { |
156 | pr_warning("addr2line_init failed for %s\n", dso_name); | 160 | pr_warning("addr2line_init failed for %s\n", dso_name); |
157 | return 0; | 161 | return 0; |
158 | } | 162 | } |
159 | 163 | ||
160 | a2l->addr = addr; | 164 | a2l->addr = addr; |
165 | a2l->found = false; | ||
166 | |||
161 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); | 167 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); |
162 | 168 | ||
163 | if (a2l->found && a2l->filename) { | 169 | if (a2l->found && a2l->filename) { |
@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr, | |||
168 | ret = 1; | 174 | ret = 1; |
169 | } | 175 | } |
170 | 176 | ||
171 | addr2line_cleanup(a2l); | ||
172 | return ret; | 177 | return ret; |
173 | } | 178 | } |
174 | 179 | ||
180 | void dso__free_a2l(struct dso *dso) | ||
181 | { | ||
182 | struct a2l_data *a2l = dso->a2l; | ||
183 | |||
184 | if (!a2l) | ||
185 | return; | ||
186 | |||
187 | addr2line_cleanup(a2l); | ||
188 | |||
189 | dso->a2l = NULL; | ||
190 | } | ||
191 | |||
175 | #else /* HAVE_LIBBFD_SUPPORT */ | 192 | #else /* HAVE_LIBBFD_SUPPORT */ |
176 | 193 | ||
177 | static int addr2line(const char *dso_name, unsigned long addr, | 194 | static int addr2line(const char *dso_name, unsigned long addr, |
178 | char **file, unsigned int *line_nr) | 195 | char **file, unsigned int *line_nr, |
196 | struct dso *dso __maybe_unused) | ||
179 | { | 197 | { |
180 | FILE *fp; | 198 | FILE *fp; |
181 | char cmd[PATH_MAX]; | 199 | char cmd[PATH_MAX]; |
@@ -219,42 +237,58 @@ out: | |||
219 | pclose(fp); | 237 | pclose(fp); |
220 | return ret; | 238 | return ret; |
221 | } | 239 | } |
240 | |||
241 | void dso__free_a2l(struct dso *dso __maybe_unused) | ||
242 | { | ||
243 | } | ||
244 | |||
222 | #endif /* HAVE_LIBBFD_SUPPORT */ | 245 | #endif /* HAVE_LIBBFD_SUPPORT */ |
223 | 246 | ||
247 | /* | ||
248 | * Number of addr2line failures (without success) before disabling it for that | ||
249 | * dso. | ||
250 | */ | ||
251 | #define A2L_FAIL_LIMIT 123 | ||
252 | |||
224 | char *get_srcline(struct dso *dso, unsigned long addr) | 253 | char *get_srcline(struct dso *dso, unsigned long addr) |
225 | { | 254 | { |
226 | char *file = NULL; | 255 | char *file = NULL; |
227 | unsigned line = 0; | 256 | unsigned line = 0; |
228 | char *srcline; | 257 | char *srcline; |
229 | char *dso_name = dso->long_name; | 258 | const char *dso_name; |
230 | size_t size; | ||
231 | 259 | ||
232 | if (!dso->has_srcline) | 260 | if (!dso->has_srcline) |
233 | return SRCLINE_UNKNOWN; | 261 | return SRCLINE_UNKNOWN; |
234 | 262 | ||
263 | if (dso->symsrc_filename) | ||
264 | dso_name = dso->symsrc_filename; | ||
265 | else | ||
266 | dso_name = dso->long_name; | ||
267 | |||
235 | if (dso_name[0] == '[') | 268 | if (dso_name[0] == '[') |
236 | goto out; | 269 | goto out; |
237 | 270 | ||
238 | if (!strncmp(dso_name, "/tmp/perf-", 10)) | 271 | if (!strncmp(dso_name, "/tmp/perf-", 10)) |
239 | goto out; | 272 | goto out; |
240 | 273 | ||
241 | if (!addr2line(dso_name, addr, &file, &line)) | 274 | if (!addr2line(dso_name, addr, &file, &line, dso)) |
242 | goto out; | 275 | goto out; |
243 | 276 | ||
244 | /* just calculate actual length */ | 277 | if (asprintf(&srcline, "%s:%u", file, line) < 0) { |
245 | size = snprintf(NULL, 0, "%s:%u", file, line) + 1; | 278 | free(file); |
279 | goto out; | ||
280 | } | ||
246 | 281 | ||
247 | srcline = malloc(size); | 282 | dso->a2l_fails = 0; |
248 | if (srcline) | ||
249 | snprintf(srcline, size, "%s:%u", file, line); | ||
250 | else | ||
251 | srcline = SRCLINE_UNKNOWN; | ||
252 | 283 | ||
253 | free(file); | 284 | free(file); |
254 | return srcline; | 285 | return srcline; |
255 | 286 | ||
256 | out: | 287 | out: |
257 | dso->has_srcline = 0; | 288 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { |
289 | dso->has_srcline = 0; | ||
290 | dso__free_a2l(dso); | ||
291 | } | ||
258 | return SRCLINE_UNKNOWN; | 292 | return SRCLINE_UNKNOWN; |
259 | } | 293 | } |
260 | 294 | ||