Color output system call name, return value, error message, fd, address and prefix pid.
* color.h: New file. * Makefile.am (strace_SOURCES): Add color.h. * defs.h (color_attr): New enum. (color_tprintf, color_tprints): New prototype. * syscall.c (trace_syscall_entering): Color output system call name. (trace_syscall_exiting): Color output error msg, return value and fd. * util.c (printfd): Color output fd. (printaddr): Color output address. * strace.1: Document -H option. * strace.c (usage): Likewise. (init): Handle -H option. (color_tprints, color_tprintf): New function. (printleader): Color output prefix pid. (print_event_exit): Color output return value. * NEWS: Mention this. --- Hi, I implement simple color output, it only color output system call name, return value, error message, fd, address and prefix pid, please give me some feedback. Thank you. Makefile.am | 1 + NEWS | 1 + color.h | 29 +++++++++++++++++++++++++++++ defs.h | 14 ++++++++++++++ strace.1 | 5 ++++- strace.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++----- syscall.c | 57 ++++++++++++++++++++++++++++++++++++--------------------- util.c | 9 +++++---- 8 files changed, 140 insertions(+), 31 deletions(-) create mode 100644 color.h diff --git a/Makefile.am b/Makefile.am index 8af709b..d299cbb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,6 +96,7 @@ strace_SOURCES = \ chdir.c \ chmod.c \ clone.c \ + color.h \ copy_file_range.c \ count.c \ defs.h \ diff --git a/NEWS b/NEWS index 5e0941f..5390e8c 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Noteworthy changes in release ?.?? (????-??-??) powerpc, powerpc64, riscv, sh, sh64, sparc, sparc64, tile, x86, and xtensa architectures. * Implemented decoding of statx syscall. + * Implemented color output option. * Updated lists of ioctl commands from Linux 4.11. * Bug fixes diff --git a/color.h b/color.h new file mode 100644 index 0000000..8e58c90 --- /dev/null +++ b/color.h @@ -0,0 +1,29 @@ +#ifndef STRACE_COLOR_H +#define STRACE_COLOR_H + +#define C_CLEAR "\033[0m" +#define C_BOLD "\033[1m" +#define C_HALFBRIGHT "\033[2m" +#define C_UNDERSCORE "\033[4m" +#define C_BLINK "\033[5m" +#define C_REVERSE "\033[7m" + +#define C_BLACK "\033[30m" +#define C_RED "\033[31m" +#define C_GREEN "\033[32m" +#define C_BROWN "\033[33m" +#define C_BLUE "\033[34m" +#define C_MAGENTA "\033[35m" +#define C_CYAN "\033[36m" +#define C_GRAY "\033[37m" + +#define C_DARK_GRAY "\033[1;30m" +#define C_BOLD_RED "\033[1;31m" +#define C_BOLD_GREEN "\033[1;32m" +#define C_BOLD_YELLOW "\033[1;33m" +#define C_BOLD_BLUE "\033[1;34m" +#define C_BOLD_MAGENTA "\033[1;35m" +#define C_BOLD_CYAN "\033[1;36m" +#define C_WHITE "\033[1;37m" + +#endif /* !STRACE_COLOR_H*/ diff --git a/defs.h b/defs.h index 793971e..834ddec 100644 --- a/defs.h +++ b/defs.h @@ -744,6 +744,20 @@ extern void tabto(void); extern void tprintf(const char *fmt, ...) ATTRIBUTE_FORMAT((printf, 1, 2)); extern void tprints(const char *str); +enum color_attr { + COLOR_SYS_NAME, + COLOR_RETURN_VALUE, + COLOR_ERROR_MSG, + COLOR_ADDRESS, + COLOR_PREFIX_PID, + COLOR_FD, + COLOR_CLEAR +}; + +extern void color_tprintf(enum color_attr attr, const char *fmt, ...) + ATTRIBUTE_FORMAT((printf, 2, 3)); +extern void color_tprints(enum color_attr attr, const char *str); + #if SUPPORTED_PERSONALITIES > 1 extern void set_personality(int personality); extern unsigned current_personality; diff --git a/strace.1 b/strace.1 index 9b69ec2..525e13d 100644 --- a/strace.1 +++ b/strace.1 @@ -44,7 +44,7 @@ strace \- trace system calls and signals .SH SYNOPSIS .B strace -[\fB-CdffhikqrtttTvVxxy\fR] +[\fB-CdffhHikqrtttTvVxxy\fR] [\fB-I\fIn\fR] [\fB-b\fIexecve\fR] [\fB-e\fIexpr\fR]... @@ -208,6 +208,9 @@ Here the second argument represents the full set of all signals. .BI "\-a " column Align return values in a specific column (default column 40). .TP +.B \-H +Color output syscall name, return value, error message, fd, address and prefix pid. +.TP .B \-i Print the instruction pointer at the time of the system call. .TP diff --git a/strace.c b/strace.c index 2b50cc0..9c4cbc5 100644 --- a/strace.c +++ b/strace.c @@ -45,6 +45,7 @@ #endif #include <asm/unistd.h> +#include "color.h" #include "scno.h" #include "ptrace.h" #include "printsiginfo.h" @@ -144,6 +145,7 @@ static char *acolumn_spaces; static char *outfname = NULL; /* If -ff, points to stderr. Else, it's our common output log */ static FILE *shared_log; +static bool color_enabled = false; struct tcb *printing_tcp = NULL; static struct tcb *current_tcp; @@ -200,7 +202,7 @@ static void usage(void) { printf("\ -usage: strace [-CdffhiqrtttTvVwxxy] [-I n] [-e expr]...\n\ +usage: strace [-CdffhHiqrtttTvVwxxy] [-I n] [-e expr]...\n\ [-a column] [-o file] [-s strsize] [-P path]...\n\ -p pid... / [-D] [-E var=val]... [-u username] PROG [ARGS]\n\ or: strace -c[dfw] [-I n] [-e expr]... [-O overhead] [-S sortby]\n\ @@ -208,6 +210,7 @@ usage: strace [-CdffhiqrtttTvVwxxy] [-I n] [-e expr]...\n\ \n\ Output format:\n\ -a column alignment COLUMN for printing syscall results (default %d)\n\ + -H color output syscall name, return value, error message, fd, etc.\n\ -i print instruction pointer at time of syscall\n\ " #ifdef USE_LIBUNWIND @@ -592,6 +595,44 @@ tprintf(const char *fmt, ...) va_end(args); } +static const char *colors[] = { + [COLOR_SYS_NAME] = C_BROWN, + [COLOR_RETURN_VALUE] = C_CYAN, + [COLOR_ERROR_MSG] = C_RED, + [COLOR_ADDRESS] = C_MAGENTA, + [COLOR_PREFIX_PID] = C_GRAY, + [COLOR_FD] = C_BLUE, + [COLOR_CLEAR] = C_CLEAR +}; + +void color_tprints(enum color_attr attr, const char *str) +{ + if (color_enabled && isatty(fileno(current_tcp->outf))) { + fprintf(current_tcp->outf, "%s", colors[attr]); + tprints(str); + fprintf(current_tcp->outf, "%s", colors[COLOR_CLEAR]); + } else { + tprints(str); + } +} + +void color_tprintf(enum color_attr attr, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + + if (color_enabled && isatty(fileno(current_tcp->outf))) { + fprintf(current_tcp->outf, "%s", colors[attr]); + vtprintf(fmt, args); + fprintf(current_tcp->outf, "%s", colors[COLOR_CLEAR]); + } else { + vtprintf(fmt, args); + } + + va_end(args); +} + #ifndef HAVE_FPUTS_UNLOCKED # define fputs_unlocked fputs #endif @@ -651,9 +692,9 @@ printleader(struct tcb *tcp) current_tcp->curcol = 0; if (print_pid_pfx) - tprintf("%-5d ", tcp->pid); + color_tprintf(COLOR_PREFIX_PID, "%-5d ", tcp->pid); else if (nprocs > 1 && !outfname) - tprintf("[pid %5u] ", tcp->pid); + color_tprintf(COLOR_PREFIX_PID, "[pid %5u] ", tcp->pid); if (tflag) { char str[sizeof("HH:MM:SS")]; @@ -1612,7 +1653,7 @@ init(int argc, char *argv[]) #endif qualify("signal=all"); while ((c = getopt(argc, argv, - "+b:cCdfFhiqrtTvVwxyz" + "+b:cCdfFhHiqrtTvVwxyz" #ifdef USE_LIBUNWIND "k" #endif @@ -1735,6 +1776,9 @@ init(int argc, char *argv[]) if (opt_intr <= 0) error_opt_arg(c, optarg); break; + case 'H': + color_enabled = true; + break; default: error_msg_and_help(NULL); break; @@ -2222,7 +2266,8 @@ print_event_exit(struct tcb *tcp) } tprints(") "); tabto(); - tprints("= ?\n"); + tprints("= "); + color_tprints(COLOR_RETURN_VALUE, "?\n"); line_ended(); } diff --git a/syscall.c b/syscall.c index 569055f..142e325 100644 --- a/syscall.c +++ b/syscall.c @@ -650,7 +650,9 @@ trace_syscall_entering(struct tcb *tcp, unsigned int *sig) if (res != 1) { printleader(tcp); - tprintf("%s(", scno_good == 1 ? tcp->s_ent->sys_name : "????"); + color_tprintf(COLOR_SYS_NAME, "%s", scno_good == 1 ? + tcp->s_ent->sys_name : "????"); + tprints("("); /* * " <unavailable>" will be added later by the code which * detects ptrace errors. @@ -724,7 +726,8 @@ trace_syscall_entering(struct tcb *tcp, unsigned int *sig) #endif printleader(tcp); - tprintf("%s(", tcp->s_ent->sys_name); + color_tprintf(COLOR_SYS_NAME, "%s", tcp->s_ent->sys_name); + tprints("("); if (tcp->qual_flg & QUAL_RAW) res = printargs(tcp); else @@ -804,7 +807,9 @@ trace_syscall_exiting(struct tcb *tcp) /* There was error in one of prior ptrace ops */ tprints(") "); tabto(); - tprints("= ? <unavailable>\n"); + tprints("= "); + color_tprints(COLOR_RETURN_VALUE, "?"); + tprints(" <unavailable>\n"); line_ended(); tcp->flags &= ~(TCB_INSYSCALL | TCB_TAMPERED); tcp->sys_func_rval = 0; @@ -837,11 +842,14 @@ trace_syscall_exiting(struct tcb *tcp) tabto(); u_error = tcp->u_error; + tprints("= "); if (tcp->qual_flg & QUAL_RAW) { if (u_error) { - tprintf("= -1 (errno %lu)", u_error); + color_tprintf(COLOR_ERROR_MSG, + "-1 (errno %lu)", u_error); } else { - tprintf("= %#" PRI_klx, tcp->u_rval); + color_tprintf(COLOR_RETURN_VALUE, + "%#" PRI_klx, tcp->u_rval); } if (syscall_tampered(tcp)) tprints(" (INJECTED)"); @@ -869,13 +877,15 @@ trace_syscall_exiting(struct tcb *tcp) * The system call will be restarted with the same arguments * if SA_RESTART is set; otherwise, it will fail with EINTR. */ - tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)"); + color_tprints(COLOR_ERROR_MSG, + "? ERESTARTSYS (To be restarted if SA_RESTART is set)"); break; case ERESTARTNOINTR: /* Rare. For example, fork() returns this if interrupted. * SA_RESTART is ignored (assumed set): the restart is unconditional. */ - tprints("= ? ERESTARTNOINTR (To be restarted)"); + color_tprints(COLOR_ERROR_MSG, + "? ERESTARTNOINTR (To be restarted)"); break; case ERESTARTNOHAND: /* pause(), rt_sigsuspend() etc use this code. @@ -885,7 +895,8 @@ trace_syscall_exiting(struct tcb *tcp) * after SIG_IGN or SIG_DFL signal it will restart * (thus the name "restart only if has no handler"). */ - tprints("= ? ERESTARTNOHAND (To be restarted if no handler)"); + color_tprints(COLOR_ERROR_MSG, + "? ERESTARTNOHAND (To be restarted if no handler)"); break; case ERESTART_RESTARTBLOCK: /* Syscalls like nanosleep(), poll() which can't be @@ -899,15 +910,16 @@ trace_syscall_exiting(struct tcb *tcp) * which in turn saves another such restart block, * old data is lost and restart becomes impossible) */ - tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)"); + color_tprints(COLOR_ERROR_MSG, + "? ERESTART_RESTARTBLOCK (Interrupted by signal)"); break; default: u_error_str = err_name(u_error); if (u_error_str) - tprintf("= -1 %s (%s)", + color_tprintf(COLOR_ERROR_MSG, "-1 %s (%s)", u_error_str, strerror(u_error)); else - tprintf("= -1 %lu (%s)", + color_tprintf(COLOR_ERROR_MSG, "-1 %lu (%s)", u_error, strerror(u_error)); break; } @@ -918,45 +930,48 @@ trace_syscall_exiting(struct tcb *tcp) } else { if (sys_res & RVAL_NONE) - tprints("= ?"); + color_tprints(COLOR_RETURN_VALUE, "?"); else { switch (sys_res & RVAL_MASK) { case RVAL_HEX: #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG if (current_wordsize < sizeof(tcp->u_rval)) { - tprintf("= %#x", + color_tprintf(COLOR_RETURN_VALUE, "%#x", (unsigned int) tcp->u_rval); } else #endif { - tprintf("= %#" PRI_klx, tcp->u_rval); + color_tprintf(COLOR_RETURN_VALUE, + "%#" PRI_klx, tcp->u_rval); } break; case RVAL_OCTAL: - tprints("= "); - print_numeric_long_umask(tcp->u_rval); + color_tprintf(COLOR_RETURN_VALUE, + "%#03lo", tcp->u_rval); break; case RVAL_UDECIMAL: #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG if (current_wordsize < sizeof(tcp->u_rval)) { - tprintf("= %u", + color_tprintf(COLOR_RETURN_VALUE, "%u", (unsigned int) tcp->u_rval); } else #endif { - tprintf("= %" PRI_klu, tcp->u_rval); + color_tprintf(COLOR_RETURN_VALUE, + "%" PRI_klu, tcp->u_rval); } break; case RVAL_DECIMAL: - tprintf("= %" PRI_kld, tcp->u_rval); + color_tprintf(COLOR_RETURN_VALUE, + "%" PRI_kld, tcp->u_rval); break; case RVAL_FD: if (show_fd_path) { - tprints("= "); printfd(tcp, tcp->u_rval); } else - tprintf("= %" PRI_kld, tcp->u_rval); + color_tprintf(COLOR_FD, + "%" PRI_kld, tcp->u_rval); break; default: error_msg("invalid rval format"); diff --git a/util.c b/util.c index f05d4ef..7d78121 100644 --- a/util.c +++ b/util.c @@ -453,9 +453,9 @@ void printaddr(const kernel_ulong_t addr) { if (!addr) - tprints("NULL"); + color_tprints(COLOR_ADDRESS, "NULL"); else - tprintf("%#" PRI_klx, addr); + color_tprintf(COLOR_ADDRESS, "%#" PRI_klx, addr); } #define DEF_PRINTNUM(name, type) \ @@ -602,7 +602,8 @@ printfd(struct tcb *tcp, int fd) const size_t socket_prefix_len = sizeof(socket_prefix) - 1; const size_t path_len = strlen(path); - tprintf("%d<", fd); + color_tprintf(COLOR_FD, "%d", fd); + tprints("<"); if (show_fd_path > 1 && strncmp(path, socket_prefix, socket_prefix_len) == 0 && path[path_len - 1] == ']') { @@ -621,7 +622,7 @@ printfd(struct tcb *tcp, int fd) } tprints(">"); } else - tprintf("%d", fd); + color_tprintf(COLOR_FD, "%d", fd); } /* -- 2.7.4 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel