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

Reply via email to