diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/data_map.c | 37 | ||||
-rw-r--r-- | tools/perf/util/event.h | 7 | ||||
-rw-r--r-- | tools/perf/util/header.c | 10 | ||||
-rw-r--r-- | tools/perf/util/header.h | 4 | ||||
-rw-r--r-- | tools/perf/util/map.c | 14 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 78 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 10 |
7 files changed, 133 insertions, 27 deletions
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index c458db9ede6d..00a9c114c8d0 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c | |||
@@ -70,6 +70,39 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | static int perf_header__read_build_ids(const struct perf_header *self, | ||
74 | int input, off_t file_size) | ||
75 | { | ||
76 | off_t offset = self->data_offset + self->data_size; | ||
77 | struct build_id_event bev; | ||
78 | char filename[PATH_MAX]; | ||
79 | int err = -1; | ||
80 | |||
81 | if (lseek(input, offset, SEEK_SET) < 0) | ||
82 | return -1; | ||
83 | |||
84 | while (offset < file_size) { | ||
85 | struct dso *dso; | ||
86 | ssize_t len; | ||
87 | |||
88 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | ||
89 | goto out; | ||
90 | |||
91 | len = bev.header.size - sizeof(bev); | ||
92 | if (read(input, filename, len) != len) | ||
93 | goto out; | ||
94 | |||
95 | dso = dsos__findnew(filename); | ||
96 | if (dso != NULL) | ||
97 | dso__set_build_id(dso, &bev.build_id); | ||
98 | |||
99 | offset += bev.header.size; | ||
100 | } | ||
101 | err = 0; | ||
102 | out: | ||
103 | return err; | ||
104 | } | ||
105 | |||
73 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 106 | int mmap_dispatch_perf_file(struct perf_header **pheader, |
74 | const char *input_name, | 107 | const char *input_name, |
75 | int force, | 108 | int force, |
@@ -130,6 +163,10 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, | |||
130 | if (curr_handler->sample_type_check(sample_type) < 0) | 163 | if (curr_handler->sample_type_check(sample_type) < 0) |
131 | exit(-1); | 164 | exit(-1); |
132 | 165 | ||
166 | if (perf_header__has_feat(header, HEADER_BUILD_ID) && | ||
167 | perf_header__read_build_ids(header, input, input_stat.st_size)) | ||
168 | pr_debug("failed to read buildids, continuing...\n"); | ||
169 | |||
133 | if (load_kernel(NULL) < 0) { | 170 | if (load_kernel(NULL) < 0) { |
134 | perror("failed to load kernel symbols"); | 171 | perror("failed to load kernel symbols"); |
135 | return EXIT_FAILURE; | 172 | return EXIT_FAILURE; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 0a443bea68db..34c6fcb82d92 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -61,6 +61,13 @@ struct sample_event{ | |||
61 | u64 array[]; | 61 | u64 array[]; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | #define BUILD_ID_SIZE 20 | ||
65 | |||
66 | struct build_id_event { | ||
67 | struct perf_event_header header; | ||
68 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | ||
69 | char filename[]; | ||
70 | }; | ||
64 | 71 | ||
65 | typedef union event_union { | 72 | typedef union event_union { |
66 | struct perf_event_header header; | 73 | struct perf_event_header header; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 7d26659b806c..050f543fd965 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -149,6 +149,16 @@ void perf_header__feat_trace_info(struct perf_header *header) | |||
149 | set_bit(HEADER_TRACE_INFO, header->adds_features); | 149 | set_bit(HEADER_TRACE_INFO, header->adds_features); |
150 | } | 150 | } |
151 | 151 | ||
152 | void perf_header__set_feat(struct perf_header *self, int feat) | ||
153 | { | ||
154 | set_bit(feat, self->adds_features); | ||
155 | } | ||
156 | |||
157 | bool perf_header__has_feat(const struct perf_header *self, int feat) | ||
158 | { | ||
159 | return test_bit(feat, self->adds_features); | ||
160 | } | ||
161 | |||
152 | static void do_write(int fd, void *buf, size_t size) | 162 | static void do_write(int fd, void *buf, size_t size) |
153 | { | 163 | { |
154 | while (size) { | 164 | while (size) { |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 2ea9dfb1236a..2f233c5db7e9 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include "../../../include/linux/perf_event.h" | 4 | #include "../../../include/linux/perf_event.h" |
5 | #include <sys/types.h> | 5 | #include <sys/types.h> |
6 | #include <stdbool.h> | ||
6 | #include "types.h" | 7 | #include "types.h" |
7 | 8 | ||
8 | #include <linux/bitmap.h> | 9 | #include <linux/bitmap.h> |
@@ -15,6 +16,7 @@ struct perf_header_attr { | |||
15 | }; | 16 | }; |
16 | 17 | ||
17 | #define HEADER_TRACE_INFO 1 | 18 | #define HEADER_TRACE_INFO 1 |
19 | #define HEADER_BUILD_ID 2 | ||
18 | 20 | ||
19 | #define HEADER_FEAT_BITS 256 | 21 | #define HEADER_FEAT_BITS 256 |
20 | 22 | ||
@@ -48,6 +50,8 @@ u64 perf_header__sample_type(struct perf_header *header); | |||
48 | struct perf_event_attr * | 50 | struct perf_event_attr * |
49 | perf_header__find_attr(u64 id, struct perf_header *header); | 51 | perf_header__find_attr(u64 id, struct perf_header *header); |
50 | void perf_header__feat_trace_info(struct perf_header *header); | 52 | void perf_header__feat_trace_info(struct perf_header *header); |
53 | void perf_header__set_feat(struct perf_header *self, int feat); | ||
54 | bool perf_header__has_feat(const struct perf_header *self, int feat); | ||
51 | 55 | ||
52 | struct perf_header *perf_header__new(void); | 56 | struct perf_header *perf_header__new(void); |
53 | 57 | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 33f868420d73..94ca95073c40 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -84,8 +84,18 @@ map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter) | |||
84 | int nr = dso__load(self->dso, self, filter); | 84 | int nr = dso__load(self->dso, self, filter); |
85 | 85 | ||
86 | if (nr < 0) { | 86 | if (nr < 0) { |
87 | pr_warning("Failed to open %s, continuing without symbols\n", | 87 | if (self->dso->has_build_id) { |
88 | self->dso->long_name); | 88 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
89 | |||
90 | build_id__sprintf(self->dso->build_id, | ||
91 | sizeof(self->dso->build_id), | ||
92 | sbuild_id); | ||
93 | pr_warning("%s with build id %s not found", | ||
94 | self->dso->long_name, sbuild_id); | ||
95 | } else | ||
96 | pr_warning("Failed to open %s", | ||
97 | self->dso->long_name); | ||
98 | pr_warning(", continuing without symbols\n"); | ||
89 | return NULL; | 99 | return NULL; |
90 | } else if (nr == 0) { | 100 | } else if (nr == 0) { |
91 | const char *name = self->dso->long_name; | 101 | const char *name = self->dso->long_name; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7c7cdb851c2..a2e95ce1f223 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -121,7 +121,8 @@ struct dso *dso__new(const char *name) | |||
121 | self->find_symbol = dso__find_symbol; | 121 | self->find_symbol = dso__find_symbol; |
122 | self->slen_calculated = 0; | 122 | self->slen_calculated = 0; |
123 | self->origin = DSO__ORIG_NOT_FOUND; | 123 | self->origin = DSO__ORIG_NOT_FOUND; |
124 | self->loaded = false; | 124 | self->loaded = 0; |
125 | self->has_build_id = 0; | ||
125 | } | 126 | } |
126 | 127 | ||
127 | return self; | 128 | return self; |
@@ -148,6 +149,12 @@ void dso__delete(struct dso *self) | |||
148 | free(self); | 149 | free(self); |
149 | } | 150 | } |
150 | 151 | ||
152 | void dso__set_build_id(struct dso *self, void *build_id) | ||
153 | { | ||
154 | memcpy(self->build_id, build_id, sizeof(self->build_id)); | ||
155 | self->has_build_id = 1; | ||
156 | } | ||
157 | |||
151 | static void dso__insert_symbol(struct dso *self, struct symbol *sym) | 158 | static void dso__insert_symbol(struct dso *self, struct symbol *sym) |
152 | { | 159 | { |
153 | struct rb_node **p = &self->syms.rb_node; | 160 | struct rb_node **p = &self->syms.rb_node; |
@@ -190,11 +197,30 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip) | |||
190 | return NULL; | 197 | return NULL; |
191 | } | 198 | } |
192 | 199 | ||
193 | size_t dso__fprintf(struct dso *self, FILE *fp) | 200 | int build_id__sprintf(u8 *self, int len, char *bf) |
194 | { | 201 | { |
195 | size_t ret = fprintf(fp, "dso: %s\n", self->short_name); | 202 | char *bid = bf; |
203 | u8 *raw = self; | ||
204 | int i; | ||
196 | 205 | ||
206 | for (i = 0; i < len; ++i) { | ||
207 | sprintf(bid, "%02x", *raw); | ||
208 | ++raw; | ||
209 | bid += 2; | ||
210 | } | ||
211 | |||
212 | return raw - self; | ||
213 | } | ||
214 | |||
215 | size_t dso__fprintf(struct dso *self, FILE *fp) | ||
216 | { | ||
217 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
197 | struct rb_node *nd; | 218 | struct rb_node *nd; |
219 | size_t ret; | ||
220 | |||
221 | build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); | ||
222 | ret = fprintf(fp, "dso: %s (%s)\n", self->short_name, sbuild_id); | ||
223 | |||
198 | for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { | 224 | for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { |
199 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | 225 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); |
200 | ret += symbol__fprintf(pos, fp); | 226 | ret += symbol__fprintf(pos, fp); |
@@ -825,8 +851,6 @@ out_close: | |||
825 | return err; | 851 | return err; |
826 | } | 852 | } |
827 | 853 | ||
828 | #define BUILD_ID_SIZE 20 | ||
829 | |||
830 | int filename__read_build_id(const char *filename, void *bf, size_t size) | 854 | int filename__read_build_id(const char *filename, void *bf, size_t size) |
831 | { | 855 | { |
832 | int fd, err = -1; | 856 | int fd, err = -1; |
@@ -845,7 +869,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size) | |||
845 | 869 | ||
846 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 870 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
847 | if (elf == NULL) { | 871 | if (elf == NULL) { |
848 | pr_err("%s: cannot read %s ELF file.\n", __func__, filename); | 872 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); |
849 | goto out_close; | 873 | goto out_close; |
850 | } | 874 | } |
851 | 875 | ||
@@ -874,9 +898,9 @@ out: | |||
874 | 898 | ||
875 | static char *dso__read_build_id(struct dso *self) | 899 | static char *dso__read_build_id(struct dso *self) |
876 | { | 900 | { |
877 | int i, len; | 901 | int len; |
878 | char *build_id = NULL, *bid; | 902 | char *build_id = NULL; |
879 | unsigned char rawbf[BUILD_ID_SIZE], *raw; | 903 | unsigned char rawbf[BUILD_ID_SIZE]; |
880 | 904 | ||
881 | len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf)); | 905 | len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf)); |
882 | if (len < 0) | 906 | if (len < 0) |
@@ -885,15 +909,8 @@ static char *dso__read_build_id(struct dso *self) | |||
885 | build_id = malloc(len * 2 + 1); | 909 | build_id = malloc(len * 2 + 1); |
886 | if (build_id == NULL) | 910 | if (build_id == NULL) |
887 | goto out; | 911 | goto out; |
888 | bid = build_id; | ||
889 | 912 | ||
890 | raw = rawbf; | 913 | build_id__sprintf(rawbf, len, build_id); |
891 | for (i = 0; i < len; ++i) { | ||
892 | sprintf(bid, "%02x", *raw); | ||
893 | ++raw; | ||
894 | bid += 2; | ||
895 | } | ||
896 | pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id); | ||
897 | out: | 914 | out: |
898 | return build_id; | 915 | return build_id; |
899 | } | 916 | } |
@@ -922,7 +939,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
922 | int ret = -1; | 939 | int ret = -1; |
923 | int fd; | 940 | int fd; |
924 | 941 | ||
925 | self->loaded = true; | 942 | self->loaded = 1; |
926 | 943 | ||
927 | if (!name) | 944 | if (!name) |
928 | return -1; | 945 | return -1; |
@@ -940,6 +957,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
940 | 957 | ||
941 | more: | 958 | more: |
942 | do { | 959 | do { |
960 | int berr = 0; | ||
961 | |||
943 | self->origin++; | 962 | self->origin++; |
944 | switch (self->origin) { | 963 | switch (self->origin) { |
945 | case DSO__ORIG_FEDORA: | 964 | case DSO__ORIG_FEDORA: |
@@ -956,8 +975,7 @@ more: | |||
956 | snprintf(name, size, | 975 | snprintf(name, size, |
957 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | 976 | "/usr/lib/debug/.build-id/%.2s/%s.debug", |
958 | build_id, build_id + 2); | 977 | build_id, build_id + 2); |
959 | free(build_id); | 978 | goto compare_build_id; |
960 | break; | ||
961 | } | 979 | } |
962 | self->origin++; | 980 | self->origin++; |
963 | /* Fall thru */ | 981 | /* Fall thru */ |
@@ -969,6 +987,22 @@ more: | |||
969 | goto out; | 987 | goto out; |
970 | } | 988 | } |
971 | 989 | ||
990 | if (self->has_build_id) { | ||
991 | bool match; | ||
992 | build_id = malloc(BUILD_ID_SIZE); | ||
993 | if (build_id == NULL) | ||
994 | goto more; | ||
995 | berr = filename__read_build_id(name, build_id, | ||
996 | BUILD_ID_SIZE); | ||
997 | compare_build_id: | ||
998 | match = berr > 0 && memcmp(build_id, self->build_id, | ||
999 | sizeof(self->build_id)) == 0; | ||
1000 | free(build_id); | ||
1001 | build_id = NULL; | ||
1002 | if (!match) | ||
1003 | goto more; | ||
1004 | } | ||
1005 | |||
972 | fd = open(name, O_RDONLY); | 1006 | fd = open(name, O_RDONLY); |
973 | } while (fd < 0); | 1007 | } while (fd < 0); |
974 | 1008 | ||
@@ -1034,7 +1068,7 @@ static int dso__load_module_sym(struct dso *self, struct map *map, | |||
1034 | { | 1068 | { |
1035 | int err = 0, fd = open(self->long_name, O_RDONLY); | 1069 | int err = 0, fd = open(self->long_name, O_RDONLY); |
1036 | 1070 | ||
1037 | self->loaded = true; | 1071 | self->loaded = 1; |
1038 | 1072 | ||
1039 | if (fd < 0) { | 1073 | if (fd < 0) { |
1040 | pr_err("%s: cannot open %s\n", __func__, self->long_name); | 1074 | pr_err("%s: cannot open %s\n", __func__, self->long_name); |
@@ -1225,7 +1259,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, | |||
1225 | { | 1259 | { |
1226 | int err, fd = open(vmlinux, O_RDONLY); | 1260 | int err, fd = open(vmlinux, O_RDONLY); |
1227 | 1261 | ||
1228 | self->loaded = true; | 1262 | self->loaded = 1; |
1229 | 1263 | ||
1230 | if (fd < 0) | 1264 | if (fd < 0) |
1231 | return -1; | 1265 | return -1; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e0d4a583f8dd..f8c1899af483 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -60,10 +60,12 @@ struct dso { | |||
60 | struct list_head node; | 60 | struct list_head node; |
61 | struct rb_root syms; | 61 | struct rb_root syms; |
62 | struct symbol *(*find_symbol)(struct dso *, u64 ip); | 62 | struct symbol *(*find_symbol)(struct dso *, u64 ip); |
63 | unsigned char adjust_symbols; | 63 | u8 adjust_symbols:1; |
64 | unsigned char slen_calculated; | 64 | u8 slen_calculated:1; |
65 | bool loaded; | 65 | u8 loaded:1; |
66 | u8 has_build_id:1; | ||
66 | unsigned char origin; | 67 | unsigned char origin; |
68 | u8 build_id[BUILD_ID_SIZE]; | ||
67 | const char *short_name; | 69 | const char *short_name; |
68 | char *long_name; | 70 | char *long_name; |
69 | char name[0]; | 71 | char name[0]; |
@@ -81,8 +83,10 @@ void dsos__fprintf(FILE *fp); | |||
81 | 83 | ||
82 | size_t dso__fprintf(struct dso *self, FILE *fp); | 84 | size_t dso__fprintf(struct dso *self, FILE *fp); |
83 | char dso__symtab_origin(const struct dso *self); | 85 | char dso__symtab_origin(const struct dso *self); |
86 | void dso__set_build_id(struct dso *self, void *build_id); | ||
84 | 87 | ||
85 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 88 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
89 | int build_id__sprintf(u8 *self, int len, char *bf); | ||
86 | 90 | ||
87 | int load_kernel(symbol_filter_t filter); | 91 | int load_kernel(symbol_filter_t filter); |
88 | 92 | ||