From nobody Sat Nov 15 09:50:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1753126571; cv=none; d=zohomail.com; s=zohoarc; b=keK1d0sKbqQdDa9p46Vc9c7GuU/968J1Gi25PTf4AkXnPbP8I490nnNHg8ZI2NckjxMSOpKOe3LydDiSh6t0M3EYTrry8bzjNJ42Aqj2qELXl9KiABZ9aUO7REJg+rSOTQXyjCUUqGopqNagPcP/EWhwlsQsfCPdontPhJsPbvk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1753126571; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=MJ3zRUCxuMWrTsnxPjA3KHqLGZLQ+I0mJ1zvOgqpgdo=; b=hv39+EXyqzKN0Ar1UFXxm0rfyHhy8NY702Pb9R96YGZrwBl6xMLC6X4Fm4Wmv5xNKwFx6l0TFQDH8BdzVgL1XYgZC1OUcHVmdtYAPcY/c/wwIkA0/610LDtS9rswdIjQEERSsNGsutX64lEzg7aQ4AXKmb3kh01rj3cffcMnku8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17531265714410.15691834566416674; Mon, 21 Jul 2025 12:36:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1udwIY-0004BV-50; Mon, 21 Jul 2025 15:35:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1udwGq-0002b2-2F for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:33:59 -0400 Received: from mail-pl1-x62e.google.com ([2607:f8b0:4864:20::62e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1udwGn-0003U8-19 for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:33:55 -0400 Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-2349f096605so54682105ad.3 for ; Mon, 21 Jul 2025 12:33:52 -0700 (PDT) Received: from pc.. ([38.41.223.211]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-23e3b5e4750sm62238685ad.6.2025.07.21.12.33.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jul 2025 12:33:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753126432; x=1753731232; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=MJ3zRUCxuMWrTsnxPjA3KHqLGZLQ+I0mJ1zvOgqpgdo=; b=ffPRfDbNH2OBAX/RyAPZSrMf7G/kcK9TR0X2Lhadd8gn9v62EWfpU+bnJcXhro0EqN rz/j4xli5vf0eQEIW305x0O+GTvQFoOaAk+In9HcWPCaP1dHAIy8DsjN1bZsDt0JBJg+ o6M+70ljsIj6VKKqI6zDTGe5oHpOcqbX/ypaR+k/a1LDMpciXqDRStZ/kk83TOCPXwO9 SZ5DHumbVHr3VXkOgMOkY2NR7PGALFDh+lzTAjhN72YEbu+eyLbeIK2rng/tLIky/yA+ k/oJJsxZWRXbXG2G4/ZTdobaTXcfY+ZSYm1HiFXS98PSI3gVPCgCgH9EsUiu/9jcaIKx NW7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753126432; x=1753731232; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MJ3zRUCxuMWrTsnxPjA3KHqLGZLQ+I0mJ1zvOgqpgdo=; b=ck+wU+T2zR9/2/RGzCkAy3me8QUvc92Ss4hIaE+DAPknkdJZQ07Sj/J2I9/+ZgFyU8 qHNVXgjG+B98sBKH7rUdu1y8p0R/IWaAz13un51QQnYt+QSzUB5IVS86zx3kn3vMDTDE xD1fwS1InHDjAeiyMdYaf64ajM9BVPEQqvmll+yf6PUgVlUQFbtv8AISZizbbbmAY/PR bGM+hrCeYPJaB/kAzMCxM20sWD9smWGRPC2bJECZEefqxQkCHFtqzK2bG8oV52nzYwRg aeZopJVrZDzXdHtPxwD1g3wK+2LF4EAfl25I6mKafjchTCW6rpqAMv9x4Anka1yFb3RW T0PA== X-Gm-Message-State: AOJu0YxWxUpW7PW+jWzuy2q2/SccM/vPZa90m0gFHLeyLBloaz3mrjuk 6MqnspXLm8BawrVx0zKrLrrDQToQX9rpQeZ31Ram1P+aAmFjoaIzmBpXYJXgGulZ9uR1z3Gusx8 3uen4 X-Gm-Gg: ASbGncsNzpr5VgzL6Dlme7IGDON5+HsDRwz78rdsXjGKvUiK0+ZHKtzLyxWib8G9+4n /ySNuD+HSItsWx9GAI0LJ6sYrJuD7uEYoagNO4vG87llm8c1rrk95BwtXHCL9OFu8FosDoaka4d e++Pyi73he17DXGBvYxTrim/NcxbMX1/NQJBKnpKEVYhmFzhic92VQWEotYz0lWTrmBGhrnJXmv O+eezR952sFp3Kx3/HZYeqspn8Vhzgx9r7rI/CWI/n0JqTbEMa2U2VNday6KwG4ZNEgM+/3nGjm goXp5OCa7d5YXo1/tf1LvLctld/s3zRib3RBJKqEci55SWWIPDxzuZnne7loMxaVrSrjgb0A8zG N029Ai+iIpIgvH859D8EghA== X-Google-Smtp-Source: AGHT+IFEKFNEDJL4YM+qtOx3kKTmnyLRXNT6ansTY8KvMpMMWB9eDBjyiKsE2Enj8MgQMk7lgQ+h8g== X-Received: by 2002:a17:903:41d1:b0:235:f078:4746 with SMTP id d9443c01a7336-23e25764c89mr279570215ad.42.1753126431587; Mon, 21 Jul 2025 12:33:51 -0700 (PDT) From: Pierrick Bouvier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Peter Maydell , Gustavo Romero , Manos Pitsidianakis , Pierrick Bouvier , Alexandre Iooss , rowan Hart , Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Mahmoud Mandour Subject: [PATCH v2 1/6] contrib/plugins/uftrace: new uftrace plugin Date: Mon, 21 Jul 2025 12:33:35 -0700 Message-ID: <20250721193340.1059019-2-pierrick.bouvier@linaro.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> References: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62e; envelope-from=pierrick.bouvier@linaro.org; helo=mail-pl1-x62e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1753126572468116600 Content-Type: text/plain; charset="utf-8" This plugin generates a binary trace compatible with: https://github.com/namhyung/uftrace It tracks frame pointer during execution, detecting function calls/returns and works in system and user mode. It's implemented for aarch64 only (adding other architecture should be trivial, especially x86_64 that share the same stack layout). Signed-off-by: Pierrick Bouvier --- contrib/plugins/uftrace.c | 629 ++++++++++++++++++++++++++++++++++++ contrib/plugins/meson.build | 3 +- 2 files changed, 631 insertions(+), 1 deletion(-) create mode 100644 contrib/plugins/uftrace.c diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c new file mode 100644 index 00000000000..d55eb32c5e8 --- /dev/null +++ b/contrib/plugins/uftrace.c @@ -0,0 +1,629 @@ +/* + * Copyright (C) 2025, Pierrick Bouvier + * + * Generates a trace compatible with uftrace (similar to uftrace record). + * https://github.com/namhyung/uftrace + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include +#include +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version =3D QEMU_PLUGIN_VERSION; + +typedef struct { + GArray *s; +} callstack; + +typedef struct { + uint64_t pc; + uint64_t frame_pointer; +} callstack_entry; + +typedef struct { + GArray *t; + GString *path; + GString *name; + uint32_t id; +} trace; + +typedef struct Cpu Cpu; + +typedef struct { + void (*init)(Cpu *cpu); + void (*end)(Cpu *cpu); + uint64_t (*get_frame_pointer)(Cpu *cpu); + bool (*does_insn_modify_frame_pointer)(const char *disas); +} CpuOps; + +typedef struct Cpu { + uint64_t insn_count; + trace *trace; + callstack *cs; + GArray *callstacks; /* callstack *callstacks[] */ + GArray *traces; /* trace *traces [] */ + GByteArray *buf; + CpuOps ops; + void *arch; +} Cpu; + +typedef struct { + struct qemu_plugin_register *reg_fp; +} Aarch64Cpu; + +typedef struct { + uint64_t timestamp; + uint64_t data; +} uftrace_entry; + +enum uftrace_record_type { + UFTRACE_ENTRY, + UFTRACE_EXIT, + UFTRACE_LOST, + UFTRACE_EVENT +}; + +static struct qemu_plugin_scoreboard *score; +static CpuOps arch_ops; + +static void uftrace_write_map(bool system_emulation) +{ + const char *path =3D "./uftrace.data/sid-0.map"; + + if (system_emulation && access(path, F_OK) =3D=3D 0) { + /* do not erase existing map in system emulation, as a custom one = might + * already have been generated by uftrace_symbols.py */ + return; + } + + FILE *sid_map =3D fopen(path, "w"); + g_assert(sid_map); + + if (system_emulation) { + fprintf(sid_map, + "# map stack on highest address possible, to prevent uftra= ce\n" + "# from considering any kernel address\n"); + fprintf(sid_map, + "ffffffffffff-ffffffffffff rw-p 00000000 00:00 0 [stack]\n"); + } else { + /* in user mode, copy /proc/self/maps instead */ + FILE *self_map =3D fopen("/proc/self/maps", "r"); + g_assert(self_map); + for (;;) { + int c =3D fgetc(self_map); + if (c =3D=3D EOF) { + break; + } + fputc(c, sid_map); + } + fclose(self_map); + } + fclose(sid_map); +} + +static void uftrace_write_task(const GArray *traces) +{ + FILE *task =3D fopen("./uftrace.data/task.txt", "w"); + g_assert(task); + for (int i =3D 0; i < traces->len; ++i) { + trace *t =3D g_array_index(traces, trace*, i); + fprintf(task, "SESS timestamp=3D0.0 pid=3D%"PRIu32" sid=3D0 exenam= e=3D\"%s\"\n", + t->id, t->name->str); + fprintf(task, "TASK timestamp=3D0.0 tid=3D%"PRIu32" pid=3D%"PRIu32= "\n", + t->id, t->id); + } + fclose(task); +} + +static void uftrace_write_info(const GArray *traces) +{ + g_autoptr(GString) taskinfo_tids =3D g_string_new("taskinfo:tids=3D"); + for (int i =3D 0; i < traces->len; ++i) { + trace *t =3D g_array_index(traces, trace*, i); + const char *delim =3D i > 0 ? "," : ""; + g_string_append_printf(taskinfo_tids, "%s%"PRIu32, delim, t->id); + } + + g_autoptr(GString) taskinfo_nr_tid =3D g_string_new("taskinfo:nr_tid= =3D"); + g_string_append_printf(taskinfo_nr_tid, "%d", traces->len); + + FILE *info =3D fopen("./uftrace.data/info", "w"); + g_assert(info); + /* + * $ uftrace dump --debug + * uftrace file header: magic =3D 4674726163652100 + * uftrace file header: version =3D 4 + * uftrace file header: header size =3D 40 + * uftrace file header: endian =3D 1 (little) + * ftrace file header: class =3D 2 (64 bit) + * uftrace file header: features =3D 0x1263 (PLTHOOK | ... + * uftrace file header: info =3D 0x7bff (EXE_NAME | ... + * <0000000000000000>: 46 74 72 61 63 65 21 00 04 00 00 00 28 00 01 = 02 + * <0000000000000010>: 63 12 00 00 00 00 00 00 ff 7b 00 00 00 00 00 = 00 + * <0000000000000020>: 00 04 00 00 00 00 00 00 + */ + const uint8_t header[] =3D {0x46, 0x74, 0x72, 0x61, 0x63, 0x65, 0x21, = 0x00, + 0x04, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x= 02, + 0x63, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, + 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00}; + fwrite(header, sizeof(header), 1, info); + const char *info_data[] =3D { + "exename:from_qemu", + "build_id:0123456789abcdef0123456789abcdef01234567", + "exit_status:0", + "cmdline:uftrace record qemu", + "cpuinfo:lines=3D2", + "cpuinfo:nr_cpus=3D1 / 1 (online/possible)", + "cpuinfo:desc=3DIntel 8086", + "meminfo:1.0 / 1.0 GB (free / total)", + "osinfo:lines=3D3", + "osinfo:kernel=3DLinux 6.12.33", + "osinfo:hostname=3Dpc", + "osinfo:distro=3D\"Debian GNU/Linux 13 (trixie)\"", + "taskinfo:lines=3D2", + taskinfo_nr_tid->str, + taskinfo_tids->str, + "usageinfo:lines=3D6", + "usageinfo:systime=3D0.000000", + "usageinfo:usrtime=3D0.000000", + "usageinfo:ctxsw=3D0 / 0 (voluntary / involuntary)", + "usageinfo:maxrss=3D8016", + "usageinfo:pagefault=3D0 / 0 (major / minor)", + "usageinfo:iops=3D0 / 0 (read / write)", + "loadinfo:0.0 / 0.0 / 0.0", + "record_date:Mon Jan 1 00:00:00 2025", + "elapsed_time:1000000000000.0 sec", + "pattern_type:regex", + "uftrace_version:v0.17 ( x86_64 dwarf python3 luajit tui perf sche= d dynamic kernel )", + "utc_offset:1751552954", + 0}; + const char **info_data_it =3D info_data; + while (*(info_data_it)) { + fprintf(info, "%s\n", *info_data_it); + ++info_data_it; + } + fclose(info); +} + +static callstack *callstack_new(void) +{ + callstack *cs =3D g_malloc0(sizeof(callstack)); + cs->s =3D g_array_new(false, false, sizeof(callstack_entry)); + return cs; +} + +static void callstack_free(callstack *cs) +{ + g_array_free(cs->s, true); + cs->s =3D NULL; + g_free(cs); +} + +static size_t callstack_depth(const callstack *cs) +{ + return cs->s->len; +} + +static size_t callstack_empty(const callstack *cs) +{ + return callstack_depth(cs) =3D=3D 0; +} + +static void callstack_clear(callstack *cs) +{ + g_array_set_size(cs->s, 0); +} + +static const callstack_entry *callstack_at(const callstack *cs, size_t dep= th) +{ + g_assert(depth > 0); + g_assert(depth <=3D callstack_depth(cs)); + return &g_array_index(cs->s, callstack_entry, depth - 1); +} + +static callstack_entry callstack_top(const callstack *cs) +{ + if (callstack_depth(cs) >=3D 1) { + return *callstack_at(cs, callstack_depth(cs)); + } + return (callstack_entry){}; +} + +static callstack_entry callstack_caller(const callstack *cs) +{ + if (callstack_depth(cs) >=3D 2) { + return *callstack_at(cs, callstack_depth(cs) - 1); + } + return (callstack_entry){}; +} + +static void callstack_push(callstack *cs, callstack_entry e) +{ + g_array_append_val(cs->s, e); +} + +static callstack_entry callstack_pop(callstack *cs) +{ + g_assert(!callstack_empty(cs)); + callstack_entry e =3D callstack_top(cs); + g_array_set_size(cs->s, callstack_depth(cs) - 1); + return e; +} + +static trace *trace_new(uint32_t id, GString *name) +{ + trace *t =3D g_malloc0(sizeof(trace)); + t->t =3D g_array_new(false, false, sizeof(uftrace_entry)); + t->path =3D g_string_new(NULL); + g_string_append_printf(t->path, "./uftrace.data/%"PRIu32".dat", id); + t->name =3D g_string_new(name->str); + t->id =3D id; + return t; +} + +static void trace_free(trace *t) +{ + g_assert(t->t->len =3D=3D 0); + g_array_free(t->t, true); + t->t =3D NULL; + g_string_free(t->path, true); + t->path =3D NULL; + g_string_free(t->name, true); + t->name =3D NULL; + g_free(t); +} + +static void trace_flush(trace *t, bool append) +{ + int create_dir =3D g_mkdir_with_parents("./uftrace.data", + S_IRWXU | S_IRWXG | S_IRWXO); + g_assert(create_dir =3D=3D 0); + FILE *dat =3D fopen(t->path->str, append ? "a" : "w"); + g_assert(dat); + GArray *data =3D t->t; + if (data->len) { + fwrite(data->data, data->len, sizeof(uftrace_entry), dat); + } + fclose(dat); + g_array_set_size(data, 0); +} + +static void trace_add_entry(trace *t, uint64_t timestamp, uint64_t pc, + size_t depth, enum uftrace_record_type type) +{ + /* libmcount/record.c:record_event */ + const uint64_t record_magic =3D 0x5; + uint64_t data =3D type | record_magic << 3; + data +=3D depth << 6; + data +=3D pc << 16; + uftrace_entry e =3D {.timestamp =3D timestamp, .data =3D data}; + g_array_append_val(t->t, e); + if (t->t->len * sizeof(uftrace_entry) > 32 * 1024 * 1024) { + /* flush every 32 MB */ + trace_flush(t, true); + } +} + +static void trace_enter_function(trace *t, uint64_t timestamp, + uint64_t pc, size_t depth) +{ + trace_add_entry(t, timestamp, pc, depth, UFTRACE_ENTRY); +} + +static void trace_exit_function(trace *t, uint64_t timestamp, + uint64_t pc, size_t depth) +{ + trace_add_entry(t, timestamp, pc, depth, UFTRACE_EXIT); +} + +static void trace_enter_stack(trace *t, callstack *cs, uint64_t timestamp) +{ + for (size_t depth =3D 1; depth <=3D callstack_depth(cs); ++depth) { + trace_enter_function(t, timestamp, callstack_at(cs, depth)->pc, de= pth); + } +} + +static void trace_exit_stack(trace *t, callstack *cs, uint64_t timestamp) +{ + for (size_t depth =3D callstack_depth(cs); depth > 0; --depth) { + trace_exit_function(t, timestamp, callstack_at(cs, depth)->pc, dep= th); + } +} + +static uint64_t cpu_read_register64(Cpu *cpu, struct qemu_plugin_register = *reg) +{ + GByteArray *buf =3D cpu->buf; + g_byte_array_set_size(buf, 0); + size_t sz =3D qemu_plugin_read_register(reg, buf); + g_assert(sz =3D=3D 8); + g_assert(buf->len =3D=3D 8); + return *((uint64_t *) buf->data); +} + +static uint64_t cpu_read_memory64(Cpu *cpu, uint64_t addr) +{ + g_assert(addr); + GByteArray *buf =3D cpu->buf; + g_byte_array_set_size(buf, 0); + bool read =3D qemu_plugin_read_memory_vaddr(addr, buf, 8); + if (!read) { + return 0; + } + g_assert(buf->len =3D=3D 8); + return *((uint64_t *) buf->data); +} + +static void cpu_unwind_stack(Cpu *cpu, uint64_t frame_pointer, uint64_t pc) +{ + g_assert(callstack_empty(cpu->cs)); + + #define UNWIND_STACK_MAX_DEPTH 1024 + callstack_entry unwind[UNWIND_STACK_MAX_DEPTH]; + size_t depth =3D 0; + do { + /* check we don't have an infinite stack */ + for (size_t i =3D 0; i < depth; ++i) { + if (frame_pointer =3D=3D unwind[i].frame_pointer) { + break; + } + } + callstack_entry e =3D {.frame_pointer =3D frame_pointer, .pc =3D p= c}; + unwind[depth] =3D e; + depth++; + if (frame_pointer) { + frame_pointer =3D cpu_read_memory64(cpu, frame_pointer); + } + pc =3D cpu_read_memory64(cpu, frame_pointer + 8); /* read previous= lr */ + } while (frame_pointer && pc && depth < UNWIND_STACK_MAX_DEPTH); + #undef UNWIND_STACK_MAX_DEPTH + + /* push it from bottom to top */ + while (depth) { + callstack_push(cpu->cs, unwind[depth - 1]); + --depth; + } +} + +static uint64_t cpu_get_timestamp(const Cpu *cpu) +{ + return cpu->insn_count; +} + +static uint64_t aarch64_get_frame_pointer(Cpu *cpu_) +{ + Aarch64Cpu *cpu =3D cpu_->arch; + return cpu_read_register64(cpu_, cpu->reg_fp); +} + +static void aarch64_init(Cpu *cpu_) +{ + Aarch64Cpu *cpu =3D g_malloc0(sizeof(Aarch64Cpu)); + cpu_->arch =3D cpu; + g_autoptr(GArray) regs =3D qemu_plugin_get_registers(); + for (int i =3D 0; i < regs->len; ++i) { + qemu_plugin_reg_descriptor *reg; + reg =3D &g_array_index(regs, qemu_plugin_reg_descriptor, i); + if (!strcmp(reg->name, "x29")) { + cpu->reg_fp =3D reg->handle; + } + } + if (!cpu->reg_fp) { + fprintf(stderr, "uftrace plugin: frame pointer register (x29) is n= ot " + "available. Please use an AArch64 cpu (or -cpu max= ).\n"); + g_abort(); + } +} + +static void aarch64_end(Cpu *cpu) +{ + g_free(cpu->arch); +} + +static bool aarch64_does_insn_modify_frame_pointer(const char *disas) +{ + /* + * Check if current instruction concerns fp register "x29". + * We add a prefix space to make sure we don't match addresses dump + * in disassembly. + */ + return strstr(disas, " x29"); +} + +static CpuOps aarch64_ops =3D { + .init =3D aarch64_init, + .end =3D aarch64_end, + .get_frame_pointer =3D aarch64_get_frame_pointer, + .does_insn_modify_frame_pointer =3D aarch64_does_insn_modify_frame_poi= nter, +}; + +static void track_callstack(unsigned int cpu_index, void *udata) +{ + uint64_t pc =3D (uintptr_t) udata; + Cpu *cpu =3D qemu_plugin_scoreboard_find(score, cpu_index); + uint64_t timestamp =3D cpu_get_timestamp(cpu); + callstack *cs =3D cpu->cs; + trace *t =3D cpu->trace; + + uint64_t fp =3D cpu->ops.get_frame_pointer(cpu); + if (!fp && callstack_empty(cs)) { + /* + * We simply push current pc. Note that we won't detect symbol cha= nge as + * long as a proper call does not happen. + */ + callstack_push(cs, (callstack_entry){.frame_pointer =3D fp, + .pc =3D pc}); + trace_enter_function(t, timestamp, pc, callstack_depth(cs)); + return; + } + + callstack_entry top =3D callstack_top(cs); + if (fp =3D=3D top.frame_pointer) { + /* same function */ + return; + } + + callstack_entry caller =3D callstack_caller(cs); + if (fp =3D=3D caller.frame_pointer) { + /* return */ + callstack_entry e =3D callstack_pop(cs); + trace_exit_function(t, timestamp, e.pc, callstack_depth(cs)); + return; + } + + uint64_t caller_fp =3D fp ? cpu_read_memory64(cpu, fp) : 0; + if (caller_fp =3D=3D top.frame_pointer) { + /* call */ + callstack_push(cs, (callstack_entry){.frame_pointer =3D fp, + .pc =3D pc}); + trace_enter_function(t, timestamp, pc, callstack_depth(cs)); + return; + } + + /* discontinuity, exit current stack and unwind new one */ + trace_exit_stack(t, cs, timestamp); + callstack_clear(cs); + + cpu_unwind_stack(cpu, fp, pc); + trace_enter_stack(t, cs, timestamp); +} + +static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) +{ + size_t n_insns =3D qemu_plugin_tb_n_insns(tb); + + qemu_plugin_u64 insn_count =3D qemu_plugin_scoreboard_u64_in_struct( + score, Cpu, insn_count); + + /* + * We instrument all instructions following one that might have updated + * the frame pointer. We always instrument first instruction in block,= as + * last executed instruction, in previous tb, may have modified it. + */ + bool instrument_insn =3D true; + for (int i =3D 0; i < n_insns; i++) { + struct qemu_plugin_insn *insn =3D qemu_plugin_tb_get_insn(tb, i); + qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu( + insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1); + + if (instrument_insn) { + uintptr_t pc =3D qemu_plugin_insn_vaddr(insn); + qemu_plugin_register_vcpu_insn_exec_cb(insn, track_callstack, + QEMU_PLUGIN_CB_R_REGS, + (void *) pc); + instrument_insn =3D false; + } + + char *disas =3D qemu_plugin_insn_disas(insn); + if (arch_ops.does_insn_modify_frame_pointer(disas)) { + instrument_insn =3D true; + } + } +} + +static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index) +{ + Cpu *cpu =3D qemu_plugin_scoreboard_find(score, vcpu_index); + cpu->ops =3D arch_ops; + + cpu->ops.init(cpu); + cpu->buf =3D g_byte_array_new(); + cpu->callstacks =3D g_array_new(0, 0, sizeof(callstack *)); + cpu->traces =3D g_array_new(0, 0, sizeof(trace *)); + + g_assert(vcpu_index < 1000); + uint32_t trace_id =3D 1000 * 1000 + vcpu_index * 1000; + + g_autoptr(GString) trace_name =3D g_string_new(NULL); + g_string_append_printf(trace_name, "cpu%u", vcpu_index); + trace *t =3D trace_new(trace_id, trace_name); + g_array_append_val(cpu->traces, t); + callstack *cs =3D callstack_new(); + g_array_append_val(cpu->callstacks, cs); + /* create/truncate trace file */ + trace_flush(t, false); + + cpu->cs =3D cs; + cpu->trace =3D t; +} + +static void vcpu_end(unsigned int vcpu_index) +{ + Cpu *cpu =3D qemu_plugin_scoreboard_find(score, vcpu_index); + g_byte_array_free(cpu->buf, true); + + for (size_t i =3D 0; i < cpu->traces->len; ++i) { + trace *t =3D g_array_index(cpu->traces, trace*, i); + trace_free(t); + } + + for (size_t i =3D 0; i < cpu->callstacks->len; ++i) { + callstack *cs =3D g_array_index(cpu->callstacks, callstack*, i); + callstack_free(cs); + } + + g_array_free(cpu->traces, true); + g_array_free(cpu->callstacks, true); + memset(cpu, 0, sizeof(Cpu)); +} + +static void at_exit(qemu_plugin_id_t id, void *data) +{ + bool system_emulation =3D (bool) data; + g_autoptr(GArray) traces =3D g_array_new(0, 0, sizeof(trace *)); + + /* exit last active stacks */ + for (size_t i =3D 0; i < qemu_plugin_num_vcpus(); ++i) { + Cpu *cpu =3D qemu_plugin_scoreboard_find(score, i); + uint64_t timestamp =3D cpu_get_timestamp(cpu); + if (trace_sample) { + cpu_trace_last_sample(cpu, timestamp); + } + trace_exit_stack(cpu->trace, cpu->cs, timestamp); + callstack_clear(cpu->cs); + } + + for (size_t i =3D 0; i < qemu_plugin_num_vcpus(); ++i) { + Cpu *cpu =3D qemu_plugin_scoreboard_find(score, i); + for (size_t j =3D 0; j < cpu->traces->len; ++j) { + trace *t =3D g_array_index(cpu->traces, trace*, j); + trace_flush(t, true); + g_array_append_val(traces, t); + } + } + + uftrace_write_map(system_emulation); + uftrace_write_info(traces); + uftrace_write_task(traces); + + for (size_t i =3D 0; i < qemu_plugin_num_vcpus(); ++i) { + vcpu_end(i); + } + + qemu_plugin_scoreboard_free(score); +} + +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, + const qemu_info_t *info, + int argc, char **argv) +{ + if (!strcmp(info->target_name, "aarch64")) { + arch_ops =3D aarch64_ops; + } else { + fprintf(stderr, "plugin uftrace: %s target is not supported\n", + info->target_name); + return 1; + } + + score =3D qemu_plugin_scoreboard_new(sizeof(Cpu)); + qemu_plugin_register_vcpu_init_cb(id, vcpu_init); + qemu_plugin_register_atexit_cb(id, at_exit, (void *) info->system_emul= ation); + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); + + return 0; +} diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build index 1876bc78438..7eb3629c95d 100644 --- a/contrib/plugins/meson.build +++ b/contrib/plugins/meson.build @@ -1,5 +1,6 @@ contrib_plugins =3D ['bbv', 'cache', 'cflow', 'drcov', 'execlog', 'hotbloc= ks', - 'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger'] + 'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger', + 'uftrace'] if host_os !=3D 'windows' # lockstep uses socket.h contrib_plugins +=3D 'lockstep' --=20 2.47.2 From nobody Sat Nov 15 09:50:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1753126510; cv=none; d=zohomail.com; s=zohoarc; b=VmyfnVGKGiDZwiCczDjd0WKtnlqw3VIsV/RmoIwJYfPttE9KMmAucE5RZp3kJN0mKodeLqgQRNG0I4xo4wDxdH/sdtqVwq9Kj3XwRKsMx2eB2IeTzv1Qvr9W0k+v0WYDpms8Uc+8JosfiQjdVOVsyzA0ndV3VNSiJPRwOGwHE3A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1753126510; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=CO6s5b88R7bPgKVnmno+jgChIQN8BBD+eLtt81Bo/8I=; b=UXXqA9yRgUF/Ahqzn7bmaoy65lpMIN5xdbZkl36PTxFe80gjTRd4W7K9gRcC/yNQvcy/2faQsmqdApW1834QLyzj6hIiJMBvD/4nb1emmWzukl2UNaFp33TjRg7uOznKDUBYDEuisaJCd0hrU4UMRYpoQ1rs4/1m74WKA9XA7LA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17531265107441000.3318166592682; Mon, 21 Jul 2025 12:35:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1udwHp-0003IW-8G; Mon, 21 Jul 2025 15:34:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1udwGr-0002c9-V5 for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:34:00 -0400 Received: from mail-pl1-x636.google.com ([2607:f8b0:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1udwGp-0003UM-08 for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:33:57 -0400 Received: by mail-pl1-x636.google.com with SMTP id d9443c01a7336-23c8a505177so43031535ad.2 for ; Mon, 21 Jul 2025 12:33:53 -0700 (PDT) Received: from pc.. ([38.41.223.211]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-23e3b5e4750sm62238685ad.6.2025.07.21.12.33.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jul 2025 12:33:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753126433; x=1753731233; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CO6s5b88R7bPgKVnmno+jgChIQN8BBD+eLtt81Bo/8I=; b=wE02Ga4ZF2A9eKjr3FGFEuF7+ZCA6/JMDiojdbBZNT6gMLhaJlKdxQ8IwjSa8WrlTx vS+SyW5Kzct10Y3Y43oCzYEjwtvpMNOjPTq/383bXfW/+pFpcrNWaHT2aXOfXHqyRKiW XRmMqwje/sy9POPZzRmr1PZU4m0juWW75r6uBrqvV7qF83M9CNCsgNMTezp9nek6xIpA dbe72WlsvneDzs/9bZN7Y9pFT5wm+6ErEA+OlnHUQfCan+ude0/nye7leIIOk+S67Fvk 55u6M7OwmkYF9sQRL43RLl5BKfXWvPeOT3MyRy2RWl/RKA2f41+1y3YSFP84SQX0Lp2U JMHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753126433; x=1753731233; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CO6s5b88R7bPgKVnmno+jgChIQN8BBD+eLtt81Bo/8I=; b=PcTRgHcJgSJ9QfabTsApnZc9wBQKdGTDe1MfD0BTje087kiIDSTFXfxlIEQzuhFT1+ k6t+rcjBTiYboAN50DPLjJZ48G5yfSbuTIdiWd4MWUmB36OF7RV6347+jpehTjAjY0jm aJfzisp4XDLcsA7+xBKIS708kQjtwGAWjtAwMGVx34WV12c1FeLty72XM6nK9OM2P3r5 w4s0qJhnsk32Ja9yBE95vH7moZDxz7HAo3V7D0Gdsko4yfW1atvKBQi4alO0Cig/Yn3U N9u+v4MgI5+XW3Tc00IoJLXsKWykAXGTXk/Xl2w9aqbvv+tRDvORkGcJoL9dmcX/sEMd 1how== X-Gm-Message-State: AOJu0YzkdhxWQh0YVn73mwMN9uKDQS2eIkZ+0vYRL4ZwInx+aZSMrqem 10y3sHodIgyFdqBTZMEJ/PQAQdSANE+SERUw7Htr+2TCyRRIIU+iYy054DNNQewm95jVB1CYVOx 4yheC X-Gm-Gg: ASbGncuuDV01LVZl7pHYM5KW1H+zqGmmMGPQffyk3UBUnqvmyMT3i+BkBamIzGRyeuw rTfzTqSrE8xDDFkfTf23GCiSQdWDRkzW89P53jvppcqGeCfZ828gCwGEKaopSeCbdQotbmR5o4b reNCy1nCx7i9u3Ls41CdLZC1wz2tG5ekXRS4ls0I1SpuEJpzwe/a8aVYvG2OByxcM+h3ZCpNaEf 0vT88gPoJNas4oHs9aiym4ROjuWnj3fm9JVvTMiA3QNi1D1s/iqs8GoHHZUkgLSRF5WpoPFG/G9 GzXZm74lBGREHqjfdzWGNWouVqAa4fdTaaRXI2f3yE3D+OrZxIIl+M0LWWoZqXy+ozfgww1//ch 54OihKwvLxFvv/Tw9rum9NleDP8rrFcDB X-Google-Smtp-Source: AGHT+IGVHOJbEOX8dKnzAggjI1UmesEoYVfoyYWDvwiemFlQPljMxhujG3uvVIJXpagAwD3zAc7TtA== X-Received: by 2002:a17:902:d483:b0:234:d292:be84 with SMTP id d9443c01a7336-23e3b765f71mr200611985ad.10.1753126432528; Mon, 21 Jul 2025 12:33:52 -0700 (PDT) From: Pierrick Bouvier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Peter Maydell , Gustavo Romero , Manos Pitsidianakis , Pierrick Bouvier , Alexandre Iooss , rowan Hart , Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Mahmoud Mandour Subject: [PATCH v2 2/6] contrib/plugins/uftrace: add trace-sample option Date: Mon, 21 Jul 2025 12:33:36 -0700 Message-ID: <20250721193340.1059019-3-pierrick.bouvier@linaro.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> References: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::636; envelope-from=pierrick.bouvier@linaro.org; helo=mail-pl1-x636.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1753126511691116600 Content-Type: text/plain; charset="utf-8" usage: trace-sample=3DN Allow to use sampling (every N instructions) for tracking the stack. We implement a fast mode, where instrumentation is only per tb, and simply dump current stack, and unwind new one, instead of tracking every frame pointer change. Signed-off-by: Pierrick Bouvier --- contrib/plugins/uftrace.c | 111 +++++++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 6 deletions(-) diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c index d55eb32c5e8..1f3b8aaf828 100644 --- a/contrib/plugins/uftrace.c +++ b/contrib/plugins/uftrace.c @@ -43,6 +43,9 @@ typedef struct { =20 typedef struct Cpu { uint64_t insn_count; + uint64_t sample_insn_count; + uint64_t sample_timestamp; + callstack *sample_cs; trace *trace; callstack *cs; GArray *callstacks; /* callstack *callstacks[] */ @@ -69,6 +72,7 @@ enum uftrace_record_type { }; =20 static struct qemu_plugin_scoreboard *score; +static uint64_t trace_sample; static CpuOps arch_ops; =20 static void uftrace_write_map(bool system_emulation) @@ -198,6 +202,13 @@ static callstack *callstack_new(void) return cs; } =20 +static callstack *callstack_clone(const callstack *cs) +{ + callstack *clone =3D g_malloc0(sizeof(callstack)); + clone->s =3D g_array_copy(cs->s); + return clone; +} + static void callstack_free(callstack *cs) { g_array_free(cs->s, true); @@ -390,6 +401,26 @@ static void cpu_unwind_stack(Cpu *cpu, uint64_t frame_= pointer, uint64_t pc) } } =20 +static void cpu_trace_last_sample(Cpu *cpu, uint64_t timestamp) +{ + if (!cpu->sample_cs) { + return; + } + uint64_t elapsed =3D timestamp - cpu->sample_timestamp; + uint64_t middle_timestamp =3D cpu->sample_timestamp + (elapsed / 2); + trace_exit_stack(cpu->trace, cpu->sample_cs, middle_timestamp); + callstack_free(cpu->sample_cs); + cpu->sample_cs =3D NULL; + trace_enter_stack(cpu->trace, cpu->cs, middle_timestamp); +} + +static void cpu_set_new_sample(Cpu *cpu, uint64_t timestamp) +{ + cpu->sample_insn_count =3D 0; + cpu->sample_cs =3D callstack_clone(cpu->cs); + cpu->sample_timestamp =3D timestamp; +} + static uint64_t cpu_get_timestamp(const Cpu *cpu) { return cpu->insn_count; @@ -450,6 +481,13 @@ static void track_callstack(unsigned int cpu_index, vo= id *udata) callstack *cs =3D cpu->cs; trace *t =3D cpu->trace; =20 + if (trace_sample && cpu->sample_insn_count >=3D trace_sample) { + cpu_trace_last_sample(cpu, timestamp); + cpu_set_new_sample(cpu, timestamp); + } + + bool trace_change =3D !trace_sample; + uint64_t fp =3D cpu->ops.get_frame_pointer(cpu); if (!fp && callstack_empty(cs)) { /* @@ -458,7 +496,9 @@ static void track_callstack(unsigned int cpu_index, voi= d *udata) */ callstack_push(cs, (callstack_entry){.frame_pointer =3D fp, .pc =3D pc}); - trace_enter_function(t, timestamp, pc, callstack_depth(cs)); + if (trace_change) { + trace_enter_function(t, timestamp, pc, callstack_depth(cs)); + } return; } =20 @@ -472,7 +512,9 @@ static void track_callstack(unsigned int cpu_index, voi= d *udata) if (fp =3D=3D caller.frame_pointer) { /* return */ callstack_entry e =3D callstack_pop(cs); - trace_exit_function(t, timestamp, e.pc, callstack_depth(cs)); + if (trace_change) { + trace_exit_function(t, timestamp, e.pc, callstack_depth(cs)); + } return; } =20 @@ -481,27 +523,65 @@ static void track_callstack(unsigned int cpu_index, v= oid *udata) /* call */ callstack_push(cs, (callstack_entry){.frame_pointer =3D fp, .pc =3D pc}); - trace_enter_function(t, timestamp, pc, callstack_depth(cs)); + if (trace_change) { + trace_enter_function(t, timestamp, pc, callstack_depth(cs)); + } return; } =20 /* discontinuity, exit current stack and unwind new one */ - trace_exit_stack(t, cs, timestamp); + if (trace_change) { + trace_exit_stack(t, cs, timestamp); + } callstack_clear(cs); =20 cpu_unwind_stack(cpu, fp, pc); - trace_enter_stack(t, cs, timestamp); + if (trace_change) { + trace_enter_stack(t, cs, timestamp); + } +} + +static void sample_callstack(unsigned int cpu_index, void *udata) +{ + uint64_t pc =3D (uintptr_t) udata; + Cpu *cpu =3D qemu_plugin_scoreboard_find(score, cpu_index); + uint64_t timestamp =3D cpu_get_timestamp(cpu); + + trace_exit_stack(cpu->trace, cpu->cs, timestamp); + callstack_clear(cpu->cs); + + cpu_unwind_stack(cpu, cpu->ops.get_frame_pointer(cpu), pc); + trace_enter_stack(cpu->trace, cpu->cs, timestamp); + + /* reset counter */ + cpu->sample_insn_count =3D 0; } =20 static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) { size_t n_insns =3D qemu_plugin_tb_n_insns(tb); + uintptr_t tb_pc =3D qemu_plugin_tb_vaddr(tb); =20 qemu_plugin_u64 insn_count =3D qemu_plugin_scoreboard_u64_in_struct( score, Cpu, insn_count); + qemu_plugin_u64 sample_insn_count =3D qemu_plugin_scoreboard_u64_in_st= ruct( + score, Cpu, sample_insn_count); + + if (trace_sample) { + /* We can do a light instrumentation, per tb only */ + qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu( + tb, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, n_insns); + qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu( + tb, QEMU_PLUGIN_INLINE_ADD_U64, sample_insn_count, n_insns); + qemu_plugin_register_vcpu_tb_exec_cond_cb( + tb, sample_callstack, QEMU_PLUGIN_CB_R_REGS, + QEMU_PLUGIN_COND_GE, sample_insn_count, trace_sample, + (void *) tb_pc); + return; + } =20 /* - * We instrument all instructions following one that might have updated + * We now instrument all instructions following one that might have up= dated * the frame pointer. We always instrument first instruction in block,= as * last executed instruction, in previous tb, may have modified it. */ @@ -510,6 +590,8 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct q= emu_plugin_tb *tb) struct qemu_plugin_insn *insn =3D qemu_plugin_tb_get_insn(tb, i); qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu( insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1); + qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu( + insn, QEMU_PLUGIN_INLINE_ADD_U64, sample_insn_count, 1); =20 if (instrument_insn) { uintptr_t pc =3D qemu_plugin_insn_vaddr(insn); @@ -535,6 +617,7 @@ static void vcpu_init(qemu_plugin_id_t id, unsigned int= vcpu_index) cpu->buf =3D g_byte_array_new(); cpu->callstacks =3D g_array_new(0, 0, sizeof(callstack *)); cpu->traces =3D g_array_new(0, 0, sizeof(trace *)); + cpu->sample_timestamp =3D cpu_get_timestamp(cpu); =20 g_assert(vcpu_index < 1000); uint32_t trace_id =3D 1000 * 1000 + vcpu_index * 1000; @@ -612,6 +695,22 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin= _id_t id, const qemu_info_t *info, int argc, char **argv) { + for (int i =3D 0; i < argc; i++) { + char *opt =3D argv[i]; + g_auto(GStrv) tokens =3D g_strsplit(opt, "=3D", 2); + if (g_strcmp0(tokens[0], "trace-sample") =3D=3D 0) { + gint64 value =3D g_ascii_strtoll(tokens[1], NULL, 10); + if (value <=3D 0) { + fprintf(stderr, "bad trace-sample value: %s\n", tokens[1]); + return -1; + } + trace_sample =3D value; + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } + } + if (!strcmp(info->target_name, "aarch64")) { arch_ops =3D aarch64_ops; } else { --=20 2.47.2 From nobody Sat Nov 15 09:50:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1753126515; cv=none; d=zohomail.com; s=zohoarc; b=ZOQ89zkDx5diHk1N6l/4k3acuUv2wRUSHiioSJk4WFPITV3olDntAXKy9Eb08gwpqDMZOBbitxFUIa4L7zj2Z5uA+cnld8hJIiZ+2LRw7LEP3QCodLXlJZVGOa8UhwmeAF9jJfWAxeT+ihQTk9ya1qEkg/baFM8ksOV5QhoeeeE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1753126515; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=jcmFbOiVpquKEieZ7mSi2vF0OBN5CJXXV8GbAAyMRJg=; b=Ln+nayYF2BNb4yTz2H5jqnFQivZlnd6RGgX+GxOpijt6RJRIctonn8LiJnoM4Z/gqKqlsnDQr1iCi1/QCphtasnVrIeRd3qu4cQKB7ArdaMBu/4bcAJZdlof6wuhrYeqzvlmAwj8dEeAs5bhlAncY0kYpkcWcNwdYnwB/qAAIc8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1753126515452807.3105236455448; Mon, 21 Jul 2025 12:35:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1udwHs-0003Ro-KW; Mon, 21 Jul 2025 15:35:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1udwGr-0002c7-Tq for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:34:00 -0400 Received: from mail-pl1-x62d.google.com ([2607:f8b0:4864:20::62d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1udwGp-0003Uf-A3 for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:33:57 -0400 Received: by mail-pl1-x62d.google.com with SMTP id d9443c01a7336-235d6de331fso54300135ad.3 for ; Mon, 21 Jul 2025 12:33:54 -0700 (PDT) Received: from pc.. ([38.41.223.211]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-23e3b5e4750sm62238685ad.6.2025.07.21.12.33.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jul 2025 12:33:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753126434; x=1753731234; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=jcmFbOiVpquKEieZ7mSi2vF0OBN5CJXXV8GbAAyMRJg=; b=gd3sR8/4RHi6sITJCkIHYuYoq+LCGuRwpQhCJrmm4ywrgWLNcCQlX9+P9TYBHGhnYj Yh8T07TbdrkelGoUSZJrsbjFvIkltCAEe+6zDI2bgQuVUZ/KTd2FHO10sZIXiXz0l1yY 4CbgKQUHD9nvwI1Xsi4Tslr0vOxc3Kxea/FSX1mLk1GQVHd3FnC8YDesHggzuEJHrRaH 2b1wsSpsMDZ4EOkIhl2uNwiAfXnu4mkqfZJa7DVOqOw4OJlTm2flxK8VoFN7ztPdXg1w Oa69nyAJJByII8DPFN9MUt/Gsq9iPJL+VXJjAAKyCL5Ei4LO+sN7pGoh8HkWeFn498Tb +mhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753126434; x=1753731234; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=jcmFbOiVpquKEieZ7mSi2vF0OBN5CJXXV8GbAAyMRJg=; b=TqfneLxLN3wpU4jL9bx70Ve6cY6/4WkK/wG5yUxoHqH5Hjgl9HOZtm+SKeYPnxOr5R /qzon596OQumMUbrokXqH/1ga6LKj1ZRAmvAo1buqJGOodTWUPYHWw17oZ5Bv6jIhX1v fnnU/NCowZofn26P/jjuRfp3ImW8OYk/lsjqfhNqveS5IaptPkg2KxawvPRh1cQ0yGzr fcQ29qvmJ9dXfA55gk+OBReALs2VLxiiEc04mbeIYuAyIACug5MEO7YHXYPED9zd1r4S yqyUDrZuHXrQexis6uWf9o1nWW+hGRvTvpzzs584Pic6hbIVQZTQOAaoTnm59wtjdujr 5ntg== X-Gm-Message-State: AOJu0Yz1miBscn/Hqc4i/KxFChhvhiZdWsCWGZQU1Ur+oV0JDomI+Lta MgLZQeGV2x7tzfKggWKPhdQxYSYAVRUp+mNCJKG2La5yY5DSuTltp696PfsrVqJPrHEAWKXqmaN /Sj4Y X-Gm-Gg: ASbGncsXjczd8JJnc2bIFRzAdAL1+mfyx2AIaUsuKTLCOWMCh06v9d+L0JffR5shyhf Lhf8DRlONxdZQu3vDomMhc/bZhDip5G1ZO1h/nPWaSEXL9jLV6uoBU+LzGq4VGSmct+sloOiolz /Nyh4xN+Ey8yMc6/XlpgzUlawHh3zNPJUuMH5DIcEKVTvDgYLsF3UlXjHAC+6cpoBXaLjuuYGK5 MmveCWMWGpa8f3vjgc7URC+CJ6ZOWMQQTzifyARNgowUYsaMuZt8Wq7IGht3GCWYb6ac4PPCXqw quGf+Rgmfj+Gat0ghmUJCB35Ef/cYwq7mUN6UAA/yGgtJlD5zeVWjjNtkegqNnybWRvj4ZcfYlj 64MFVoElObtxE/A0uej+XoQ== X-Google-Smtp-Source: AGHT+IGFuQUMpIH71NSx6IYTyttEr2Xq5FXAftKCA2WQWFJLdgo+Kc6/DVEYYEjChDjELms6HFR0pg== X-Received: by 2002:a17:903:1112:b0:235:ec11:f0ee with SMTP id d9443c01a7336-23e2569bbe0mr284901465ad.14.1753126433601; Mon, 21 Jul 2025 12:33:53 -0700 (PDT) From: Pierrick Bouvier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Peter Maydell , Gustavo Romero , Manos Pitsidianakis , Pierrick Bouvier , Alexandre Iooss , rowan Hart , Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Mahmoud Mandour Subject: [PATCH v2 3/6] contrib/plugins/uftrace: add trace-privilege-level option Date: Mon, 21 Jul 2025 12:33:37 -0700 Message-ID: <20250721193340.1059019-4-pierrick.bouvier@linaro.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> References: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62d; envelope-from=pierrick.bouvier@linaro.org; helo=mail-pl1-x62d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1753126518082116600 Content-Type: text/plain; charset="utf-8" usage: trace-privilege-level=3D[on|off] This option generates different traces (represented as different processes in uftrace), allowing to follow privilege level changes. For aarch64, we track current EL and Security State. As well, we make sure that sampling works correctly with this option. If user requests sampling and privilege-level tracing, we perform an accurate callstack tracking (slower), and only sample the information we present. This gives accurate backtraces on all privilege switches, while keeping the trace sampled if needed. Signed-off-by: Pierrick Bouvier --- contrib/plugins/uftrace.c | 182 +++++++++++++++++++++++++++++++++++--- 1 file changed, 171 insertions(+), 11 deletions(-) diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c index 1f3b8aaf828..ff4dcb4e9bf 100644 --- a/contrib/plugins/uftrace.c +++ b/contrib/plugins/uftrace.c @@ -38,6 +38,9 @@ typedef struct { void (*init)(Cpu *cpu); void (*end)(Cpu *cpu); uint64_t (*get_frame_pointer)(Cpu *cpu); + uint8_t (*get_privilege_level)(Cpu *cpu); + uint8_t (*num_privilege_levels)(void); + const char *(*get_privilege_level_name)(uint8_t pl); bool (*does_insn_modify_frame_pointer)(const char *disas); } CpuOps; =20 @@ -48,6 +51,7 @@ typedef struct Cpu { callstack *sample_cs; trace *trace; callstack *cs; + uint8_t privilege_level; GArray *callstacks; /* callstack *callstacks[] */ GArray *traces; /* trace *traces [] */ GByteArray *buf; @@ -55,8 +59,23 @@ typedef struct Cpu { void *arch; } Cpu; =20 +typedef enum { + AARCH64_EL0_SECURE, + AARCH64_EL0_NONSECURE, + AARCH64_EL0_REALM, + AARCH64_EL1_SECURE, + AARCH64_EL1_NONSECURE, + AARCH64_EL1_REALM, + AARCH64_EL2_SECURE, + AARCH64_EL2_NONSECURE, + AARCH64_EL2_REALM, + AARCH64_EL3, +} Aarch64PrivilegeLevel; + typedef struct { struct qemu_plugin_register *reg_fp; + struct qemu_plugin_register *reg_cpsr; + struct qemu_plugin_register *reg_scr_el3; } Aarch64Cpu; =20 typedef struct { @@ -73,6 +92,7 @@ enum uftrace_record_type { =20 static struct qemu_plugin_scoreboard *score; static uint64_t trace_sample; +static bool trace_privilege_level; static CpuOps arch_ops; =20 static void uftrace_write_map(bool system_emulation) @@ -357,6 +377,16 @@ static uint64_t cpu_read_register64(Cpu *cpu, struct q= emu_plugin_register *reg) return *((uint64_t *) buf->data); } =20 +static uint32_t cpu_read_register32(Cpu *cpu, struct qemu_plugin_register = *reg) +{ + GByteArray *buf =3D cpu->buf; + g_byte_array_set_size(buf, 0); + size_t sz =3D qemu_plugin_read_register(reg, buf); + g_assert(sz =3D=3D 4); + g_assert(buf->len =3D=3D 4); + return *((uint32_t *) buf->data); +} + static uint64_t cpu_read_memory64(Cpu *cpu, uint64_t addr) { g_assert(addr); @@ -426,6 +456,68 @@ static uint64_t cpu_get_timestamp(const Cpu *cpu) return cpu->insn_count; } =20 +static uint8_t aarch64_num_privilege_levels(void) +{ + return AARCH64_EL3 + 1; +} + +static const char *aarch64_get_privilege_level_name(uint8_t pl) +{ + switch (pl) { + case AARCH64_EL0_SECURE: return "S-EL0"; + case AARCH64_EL0_NONSECURE: return "NS-EL0"; + case AARCH64_EL0_REALM: return "R-EL0"; + case AARCH64_EL1_SECURE: return "S-EL1"; + case AARCH64_EL1_NONSECURE: return "NS-EL1"; + case AARCH64_EL1_REALM: return "R-EL1"; + case AARCH64_EL2_SECURE: return "S-EL2"; + case AARCH64_EL2_NONSECURE: return "NS-EL2"; + case AARCH64_EL2_REALM: return "R-EL2"; + case AARCH64_EL3: return "EL3"; + default: + g_assert_not_reached(); + } +} + +static uint8_t aarch64_get_privilege_level(Cpu *cpu_) +{ + Aarch64Cpu *cpu =3D cpu_->arch; + /* + * QEMU gdbstub does not provide access to CurrentEL, + * so we use CPSR instead. + */ + uint8_t el =3D cpu_read_register32(cpu_, cpu->reg_cpsr) >> 2 & 0b11; + + if (el =3D=3D 3) { + return AARCH64_EL3; + } + + uint8_t ss =3D AARCH64_EL0_SECURE; + if (!cpu->reg_scr_el3) { + ss =3D AARCH64_EL0_NONSECURE; + } + uint64_t scr_el3 =3D cpu_read_register64(cpu_, cpu->reg_scr_el3); + uint64_t ns =3D (scr_el3 >> 0) & 0b1; + uint64_t nse =3D (scr_el3 >> 62) & 0b1; + switch (nse << 1 | ns) { + case 0b00: + ss =3D AARCH64_EL0_SECURE; + break; + case 0b01: + ss =3D AARCH64_EL0_NONSECURE; + break; + case 0b11: + ss =3D AARCH64_EL0_REALM; + break; + default: + g_assert_not_reached(); + } + + const uint8_t num_ss =3D 3; + Aarch64PrivilegeLevel pl =3D el * num_ss + ss; + return pl; +} + static uint64_t aarch64_get_frame_pointer(Cpu *cpu_) { Aarch64Cpu *cpu =3D cpu_->arch; @@ -442,6 +534,10 @@ static void aarch64_init(Cpu *cpu_) reg =3D &g_array_index(regs, qemu_plugin_reg_descriptor, i); if (!strcmp(reg->name, "x29")) { cpu->reg_fp =3D reg->handle; + } else if (!strcmp(reg->name, "cpsr")) { + cpu->reg_cpsr =3D reg->handle; + } else if (!strcmp(reg->name, "SCR_EL3")) { + cpu->reg_scr_el3 =3D reg->handle; } } if (!cpu->reg_fp) { @@ -449,6 +545,8 @@ static void aarch64_init(Cpu *cpu_) "available. Please use an AArch64 cpu (or -cpu max= ).\n"); g_abort(); } + g_assert(cpu->reg_cpsr); + /* scr_el3 is optional */ } =20 static void aarch64_end(Cpu *cpu) @@ -470,9 +568,43 @@ static CpuOps aarch64_ops =3D { .init =3D aarch64_init, .end =3D aarch64_end, .get_frame_pointer =3D aarch64_get_frame_pointer, + .get_privilege_level =3D aarch64_get_privilege_level, + .num_privilege_levels =3D aarch64_num_privilege_levels, + .get_privilege_level_name =3D aarch64_get_privilege_level_name, .does_insn_modify_frame_pointer =3D aarch64_does_insn_modify_frame_poi= nter, }; =20 +static void track_privilege_change(unsigned int cpu_index, void *udata) +{ + Cpu *cpu =3D qemu_plugin_scoreboard_find(score, cpu_index); + uint8_t new_pl =3D cpu->ops.get_privilege_level(cpu); + + if (new_pl =3D=3D cpu->privilege_level) { + return; + } + + uint64_t pc =3D (uintptr_t) udata; + uint64_t timestamp =3D cpu_get_timestamp(cpu); + + if (trace_sample) { + cpu_trace_last_sample(cpu, timestamp); + } + + trace_exit_stack(cpu->trace, cpu->cs, timestamp); + callstack_clear(cpu->cs); + + cpu->privilege_level =3D new_pl; + cpu->cs =3D g_array_index(cpu->callstacks, callstack*, new_pl); + cpu->trace =3D g_array_index(cpu->traces, trace*, new_pl); + + cpu_unwind_stack(cpu, cpu->ops.get_frame_pointer(cpu), pc); + trace_enter_stack(cpu->trace, cpu->cs, timestamp); + + if (trace_sample) { + cpu_set_new_sample(cpu, timestamp); + } +} + static void track_callstack(unsigned int cpu_index, void *udata) { uint64_t pc =3D (uintptr_t) udata; @@ -567,7 +699,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct q= emu_plugin_tb *tb) qemu_plugin_u64 sample_insn_count =3D qemu_plugin_scoreboard_u64_in_st= ruct( score, Cpu, sample_insn_count); =20 - if (trace_sample) { + if (trace_sample && !trace_privilege_level) { /* We can do a light instrumentation, per tb only */ qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu( tb, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, n_insns); @@ -580,6 +712,12 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct = qemu_plugin_tb *tb) return; } =20 + if (trace_privilege_level) { + qemu_plugin_register_vcpu_tb_exec_cb(tb, track_privilege_change, + QEMU_PLUGIN_CB_R_REGS, + (void *) tb_pc); + } + /* * We now instrument all instructions following one that might have up= dated * the frame pointer. We always instrument first instruction in block,= as @@ -622,17 +760,33 @@ static void vcpu_init(qemu_plugin_id_t id, unsigned i= nt vcpu_index) g_assert(vcpu_index < 1000); uint32_t trace_id =3D 1000 * 1000 + vcpu_index * 1000; =20 - g_autoptr(GString) trace_name =3D g_string_new(NULL); - g_string_append_printf(trace_name, "cpu%u", vcpu_index); - trace *t =3D trace_new(trace_id, trace_name); - g_array_append_val(cpu->traces, t); - callstack *cs =3D callstack_new(); - g_array_append_val(cpu->callstacks, cs); - /* create/truncate trace file */ - trace_flush(t, false); + if (trace_privilege_level) { + for (uint8_t pl =3D 0; pl < cpu->ops.num_privilege_levels(); ++pl)= { + g_autoptr(GString) trace_name =3D g_string_new(NULL); + g_string_append_printf(trace_name, "cpu%u %s", vcpu_index, + cpu->ops.get_privilege_level_name(pl)); + trace *t =3D trace_new(trace_id + pl, trace_name); + g_array_append_val(cpu->traces, t); + callstack *cs =3D callstack_new(); + g_array_append_val(cpu->callstacks, cs); + } + } else { + g_autoptr(GString) trace_name =3D g_string_new(NULL); + g_string_append_printf(trace_name, "cpu%u", vcpu_index); + trace *t =3D trace_new(trace_id, trace_name); + g_array_append_val(cpu->traces, t); + callstack *cs =3D callstack_new(); + g_array_append_val(cpu->callstacks, cs); + } =20 - cpu->cs =3D cs; - cpu->trace =3D t; + for (size_t i =3D 0; i < cpu->traces->len; ++i) { + /* create/truncate trace files */ + trace *t =3D g_array_index(cpu->traces, trace*, i); + trace_flush(t, false); + } + + cpu->cs =3D g_array_index(cpu->callstacks, callstack*, cpu->privilege_= level); + cpu->trace =3D g_array_index(cpu->traces, trace*, cpu->privilege_level= ); } =20 static void vcpu_end(unsigned int vcpu_index) @@ -705,6 +859,12 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin= _id_t id, return -1; } trace_sample =3D value; + } else if (g_strcmp0(tokens[0], "trace-privilege-level") =3D=3D 0)= { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], + &trace_privilege_level)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", o= pt); + return -1; + } } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; --=20 2.47.2 From nobody Sat Nov 15 09:50:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1753126571; cv=none; d=zohomail.com; s=zohoarc; b=M9RZmQgmSoVt0KCRfXDJ/bZCIm59pbrAIJLTaBGmU5DAOEzhmbyRJgoLssEkzI/4udM6/Na2/FGUZkgLcXlFNklRwu6M5KirLUNr54OXRVo+QbDIn4TlVcw0X+5/g2HfnnIHJIdwxm7kwmXCNQjSU+juXNuPTeUwB+0YJGo7SLA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1753126571; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=BBOR3bawaV5LsRRquIEasW/Jg5XqUZiqsCVsDF+w8YY=; b=GP438RSLq1h9ktOJZ4+sGBv4mCNtVuFTeWoY/ylyXRrOrc8RC3puk9EBBLM6Sen/X/FVsrWPxSf6EPoV853EM4KuDalGcGpWNo84V2GcwsfNdSYnA1aZXxfGC5Mxn3DDBJFFCJ0Hn7vBYugBFTSQAI46zDlGbhyAAksoMdfMCsQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1753126571228793.2849903909953; Mon, 21 Jul 2025 12:36:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1udwIX-0004BW-W0; Mon, 21 Jul 2025 15:35:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1udwGr-0002c6-T2 for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:34:00 -0400 Received: from mail-pl1-x62e.google.com ([2607:f8b0:4864:20::62e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1udwGp-0003Uo-Qj for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:33:57 -0400 Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-235f9e87f78so43302935ad.2 for ; Mon, 21 Jul 2025 12:33:55 -0700 (PDT) Received: from pc.. ([38.41.223.211]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-23e3b5e4750sm62238685ad.6.2025.07.21.12.33.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jul 2025 12:33:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753126434; x=1753731234; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BBOR3bawaV5LsRRquIEasW/Jg5XqUZiqsCVsDF+w8YY=; b=aKtSk+0X8+eLZ5ho9FE3Icnscl5pbbxPlW4pHIcGzswxDMSbKPyf4ZFagzNXtJTuXy d+wnBo5npguDUyU8/kHz0fwFNA/mc4WrfM9VNF+YJYnZ0RueWNMD0uD2/rfmRuRCC8tD 5ssnH69Zse82I9mEb7CdUITMdzL2gSWF05Mvw84XOKqTDvMpbe2D4UMNNi6d5SVgeZaF HDEpPJHsOO6yXAKHM9Yd1n3zM5tv0OSF/U4lhSBPSY9PcrlsRxZ0ri4TKP1MdA9Oioa9 F54F1x70rEIDj5jNwCfGeDCHvcefkHKq7msq9zYPAVwvUJtPDXDqXOaZzKfOqd8CGEVe 7kCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753126434; x=1753731234; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BBOR3bawaV5LsRRquIEasW/Jg5XqUZiqsCVsDF+w8YY=; b=Fm3KuvhPmWHYfcOy59Tw2D9itUnaVa9+/i1ZN+gwxS27/dPmWGpq90ZTgZiOHhFzJQ BCCgZ1KdzbZ7zSfpEhkJxbdpToSDtWg71QWxHGdkEY2LpO1vvpIY3a3/iIjnHpvJJl3K weM4XkN+mv7uOdFQzPlm4dmULYmNfy/ZavXb6t3ahosLj4DI2XaF4SxtoHMY1jrmE/uu CFe0VXVlvlVcn1wdd/5Aq9p2K0DBeLoB+53VCMnb4QUXiR7l4xIO8fLObm2oe8F9sVuL JT4qT15BAoU9ZQ+BYI6PS+UiiQ5x2/4eBMHQvejqIMJt9ej+59SIPiJ5lkp5EV3QdolH voOw== X-Gm-Message-State: AOJu0YyS5XBTwjD74r2yi4kyjWpcRowkVoEvQGXBhEgwDA8pxfi3+idG uRWdxPE287/C8+YZh0TLRuCuZf03UOe7cJHyIVPvtGtRSU60XUAmb3G4Yw4ZNcqF0BnAR97eLJH zoPkQ X-Gm-Gg: ASbGncutum2Nhc6iaPeQScruInnXLBvy5VKQT+VwY0VuTSmT6d8CoXy9JRZtQ6fdYYN MhLC4XU6728VfkjakV56cNk3dstlLAVz+etP06v+lUrEkpe6l7P42OZIGGOBbv3+XrWRO0hcl4a UtSIc9j5ImGHdd5CsBWN0HfVH/rMNlUGz+lUoZdazdmV/D3WQxiHpGJ3Bo6cZ9+S/lMag8yEkQB zR1nxyCj2Db67hggCFmusyEVXh63YR2VGnwUDM71DJh4g3IUlC2ocx4rjDb9CHR5BwXwax8OolF hOeMZ+tOrp3DtSMdp4Cm7p16fZv2piPu//r3KV4HB7Xwx+okc6ffha+LOItSjGo+kKiztEryP+l zVorvId1iP4KhGVWCx2J0Cw== X-Google-Smtp-Source: AGHT+IFGq14liDmmWxsUqf8oZE2YiHYUpdBbMGcsXsgTqCJppiCXqBw0f2d1eGlVxIeDi0LG7TjC8g== X-Received: by 2002:a17:903:faf:b0:235:799:eca5 with SMTP id d9443c01a7336-23e2576e67cmr318939825ad.44.1753126434521; Mon, 21 Jul 2025 12:33:54 -0700 (PDT) From: Pierrick Bouvier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Peter Maydell , Gustavo Romero , Manos Pitsidianakis , Pierrick Bouvier , Alexandre Iooss , rowan Hart , Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Mahmoud Mandour Subject: [PATCH v2 4/6] contrib/plugins/uftrace: add timestamp-based-on-real-time option Date: Mon, 21 Jul 2025 12:33:38 -0700 Message-ID: <20250721193340.1059019-5-pierrick.bouvier@linaro.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> References: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62e; envelope-from=pierrick.bouvier@linaro.org; helo=mail-pl1-x62e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1753126572292116600 Content-Type: text/plain; charset="utf-8" usage: timestamp-based-on-real-time=3D[on|off] Instead of using number of instructions executed (which is per vcpu), we use the wall time for timestamps. This is useful when tracing user mode programs as well. Signed-off-by: Pierrick Bouvier --- contrib/plugins/uftrace.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c index ff4dcb4e9bf..6709b38918e 100644 --- a/contrib/plugins/uftrace.c +++ b/contrib/plugins/uftrace.c @@ -93,8 +93,28 @@ enum uftrace_record_type { static struct qemu_plugin_scoreboard *score; static uint64_t trace_sample; static bool trace_privilege_level; +static bool timestamp_based_on_real_time; static CpuOps arch_ops; =20 +static uint64_t gettime_ns(void) +{ +#ifdef _WIN32 + /* + * On Windows, timespec_get is available only with UCRT, but not with + * MinGW64 environment. Simplify by using only gettimeofday on this + * platform. + */ + struct timeval tv; + gettimeofday(&tv, NULL); + uint64_t now_ns =3D tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; +#else + struct timespec ts; + timespec_get(&ts, TIME_UTC); + uint64_t now_ns =3D ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; +#endif + return now_ns; +} + static void uftrace_write_map(bool system_emulation) { const char *path =3D "./uftrace.data/sid-0.map"; @@ -453,6 +473,9 @@ static void cpu_set_new_sample(Cpu *cpu, uint64_t times= tamp) =20 static uint64_t cpu_get_timestamp(const Cpu *cpu) { + if (timestamp_based_on_real_time) { + return gettime_ns(); + } return cpu->insn_count; } =20 @@ -865,6 +888,12 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin= _id_t id, fprintf(stderr, "boolean argument parsing failed: %s\n", o= pt); return -1; } + } else if (g_strcmp0(tokens[0], "timestamp-based-on-real-time") = =3D=3D 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], + ×tamp_based_on_real_time)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", o= pt); + return -1; + } } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; --=20 2.47.2 From nobody Sat Nov 15 09:50:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1753126515; cv=none; d=zohomail.com; s=zohoarc; b=H2oljg5+XAG/lfcoF6TG001kX7J8ywH6DXLpt91X7gjNutD8JhVvMlWCNlduwvyrvufn8KQCNUG40nQJCnkUL2Helb5ikFpOEJQegzIw01eZPB9A+ffyW8/SvvPWPiBmX6EcG/S/A1JPMggZ8q1pJtXRplZheiftQWC6T7kUU0w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1753126515; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=6LQZIHbBuXid8iCd4uQRcE8cD4Q27Dve1/07zd+zCHI=; b=l7kWVVvqk+dBQvHHPxITjPWefzK65DhyVRAFv//JK7ba4V0qmLviyYYe8LhxbjRy/7bIva2a/SmvHoOY3VJSOvuE887kZWB/RCrPX1e3sHB4L35vI7mZLySvUgI+2k17fTIXYSkfHQx+t+Mme6hT2sc/KYwH1t+ZXnqzJ26I+B8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 175312651536365.03772739807164; Mon, 21 Jul 2025 12:35:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1udwHv-0003Zc-KW; Mon, 21 Jul 2025 15:35:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1udwGv-0002ev-2O for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:34:06 -0400 Received: from mail-pl1-x62b.google.com ([2607:f8b0:4864:20::62b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1udwGr-0003VF-5Q for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:34:00 -0400 Received: by mail-pl1-x62b.google.com with SMTP id d9443c01a7336-23694cec0feso43868845ad.2 for ; Mon, 21 Jul 2025 12:33:56 -0700 (PDT) Received: from pc.. ([38.41.223.211]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-23e3b5e4750sm62238685ad.6.2025.07.21.12.33.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jul 2025 12:33:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753126435; x=1753731235; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6LQZIHbBuXid8iCd4uQRcE8cD4Q27Dve1/07zd+zCHI=; b=HtNmKbh2L3alZlNY5q1TvSEsjhU2dZxNByvSnOu2tJVXeed47aYa8q31sVlugRZx9J 1gaPfnNeIJBLnxKiwaj/salesiBGjda7SjmfjksbCgsq3pJ6v4HqwgMlBpS9NpjOypmj /7BTL5wkrO5EUNd+olc59tfYZ+cn+1AwHQRo/65XJ7YY4dt+K+cjtoIQBaASx9aQkyzh thzHZc+r5mXJxRgbodukttHgKlmgMxOQj6jSfSLVBaK5NeQRanzLg0a9ZomAgcczttmt inulfjOq13yP9o2GNHpyUXffw2uS1VfSbfiQst1ih/Rg4UNzqyGC0G7WejLr9MH8ad9D Fpkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753126435; x=1753731235; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6LQZIHbBuXid8iCd4uQRcE8cD4Q27Dve1/07zd+zCHI=; b=Ogyql0J1B4dUL1PASZJU+6dDg4YaAg3nSrpbQ7or60+iZXKvZZpKkYcCju3zP86Buy FaGxt/Sinwu24Yqq4TFB6fNEpOrkQK0lyCQzCpmP1A00IxAeyeSL5Ab8EPhjCUUTPy5u FYlqqzer7SKtMvsIZLwvVweo7jcFrr9YR8h44aWaWvrbRBueC8ScGDwhhk6M/9gRC3Kn abD6NqzGR7NtmbFiWuyD1psiUsyMKMm77HUCGsEz/WZSLA+cCCbztQgY0Nj488Ofaz8I TMrMae4/Wy7aTLaytLBORwng9KdUbG9HII2XVXRNX+Wi6AwXROoPkdqY3zFvLhQkUCgH P7Xw== X-Gm-Message-State: AOJu0Yz4YVIGS93Wq+DuByoiU6V/BxzSBdBCDZX2PbqDr+FpZrIQlW1c 9wrSzTgb98F0bGajxa5QccXtHySV2kfNus5Ug3CLeoXbUoMYvlMShtjSuVvYd1Up4eUQ5JupOAN iqUgH X-Gm-Gg: ASbGnctaqWJDCmK79hJDU6hoV5XC1nWPJv+KjPWdAaMzaBtGu328NF2SPs9GSWcvQ92 v+NJiCbYKxuZ8GNwMFGlrOcg2AqLXzODCFsx98ENOeJHk3KAGLhvZJ926QF01on6SfvplSm39EO 4iuapV0E+jlLAO1rKX6PeJ2M3k3yf4PPxs92acNpGuZfX1cjVRLK9thPHVlQD1ledScu2E2kLbx zcQTPbJuSjiKaK6NknHXBFjxX+w8C+wXRgLyu1TBg9TMqjOvIJy5hT5bE51QSzrNv8H7izrRyFb 3b5oq62Y7IgDWzqthGh2G55HIN7BQy0RX0Pj8qThADtevRiF2gRri5MRxV9kz4wAkANnxQVSgnG +Gw2kQBb0SyKsziqqxoRbOw== X-Google-Smtp-Source: AGHT+IG/azbmMlf7krgDA7Rr1usvx9g/0JbWNNdw5xiQ5QSop8Y0DuGFFAIADfG3PPEcXzThKYfOGw== X-Received: by 2002:a17:903:2d1:b0:234:d2fb:2d28 with SMTP id d9443c01a7336-23e24ec73b2mr344169515ad.2.1753126435455; Mon, 21 Jul 2025 12:33:55 -0700 (PDT) From: Pierrick Bouvier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Peter Maydell , Gustavo Romero , Manos Pitsidianakis , Pierrick Bouvier , Alexandre Iooss , rowan Hart , Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Mahmoud Mandour Subject: [PATCH v2 5/6] contrib/plugins/uftrace_symbols.py Date: Mon, 21 Jul 2025 12:33:39 -0700 Message-ID: <20250721193340.1059019-6-pierrick.bouvier@linaro.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> References: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62b; envelope-from=pierrick.bouvier@linaro.org; helo=mail-pl1-x62b.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1753126517996116600 Content-Type: text/plain; charset="utf-8" usage: contrib/plugins/uftrace_symbols.py \ --prefix-symbols \ arm-trusted-firmware/build/qemu/debug/bl1/bl1.elf \ arm-trusted-firmware/build/qemu/debug/bl2/bl2.elf \ arm-trusted-firmware/build/qemu/debug/bl31/bl31.elf \ u-boot/u-boot:0x60000000 \ u-boot/u-boot.relocated:0x000000023f6b6000 \ linux/vmlinux Will generate symbols and memory mapping files for uftrace, allowing to have an enhanced trace, instead of raw addresses. It takes a collection of elf files, and automatically find all their symbols, and generate an ordered memory map based on that. This script uses the python (native) pyelftools module. Signed-off-by: Pierrick Bouvier --- contrib/plugins/uftrace_symbols.py | 152 +++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100755 contrib/plugins/uftrace_symbols.py diff --git a/contrib/plugins/uftrace_symbols.py b/contrib/plugins/uftrace_s= ymbols.py new file mode 100755 index 00000000000..b49e03203c8 --- /dev/null +++ b/contrib/plugins/uftrace_symbols.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Create symbols and mapping files for uftrace. +# +# Copyright 2025 Linaro Ltd +# Author: Pierrick Bouvier +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import argparse +import elftools # pip install pyelftools +import os + +from elftools.elf.elffile import ELFFile +from elftools.elf.sections import SymbolTableSection + +def elf_func_symbols(elf): + symbol_tables =3D [(idx, s) for idx, s in enumerate(elf.iter_sections(= )) + if isinstance(s, SymbolTableSection)] + symbols =3D [] + for _, section in symbol_tables: + for _, symbol in enumerate(section.iter_symbols()): + if symbol_size(symbol) =3D=3D 0: + continue + type =3D symbol['st_info']['type'] + if type =3D=3D 'STT_FUNC' or type =3D=3D 'STT_NOTYPE': + symbols.append(symbol) + symbols.sort(key =3D lambda x: symbol_addr(x)) + return symbols + +def symbol_size(symbol): + return symbol['st_size'] + +def symbol_addr(symbol): + addr =3D symbol['st_value'] + # clamp addr to 48 bits, like uftrace entries + return addr & 0xffffffffffff + +def symbol_name(symbol): + return symbol.name + +class BinaryFile: + def __init__(self, path, map_offset): + self.fullpath =3D os.path.realpath(path) + self.map_offset =3D map_offset + with open(path, 'rb') as f: + self.elf =3D ELFFile(f) + self.symbols =3D elf_func_symbols(self.elf) + + def path(self): + return self.fullpath + + def addr_start(self): + return self.map_offset + + def addr_end(self): + last_sym =3D self.symbols[-1] + return symbol_addr(last_sym) + symbol_size(last_sym) + self.map_of= fset + + def generate_symbol_file(self, prefix_symbols): + binary_name =3D os.path.basename(self.fullpath) + sym_file_path =3D f'./uftrace.data/{binary_name}.sym' + print(f'{sym_file_path} ({len(self.symbols)} symbols)') + with open(sym_file_path, 'w') as sym_file: + # print hexadecimal addresses on 48 bits + addrx =3D "0>12x" + for s in self.symbols: + addr =3D symbol_addr(s) + addr =3D f'{addr:{addrx}}' + size =3D f'{symbol_size(s):{addrx}}' + name =3D symbol_name(s) + if prefix_symbols: + name =3D f'{binary_name}:{name}' + print(addr, size, 'T', name, file=3Dsym_file) + +def parse_parameter(p): + s =3D p.split(":") + path =3D s[0] + if len(s) =3D=3D 1: + return path, 0 + if len(s) > 2: + raise ValueError('only one offset can be set') + offset =3D s[1] + if not offset.startswith('0x'): + err =3D f'offset "{offset}" is not an hexadecimal constant. ' + err +=3D 'It should starts with "0x".' + raise ValueError(err) + offset =3D int(offset, 16) + return path, offset + +def is_from_user_mode(map_file_path): + if os.path.exists(map_file_path): + with open(map_file_path, 'r') as map_file: + if not map_file.readline().startswith('# map stack on'): + return True + return False + +def generate_map(binaries): + map_file_path =3D './uftrace.data/sid-0.map' + + if is_from_user_mode(map_file_path): + print(f'do not overwrite {map_file_path} generated from qemu-user') + return + + mappings =3D [] + + # print hexadecimal addresses on 48 bits + addrx =3D "0>12x" + + mappings +=3D ['# map stack on highest address possible, to prevent uf= trace'] + mappings +=3D ['# from considering any kernel address'] + mappings +=3D ['ffffffffffff-ffffffffffff rw-p 00000000 00:00 0 [stack= ]'] + + for b in binaries: + m =3D f'{b.addr_start():{addrx}}-{b.addr_end():{addrx}}' + m +=3D f' r--p 00000000 00:00 0 {b.path()}' + mappings.append(m) + + with open(map_file_path, 'w') as map_file: + print('\n'.join(mappings), file=3Dmap_file) + print(f'{map_file_path}') + print('\n'.join(mappings)) + +def main(): + parser =3D argparse.ArgumentParser(description=3D + 'generate symbol files for uftrace') + parser.add_argument('elf_file', nargs=3D'+', + help=3D'path to an ELF file. ' + 'Use /path/to/file:0xdeadbeef to add a mapping off= set.') + parser.add_argument('--prefix-symbols', + help=3D'prepend binary name to symbols', + action=3Dargparse.BooleanOptionalAction) + args =3D parser.parse_args() + + if not os.path.exists('./uftrace.data'): + os.mkdir('./uftrace.data') + + binaries =3D [] + for file in args.elf_file: + path, offset =3D parse_parameter(file) + b =3D BinaryFile(path, offset) + binaries.append(b) + binaries.sort(key =3D lambda b: b.addr_end()); + + for b in binaries: + b.generate_symbol_file(args.prefix_symbols) + + generate_map(binaries) + +if __name__ =3D=3D '__main__': + main() --=20 2.47.2 From nobody Sat Nov 15 09:50:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1753126769; cv=none; d=zohomail.com; s=zohoarc; b=KnCQiSKOTCKXfTRGOpCBiHufzBwgLLRwtZQig4IdmnPfQdE7x+NfISNuAflJNBOkwiuimznvzuS9j6JnWg3P3Uf6FURH1BIqUYg3P6AIrE1M0eLXoCq4c9LdwEvG4xSZ/uj3SjCrX74b/El/WMVdHJfxNBXIFWFGGPyOPpEfwXw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1753126769; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=6Zn/ayMPPk99hnhN3bzhknk1HdBqHZee+zR0CqprdCU=; b=H7FfAlkLb/XRVPStNaOW7t+0YsgkdnTLjygef3QaZCS5VtClPecr0kBvOxTzO4QfCmHzdia4Hqsl7TganCaQgYaW2bc6kO0rZZAoZQ+nUomsJtsdpDDl4HL/ABF8RzP4Dr6SUyXffHVBpcMWfBWX6dYmQ/OKnkoi228TjIaiMBE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1753126769230360.57835251449706; Mon, 21 Jul 2025 12:39:29 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1udwJj-0005PV-Gp; Mon, 21 Jul 2025 15:36:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1udwGv-0002f0-6h for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:34:06 -0400 Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1udwGs-0003Vi-M4 for qemu-devel@nongnu.org; Mon, 21 Jul 2025 15:34:00 -0400 Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-235f9ea8d08so39012885ad.1 for ; Mon, 21 Jul 2025 12:33:58 -0700 (PDT) Received: from pc.. ([38.41.223.211]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-23e3b5e4750sm62238685ad.6.2025.07.21.12.33.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jul 2025 12:33:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1753126437; x=1753731237; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6Zn/ayMPPk99hnhN3bzhknk1HdBqHZee+zR0CqprdCU=; b=KVYK1kOhBsvJMrBLV4YZ+exh5qk+r064lmv/zZQaPjvfjP07EiEiw3DKPLePCxzjH/ oAv6A7f4vUGmp3X2GdSCrbetw4GnSUd2ZYa8QfaUl+kxUWIVC+kSXfxxoGzS72sbD/Hd uWJt5uTs9newMDO2/yJhGx+NJpLwwJprGVgLAFPolm+zFYHUqRnJbtzFyIenh830pNtq o6WS9W+oHuKG0NArZVHwPi3xhZPpHZpfHLFWnbM1wcH90KAeSF+dDg7vIpZz1ymCz7x7 hGFe7Jq5oFUK44jrWpm8FD7lJmTQokhNqpsaO7EVVRuJ3bqS7i3t8BBwkpCciRGg7bn8 w2rw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753126437; x=1753731237; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6Zn/ayMPPk99hnhN3bzhknk1HdBqHZee+zR0CqprdCU=; b=urZy4chdZxZXgpf18B/kqSMDjsUuBUgxDeQUhit1cIGo0AdyRS3uhyhDK0U5ojYY0l DFrG6LIZzHsRuKmBUB6T+XgHDaUZe4ieOfgImN1gFyJ5+OoswmsFEDTx+aUan7hGzCcH sBj8c9mayAyF79RM+yIPWb/Kl0LIYFGADy9Ucn5S9dS3PFsP2L8rIuEtxsnqCRAVHEst SVXYGEzl1r6vwGQq7T6WLRLD5LvBTB/+2vTZhXNxDERjDHNsuw83w82wyuFGloyeIqLm cQcWhZX+qWVsBHeakM8G2SqLzWlfdz6fEO1wjSO5w/EfivZ8RHR7CJ+PZzrUuFR2OcLd cKgg== X-Gm-Message-State: AOJu0YzgN5auaaE9lCbeE7crFDHwQX4IrsQMLwInitcxLo2NQtG+L5lh RrU2KuWa/JVjlGiXTSUVZIhG9o5UZMxUlNbGIrC7PnQNDaa+I0KCI5x5Z5gv++H73QtnL+m/eld qjufo X-Gm-Gg: ASbGncsgbEZDzDj3pBlCLdCiyiRSLlNATLEKIOZN2DpDR+hh5/qNmxisGH5rnqGELol iQxCv9px28ahqsImcquCn6zjo0D6LvLu790aeH+7TrmgB176mw/EwpnCjnGd1ZpzHb9ZIFh6HRz BEv07g6yQtY6ACT+BLd71RqBPnXxTPRBSZNE37qxaapKGtR4/mWmeo2R/k/tVsag5d1ZOGcgiWW ICQ0mGFOxHNgd915O9EsAQuePFKXiD2czwXDyPn1kXrreqOyJcW4T+l4M4AdRnXWbeM0a2cZzEl VLiPBqVRRIc0xIP3NfpOmmCclcGZBY8imOnLWNyTokG0Es4aTC6tp79IAYtwDXIawI7SyFSxKnV ne8JoLHNmlMM+Grq8hTlwkg== X-Google-Smtp-Source: AGHT+IEG1hRPF98bkAI7nC+Cnsx6va3nIYsFuw/xGXXJcnXbucHx2zFtTixSaYLsi9ktAM3MS3mmrQ== X-Received: by 2002:a17:902:d50e:b0:234:d7c5:a0ea with SMTP id d9443c01a7336-23e24f4aec0mr377753145ad.24.1753126437040; Mon, 21 Jul 2025 12:33:57 -0700 (PDT) From: Pierrick Bouvier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Peter Maydell , Gustavo Romero , Manos Pitsidianakis , Pierrick Bouvier , Alexandre Iooss , rowan Hart , Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Mahmoud Mandour Subject: [PATCH v2 6/6] contrib/plugins/uftrace: add documentation Date: Mon, 21 Jul 2025 12:33:40 -0700 Message-ID: <20250721193340.1059019-7-pierrick.bouvier@linaro.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> References: <20250721193340.1059019-1-pierrick.bouvier@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62a; envelope-from=pierrick.bouvier@linaro.org; helo=mail-pl1-x62a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1753126771492116600 Content-Type: text/plain; charset="utf-8" This documentation summarizes how to use the plugin, and present two examples of the possibilities offered by it. As well, it explains how to rebuild and reproduce easily the system boot example. Signed-off-by: Pierrick Bouvier --- docs/about/emulation.rst | 207 ++++++++++++++++++++++++++++++++++++++ contrib/plugins/uftrace.c | 2 + 2 files changed, 209 insertions(+) diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst index 456d01d5b08..059ff7f61c3 100644 --- a/docs/about/emulation.rst +++ b/docs/about/emulation.rst @@ -816,6 +816,213 @@ This plugin can limit the number of Instructions Per = Second that are executed:: The lower the number the more accurate time will be, but the less ef= ficient the plugin. Defaults to ips/10 =20 +Uftrace +....... + +``contrib/plugins/uftrace.c`` + +This plugin generates a binary trace compatible with +`uftrace `_. + +Plugin supports aarch64 only (x64 support should be trivial to add), and w= orks +in user and system mode, allowing to trace a system boot, which is not som= ething +possible usually. + +In user mode, the memory mapping is directly copied from ``/proc/self/maps= `` at +the end of execution. Uftrace should be able to retrieve symbols by itself, +without any additional step. +In system mode, the default memory mapping is empty, and you can generate +one (and associated symbols) using ``contrib/plugins/uftrace_symbols.py``. +Symbols must be present in ELF binaries. + +It tracks the call stack (based on frame pointer analysis). Thus, your pro= gram +and its dependencies must be compiled using ``-fno-omit-frame-pointer +-mno-omit-leaf-frame-pointer``. In 2024, `Ubuntu and Fedora enabled it by +default again on x64 +`_. +On aarch64, this is less of a problem, as they are usually part of the ABI, +except for leaf functions. That's true for user space applications, but not +necessarily for bare metal code. + +Timestamps used for events are the number of instructions executed so far = by +default. As it's tracked per vcpu, each timeline should be considered +separately. It's possible to use real timestamps by using option +``timestamp-based-on-real-time``. This is not the default, as considering = real +time when doing emulation and instrumentation may not necessarily report c= orrect +things. However, it is quite useful when running multiple cpus scenarios, = or if +you want to generate a trace around a particular time of the execution. + +When tracing long scenarios (> 1 min), the generated trace can become very= long, +making it hard to extract data from it. In this case, a simple solution is= to +trace execution using ``timestamp-based-on-real-time=3Don``, and generate a +timestamped output log using ``qemu-system-aarch64 ... | ts "%s"``. Then, +``uftrace --time-range=3Dstart~end`` can be used to reduce trace for only = this +part of execution. + +Performance wise, overhead compared to normal tcg execution can vary from = x2 +(sampling only) to x10-x15 (precise stack tracking). + +.. list-table:: Uftrace plugin arguments + :widths: 20 80 + :header-rows: 1 + + * - Option + - Description + * - trace-privilege-level=3D[on|off] + - Generate one trace per privilege level (Exception Level + Security S= tate + on aarch64). + * - trace-sample=3DN + - Instead of precise tracking, perform stack sampling every N instruct= ions. + If combined with ``trace-privilege-level``, it will still contain pr= ecise + stacks for privilege level changes, and will sample stack between th= ose. + * - timestamp-based-on-real-time=3D[on|off] + - Use real time for timestamps instead of number of instructions execu= ted. + +.. list-table:: uftrace_symbols.py arguments + :widths: 20 80 + :header-rows: 1 + + * - Option + - Description + * - elf_file [elf_file ...] + - path to an ELF file. Use /path/to/file:0xdeadbeef to add a mapping o= ffset. + * - --prefix-symbols + - prepend binary name to symbols + +Example user trace +++++++++++++++++++ + +As an example, we can trace qemu itself running git:: + + $ ./build/qemu-aarch64 -plugin \ + build/contrib/plugins/libuftrace.so,timestamp-based-on-real-time=3Do= n \ + ./build/qemu-aarch64 /usr/bin/git --help + + # and generate a chrome trace directly + $ uftrace dump --chrome | gzip > ~/qemu_aarch64_git_help.json.gz + +For convenience, you can download this trace `qemu_aarch64_git_help.json.gz +`_. +Download it and open this trace on https://ui.perfetto.dev/. You can zoom = in/out +using w,a,s,d keys. Some sequences taken from this trace: + +- Loading program and its interpreter + +.. image:: https://fileserver.linaro.org/s/fie8JgX76yyL5cq/preview + :height: 200px + +- open syscall + +.. image:: https://fileserver.linaro.org/s/rsXPTeZZPza4PcE/preview + :height: 200px + +- TB creation + +.. image:: https://fileserver.linaro.org/s/GXY6NKMw5EeRCew/preview + :height: 200px + +It's usually better to use ``uftrace record`` directly. However, tracing +binaries through qemu-user can be convenient when you don't want to recomp= ile +them (``uftrace record`` requires instrumentation), as long as symbols are +present. + +Example system trace +++++++++++++++++++++ + +A full trace example (chrome trace, from instructions below) generated fro= m a +system boot can be found `here +`_. +Download it and open this trace on https://ui.perfetto.dev/. You can see c= ode +executed for all privilege levels, and zoom in/out using w,a,s,d keys. You= can +find below some sequences taken from this trace: + +- Two first stages of boot sequence in Arm Trusted Firmware (EL3 and S-EL1) + +.. image:: https://fileserver.linaro.org/s/kkxBS552W7nYESX/preview + :height: 200px + +- U-boot initialization (until code relocation, after which we can't track= it) + +.. image:: https://fileserver.linaro.org/s/LKTgsXNZFi5GFNC/preview + :height: 200px + +- Stat and open syscalls in kernel + +.. image:: https://fileserver.linaro.org/s/dXe4MfraKg2F476/preview + :height: 200px + +- Timer interrupt + +.. image:: https://fileserver.linaro.org/s/TM5yobYzJtP7P3C/preview + :height: 200px + +- Poweroff sequence (from kernel back to firmware, NS-EL2 to EL3) + +.. image:: https://fileserver.linaro.org/s/oR2PtyGKJrqnfRf/preview + :height: 200px + +Build and run system example +++++++++++++++++++++++++++++ + +Building a full system image with frame pointers is not trivial. + +We provide a `simple way `= _ to +build an aarch64 system, combining Arm Trusted firmware, U-boot, Linux ker= nel +and debian userland. It's based on containers (``podman`` only) and +``qemu-user-binfmt`` to make sure it's easily reproducible and does not de= pend +on machine where you build it. + +To build the system:: + + # Install dependencies + $ sudo apt install -y podman qemu-user-binfmt + + $ git clone https://github.com/pbo-linaro/qemu-linux-stack + $ cd qemu-linux-stack + $ ./build.sh + + # system can be started using: + $ ./run.sh /path/to/qemu-system-aarch64 + +To generate a uftrace for a system boot from that:: + + # run true and poweroff the system + $ env INIT=3Dtrue ./run.sh path/to/qemu-system-aarch64 \ + -plugin path/to/contrib/plugins/libuftrace.so,trace-privilege-level= =3Don + + # generate symbols and memory mapping + $ path/to/contrib/plugins/uftrace_symbols.py \ + --prefix-symbols \ + arm-trusted-firmware/build/qemu/debug/bl1/bl1.elf \ + arm-trusted-firmware/build/qemu/debug/bl2/bl2.elf \ + arm-trusted-firmware/build/qemu/debug/bl31/bl31.elf \ + u-boot/u-boot:0x60000000 \ + linux/vmlinux + + # inspect trace with + $ uftrace replay + +Uftrace allows to filter the trace, and dump flamegraphs, or a chrome trac= e. +This last one is very interesting to see visually the boot process:: + + $ uftrace dump --chrome > boot.json + # Open your browser, and load boot.json on https://ui.perfetto.dev/. + +Long visual chrome traces can't be easily opened, thus, it might be +interesting to generate them around a particular point of execution:: + + # execute qemu and timestamp output log + $ env INIT=3Dtrue ./run.sh path/to/qemu-system-aarch64 \ + -plugin path/to/contrib/plugins/libuftrace.so,trace-privilege-level= =3Don,timestamp-based-on-real-time=3Don |& + ts "%s" | tee > exec.log + + $ cat exec.log | grep 'Run /init' + 1753122320 [ 11.834391] Run /init as init process + # init was launched at 1753122320 + + # generate trace around init execution (2 seconds): + $ uftrace dump --chrome --time-range=3D1753122320~1753122322 > init.js= on + Other emulation features ------------------------ =20 diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c index 6709b38918e..10793c292e6 100644 --- a/contrib/plugins/uftrace.c +++ b/contrib/plugins/uftrace.c @@ -4,6 +4,8 @@ * Generates a trace compatible with uftrace (similar to uftrace record). * https://github.com/namhyung/uftrace * + * See docs/about/emulation.rst|Uftrace for details and examples. + * * SPDX-License-Identifier: GPL-2.0-or-later */ =20 --=20 2.47.2