linux-user: Add strace support for printing arguments of some clock and time functions

This patch implements strace argument printing functionality for following syscalls:

    * clock_getres, clock_gettime, clock_settime - clock and time functions

        int clock_getres(clockid_t clockid, struct timespec *res)
        int clock_gettime(clockid_t clockid, struct timespec *tp)
        int clock_settime(clockid_t clockid, const struct timespec *tp)
        man page: https://man7.org/linux/man-pages/man2/clock_getres.2.html

    * gettimeofday - get time

        int gettimeofday(struct timeval *tv, struct timezone *tz)
        man page: https://man7.org/linux/man-pages/man2/gettimeofday.2.html

    * getitimer, setitimer - get or set value of an interval timer

        int getitimer(int which, struct itimerval *curr_value)
        int setitimer(int which, const struct itimerval *new_value,
                      struct itimerval *old_value)
        man page: https://man7.org/linux/man-pages/man2/getitimer.2.html

Implementation notes:

    All of the syscalls have some structue types as argument types and thus
    a separate printing function was stated in file "strace.list" for each
    of them. All of these functions use existing functions for their
    appropriate structure types ("print_timeval()" and "print_timezone()").

    Functions "print_timespec()" and "print_itimerval()" were added in this
    patch so that they can be used to print types "struct timespec" and
    "struct itimerval" used by some of the syscalls. Function "print_itimerval()"
    uses the existing function "print_timeval()" to print fields of the
    structure "struct itimerval" that are of type "struct timeval".

    Function "print_enums()", which was introduced in the previous patch, is used
    to print the interval timer type which is the first argument of "getitimer()"
    and "setitimer()". Also, this function is used to print the clock id which
    is the first argument of "clock_getres()" and "clock_gettime()". For that
    reason, the existing function "print_clockid()" was removed in this patch.
    Existing function "print_clock_adjtime()" was also changed for this reason
    to use "print_enums()".

    The existing function "print_timeval()" was changed a little so that it
    prints the field names beside the values.

    Syscalls "clock_getres()" and "clock_gettime()" have the same number
    and types of arguments and thus their print functions "print_clock_getres"
    and "print_clock_gettime" share a common definition in file "strace.c".

Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20200811164553.27713-6-Filip.Bozuta@syrmia.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
Filip Bozuta 2020-08-11 18:45:53 +02:00 committed by Laurent Vivier
parent 45f567994c
commit 1a674adf98
2 changed files with 232 additions and 72 deletions

View File

@ -78,7 +78,9 @@ UNUSED static void print_string(abi_long, int);
UNUSED static void print_buf(abi_long addr, abi_long len, int last); UNUSED static void print_buf(abi_long addr, abi_long len, int last);
UNUSED static void print_raw_param(const char *, abi_long, int); UNUSED static void print_raw_param(const char *, abi_long, int);
UNUSED static void print_timeval(abi_ulong, int); UNUSED static void print_timeval(abi_ulong, int);
UNUSED static void print_timespec(abi_ulong, int);
UNUSED static void print_timezone(abi_ulong, int); UNUSED static void print_timezone(abi_ulong, int);
UNUSED static void print_itimerval(abi_ulong, int);
UNUSED static void print_number(abi_long, int); UNUSED static void print_number(abi_long, int);
UNUSED static void print_signal(abi_ulong, int); UNUSED static void print_signal(abi_ulong, int);
UNUSED static void print_sockaddr(abi_ulong, abi_long, int); UNUSED static void print_sockaddr(abi_ulong, abi_long, int);
@ -582,69 +584,6 @@ print_fdset(int n, abi_ulong target_fds_addr)
} }
#endif #endif
#ifdef TARGET_NR_clock_adjtime
/* IDs of the various system clocks */
#define TARGET_CLOCK_REALTIME 0
#define TARGET_CLOCK_MONOTONIC 1
#define TARGET_CLOCK_PROCESS_CPUTIME_ID 2
#define TARGET_CLOCK_THREAD_CPUTIME_ID 3
#define TARGET_CLOCK_MONOTONIC_RAW 4
#define TARGET_CLOCK_REALTIME_COARSE 5
#define TARGET_CLOCK_MONOTONIC_COARSE 6
#define TARGET_CLOCK_BOOTTIME 7
#define TARGET_CLOCK_REALTIME_ALARM 8
#define TARGET_CLOCK_BOOTTIME_ALARM 9
#define TARGET_CLOCK_SGI_CYCLE 10
#define TARGET_CLOCK_TAI 11
static void
print_clockid(int clockid, int last)
{
switch (clockid) {
case TARGET_CLOCK_REALTIME:
qemu_log("CLOCK_REALTIME");
break;
case TARGET_CLOCK_MONOTONIC:
qemu_log("CLOCK_MONOTONIC");
break;
case TARGET_CLOCK_PROCESS_CPUTIME_ID:
qemu_log("CLOCK_PROCESS_CPUTIME_ID");
break;
case TARGET_CLOCK_THREAD_CPUTIME_ID:
qemu_log("CLOCK_THREAD_CPUTIME_ID");
break;
case TARGET_CLOCK_MONOTONIC_RAW:
qemu_log("CLOCK_MONOTONIC_RAW");
break;
case TARGET_CLOCK_REALTIME_COARSE:
qemu_log("CLOCK_REALTIME_COARSE");
break;
case TARGET_CLOCK_MONOTONIC_COARSE:
qemu_log("CLOCK_MONOTONIC_COARSE");
break;
case TARGET_CLOCK_BOOTTIME:
qemu_log("CLOCK_BOOTTIME");
break;
case TARGET_CLOCK_REALTIME_ALARM:
qemu_log("CLOCK_REALTIME_ALARM");
break;
case TARGET_CLOCK_BOOTTIME_ALARM:
qemu_log("CLOCK_BOOTTIME_ALARM");
break;
case TARGET_CLOCK_SGI_CYCLE:
qemu_log("CLOCK_SGI_CYCLE");
break;
case TARGET_CLOCK_TAI:
qemu_log("CLOCK_TAI");
break;
default:
qemu_log("%d", clockid);
break;
}
qemu_log("%s", get_comma(last));
}
#endif
/* /*
* Sysycall specific output functions * Sysycall specific output functions
*/ */
@ -843,6 +782,81 @@ print_syscall_ret_adjtimex(void *cpu_env, const struct syscallname *name,
} }
#endif #endif
#if defined(TARGET_NR_clock_gettime) || defined(TARGET_NR_clock_getres)
static void
print_syscall_ret_clock_gettime(void *cpu_env, const struct syscallname *name,
abi_long ret, abi_long arg0, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5)
{
if (!print_syscall_err(ret)) {
qemu_log(TARGET_ABI_FMT_ld, ret);
qemu_log(" (");
print_timespec(arg1, 1);
qemu_log(")");
}
qemu_log("\n");
}
#define print_syscall_ret_clock_getres print_syscall_ret_clock_gettime
#endif
#ifdef TARGET_NR_gettimeofday
static void
print_syscall_ret_gettimeofday(void *cpu_env, const struct syscallname *name,
abi_long ret, abi_long arg0, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5)
{
if (!print_syscall_err(ret)) {
qemu_log(TARGET_ABI_FMT_ld, ret);
qemu_log(" (");
print_timeval(arg0, 0);
print_timezone(arg1, 1);
qemu_log(")");
}
qemu_log("\n");
}
#endif
#ifdef TARGET_NR_getitimer
static void
print_syscall_ret_getitimer(void *cpu_env, const struct syscallname *name,
abi_long ret, abi_long arg0, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5)
{
if (!print_syscall_err(ret)) {
qemu_log(TARGET_ABI_FMT_ld, ret);
qemu_log(" (");
print_itimerval(arg1, 1);
qemu_log(")");
}
qemu_log("\n");
}
#endif
#ifdef TARGET_NR_getitimer
static void
print_syscall_ret_setitimer(void *cpu_env, const struct syscallname *name,
abi_long ret, abi_long arg0, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5)
{
if (!print_syscall_err(ret)) {
qemu_log(TARGET_ABI_FMT_ld, ret);
qemu_log(" (old_value = ");
print_itimerval(arg2, 1);
qemu_log(")");
}
qemu_log("\n");
}
#endif
#if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) \ #if defined(TARGET_NR_listxattr) || defined(TARGET_NR_llistxattr) \
|| defined(TARGGET_NR_flistxattr) || defined(TARGGET_NR_flistxattr)
static void static void
@ -1221,6 +1235,43 @@ UNUSED static struct flags mlockall_flags[] = {
FLAG_END, FLAG_END,
}; };
/* IDs of the various system clocks */
#define TARGET_CLOCK_REALTIME 0
#define TARGET_CLOCK_MONOTONIC 1
#define TARGET_CLOCK_PROCESS_CPUTIME_ID 2
#define TARGET_CLOCK_THREAD_CPUTIME_ID 3
#define TARGET_CLOCK_MONOTONIC_RAW 4
#define TARGET_CLOCK_REALTIME_COARSE 5
#define TARGET_CLOCK_MONOTONIC_COARSE 6
#define TARGET_CLOCK_BOOTTIME 7
#define TARGET_CLOCK_REALTIME_ALARM 8
#define TARGET_CLOCK_BOOTTIME_ALARM 9
#define TARGET_CLOCK_SGI_CYCLE 10
#define TARGET_CLOCK_TAI 11
UNUSED static struct enums clockids[] = {
ENUM_TARGET(CLOCK_REALTIME),
ENUM_TARGET(CLOCK_MONOTONIC),
ENUM_TARGET(CLOCK_PROCESS_CPUTIME_ID),
ENUM_TARGET(CLOCK_THREAD_CPUTIME_ID),
ENUM_TARGET(CLOCK_MONOTONIC_RAW),
ENUM_TARGET(CLOCK_REALTIME_COARSE),
ENUM_TARGET(CLOCK_MONOTONIC_COARSE),
ENUM_TARGET(CLOCK_BOOTTIME),
ENUM_TARGET(CLOCK_REALTIME_ALARM),
ENUM_TARGET(CLOCK_BOOTTIME_ALARM),
ENUM_TARGET(CLOCK_SGI_CYCLE),
ENUM_TARGET(CLOCK_TAI),
ENUM_END,
};
UNUSED static struct enums itimer_types[] = {
ENUM_GENERIC(ITIMER_REAL),
ENUM_GENERIC(ITIMER_VIRTUAL),
ENUM_GENERIC(ITIMER_PROF),
ENUM_END,
};
/* /*
* print_xxx utility functions. These are used to print syscall * print_xxx utility functions. These are used to print syscall
* parameters in certain format. All of these have parameter * parameters in certain format. All of these have parameter
@ -1439,13 +1490,34 @@ print_timeval(abi_ulong tv_addr, int last)
print_pointer(tv_addr, last); print_pointer(tv_addr, last);
return; return;
} }
qemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}%s", qemu_log("{tv_sec = " TARGET_ABI_FMT_ld
",tv_usec = " TARGET_ABI_FMT_ld "}%s",
tswapal(tv->tv_sec), tswapal(tv->tv_usec), get_comma(last)); tswapal(tv->tv_sec), tswapal(tv->tv_usec), get_comma(last));
unlock_user(tv, tv_addr, 0); unlock_user(tv, tv_addr, 0);
} else } else
qemu_log("NULL%s", get_comma(last)); qemu_log("NULL%s", get_comma(last));
} }
static void
print_timespec(abi_ulong ts_addr, int last)
{
if (ts_addr) {
struct target_timespec *ts;
ts = lock_user(VERIFY_READ, ts_addr, sizeof(*ts), 1);
if (!ts) {
print_pointer(ts_addr, last);
return;
}
qemu_log("{tv_sec = " TARGET_ABI_FMT_ld
",tv_nsec = " TARGET_ABI_FMT_ld "}%s",
tswapal(ts->tv_sec), tswapal(ts->tv_nsec), get_comma(last));
unlock_user(ts, ts_addr, 0);
} else {
qemu_log("NULL%s", get_comma(last));
}
}
static void static void
print_timezone(abi_ulong tz_addr, int last) print_timezone(abi_ulong tz_addr, int last)
{ {
@ -1465,6 +1537,22 @@ print_timezone(abi_ulong tz_addr, int last)
} }
} }
static void
print_itimerval(abi_ulong it_addr, int last)
{
if (it_addr) {
qemu_log("{it_interval=");
print_timeval(it_addr +
offsetof(struct target_itimerval, it_interval), 0);
qemu_log("it_value=");
print_timeval(it_addr +
offsetof(struct target_itimerval, it_value), 0);
qemu_log("}%s", get_comma(last));
} else {
qemu_log("NULL%s", get_comma(last));
}
}
#undef UNUSED #undef UNUSED
#ifdef TARGET_NR_accept #ifdef TARGET_NR_accept
@ -1577,7 +1665,7 @@ print_clock_adjtime(void *cpu_env, const struct syscallname *name,
abi_long arg3, abi_long arg4, abi_long arg5) abi_long arg3, abi_long arg4, abi_long arg5)
{ {
print_syscall_prologue(name); print_syscall_prologue(name);
print_clockid(arg0, 0); print_enums(clockids, arg0, 0);
print_pointer(arg1, 1); print_pointer(arg1, 1);
print_syscall_epilogue(name); print_syscall_epilogue(name);
} }
@ -1907,6 +1995,19 @@ print_futimesat(void *cpu_env, const struct syscallname *name,
} }
#endif #endif
#ifdef TARGET_NR_gettimeofday
static void
print_gettimeofday(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
print_syscall_prologue(name);
print_pointer(arg0, 0);
print_pointer(arg1, 1);
print_syscall_epilogue(name);
}
#endif
#ifdef TARGET_NR_settimeofday #ifdef TARGET_NR_settimeofday
static void static void
print_settimeofday(void *cpu_env, const struct syscallname *name, print_settimeofday(void *cpu_env, const struct syscallname *name,
@ -1920,6 +2021,60 @@ print_settimeofday(void *cpu_env, const struct syscallname *name,
} }
#endif #endif
#if defined(TARGET_NR_clock_gettime) || defined(TARGET_NR_clock_getres)
static void
print_clock_gettime(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
print_syscall_prologue(name);
print_enums(clockids, arg0, 0);
print_pointer(arg1, 1);
print_syscall_epilogue(name);
}
#define print_clock_getres print_clock_gettime
#endif
#ifdef TARGET_NR_clock_settime
static void
print_clock_settime(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
print_syscall_prologue(name);
print_enums(clockids, arg0, 0);
print_timespec(arg1, 1);
print_syscall_epilogue(name);
}
#endif
#ifdef TARGET_NR_getitimer
static void
print_getitimer(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
print_syscall_prologue(name);
print_enums(itimer_types, arg0, 0);
print_pointer(arg1, 1);
print_syscall_epilogue(name);
}
#endif
#ifdef TARGET_NR_setitimer
static void
print_setitimer(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
print_syscall_prologue(name);
print_enums(itimer_types, arg0, 0);
print_itimerval(arg1, 0);
print_pointer(arg2, 1);
print_syscall_epilogue(name);
}
#endif
#ifdef TARGET_NR_link #ifdef TARGET_NR_link
static void static void
print_link(void *cpu_env, const struct syscallname *name, print_link(void *cpu_env, const struct syscallname *name,

View File

@ -83,16 +83,18 @@
{ TARGET_NR_clock_adjtime, "clock_adjtime" , NULL, print_clock_adjtime, NULL }, { TARGET_NR_clock_adjtime, "clock_adjtime" , NULL, print_clock_adjtime, NULL },
#endif #endif
#ifdef TARGET_NR_clock_getres #ifdef TARGET_NR_clock_getres
{ TARGET_NR_clock_getres, "clock_getres" , NULL, NULL, NULL }, { TARGET_NR_clock_getres, "clock_getres" , NULL, print_clock_getres,
print_syscall_ret_clock_getres },
#endif #endif
#ifdef TARGET_NR_clock_gettime #ifdef TARGET_NR_clock_gettime
{ TARGET_NR_clock_gettime, "clock_gettime" , NULL, NULL, NULL }, { TARGET_NR_clock_gettime, "clock_gettime" , NULL, print_clock_gettime,
print_syscall_ret_clock_gettime },
#endif #endif
#ifdef TARGET_NR_clock_nanosleep #ifdef TARGET_NR_clock_nanosleep
{ TARGET_NR_clock_nanosleep, "clock_nanosleep" , NULL, NULL, NULL }, { TARGET_NR_clock_nanosleep, "clock_nanosleep" , NULL, NULL, NULL },
#endif #endif
#ifdef TARGET_NR_clock_settime #ifdef TARGET_NR_clock_settime
{ TARGET_NR_clock_settime, "clock_settime" , NULL, NULL, NULL }, { TARGET_NR_clock_settime, "clock_settime" , NULL, print_clock_settime, NULL },
#endif #endif
#ifdef TARGET_NR_clone #ifdef TARGET_NR_clone
{ TARGET_NR_clone, "clone" , NULL, print_clone, NULL }, { TARGET_NR_clone, "clone" , NULL, print_clone, NULL },
@ -315,7 +317,8 @@
{ TARGET_NR_gethostname, "gethostname" , NULL, NULL, NULL }, { TARGET_NR_gethostname, "gethostname" , NULL, NULL, NULL },
#endif #endif
#ifdef TARGET_NR_getitimer #ifdef TARGET_NR_getitimer
{ TARGET_NR_getitimer, "getitimer" , NULL, NULL, NULL }, { TARGET_NR_getitimer, "getitimer" , NULL, print_getitimer,
print_syscall_ret_getitimer },
#endif #endif
#ifdef TARGET_NR_get_kernel_syms #ifdef TARGET_NR_get_kernel_syms
{ TARGET_NR_get_kernel_syms, "get_kernel_syms" , NULL, NULL, NULL }, { TARGET_NR_get_kernel_syms, "get_kernel_syms" , NULL, NULL, NULL },
@ -388,7 +391,8 @@
{ TARGET_NR_gettid, "gettid" , "%s()", NULL, NULL }, { TARGET_NR_gettid, "gettid" , "%s()", NULL, NULL },
#endif #endif
#ifdef TARGET_NR_gettimeofday #ifdef TARGET_NR_gettimeofday
{ TARGET_NR_gettimeofday, "gettimeofday" , NULL, NULL, NULL }, { TARGET_NR_gettimeofday, "gettimeofday" , NULL, print_gettimeofday,
print_syscall_ret_gettimeofday },
#endif #endif
#ifdef TARGET_NR_getuid #ifdef TARGET_NR_getuid
{ TARGET_NR_getuid, "getuid" , "%s()", NULL, NULL }, { TARGET_NR_getuid, "getuid" , "%s()", NULL, NULL },
@ -1291,7 +1295,8 @@
{ TARGET_NR_sethostname, "sethostname" , NULL, NULL, NULL }, { TARGET_NR_sethostname, "sethostname" , NULL, NULL, NULL },
#endif #endif
#ifdef TARGET_NR_setitimer #ifdef TARGET_NR_setitimer
{ TARGET_NR_setitimer, "setitimer" , NULL, NULL, NULL }, { TARGET_NR_setitimer, "setitimer" , NULL, print_setitimer,
print_syscall_ret_setitimer },
#endif #endif
#ifdef TARGET_NR_set_mempolicy #ifdef TARGET_NR_set_mempolicy
{ TARGET_NR_set_mempolicy, "set_mempolicy" , NULL, NULL, NULL }, { TARGET_NR_set_mempolicy, "set_mempolicy" , NULL, NULL, NULL },