aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol-elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/symbol-elf.c')
-rw-r--r--tools/perf/util/symbol-elf.c607
1 files changed, 601 insertions, 6 deletions
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index a9c829be5216..eed0b96302af 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -8,7 +8,7 @@
8#include "symbol.h" 8#include "symbol.h"
9#include "debug.h" 9#include "debug.h"
10 10
11#ifndef HAVE_ELF_GETPHDRNUM 11#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
12static int elf_getphdrnum(Elf *elf, size_t *dst) 12static int elf_getphdrnum(Elf *elf, size_t *dst)
13{ 13{
14 GElf_Ehdr gehdr; 14 GElf_Ehdr gehdr;
@@ -487,27 +487,27 @@ int filename__read_debuglink(const char *filename, char *debuglink,
487 487
488 ek = elf_kind(elf); 488 ek = elf_kind(elf);
489 if (ek != ELF_K_ELF) 489 if (ek != ELF_K_ELF)
490 goto out_close; 490 goto out_elf_end;
491 491
492 if (gelf_getehdr(elf, &ehdr) == NULL) { 492 if (gelf_getehdr(elf, &ehdr) == NULL) {
493 pr_err("%s: cannot get elf header.\n", __func__); 493 pr_err("%s: cannot get elf header.\n", __func__);
494 goto out_close; 494 goto out_elf_end;
495 } 495 }
496 496
497 sec = elf_section_by_name(elf, &ehdr, &shdr, 497 sec = elf_section_by_name(elf, &ehdr, &shdr,
498 ".gnu_debuglink", NULL); 498 ".gnu_debuglink", NULL);
499 if (sec == NULL) 499 if (sec == NULL)
500 goto out_close; 500 goto out_elf_end;
501 501
502 data = elf_getdata(sec, NULL); 502 data = elf_getdata(sec, NULL);
503 if (data == NULL) 503 if (data == NULL)
504 goto out_close; 504 goto out_elf_end;
505 505
506 /* the start of this section is a zero-terminated string */ 506 /* the start of this section is a zero-terminated string */
507 strncpy(debuglink, data->d_buf, size); 507 strncpy(debuglink, data->d_buf, size);
508 508
509out_elf_end:
509 elf_end(elf); 510 elf_end(elf);
510
511out_close: 511out_close:
512 close(fd); 512 close(fd);
513out: 513out:
@@ -1018,6 +1018,601 @@ 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
1205struct phdr_data {
1206 off_t offset;
1207 u64 addr;
1208 u64 len;
1209};
1210
1211struct kcore_copy_info {
1212 u64 stext;
1213 u64 etext;
1214 u64 first_symbol;
1215 u64 last_symbol;
1216 u64 first_module;
1217 u64 last_module_symbol;
1218 struct phdr_data kernel_map;
1219 struct phdr_data modules_map;
1220};
1221
1222static int kcore_copy__process_kallsyms(void *arg, const char *name, char type,
1223 u64 start)
1224{
1225 struct kcore_copy_info *kci = arg;
1226
1227 if (!symbol_type__is_a(type, MAP__FUNCTION))
1228 return 0;
1229
1230 if (strchr(name, '[')) {
1231 if (start > kci->last_module_symbol)
1232 kci->last_module_symbol = start;
1233 return 0;
1234 }
1235
1236 if (!kci->first_symbol || start < kci->first_symbol)
1237 kci->first_symbol = start;
1238
1239 if (!kci->last_symbol || start > kci->last_symbol)
1240 kci->last_symbol = start;
1241
1242 if (!strcmp(name, "_stext")) {
1243 kci->stext = start;
1244 return 0;
1245 }
1246
1247 if (!strcmp(name, "_etext")) {
1248 kci->etext = start;
1249 return 0;
1250 }
1251
1252 return 0;
1253}
1254
1255static int kcore_copy__parse_kallsyms(struct kcore_copy_info *kci,
1256 const char *dir)
1257{
1258 char kallsyms_filename[PATH_MAX];
1259
1260 scnprintf(kallsyms_filename, PATH_MAX, "%s/kallsyms", dir);
1261
1262 if (symbol__restricted_filename(kallsyms_filename, "/proc/kallsyms"))
1263 return -1;
1264
1265 if (kallsyms__parse(kallsyms_filename, kci,
1266 kcore_copy__process_kallsyms) < 0)
1267 return -1;
1268
1269 return 0;
1270}
1271
1272static int kcore_copy__process_modules(void *arg,
1273 const char *name __maybe_unused,
1274 u64 start)
1275{
1276 struct kcore_copy_info *kci = arg;
1277
1278 if (!kci->first_module || start < kci->first_module)
1279 kci->first_module = start;
1280
1281 return 0;
1282}
1283
1284static int kcore_copy__parse_modules(struct kcore_copy_info *kci,
1285 const char *dir)
1286{
1287 char modules_filename[PATH_MAX];
1288
1289 scnprintf(modules_filename, PATH_MAX, "%s/modules", dir);
1290
1291 if (symbol__restricted_filename(modules_filename, "/proc/modules"))
1292 return -1;
1293
1294 if (modules__parse(modules_filename, kci,
1295 kcore_copy__process_modules) < 0)
1296 return -1;
1297
1298 return 0;
1299}
1300
1301static void kcore_copy__map(struct phdr_data *p, u64 start, u64 end, u64 pgoff,
1302 u64 s, u64 e)
1303{
1304 if (p->addr || s < start || s >= end)
1305 return;
1306
1307 p->addr = s;
1308 p->offset = (s - start) + pgoff;
1309 p->len = e < end ? e - s : end - s;
1310}
1311
1312static int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data)
1313{
1314 struct kcore_copy_info *kci = data;
1315 u64 end = start + len;
1316
1317 kcore_copy__map(&kci->kernel_map, start, end, pgoff, kci->stext,
1318 kci->etext);
1319
1320 kcore_copy__map(&kci->modules_map, start, end, pgoff, kci->first_module,
1321 kci->last_module_symbol);
1322
1323 return 0;
1324}
1325
1326static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)
1327{
1328 if (elf_read_maps(elf, true, kcore_copy__read_map, kci) < 0)
1329 return -1;
1330
1331 return 0;
1332}
1333
1334static int kcore_copy__calc_maps(struct kcore_copy_info *kci, const char *dir,
1335 Elf *elf)
1336{
1337 if (kcore_copy__parse_kallsyms(kci, dir))
1338 return -1;
1339
1340 if (kcore_copy__parse_modules(kci, dir))
1341 return -1;
1342
1343 if (kci->stext)
1344 kci->stext = round_down(kci->stext, page_size);
1345 else
1346 kci->stext = round_down(kci->first_symbol, page_size);
1347
1348 if (kci->etext) {
1349 kci->etext = round_up(kci->etext, page_size);
1350 } else if (kci->last_symbol) {
1351 kci->etext = round_up(kci->last_symbol, page_size);
1352 kci->etext += page_size;
1353 }
1354
1355 kci->first_module = round_down(kci->first_module, page_size);
1356
1357 if (kci->last_module_symbol) {
1358 kci->last_module_symbol = round_up(kci->last_module_symbol,
1359 page_size);
1360 kci->last_module_symbol += page_size;
1361 }
1362
1363 if (!kci->stext || !kci->etext)
1364 return -1;
1365
1366 if (kci->first_module && !kci->last_module_symbol)
1367 return -1;
1368
1369 return kcore_copy__read_maps(kci, elf);
1370}
1371
1372static int kcore_copy__copy_file(const char *from_dir, const char *to_dir,
1373 const char *name)
1374{
1375 char from_filename[PATH_MAX];
1376 char to_filename[PATH_MAX];
1377
1378 scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
1379 scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
1380
1381 return copyfile_mode(from_filename, to_filename, 0400);
1382}
1383
1384static int kcore_copy__unlink(const char *dir, const char *name)
1385{
1386 char filename[PATH_MAX];
1387
1388 scnprintf(filename, PATH_MAX, "%s/%s", dir, name);
1389
1390 return unlink(filename);
1391}
1392
1393static int kcore_copy__compare_fds(int from, int to)
1394{
1395 char *buf_from;
1396 char *buf_to;
1397 ssize_t ret;
1398 size_t len;
1399 int err = -1;
1400
1401 buf_from = malloc(page_size);
1402 buf_to = malloc(page_size);
1403 if (!buf_from || !buf_to)
1404 goto out;
1405
1406 while (1) {
1407 /* Use read because mmap won't work on proc files */
1408 ret = read(from, buf_from, page_size);
1409 if (ret < 0)
1410 goto out;
1411
1412 if (!ret)
1413 break;
1414
1415 len = ret;
1416
1417 if (readn(to, buf_to, len) != (int)len)
1418 goto out;
1419
1420 if (memcmp(buf_from, buf_to, len))
1421 goto out;
1422 }
1423
1424 err = 0;
1425out:
1426 free(buf_to);
1427 free(buf_from);
1428 return err;
1429}
1430
1431static int kcore_copy__compare_files(const char *from_filename,
1432 const char *to_filename)
1433{
1434 int from, to, err = -1;
1435
1436 from = open(from_filename, O_RDONLY);
1437 if (from < 0)
1438 return -1;
1439
1440 to = open(to_filename, O_RDONLY);
1441 if (to < 0)
1442 goto out_close_from;
1443
1444 err = kcore_copy__compare_fds(from, to);
1445
1446 close(to);
1447out_close_from:
1448 close(from);
1449 return err;
1450}
1451
1452static int kcore_copy__compare_file(const char *from_dir, const char *to_dir,
1453 const char *name)
1454{
1455 char from_filename[PATH_MAX];
1456 char to_filename[PATH_MAX];
1457
1458 scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
1459 scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
1460
1461 return kcore_copy__compare_files(from_filename, to_filename);
1462}
1463
1464/**
1465 * kcore_copy - copy kallsyms, modules and kcore from one directory to another.
1466 * @from_dir: from directory
1467 * @to_dir: to directory
1468 *
1469 * This function copies kallsyms, modules and kcore files from one directory to
1470 * another. kallsyms and modules are copied entirely. Only code segments are
1471 * copied from kcore. It is assumed that two segments suffice: one for the
1472 * kernel proper and one for all the modules. The code segments are determined
1473 * from kallsyms and modules files. The kernel map starts at _stext or the
1474 * lowest function symbol, and ends at _etext or the highest function symbol.
1475 * The module map starts at the lowest module address and ends at the highest
1476 * module symbol. Start addresses are rounded down to the nearest page. End
1477 * addresses are rounded up to the nearest page. An extra page is added to the
1478 * highest kernel symbol and highest module symbol to, hopefully, encompass that
1479 * symbol too. Because it contains only code sections, the resulting kcore is
1480 * unusual. One significant peculiarity is that the mapping (start -> pgoff)
1481 * is not the same for the kernel map and the modules map. That happens because
1482 * the data is copied adjacently whereas the original kcore has gaps. Finally,
1483 * kallsyms and modules files are compared with their copies to check that
1484 * modules have not been loaded or unloaded while the copies were taking place.
1485 *
1486 * Return: %0 on success, %-1 on failure.
1487 */
1488int kcore_copy(const char *from_dir, const char *to_dir)
1489{
1490 struct kcore kcore;
1491 struct kcore extract;
1492 size_t count = 2;
1493 int idx = 0, err = -1;
1494 off_t offset = page_size, sz, modules_offset = 0;
1495 struct kcore_copy_info kci = { .stext = 0, };
1496 char kcore_filename[PATH_MAX];
1497 char extract_filename[PATH_MAX];
1498
1499 if (kcore_copy__copy_file(from_dir, to_dir, "kallsyms"))
1500 return -1;
1501
1502 if (kcore_copy__copy_file(from_dir, to_dir, "modules"))
1503 goto out_unlink_kallsyms;
1504
1505 scnprintf(kcore_filename, PATH_MAX, "%s/kcore", from_dir);
1506 scnprintf(extract_filename, PATH_MAX, "%s/kcore", to_dir);
1507
1508 if (kcore__open(&kcore, kcore_filename))
1509 goto out_unlink_modules;
1510
1511 if (kcore_copy__calc_maps(&kci, from_dir, kcore.elf))
1512 goto out_kcore_close;
1513
1514 if (kcore__init(&extract, extract_filename, kcore.elfclass, false))
1515 goto out_kcore_close;
1516
1517 if (!kci.modules_map.addr)
1518 count -= 1;
1519
1520 if (kcore__copy_hdr(&kcore, &extract, count))
1521 goto out_extract_close;
1522
1523 if (kcore__add_phdr(&extract, idx++, offset, kci.kernel_map.addr,
1524 kci.kernel_map.len))
1525 goto out_extract_close;
1526
1527 if (kci.modules_map.addr) {
1528 modules_offset = offset + kci.kernel_map.len;
1529 if (kcore__add_phdr(&extract, idx, modules_offset,
1530 kci.modules_map.addr, kci.modules_map.len))
1531 goto out_extract_close;
1532 }
1533
1534 sz = kcore__write(&extract);
1535 if (sz < 0 || sz > offset)
1536 goto out_extract_close;
1537
1538 if (copy_bytes(kcore.fd, kci.kernel_map.offset, extract.fd, offset,
1539 kci.kernel_map.len))
1540 goto out_extract_close;
1541
1542 if (modules_offset && copy_bytes(kcore.fd, kci.modules_map.offset,
1543 extract.fd, modules_offset,
1544 kci.modules_map.len))
1545 goto out_extract_close;
1546
1547 if (kcore_copy__compare_file(from_dir, to_dir, "modules"))
1548 goto out_extract_close;
1549
1550 if (kcore_copy__compare_file(from_dir, to_dir, "kallsyms"))
1551 goto out_extract_close;
1552
1553 err = 0;
1554
1555out_extract_close:
1556 kcore__close(&extract);
1557 if (err)
1558 unlink(extract_filename);
1559out_kcore_close:
1560 kcore__close(&kcore);
1561out_unlink_modules:
1562 if (err)
1563 kcore_copy__unlink(to_dir, "modules");
1564out_unlink_kallsyms:
1565 if (err)
1566 kcore_copy__unlink(to_dir, "kallsyms");
1567
1568 return err;
1569}
1570
1571int kcore_extract__create(struct kcore_extract *kce)
1572{
1573 struct kcore kcore;
1574 struct kcore extract;
1575 size_t count = 1;
1576 int idx = 0, err = -1;
1577 off_t offset = page_size, sz;
1578
1579 if (kcore__open(&kcore, kce->kcore_filename))
1580 return -1;
1581
1582 strcpy(kce->extract_filename, PERF_KCORE_EXTRACT);
1583 if (kcore__init(&extract, kce->extract_filename, kcore.elfclass, true))
1584 goto out_kcore_close;
1585
1586 if (kcore__copy_hdr(&kcore, &extract, count))
1587 goto out_extract_close;
1588
1589 if (kcore__add_phdr(&extract, idx, offset, kce->addr, kce->len))
1590 goto out_extract_close;
1591
1592 sz = kcore__write(&extract);
1593 if (sz < 0 || sz > offset)
1594 goto out_extract_close;
1595
1596 if (copy_bytes(kcore.fd, kce->offs, extract.fd, offset, kce->len))
1597 goto out_extract_close;
1598
1599 err = 0;
1600
1601out_extract_close:
1602 kcore__close(&extract);
1603 if (err)
1604 unlink(kce->extract_filename);
1605out_kcore_close:
1606 kcore__close(&kcore);
1607
1608 return err;
1609}
1610
1611void kcore_extract__delete(struct kcore_extract *kce)
1612{
1613 unlink(kce->extract_filename);
1614}
1615
1021void symbol__elf_init(void) 1616void symbol__elf_init(void)
1022{ 1617{
1023 elf_version(EV_CURRENT); 1618 elf_version(EV_CURRENT);