diff options
Diffstat (limited to 'tools/perf/util/symbol-elf.c')
-rw-r--r-- | tools/perf/util/symbol-elf.c | 607 |
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 |
12 | static int elf_getphdrnum(Elf *elf, size_t *dst) | 12 | static 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 | ||
509 | out_elf_end: | ||
509 | elf_end(elf); | 510 | elf_end(elf); |
510 | |||
511 | out_close: | 511 | out_close: |
512 | close(fd); | 512 | close(fd); |
513 | out: | 513 | out: |
@@ -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 | ||
1021 | static 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; | ||
1057 | out: | ||
1058 | free(buf); | ||
1059 | return err; | ||
1060 | } | ||
1061 | |||
1062 | struct kcore { | ||
1063 | int fd; | ||
1064 | int elfclass; | ||
1065 | Elf *elf; | ||
1066 | GElf_Ehdr ehdr; | ||
1067 | }; | ||
1068 | |||
1069 | static 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 | |||
1091 | out_end: | ||
1092 | elf_end(kcore->elf); | ||
1093 | out_close: | ||
1094 | close(kcore->fd); | ||
1095 | return -1; | ||
1096 | } | ||
1097 | |||
1098 | static 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 | |||
1125 | out_end: | ||
1126 | elf_end(kcore->elf); | ||
1127 | out_close: | ||
1128 | close(kcore->fd); | ||
1129 | unlink(filename); | ||
1130 | return -1; | ||
1131 | } | ||
1132 | |||
1133 | static void kcore__close(struct kcore *kcore) | ||
1134 | { | ||
1135 | elf_end(kcore->elf); | ||
1136 | close(kcore->fd); | ||
1137 | } | ||
1138 | |||
1139 | static 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 | |||
1175 | static 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 | |||
1200 | static off_t kcore__write(struct kcore *kcore) | ||
1201 | { | ||
1202 | return elf_update(kcore->elf, ELF_C_WRITE); | ||
1203 | } | ||
1204 | |||
1205 | struct phdr_data { | ||
1206 | off_t offset; | ||
1207 | u64 addr; | ||
1208 | u64 len; | ||
1209 | }; | ||
1210 | |||
1211 | struct 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 | |||
1222 | static 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 | |||
1255 | static 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 | |||
1272 | static 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 | |||
1284 | static 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 | |||
1301 | static 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 | |||
1312 | static 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 | |||
1326 | static 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 | |||
1334 | static 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 | |||
1372 | static 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 | |||
1384 | static 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 | |||
1393 | static 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; | ||
1425 | out: | ||
1426 | free(buf_to); | ||
1427 | free(buf_from); | ||
1428 | return err; | ||
1429 | } | ||
1430 | |||
1431 | static 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); | ||
1447 | out_close_from: | ||
1448 | close(from); | ||
1449 | return err; | ||
1450 | } | ||
1451 | |||
1452 | static 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 | */ | ||
1488 | int 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 | |||
1555 | out_extract_close: | ||
1556 | kcore__close(&extract); | ||
1557 | if (err) | ||
1558 | unlink(extract_filename); | ||
1559 | out_kcore_close: | ||
1560 | kcore__close(&kcore); | ||
1561 | out_unlink_modules: | ||
1562 | if (err) | ||
1563 | kcore_copy__unlink(to_dir, "modules"); | ||
1564 | out_unlink_kallsyms: | ||
1565 | if (err) | ||
1566 | kcore_copy__unlink(to_dir, "kallsyms"); | ||
1567 | |||
1568 | return err; | ||
1569 | } | ||
1570 | |||
1571 | int 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 | |||
1601 | out_extract_close: | ||
1602 | kcore__close(&extract); | ||
1603 | if (err) | ||
1604 | unlink(kce->extract_filename); | ||
1605 | out_kcore_close: | ||
1606 | kcore__close(&kcore); | ||
1607 | |||
1608 | return err; | ||
1609 | } | ||
1610 | |||
1611 | void kcore_extract__delete(struct kcore_extract *kce) | ||
1612 | { | ||
1613 | unlink(kce->extract_filename); | ||
1614 | } | ||
1615 | |||
1021 | void symbol__elf_init(void) | 1616 | void symbol__elf_init(void) |
1022 | { | 1617 | { |
1023 | elf_version(EV_CURRENT); | 1618 | elf_version(EV_CURRENT); |