Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'perf-tools-for-linus' of git://github.com/acmel/linux

* 'perf-tools-for-linus' of git://github.com/acmel/linux:
perf tools: Add support for disabling -Werror via WERROR=0
perf top: Fix userspace sample addr map offset
perf symbols: Fix issue with binaries using 16-bytes buildids (v2)
perf tool: Fix endianness handling of u32 data in samples
perf sort: Fix symbol sort output by separating unresolved samples by type
perf symbols: Synthesize anonymous mmap events
perf record: Create events initially disabled and enable after init
perf symbols: Add some heuristics for choosing the best duplicate symbol
perf symbols: Preserve symbol scope when parsing /proc/kallsyms
perf symbols: /proc/kallsyms does not sort module symbols
perf symbols: Fix ppc64 SEGV in dso__load_sym with debuginfo files
perf probe: Fix regression of variable finder

+209 -57
+8 -1
tools/perf/Makefile
··· 30 30 # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. 31 31 # 32 32 # Define NO_DWARF if you do not want debug-info analysis feature at all. 33 + # 34 + # Define WERROR=0 to disable treating any warnings as errors. 33 35 34 36 $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 35 37 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) ··· 63 61 ARCH_CFLAGS := -DARCH_X86_64 64 62 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S 65 63 endif 64 + endif 65 + 66 + # Treat warnings as errors unless directed not to 67 + ifneq ($(WERROR),0) 68 + CFLAGS_WERROR := -Werror 66 69 endif 67 70 68 71 # ··· 102 95 CFLAGS_OPTIMIZE = -O6 103 96 endif 104 97 105 - CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 98 + CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 106 99 EXTLIBS = -lpthread -lrt -lelf -lm 107 100 ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 108 101 ALL_LDFLAGS = $(LDFLAGS)
+3
tools/perf/builtin-record.c
··· 161 161 struct perf_event_attr *attr = &evsel->attr; 162 162 int track = !evsel->idx; /* only the first counter needs these */ 163 163 164 + attr->disabled = 1; 164 165 attr->inherit = !no_inherit; 165 166 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 166 167 PERF_FORMAT_TOTAL_TIME_RUNNING | ··· 671 670 exit(-1); 672 671 } 673 672 } 673 + 674 + perf_evlist__enable(evsel_list); 674 675 675 676 /* 676 677 * Let the child rip
+1 -1
tools/perf/builtin-test.c
··· 561 561 } 562 562 563 563 err = perf_event__parse_sample(event, attr.sample_type, sample_size, 564 - false, &sample); 564 + false, &sample, false); 565 565 if (err) { 566 566 pr_err("Can't parse sample, err = %d\n", err); 567 567 goto out_munmap;
+5 -4
tools/perf/builtin-top.c
··· 191 191 symbol__annotate_zero_histograms(sym); 192 192 } 193 193 194 - static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 194 + static void record_precise_ip(struct sym_entry *syme, struct map *map, 195 + int counter, u64 ip) 195 196 { 196 197 struct annotation *notes; 197 198 struct symbol *sym; ··· 206 205 if (pthread_mutex_trylock(&notes->lock)) 207 206 return; 208 207 209 - ip = syme->map->map_ip(syme->map, ip); 210 - symbol__inc_addr_samples(sym, syme->map, counter, ip); 208 + ip = map->map_ip(map, ip); 209 + symbol__inc_addr_samples(sym, map, counter, ip); 211 210 212 211 pthread_mutex_unlock(&notes->lock); 213 212 } ··· 811 810 evsel = perf_evlist__id2evsel(top.evlist, sample->id); 812 811 assert(evsel != NULL); 813 812 syme->count[evsel->idx]++; 814 - record_precise_ip(syme, evsel->idx, ip); 813 + record_precise_ip(syme, al.map, evsel->idx, ip); 815 814 pthread_mutex_lock(&top.active_symbols_lock); 816 815 if (list_empty(&syme->node) || !syme->node.next) { 817 816 static bool first = true;
+5
tools/perf/util/event.c
··· 169 169 continue; 170 170 pbf += n + 3; 171 171 if (*pbf == 'x') { /* vm_exec */ 172 + char anonstr[] = "//anon\n"; 172 173 char *execname = strchr(bf, '/'); 173 174 174 175 /* Catch VDSO */ 175 176 if (execname == NULL) 176 177 execname = strstr(bf, "[vdso]"); 178 + 179 + /* Catch anonymous mmaps */ 180 + if ((execname == NULL) && !strstr(bf, "[")) 181 + execname = anonstr; 177 182 178 183 if (execname == NULL) 179 184 continue;
+1 -1
tools/perf/util/event.h
··· 186 186 187 187 int perf_event__parse_sample(const union perf_event *event, u64 type, 188 188 int sample_size, bool sample_id_all, 189 - struct perf_sample *sample); 189 + struct perf_sample *sample, bool swapped); 190 190 191 191 #endif /* __PERF_RECORD_H */
+13
tools/perf/util/evlist.c
··· 113 113 } 114 114 } 115 115 116 + void perf_evlist__enable(struct perf_evlist *evlist) 117 + { 118 + int cpu, thread; 119 + struct perf_evsel *pos; 120 + 121 + for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 122 + list_for_each_entry(pos, &evlist->entries, node) { 123 + for (thread = 0; thread < evlist->threads->nr; thread++) 124 + ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); 125 + } 126 + } 127 + } 128 + 116 129 int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 117 130 { 118 131 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
+1
tools/perf/util/evlist.h
··· 54 54 void perf_evlist__munmap(struct perf_evlist *evlist); 55 55 56 56 void perf_evlist__disable(struct perf_evlist *evlist); 57 + void perf_evlist__enable(struct perf_evlist *evlist); 57 58 58 59 static inline void perf_evlist__set_maps(struct perf_evlist *evlist, 59 60 struct cpu_map *cpus,
+43 -11
tools/perf/util/evsel.c
··· 7 7 * Released under the GPL v2. (and only v2, not any later version) 8 8 */ 9 9 10 + #include <byteswap.h> 11 + #include "asm/bug.h" 10 12 #include "evsel.h" 11 13 #include "evlist.h" 12 14 #include "util.h" ··· 344 342 345 343 int perf_event__parse_sample(const union perf_event *event, u64 type, 346 344 int sample_size, bool sample_id_all, 347 - struct perf_sample *data) 345 + struct perf_sample *data, bool swapped) 348 346 { 349 347 const u64 *array; 348 + 349 + /* 350 + * used for cross-endian analysis. See git commit 65014ab3 351 + * for why this goofiness is needed. 352 + */ 353 + union { 354 + u64 val64; 355 + u32 val32[2]; 356 + } u; 357 + 350 358 351 359 data->cpu = data->pid = data->tid = -1; 352 360 data->stream_id = data->id = data->time = -1ULL; ··· 378 366 } 379 367 380 368 if (type & PERF_SAMPLE_TID) { 381 - u32 *p = (u32 *)array; 382 - data->pid = p[0]; 383 - data->tid = p[1]; 369 + u.val64 = *array; 370 + if (swapped) { 371 + /* undo swap of u64, then swap on individual u32s */ 372 + u.val64 = bswap_64(u.val64); 373 + u.val32[0] = bswap_32(u.val32[0]); 374 + u.val32[1] = bswap_32(u.val32[1]); 375 + } 376 + 377 + data->pid = u.val32[0]; 378 + data->tid = u.val32[1]; 384 379 array++; 385 380 } 386 381 ··· 414 395 } 415 396 416 397 if (type & PERF_SAMPLE_CPU) { 417 - u32 *p = (u32 *)array; 418 - data->cpu = *p; 398 + 399 + u.val64 = *array; 400 + if (swapped) { 401 + /* undo swap of u64, then swap on individual u32s */ 402 + u.val64 = bswap_64(u.val64); 403 + u.val32[0] = bswap_32(u.val32[0]); 404 + } 405 + 406 + data->cpu = u.val32[0]; 419 407 array++; 420 408 } 421 409 ··· 449 423 } 450 424 451 425 if (type & PERF_SAMPLE_RAW) { 452 - u32 *p = (u32 *)array; 426 + u.val64 = *array; 427 + if (WARN_ONCE(swapped, 428 + "Endianness of raw data not corrected!\n")) { 429 + /* undo swap of u64, then swap on individual u32s */ 430 + u.val64 = bswap_64(u.val64); 431 + u.val32[0] = bswap_32(u.val32[0]); 432 + u.val32[1] = bswap_32(u.val32[1]); 433 + } 453 434 454 435 if (sample_overlap(event, array, sizeof(u32))) 455 436 return -EFAULT; 456 437 457 - data->raw_size = *p; 458 - p++; 438 + data->raw_size = u.val32[0]; 459 439 460 - if (sample_overlap(event, p, data->raw_size)) 440 + if (sample_overlap(event, &u.val32[1], data->raw_size)) 461 441 return -EFAULT; 462 442 463 - data->raw_data = p; 443 + data->raw_data = &u.val32[1]; 464 444 } 465 445 466 446 return 0;
+1 -1
tools/perf/util/probe-finder.c
··· 659 659 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 660 660 ret = -ENOENT; 661 661 } 662 - if (ret == 0) 662 + if (ret >= 0) 663 663 ret = convert_variable(&vr_die, pf); 664 664 665 665 if (ret < 0)
+2 -1
tools/perf/util/session.h
··· 162 162 { 163 163 return perf_event__parse_sample(event, session->sample_type, 164 164 session->sample_size, 165 - session->sample_id_all, sample); 165 + session->sample_id_all, sample, 166 + session->header.needs_swap); 166 167 } 167 168 168 169 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
+8 -2
tools/perf/util/sort.c
··· 151 151 { 152 152 u64 ip_l, ip_r; 153 153 154 + if (!left->ms.sym && !right->ms.sym) 155 + return right->level - left->level; 156 + 157 + if (!left->ms.sym || !right->ms.sym) 158 + return cmp_null(left->ms.sym, right->ms.sym); 159 + 154 160 if (left->ms.sym == right->ms.sym) 155 161 return 0; 156 162 157 - ip_l = left->ms.sym ? left->ms.sym->start : left->ip; 158 - ip_r = right->ms.sym ? right->ms.sym->start : right->ip; 163 + ip_l = left->ms.sym->start; 164 + ip_r = right->ms.sym->start; 159 165 160 166 return (int64_t)(ip_r - ip_l); 161 167 }
+118 -35
tools/perf/util/symbol.c
··· 74 74 75 75 bool symbol_type__is_a(char symbol_type, enum map_type map_type) 76 76 { 77 + symbol_type = toupper(symbol_type); 78 + 77 79 switch (map_type) { 78 80 case MAP__FUNCTION: 79 81 return symbol_type == 'T' || symbol_type == 'W'; 80 82 case MAP__VARIABLE: 81 - return symbol_type == 'D' || symbol_type == 'd'; 83 + return symbol_type == 'D'; 82 84 default: 83 85 return false; 86 + } 87 + } 88 + 89 + static int prefix_underscores_count(const char *str) 90 + { 91 + const char *tail = str; 92 + 93 + while (*tail == '_') 94 + tail++; 95 + 96 + return tail - str; 97 + } 98 + 99 + #define SYMBOL_A 0 100 + #define SYMBOL_B 1 101 + 102 + static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 103 + { 104 + s64 a; 105 + s64 b; 106 + 107 + /* Prefer a symbol with non zero length */ 108 + a = syma->end - syma->start; 109 + b = symb->end - symb->start; 110 + if ((b == 0) && (a > 0)) 111 + return SYMBOL_A; 112 + else if ((a == 0) && (b > 0)) 113 + return SYMBOL_B; 114 + 115 + /* Prefer a non weak symbol over a weak one */ 116 + a = syma->binding == STB_WEAK; 117 + b = symb->binding == STB_WEAK; 118 + if (b && !a) 119 + return SYMBOL_A; 120 + if (a && !b) 121 + return SYMBOL_B; 122 + 123 + /* Prefer a global symbol over a non global one */ 124 + a = syma->binding == STB_GLOBAL; 125 + b = symb->binding == STB_GLOBAL; 126 + if (a && !b) 127 + return SYMBOL_A; 128 + if (b && !a) 129 + return SYMBOL_B; 130 + 131 + /* Prefer a symbol with less underscores */ 132 + a = prefix_underscores_count(syma->name); 133 + b = prefix_underscores_count(symb->name); 134 + if (b > a) 135 + return SYMBOL_A; 136 + else if (a > b) 137 + return SYMBOL_B; 138 + 139 + /* If all else fails, choose the symbol with the longest name */ 140 + if (strlen(syma->name) >= strlen(symb->name)) 141 + return SYMBOL_A; 142 + else 143 + return SYMBOL_B; 144 + } 145 + 146 + static void symbols__fixup_duplicate(struct rb_root *symbols) 147 + { 148 + struct rb_node *nd; 149 + struct symbol *curr, *next; 150 + 151 + nd = rb_first(symbols); 152 + 153 + while (nd) { 154 + curr = rb_entry(nd, struct symbol, rb_node); 155 + again: 156 + nd = rb_next(&curr->rb_node); 157 + next = rb_entry(nd, struct symbol, rb_node); 158 + 159 + if (!nd) 160 + break; 161 + 162 + if (curr->start != next->start) 163 + continue; 164 + 165 + if (choose_best_symbol(curr, next) == SYMBOL_A) { 166 + rb_erase(&next->rb_node, symbols); 167 + goto again; 168 + } else { 169 + nd = rb_next(&curr->rb_node); 170 + rb_erase(&curr->rb_node, symbols); 171 + } 84 172 } 85 173 } 86 174 ··· 526 438 char *line = NULL; 527 439 size_t n; 528 440 int err = -1; 529 - u64 prev_start = 0; 530 - char prev_symbol_type = 0; 531 - char *prev_symbol_name; 532 441 FILE *file = fopen(filename, "r"); 533 442 534 443 if (file == NULL) 535 444 goto out_failure; 536 - 537 - prev_symbol_name = malloc(KSYM_NAME_LEN); 538 - if (prev_symbol_name == NULL) 539 - goto out_close; 540 445 541 446 err = 0; 542 447 ··· 551 470 if (len + 2 >= line_len) 552 471 continue; 553 472 554 - symbol_type = toupper(line[len]); 473 + symbol_type = line[len]; 555 474 len += 2; 556 475 symbol_name = line + len; 557 476 len = line_len - len; ··· 561 480 break; 562 481 } 563 482 564 - if (prev_symbol_type) { 565 - u64 end = start; 566 - if (end != prev_start) 567 - --end; 568 - err = process_symbol(arg, prev_symbol_name, 569 - prev_symbol_type, prev_start, end); 570 - if (err) 571 - break; 572 - } 573 - 574 - memcpy(prev_symbol_name, symbol_name, len + 1); 575 - prev_symbol_type = symbol_type; 576 - prev_start = start; 483 + /* 484 + * module symbols are not sorted so we add all 485 + * symbols with zero length and rely on 486 + * symbols__fixup_end() to fix it up. 487 + */ 488 + err = process_symbol(arg, symbol_name, 489 + symbol_type, start, start); 490 + if (err) 491 + break; 577 492 } 578 493 579 - free(prev_symbol_name); 580 494 free(line); 581 - out_close: 582 495 fclose(file); 583 496 return err; 584 497 ··· 777 702 778 703 if (dso__load_all_kallsyms(dso, filename, map) < 0) 779 704 return -1; 705 + 706 + symbols__fixup_duplicate(&dso->symbols[map->type]); 707 + symbols__fixup_end(&dso->symbols[map->type]); 780 708 781 709 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 782 710 dso->symtab_type = SYMTAB__GUEST_KALLSYMS; ··· 1170 1092 if (dso->has_build_id) { 1171 1093 u8 build_id[BUILD_ID_SIZE]; 1172 1094 1173 - if (elf_read_build_id(elf, build_id, 1174 - BUILD_ID_SIZE) != BUILD_ID_SIZE) 1095 + if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) 1175 1096 goto out_elf_end; 1176 1097 1177 1098 if (!dso__build_id_equal(dso, build_id)) ··· 1188 1111 } 1189 1112 1190 1113 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 1114 + if (opdshdr.sh_type != SHT_PROGBITS) 1115 + opdsec = NULL; 1191 1116 if (opdsec) 1192 1117 opddata = elf_rawdata(opdsec, NULL); 1193 1118 ··· 1355 1276 * For misannotated, zeroed, ASM function sizes. 1356 1277 */ 1357 1278 if (nr > 0) { 1279 + symbols__fixup_duplicate(&dso->symbols[map->type]); 1358 1280 symbols__fixup_end(&dso->symbols[map->type]); 1359 1281 if (kmap) { 1360 1282 /* ··· 1442 1362 ptr = data->d_buf; 1443 1363 while (ptr < (data->d_buf + data->d_size)) { 1444 1364 GElf_Nhdr *nhdr = ptr; 1445 - int namesz = NOTE_ALIGN(nhdr->n_namesz), 1446 - descsz = NOTE_ALIGN(nhdr->n_descsz); 1365 + size_t namesz = NOTE_ALIGN(nhdr->n_namesz), 1366 + descsz = NOTE_ALIGN(nhdr->n_descsz); 1447 1367 const char *name; 1448 1368 1449 1369 ptr += sizeof(*nhdr); ··· 1452 1372 if (nhdr->n_type == NT_GNU_BUILD_ID && 1453 1373 nhdr->n_namesz == sizeof("GNU")) { 1454 1374 if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1455 - memcpy(bf, ptr, BUILD_ID_SIZE); 1456 - err = BUILD_ID_SIZE; 1375 + size_t sz = min(size, descsz); 1376 + memcpy(bf, ptr, sz); 1377 + memset(bf + sz, 0, size - sz); 1378 + err = descsz; 1457 1379 break; 1458 1380 } 1459 1381 } ··· 1507 1425 while (1) { 1508 1426 char bf[BUFSIZ]; 1509 1427 GElf_Nhdr nhdr; 1510 - int namesz, descsz; 1428 + size_t namesz, descsz; 1511 1429 1512 1430 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1513 1431 break; ··· 1516 1434 descsz = NOTE_ALIGN(nhdr.n_descsz); 1517 1435 if (nhdr.n_type == NT_GNU_BUILD_ID && 1518 1436 nhdr.n_namesz == sizeof("GNU")) { 1519 - if (read(fd, bf, namesz) != namesz) 1437 + if (read(fd, bf, namesz) != (ssize_t)namesz) 1520 1438 break; 1521 1439 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1522 - if (read(fd, build_id, 1523 - BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1440 + size_t sz = min(descsz, size); 1441 + if (read(fd, build_id, sz) == (ssize_t)sz) { 1442 + memset(build_id + sz, 0, size - sz); 1524 1443 err = 0; 1525 1444 break; 1526 1445 } 1527 - } else if (read(fd, bf, descsz) != descsz) 1446 + } else if (read(fd, bf, descsz) != (ssize_t)descsz) 1528 1447 break; 1529 1448 } else { 1530 1449 int n = namesz + descsz;