diff options
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r-- | tools/perf/util/machine.c | 142 |
1 files changed, 89 insertions, 53 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 34fc7c8672e4..d97309c87bd6 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -21,7 +21,7 @@ static void dsos__init(struct dsos *dsos) | |||
21 | 21 | ||
22 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 22 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
23 | { | 23 | { |
24 | map_groups__init(&machine->kmaps); | 24 | map_groups__init(&machine->kmaps, machine); |
25 | RB_CLEAR_NODE(&machine->rb_node); | 25 | RB_CLEAR_NODE(&machine->rb_node); |
26 | dsos__init(&machine->user_dsos); | 26 | dsos__init(&machine->user_dsos); |
27 | dsos__init(&machine->kernel_dsos); | 27 | dsos__init(&machine->kernel_dsos); |
@@ -32,7 +32,6 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
32 | 32 | ||
33 | machine->vdso_info = NULL; | 33 | machine->vdso_info = NULL; |
34 | 34 | ||
35 | machine->kmaps.machine = machine; | ||
36 | machine->pid = pid; | 35 | machine->pid = pid; |
37 | 36 | ||
38 | machine->symbol_filter = NULL; | 37 | machine->symbol_filter = NULL; |
@@ -319,7 +318,7 @@ static void machine__update_thread_pid(struct machine *machine, | |||
319 | goto out_err; | 318 | goto out_err; |
320 | 319 | ||
321 | if (!leader->mg) | 320 | if (!leader->mg) |
322 | leader->mg = map_groups__new(); | 321 | leader->mg = map_groups__new(machine); |
323 | 322 | ||
324 | if (!leader->mg) | 323 | if (!leader->mg) |
325 | goto out_err; | 324 | goto out_err; |
@@ -465,6 +464,7 @@ struct map *machine__new_module(struct machine *machine, u64 start, | |||
465 | { | 464 | { |
466 | struct map *map; | 465 | struct map *map; |
467 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); | 466 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); |
467 | bool compressed; | ||
468 | 468 | ||
469 | if (dso == NULL) | 469 | if (dso == NULL) |
470 | return NULL; | 470 | return NULL; |
@@ -477,6 +477,11 @@ struct map *machine__new_module(struct machine *machine, u64 start, | |||
477 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | 477 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; |
478 | else | 478 | else |
479 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | 479 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; |
480 | |||
481 | /* _KMODULE_COMP should be next to _KMODULE */ | ||
482 | if (is_kernel_module(filename, &compressed) && compressed) | ||
483 | dso->symtab_type++; | ||
484 | |||
480 | map_groups__insert(&machine->kmaps, map); | 485 | map_groups__insert(&machine->kmaps, map); |
481 | return map; | 486 | return map; |
482 | } | 487 | } |
@@ -862,8 +867,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, | |||
862 | struct map *map; | 867 | struct map *map; |
863 | char *long_name; | 868 | char *long_name; |
864 | 869 | ||
865 | if (dot == NULL || strcmp(dot, ".ko")) | 870 | if (dot == NULL) |
866 | continue; | 871 | continue; |
872 | |||
873 | /* On some system, modules are compressed like .ko.gz */ | ||
874 | if (is_supported_compression(dot + 1) && | ||
875 | is_kmodule_extension(dot - 2)) | ||
876 | dot -= 3; | ||
877 | |||
867 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | 878 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", |
868 | (int)(dot - dent->d_name), dent->d_name); | 879 | (int)(dot - dent->d_name), dent->d_name); |
869 | 880 | ||
@@ -1045,6 +1056,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
1045 | dot = strrchr(name, '.'); | 1056 | dot = strrchr(name, '.'); |
1046 | if (dot == NULL) | 1057 | if (dot == NULL) |
1047 | goto out_problem; | 1058 | goto out_problem; |
1059 | /* On some system, modules are compressed like .ko.gz */ | ||
1060 | if (is_supported_compression(dot + 1)) | ||
1061 | dot -= 3; | ||
1062 | if (!is_kmodule_extension(dot + 1)) | ||
1063 | goto out_problem; | ||
1048 | snprintf(short_module_name, sizeof(short_module_name), | 1064 | snprintf(short_module_name, sizeof(short_module_name), |
1049 | "[%.*s]", (int)(dot - name), name); | 1065 | "[%.*s]", (int)(dot - name), name); |
1050 | strxfrchar(short_module_name, '-', '_'); | 1066 | strxfrchar(short_module_name, '-', '_'); |
@@ -1069,8 +1085,20 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
1069 | * Should be there already, from the build-id table in | 1085 | * Should be there already, from the build-id table in |
1070 | * the header. | 1086 | * the header. |
1071 | */ | 1087 | */ |
1072 | struct dso *kernel = __dsos__findnew(&machine->kernel_dsos, | 1088 | struct dso *kernel = NULL; |
1073 | kmmap_prefix); | 1089 | struct dso *dso; |
1090 | |||
1091 | list_for_each_entry(dso, &machine->kernel_dsos.head, node) { | ||
1092 | if (is_kernel_module(dso->long_name, NULL)) | ||
1093 | continue; | ||
1094 | |||
1095 | kernel = dso; | ||
1096 | break; | ||
1097 | } | ||
1098 | |||
1099 | if (kernel == NULL) | ||
1100 | kernel = __dsos__findnew(&machine->kernel_dsos, | ||
1101 | kmmap_prefix); | ||
1074 | if (kernel == NULL) | 1102 | if (kernel == NULL) |
1075 | goto out_problem; | 1103 | goto out_problem; |
1076 | 1104 | ||
@@ -1078,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
1078 | if (__machine__create_kernel_maps(machine, kernel) < 0) | 1106 | if (__machine__create_kernel_maps(machine, kernel) < 0) |
1079 | goto out_problem; | 1107 | goto out_problem; |
1080 | 1108 | ||
1109 | if (strstr(dso->long_name, "vmlinux")) | ||
1110 | dso__set_short_name(dso, "[kernel.vmlinux]", false); | ||
1111 | |||
1081 | machine__set_kernel_mmap_len(machine, event); | 1112 | machine__set_kernel_mmap_len(machine, event); |
1082 | 1113 | ||
1083 | /* | 1114 | /* |
@@ -1290,7 +1321,7 @@ static bool symbol__match_regex(struct symbol *sym, regex_t *regex) | |||
1290 | return 0; | 1321 | return 0; |
1291 | } | 1322 | } |
1292 | 1323 | ||
1293 | static void ip__resolve_ams(struct machine *machine, struct thread *thread, | 1324 | static void ip__resolve_ams(struct thread *thread, |
1294 | struct addr_map_symbol *ams, | 1325 | struct addr_map_symbol *ams, |
1295 | u64 ip) | 1326 | u64 ip) |
1296 | { | 1327 | { |
@@ -1304,7 +1335,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, | |||
1304 | * Thus, we have to try consecutively until we find a match | 1335 | * Thus, we have to try consecutively until we find a match |
1305 | * or else, the symbol is unknown | 1336 | * or else, the symbol is unknown |
1306 | */ | 1337 | */ |
1307 | thread__find_cpumode_addr_location(thread, machine, MAP__FUNCTION, ip, &al); | 1338 | thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al); |
1308 | 1339 | ||
1309 | ams->addr = ip; | 1340 | ams->addr = ip; |
1310 | ams->al_addr = al.addr; | 1341 | ams->al_addr = al.addr; |
@@ -1312,23 +1343,21 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, | |||
1312 | ams->map = al.map; | 1343 | ams->map = al.map; |
1313 | } | 1344 | } |
1314 | 1345 | ||
1315 | static void ip__resolve_data(struct machine *machine, struct thread *thread, | 1346 | static void ip__resolve_data(struct thread *thread, |
1316 | u8 m, struct addr_map_symbol *ams, u64 addr) | 1347 | u8 m, struct addr_map_symbol *ams, u64 addr) |
1317 | { | 1348 | { |
1318 | struct addr_location al; | 1349 | struct addr_location al; |
1319 | 1350 | ||
1320 | memset(&al, 0, sizeof(al)); | 1351 | memset(&al, 0, sizeof(al)); |
1321 | 1352 | ||
1322 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, | 1353 | thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al); |
1323 | &al); | ||
1324 | if (al.map == NULL) { | 1354 | if (al.map == NULL) { |
1325 | /* | 1355 | /* |
1326 | * some shared data regions have execute bit set which puts | 1356 | * some shared data regions have execute bit set which puts |
1327 | * their mapping in the MAP__FUNCTION type array. | 1357 | * their mapping in the MAP__FUNCTION type array. |
1328 | * Check there as a fallback option before dropping the sample. | 1358 | * Check there as a fallback option before dropping the sample. |
1329 | */ | 1359 | */ |
1330 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr, | 1360 | thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al); |
1331 | &al); | ||
1332 | } | 1361 | } |
1333 | 1362 | ||
1334 | ams->addr = addr; | 1363 | ams->addr = addr; |
@@ -1345,14 +1374,41 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample, | |||
1345 | if (!mi) | 1374 | if (!mi) |
1346 | return NULL; | 1375 | return NULL; |
1347 | 1376 | ||
1348 | ip__resolve_ams(al->machine, al->thread, &mi->iaddr, sample->ip); | 1377 | ip__resolve_ams(al->thread, &mi->iaddr, sample->ip); |
1349 | ip__resolve_data(al->machine, al->thread, al->cpumode, | 1378 | ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr); |
1350 | &mi->daddr, sample->addr); | ||
1351 | mi->data_src.val = sample->data_src; | 1379 | mi->data_src.val = sample->data_src; |
1352 | 1380 | ||
1353 | return mi; | 1381 | return mi; |
1354 | } | 1382 | } |
1355 | 1383 | ||
1384 | static int add_callchain_ip(struct thread *thread, | ||
1385 | struct symbol **parent, | ||
1386 | struct addr_location *root_al, | ||
1387 | int cpumode, | ||
1388 | u64 ip) | ||
1389 | { | ||
1390 | struct addr_location al; | ||
1391 | |||
1392 | al.filtered = 0; | ||
1393 | al.sym = NULL; | ||
1394 | thread__find_addr_location(thread, cpumode, MAP__FUNCTION, | ||
1395 | ip, &al); | ||
1396 | if (al.sym != NULL) { | ||
1397 | if (sort__has_parent && !*parent && | ||
1398 | symbol__match_regex(al.sym, &parent_regex)) | ||
1399 | *parent = al.sym; | ||
1400 | else if (have_ignore_callees && root_al && | ||
1401 | symbol__match_regex(al.sym, &ignore_callees_regex)) { | ||
1402 | /* Treat this symbol as the root, | ||
1403 | forgetting its callees. */ | ||
1404 | *root_al = al; | ||
1405 | callchain_cursor_reset(&callchain_cursor); | ||
1406 | } | ||
1407 | } | ||
1408 | |||
1409 | return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); | ||
1410 | } | ||
1411 | |||
1356 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | 1412 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, |
1357 | struct addr_location *al) | 1413 | struct addr_location *al) |
1358 | { | 1414 | { |
@@ -1364,15 +1420,14 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | |||
1364 | return NULL; | 1420 | return NULL; |
1365 | 1421 | ||
1366 | for (i = 0; i < bs->nr; i++) { | 1422 | for (i = 0; i < bs->nr; i++) { |
1367 | ip__resolve_ams(al->machine, al->thread, &bi[i].to, bs->entries[i].to); | 1423 | ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to); |
1368 | ip__resolve_ams(al->machine, al->thread, &bi[i].from, bs->entries[i].from); | 1424 | ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from); |
1369 | bi[i].flags = bs->entries[i].flags; | 1425 | bi[i].flags = bs->entries[i].flags; |
1370 | } | 1426 | } |
1371 | return bi; | 1427 | return bi; |
1372 | } | 1428 | } |
1373 | 1429 | ||
1374 | static int machine__resolve_callchain_sample(struct machine *machine, | 1430 | static int thread__resolve_callchain_sample(struct thread *thread, |
1375 | struct thread *thread, | ||
1376 | struct ip_callchain *chain, | 1431 | struct ip_callchain *chain, |
1377 | struct symbol **parent, | 1432 | struct symbol **parent, |
1378 | struct addr_location *root_al, | 1433 | struct addr_location *root_al, |
@@ -1396,11 +1451,10 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1396 | * Based on DWARF debug information, some architectures skip | 1451 | * Based on DWARF debug information, some architectures skip |
1397 | * a callchain entry saved by the kernel. | 1452 | * a callchain entry saved by the kernel. |
1398 | */ | 1453 | */ |
1399 | skip_idx = arch_skip_callchain_idx(machine, thread, chain); | 1454 | skip_idx = arch_skip_callchain_idx(thread, chain); |
1400 | 1455 | ||
1401 | for (i = 0; i < chain_nr; i++) { | 1456 | for (i = 0; i < chain_nr; i++) { |
1402 | u64 ip; | 1457 | u64 ip; |
1403 | struct addr_location al; | ||
1404 | 1458 | ||
1405 | if (callchain_param.order == ORDER_CALLEE) | 1459 | if (callchain_param.order == ORDER_CALLEE) |
1406 | j = i; | 1460 | j = i; |
@@ -1437,24 +1491,10 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1437 | continue; | 1491 | continue; |
1438 | } | 1492 | } |
1439 | 1493 | ||
1440 | al.filtered = 0; | 1494 | err = add_callchain_ip(thread, parent, root_al, |
1441 | thread__find_addr_location(thread, machine, cpumode, | 1495 | cpumode, ip); |
1442 | MAP__FUNCTION, ip, &al); | 1496 | if (err == -EINVAL) |
1443 | if (al.sym != NULL) { | 1497 | break; |
1444 | if (sort__has_parent && !*parent && | ||
1445 | symbol__match_regex(al.sym, &parent_regex)) | ||
1446 | *parent = al.sym; | ||
1447 | else if (have_ignore_callees && root_al && | ||
1448 | symbol__match_regex(al.sym, &ignore_callees_regex)) { | ||
1449 | /* Treat this symbol as the root, | ||
1450 | forgetting its callees. */ | ||
1451 | *root_al = al; | ||
1452 | callchain_cursor_reset(&callchain_cursor); | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | err = callchain_cursor_append(&callchain_cursor, | ||
1457 | ip, al.map, al.sym); | ||
1458 | if (err) | 1498 | if (err) |
1459 | return err; | 1499 | return err; |
1460 | } | 1500 | } |
@@ -1469,19 +1509,15 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) | |||
1469 | entry->map, entry->sym); | 1509 | entry->map, entry->sym); |
1470 | } | 1510 | } |
1471 | 1511 | ||
1472 | int machine__resolve_callchain(struct machine *machine, | 1512 | int thread__resolve_callchain(struct thread *thread, |
1473 | struct perf_evsel *evsel, | 1513 | struct perf_evsel *evsel, |
1474 | struct thread *thread, | 1514 | struct perf_sample *sample, |
1475 | struct perf_sample *sample, | 1515 | struct symbol **parent, |
1476 | struct symbol **parent, | 1516 | struct addr_location *root_al, |
1477 | struct addr_location *root_al, | 1517 | int max_stack) |
1478 | int max_stack) | ||
1479 | { | 1518 | { |
1480 | int ret; | 1519 | int ret = thread__resolve_callchain_sample(thread, sample->callchain, |
1481 | 1520 | parent, root_al, max_stack); | |
1482 | ret = machine__resolve_callchain_sample(machine, thread, | ||
1483 | sample->callchain, parent, | ||
1484 | root_al, max_stack); | ||
1485 | if (ret) | 1521 | if (ret) |
1486 | return ret; | 1522 | return ret; |
1487 | 1523 | ||
@@ -1495,7 +1531,7 @@ int machine__resolve_callchain(struct machine *machine, | |||
1495 | (!sample->user_stack.size)) | 1531 | (!sample->user_stack.size)) |
1496 | return 0; | 1532 | return 0; |
1497 | 1533 | ||
1498 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | 1534 | return unwind__get_entries(unwind_entry, &callchain_cursor, |
1499 | thread, sample, max_stack); | 1535 | thread, sample, max_stack); |
1500 | 1536 | ||
1501 | } | 1537 | } |