[PATCH 2/3] Implement simple color output
JingPiao Chen
chenjingpiao at gmail.com
Fri Mar 31 11:20:52 UTC 2017
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
More information about the Strace-devel
mailing list