Skip to content

Commit 7035102

Browse files
captain5050namhyung
authored andcommitted
perf thread: Add support for reading the e_machine type for a thread
First try to read the e_machine from the dsos associated with the thread's maps. If live use the executable from /proc/pid/exe and read the e_machine from the ELF header. On failure use EM_HOST. Change builtin-trace syscall functions to pass e_machine from the thread rather than EM_HOST, so that in later patches when syscalltbl can use the e_machine the system calls are specific to the architecture. Signed-off-by: Ian Rogers <irogers@google.com> Reviewed-by: Namhyung Kim <namhyung@kernel.org> Acked-by: Arnaldo Carvalho de Melo <acme@kernel.org> Link: https://lore.kernel.org/r/20250319050741.269828-8-irogers@google.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
1 parent afffec6 commit 7035102

3 files changed

Lines changed: 115 additions & 22 deletions

File tree

tools/perf/builtin-trace.c

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2731,16 +2731,16 @@ static int trace__sys_enter(struct trace *trace, struct evsel *evsel,
27312731
int printed = 0;
27322732
struct thread *thread;
27332733
int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
2734-
int augmented_args_size = 0;
2734+
int augmented_args_size = 0, e_machine;
27352735
void *augmented_args = NULL;
2736-
/* TODO: get e_machine from thread. */
2737-
struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id);
2736+
struct syscall *sc;
27382737
struct thread_trace *ttrace;
27392738

2740-
if (sc == NULL)
2741-
return -1;
2742-
27432739
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2740+
e_machine = thread__e_machine(thread, trace->host);
2741+
sc = trace__syscall_info(trace, evsel, e_machine, id);
2742+
if (sc == NULL)
2743+
goto out_put;
27442744
ttrace = thread__trace(thread, trace);
27452745
if (ttrace == NULL)
27462746
goto out_put;
@@ -2808,17 +2808,18 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel,
28082808
struct thread_trace *ttrace;
28092809
struct thread *thread;
28102810
int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
2811-
/* TODO: get e_machine from thread. */
2812-
struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id);
2811+
struct syscall *sc;
28132812
char msg[1024];
28142813
void *args, *augmented_args = NULL;
2815-
int augmented_args_size;
2814+
int augmented_args_size, e_machine;
28162815
size_t printed = 0;
28172816

2818-
if (sc == NULL)
2819-
return -1;
28202817

28212818
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2819+
e_machine = thread__e_machine(thread, trace->host);
2820+
sc = trace__syscall_info(trace, evsel, e_machine, id);
2821+
if (sc == NULL)
2822+
return -1;
28222823
ttrace = thread__trace(thread, trace);
28232824
/*
28242825
* We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
@@ -2883,15 +2884,15 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
28832884
bool duration_calculated = false;
28842885
struct thread *thread;
28852886
int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0, printed = 0;
2886-
int alignment = trace->args_alignment;
2887-
/* TODO: get e_machine from thread. */
2888-
struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id);
2887+
int alignment = trace->args_alignment, e_machine;
2888+
struct syscall *sc;
28892889
struct thread_trace *ttrace;
28902890

2891-
if (sc == NULL)
2892-
return -1;
2893-
28942891
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2892+
e_machine = thread__e_machine(thread, trace->host);
2893+
sc = trace__syscall_info(trace, evsel, e_machine, id);
2894+
if (sc == NULL)
2895+
goto out_put;
28952896
ttrace = thread__trace(thread, trace);
28962897
if (ttrace == NULL)
28972898
goto out_put;
@@ -3238,8 +3239,8 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel,
32383239

32393240
if (evsel == trace->syscalls.events.bpf_output) {
32403241
int id = perf_evsel__sc_tp_uint(evsel, id, sample);
3241-
/* TODO: get e_machine from thread. */
3242-
struct syscall *sc = trace__syscall_info(trace, evsel, EM_HOST, id);
3242+
int e_machine = thread ? thread__e_machine(thread, trace->host) : EM_HOST;
3243+
struct syscall *sc = trace__syscall_info(trace, evsel, e_machine, id);
32433244

32443245
if (sc) {
32453246
fprintf(trace->output, "%s(", sc->name);
@@ -4889,6 +4890,7 @@ static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trac
48894890
{
48904891
size_t printed = 0;
48914892
struct thread_trace *ttrace = thread__priv(thread);
4893+
int e_machine = thread__e_machine(thread, trace->host);
48924894
double ratio;
48934895

48944896
if (ttrace == NULL)
@@ -4908,8 +4910,7 @@ static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trac
49084910
else if (fputc('\n', fp) != EOF)
49094911
++printed;
49104912

4911-
/* TODO: get e_machine from thread. */
4912-
printed += thread__dump_stats(ttrace, trace, EM_HOST, fp);
4913+
printed += thread__dump_stats(ttrace, trace, e_machine, fp);
49134914

49144915
return printed;
49154916
}

tools/perf/util/thread.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0
2+
#include <elf.h>
23
#include <errno.h>
4+
#include <fcntl.h>
35
#include <stdlib.h>
46
#include <stdio.h>
57
#include <string.h>
@@ -16,6 +18,7 @@
1618
#include "symbol.h"
1719
#include "unwind.h"
1820
#include "callchain.h"
21+
#include "dwarf-regs.h"
1922

2023
#include <api/fs/fs.h>
2124

@@ -51,6 +54,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
5154
thread__set_ppid(thread, -1);
5255
thread__set_cpu(thread, -1);
5356
thread__set_guest_cpu(thread, -1);
57+
thread__set_e_machine(thread, EM_NONE);
5458
thread__set_lbr_stitch_enable(thread, false);
5559
INIT_LIST_HEAD(thread__namespaces_list(thread));
5660
INIT_LIST_HEAD(thread__comm_list(thread));
@@ -423,6 +427,82 @@ void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
423427
}
424428
}
425429

430+
static uint16_t read_proc_e_machine_for_pid(pid_t pid)
431+
{
432+
char path[6 /* "/proc/" */ + 11 /* max length of pid */ + 5 /* "/exe\0" */];
433+
int fd;
434+
uint16_t e_machine = EM_NONE;
435+
436+
snprintf(path, sizeof(path), "/proc/%d/exe", pid);
437+
fd = open(path, O_RDONLY);
438+
if (fd >= 0) {
439+
_Static_assert(offsetof(Elf32_Ehdr, e_machine) == 18, "Unexpected offset");
440+
_Static_assert(offsetof(Elf64_Ehdr, e_machine) == 18, "Unexpected offset");
441+
if (pread(fd, &e_machine, sizeof(e_machine), 18) != sizeof(e_machine))
442+
e_machine = EM_NONE;
443+
close(fd);
444+
}
445+
return e_machine;
446+
}
447+
448+
static int thread__e_machine_callback(struct map *map, void *machine)
449+
{
450+
struct dso *dso = map__dso(map);
451+
452+
_Static_assert(0 == EM_NONE, "Unexpected EM_NONE");
453+
if (!dso)
454+
return EM_NONE;
455+
456+
return dso__e_machine(dso, machine);
457+
}
458+
459+
uint16_t thread__e_machine(struct thread *thread, struct machine *machine)
460+
{
461+
pid_t tid, pid;
462+
uint16_t e_machine = RC_CHK_ACCESS(thread)->e_machine;
463+
464+
if (e_machine != EM_NONE)
465+
return e_machine;
466+
467+
tid = thread__tid(thread);
468+
pid = thread__pid(thread);
469+
if (pid != tid) {
470+
struct thread *parent = machine__findnew_thread(machine, pid, pid);
471+
472+
if (parent) {
473+
e_machine = thread__e_machine(parent, machine);
474+
thread__set_e_machine(thread, e_machine);
475+
return e_machine;
476+
}
477+
/* Something went wrong, fallback. */
478+
}
479+
/* Reading on the PID thread. First try to find from the maps. */
480+
e_machine = maps__for_each_map(thread__maps(thread),
481+
thread__e_machine_callback,
482+
machine);
483+
if (e_machine == EM_NONE) {
484+
/* Maps failed, perhaps we're live with map events disabled. */
485+
bool is_live = machine->machines == NULL;
486+
487+
if (!is_live) {
488+
/* Check if the session has a data file. */
489+
struct perf_session *session = container_of(machine->machines,
490+
struct perf_session,
491+
machines);
492+
493+
is_live = !!session->data;
494+
}
495+
/* Read from /proc/pid/exe if live. */
496+
if (is_live)
497+
e_machine = read_proc_e_machine_for_pid(pid);
498+
}
499+
if (e_machine != EM_NONE)
500+
thread__set_e_machine(thread, e_machine);
501+
else
502+
e_machine = EM_HOST;
503+
return e_machine;
504+
}
505+
426506
struct thread *thread__main_thread(struct machine *machine, struct thread *thread)
427507
{
428508
if (thread__pid(thread) == thread__tid(thread))

tools/perf/util/thread.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ DECLARE_RC_STRUCT(thread) {
6060
struct srccode_state srccode_state;
6161
bool filter;
6262
int filter_entry_depth;
63-
63+
/**
64+
* @e_machine: The ELF EM_* associated with the thread. EM_NONE if not
65+
* computed.
66+
*/
67+
uint16_t e_machine;
6468
/* LBR call stack stitch */
6569
bool lbr_stitch_enable;
6670
struct lbr_stitch *lbr_stitch;
@@ -302,6 +306,14 @@ static inline void thread__set_filter_entry_depth(struct thread *thread, int dep
302306
RC_CHK_ACCESS(thread)->filter_entry_depth = depth;
303307
}
304308

309+
uint16_t thread__e_machine(struct thread *thread, struct machine *machine);
310+
311+
static inline void thread__set_e_machine(struct thread *thread, uint16_t e_machine)
312+
{
313+
RC_CHK_ACCESS(thread)->e_machine = e_machine;
314+
}
315+
316+
305317
static inline bool thread__lbr_stitch_enable(const struct thread *thread)
306318
{
307319
return RC_CHK_ACCESS(thread)->lbr_stitch_enable;

0 commit comments

Comments
 (0)