aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2013-10-09 08:01:12 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-10-14 09:29:00 -0400
commitafba19d9dc8eba66ea26901708cf99354c637786 (patch)
tree3b96f6610f8b776d4a4f9836205321bda4b143fd /tools/perf
parent52afdaf9f0c6a35e154ba42ac9510044e16d75ec (diff)
perf symbols: Workaround objdump difficulties with kcore
The objdump tool fails to annotate module symbols when looking at kcore. Workaround this by extracting object code from kcore and putting it in a temporary file for objdump to use instead. The temporary file is created to look like kcore but contains only the function being disassembled. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1381320078-16497-3-git-send-email-adrian.hunter@intel.com [ Renamed 'index' to 'idx' to avoid shadowing string.h's 'index' in Fedora 12, Replace local with variable length with malloc/free to fix build in Fedora 12 ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/annotate.c21
-rw-r--r--tools/perf/util/symbol-elf.c229
-rw-r--r--tools/perf/util/symbol-minimal.c9
-rw-r--r--tools/perf/util/symbol.h14
4 files changed, 273 insertions, 0 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d73e8008aada..882bb864cee0 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -879,6 +879,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
879 FILE *file; 879 FILE *file;
880 int err = 0; 880 int err = 0;
881 char symfs_filename[PATH_MAX]; 881 char symfs_filename[PATH_MAX];
882 struct kcore_extract kce;
883 bool delete_extract = false;
882 884
883 if (filename) { 885 if (filename) {
884 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 886 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
@@ -940,6 +942,23 @@ fallback:
940 pr_debug("annotating [%p] %30s : [%p] %30s\n", 942 pr_debug("annotating [%p] %30s : [%p] %30s\n",
941 dso, dso->long_name, sym, sym->name); 943 dso, dso->long_name, sym, sym->name);
942 944
945 if (dso__is_kcore(dso)) {
946 kce.kcore_filename = symfs_filename;
947 kce.addr = map__rip_2objdump(map, sym->start);
948 kce.offs = sym->start;
949 kce.len = sym->end + 1 - sym->start;
950 if (!kcore_extract__create(&kce)) {
951 delete_extract = true;
952 strlcpy(symfs_filename, kce.extract_filename,
953 sizeof(symfs_filename));
954 if (free_filename) {
955 free(filename);
956 free_filename = false;
957 }
958 filename = symfs_filename;
959 }
960 }
961
943 snprintf(command, sizeof(command), 962 snprintf(command, sizeof(command),
944 "%s %s%s --start-address=0x%016" PRIx64 963 "%s %s%s --start-address=0x%016" PRIx64
945 " --stop-address=0x%016" PRIx64 964 " --stop-address=0x%016" PRIx64
@@ -972,6 +991,8 @@ fallback:
972 991
973 pclose(file); 992 pclose(file);
974out_free_filename: 993out_free_filename:
994 if (delete_extract)
995 kcore_extract__delete(&kce);
975 if (free_filename) 996 if (free_filename)
976 free(filename); 997 free(filename);
977 return err; 998 return err;
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index c37693052800..499c71d30225 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1018,6 +1018,235 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1018 return err; 1018 return err;
1019} 1019}
1020 1020
1021static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
1022{
1023 ssize_t r;
1024 size_t n;
1025 int err = -1;
1026 char *buf = malloc(page_size);
1027
1028 if (buf == NULL)
1029 return -1;
1030
1031 if (lseek(to, to_offs, SEEK_SET) != to_offs)
1032 goto out;
1033
1034 if (lseek(from, from_offs, SEEK_SET) != from_offs)
1035 goto out;
1036
1037 while (len) {
1038 n = page_size;
1039 if (len < n)
1040 n = len;
1041 /* Use read because mmap won't work on proc files */
1042 r = read(from, buf, n);
1043 if (r < 0)
1044 goto out;
1045 if (!r)
1046 break;
1047 n = r;
1048 r = write(to, buf, n);
1049 if (r < 0)
1050 goto out;
1051 if ((size_t)r != n)
1052 goto out;
1053 len -= n;
1054 }
1055
1056 err = 0;
1057out:
1058 free(buf);
1059 return err;
1060}
1061
1062struct kcore {
1063 int fd;
1064 int elfclass;
1065 Elf *elf;
1066 GElf_Ehdr ehdr;
1067};
1068
1069static int kcore__open(struct kcore *kcore, const char *filename)
1070{
1071 GElf_Ehdr *ehdr;
1072
1073 kcore->fd = open(filename, O_RDONLY);
1074 if (kcore->fd == -1)
1075 return -1;
1076
1077 kcore->elf = elf_begin(kcore->fd, ELF_C_READ, NULL);
1078 if (!kcore->elf)
1079 goto out_close;
1080
1081 kcore->elfclass = gelf_getclass(kcore->elf);
1082 if (kcore->elfclass == ELFCLASSNONE)
1083 goto out_end;
1084
1085 ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
1086 if (!ehdr)
1087 goto out_end;
1088
1089 return 0;
1090
1091out_end:
1092 elf_end(kcore->elf);
1093out_close:
1094 close(kcore->fd);
1095 return -1;
1096}
1097
1098static int kcore__init(struct kcore *kcore, char *filename, int elfclass,
1099 bool temp)
1100{
1101 GElf_Ehdr *ehdr;
1102
1103 kcore->elfclass = elfclass;
1104
1105 if (temp)
1106 kcore->fd = mkstemp(filename);
1107 else
1108 kcore->fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400);
1109 if (kcore->fd == -1)
1110 return -1;
1111
1112 kcore->elf = elf_begin(kcore->fd, ELF_C_WRITE, NULL);
1113 if (!kcore->elf)
1114 goto out_close;
1115
1116 if (!gelf_newehdr(kcore->elf, elfclass))
1117 goto out_end;
1118
1119 ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
1120 if (!ehdr)
1121 goto out_end;
1122
1123 return 0;
1124
1125out_end:
1126 elf_end(kcore->elf);
1127out_close:
1128 close(kcore->fd);
1129 unlink(filename);
1130 return -1;
1131}
1132
1133static void kcore__close(struct kcore *kcore)
1134{
1135 elf_end(kcore->elf);
1136 close(kcore->fd);
1137}
1138
1139static int kcore__copy_hdr(struct kcore *from, struct kcore *to, size_t count)
1140{
1141 GElf_Ehdr *ehdr = &to->ehdr;
1142 GElf_Ehdr *kehdr = &from->ehdr;
1143
1144 memcpy(ehdr->e_ident, kehdr->e_ident, EI_NIDENT);
1145 ehdr->e_type = kehdr->e_type;
1146 ehdr->e_machine = kehdr->e_machine;
1147 ehdr->e_version = kehdr->e_version;
1148 ehdr->e_entry = 0;
1149 ehdr->e_shoff = 0;
1150 ehdr->e_flags = kehdr->e_flags;
1151 ehdr->e_phnum = count;
1152 ehdr->e_shentsize = 0;
1153 ehdr->e_shnum = 0;
1154 ehdr->e_shstrndx = 0;
1155
1156 if (from->elfclass == ELFCLASS32) {
1157 ehdr->e_phoff = sizeof(Elf32_Ehdr);
1158 ehdr->e_ehsize = sizeof(Elf32_Ehdr);
1159 ehdr->e_phentsize = sizeof(Elf32_Phdr);
1160 } else {
1161 ehdr->e_phoff = sizeof(Elf64_Ehdr);
1162 ehdr->e_ehsize = sizeof(Elf64_Ehdr);
1163 ehdr->e_phentsize = sizeof(Elf64_Phdr);
1164 }
1165
1166 if (!gelf_update_ehdr(to->elf, ehdr))
1167 return -1;
1168
1169 if (!gelf_newphdr(to->elf, count))
1170 return -1;
1171
1172 return 0;
1173}
1174
1175static int kcore__add_phdr(struct kcore *kcore, int idx, off_t offset,
1176 u64 addr, u64 len)
1177{
1178 GElf_Phdr gphdr;
1179 GElf_Phdr *phdr;
1180
1181 phdr = gelf_getphdr(kcore->elf, idx, &gphdr);
1182 if (!phdr)
1183 return -1;
1184
1185 phdr->p_type = PT_LOAD;
1186 phdr->p_flags = PF_R | PF_W | PF_X;
1187 phdr->p_offset = offset;
1188 phdr->p_vaddr = addr;
1189 phdr->p_paddr = 0;
1190 phdr->p_filesz = len;
1191 phdr->p_memsz = len;
1192 phdr->p_align = page_size;
1193
1194 if (!gelf_update_phdr(kcore->elf, idx, phdr))
1195 return -1;
1196
1197 return 0;
1198}
1199
1200static off_t kcore__write(struct kcore *kcore)
1201{
1202 return elf_update(kcore->elf, ELF_C_WRITE);
1203}
1204
1205int kcore_extract__create(struct kcore_extract *kce)
1206{
1207 struct kcore kcore;
1208 struct kcore extract;
1209 size_t count = 1;
1210 int idx = 0, err = -1;
1211 off_t offset = page_size, sz;
1212
1213 if (kcore__open(&kcore, kce->kcore_filename))
1214 return -1;
1215
1216 strcpy(kce->extract_filename, PERF_KCORE_EXTRACT);
1217 if (kcore__init(&extract, kce->extract_filename, kcore.elfclass, true))
1218 goto out_kcore_close;
1219
1220 if (kcore__copy_hdr(&kcore, &extract, count))
1221 goto out_extract_close;
1222
1223 if (kcore__add_phdr(&extract, idx, offset, kce->addr, kce->len))
1224 goto out_extract_close;
1225
1226 sz = kcore__write(&extract);
1227 if (sz < 0 || sz > offset)
1228 goto out_extract_close;
1229
1230 if (copy_bytes(kcore.fd, kce->offs, extract.fd, offset, kce->len))
1231 goto out_extract_close;
1232
1233 err = 0;
1234
1235out_extract_close:
1236 kcore__close(&extract);
1237 if (err)
1238 unlink(kce->extract_filename);
1239out_kcore_close:
1240 kcore__close(&kcore);
1241
1242 return err;
1243}
1244
1245void kcore_extract__delete(struct kcore_extract *kce)
1246{
1247 unlink(kce->extract_filename);
1248}
1249
1021void symbol__elf_init(void) 1250void symbol__elf_init(void)
1022{ 1251{
1023 elf_version(EV_CURRENT); 1252 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 3a802c300fc5..928556d2508f 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -308,6 +308,15 @@ int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
308 return -1; 308 return -1;
309} 309}
310 310
311int kcore_extract__create(struct kcore_extract *kce __maybe_unused)
312{
313 return -1;
314}
315
316void kcore_extract__delete(struct kcore_extract *kce __maybe_unused)
317{
318}
319
311void symbol__elf_init(void) 320void symbol__elf_init(void)
312{ 321{
313} 322}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 2d3eb43ab9f9..fb107e13e925 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -256,4 +256,18 @@ typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
256int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, 256int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
257 bool *is_64_bit); 257 bool *is_64_bit);
258 258
259#define PERF_KCORE_EXTRACT "/tmp/perf-kcore-XXXXXX"
260
261struct kcore_extract {
262 char *kcore_filename;
263 u64 addr;
264 u64 offs;
265 u64 len;
266 char extract_filename[sizeof(PERF_KCORE_EXTRACT)];
267 int fd;
268};
269
270int kcore_extract__create(struct kcore_extract *kce);
271void kcore_extract__delete(struct kcore_extract *kce);
272
259#endif /* __PERF_SYMBOL */ 273#endif /* __PERF_SYMBOL */