[PATCH] linux-user: Surface more /proc/self/stat fields to the emulated process

Stevie Alvarez posted 1 patch 1 month, 3 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20250918184935.2704752-1-steviea@google.com
Maintainers: Laurent Vivier <laurent@vivier.eu>
linux-user/syscall.c | 93 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 90 insertions(+), 3 deletions(-)
[PATCH] linux-user: Surface more /proc/self/stat fields to the emulated process
Posted by Stevie Alvarez 1 month, 3 weeks ago
From: Shu-Chun Weng <scw@google.com>


Some fields make sense even for the emulated process. Some external
programs/tests might depend on the fields, e.g. starttime.

Signed-off-by: Shu-Chun Weng <scw@google.com>
---
 linux-user/syscall.c | 93 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 3 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 91360a072c..7f3d346902 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8216,15 +8216,99 @@ static int open_self_smaps(CPUArchState *cpu_env, int fd)
     return open_self_maps_1(cpu_env, fd, true);
 }
 
+#define NUM_PROC_SELF_STAT_FIELDS 52
+
+static void read_proc_self_stat(char buf[], int buf_size, const char *fields[])
+{
+    char *p;
+    int i;
+
+    for (i = 0; i < NUM_PROC_SELF_STAT_FIELDS; i++) {
+        fields[i] = NULL;
+    }
+
+    int fd = open("/proc/self/stat", O_RDONLY);
+    if (fd < 0) {
+        return;
+    }
+    i = read(fd, buf, buf_size);
+    close(fd);
+    if (i <= 0) {
+        return;
+    }
+    if (i == buf_size) {
+        buf[buf_size - 1] = '\0';
+    } else {
+        buf[i] = '\0';
+    }
+
+    fields[0] = strtok_r(buf, " \n", &p);
+
+    /*
+     * Get the next field (comm), but don't tokenize -- we'll need to find the
+     * right-most ')' that marks the end of the file name instead.
+     */
+    fields[1] = strtok_r(NULL, "", &p);
+
+    p = strrchr(fields[1], ')');
+    if (!p) {
+        return;
+    }
+    p[1] = '\0';
+
+    fields[2] = strtok_r(p + 2, " \n", &p);
+    for (i = 3; i < NUM_PROC_SELF_STAT_FIELDS; i++) {
+        fields[i] = strtok_r(NULL, " \n", &p);
+    }
+}
+
 static int open_self_stat(CPUArchState *cpu_env, int fd)
 {
     CPUState *cpu = env_cpu(cpu_env);
     TaskState *ts = get_task_state(cpu);
     g_autoptr(GString) buf = g_string_new(NULL);
+    char host_stat_buf[1024];
+    const char *fields[NUM_PROC_SELF_STAT_FIELDS];
+    const int use_host_stat_fields[] = {
+        /*
+         * `man 5 proc` uses 1-based index, so indices here are one less than
+         * on the man page.
+         */
+        0, /* pid */
+        2, /* state */
+        3, /* ppid */
+        4, /* pgrp */
+        5, /* session */
+        6, /* tty_nr */
+        7, /* tpgid */
+        17, /* priority */
+        18, /* nice */
+        21, /* starttime */
+        38, /* processor */
+        39, /* rt_priority */
+        40, /* policy */
+        NUM_PROC_SELF_STAT_FIELDS, /* sentinel */
+    };
+
     int i;
+    const int *next_use_host_stat_field = use_host_stat_fields;
+
+    read_proc_self_stat(host_stat_buf, sizeof(host_stat_buf), fields);
+
+    for (i = 0; i < NUM_PROC_SELF_STAT_FIELDS; i++) {
+        bool may_use_host_stat = i == (*next_use_host_stat_field);
+        if (may_use_host_stat) {
+            ++next_use_host_stat_field;
+        }
 
-    for (i = 0; i < 44; i++) {
-        if (i == 0) {
+        if (may_use_host_stat && fields[i] != NULL && fields[i][0] != '\0') {
+            g_string_printf(buf, "%s ", fields[i]);
+
+            /*
+             * Some systems do not mount /proc so still check for 0 and 3 even
+             * though `may_use_host_stat` is true for them.
+             */
+        } else if (i == 0) {
             /* pid */
             g_string_printf(buf, FMT_pid " ", getpid());
         } else if (i == 1) {
@@ -8259,7 +8343,8 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
             g_string_printf(buf, TARGET_ABI_FMT_ld " ", ts->info->start_stack);
         } else {
             /* for the rest, there is MasterCard */
-            g_string_printf(buf, "0%c", i == 43 ? '\n' : ' ');
+            g_string_printf(buf, "0%c",
+                            i == NUM_PROC_SELF_STAT_FIELDS - 1 ? '\n' : ' ');
         }
 
         if (write(fd, buf->str, buf->len) != buf->len) {
@@ -8270,6 +8355,8 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
     return 0;
 }
 
+#undef NUM_PROC_SELF_STAT_FIELDS
+
 static int open_self_auxv(CPUArchState *cpu_env, int fd)
 {
     CPUState *cpu = env_cpu(cpu_env);
-- 
2.51.0.470.ga7dc726c21-goog