Skip to content

Commit b305176

Browse files
erdnaxeyhql
authored andcommitted
utils/color_functions: color only inside atty
Before this patch, piping rainbow output to a file would keep ANSI escape codes, making it harder to read and parse the output. This patch moves pygments highlight function to utils.color_functions and then configures it to only output ANSI colors if isatty is true.
1 parent b1fbf08 commit b305176

2 files changed

Lines changed: 33 additions & 32 deletions

File tree

rainbow/rainbow.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,11 @@
2424
from typing import Callable, Tuple, Optional, List, Dict, Set, Any
2525
import capstone as cs
2626
import unicorn as uc
27-
from pygments import highlight
28-
from pygments.formatters.terminal import TerminalFormatter
29-
from pygments.lexers.asm import NasmLexer
30-
# TODO: Add note about colorama use. Call init in example code.
3127
from unicorn import UcError
3228

3329
from .leakage_models import LeakageModel
3430
from .utils import region_intersects, HookWeakMethod
35-
from .utils.color_functions import color
31+
from .utils.color_functions import color, highlight_asmline
3632
from .loaders import load_selector
3733

3834

@@ -117,10 +113,6 @@ def __init__(self, print_config: Print = Print(0), trace_config: TraceConfig = T
117113
self.last_address = 0
118114
self.trace = []
119115

120-
# Prepare the formatters
121-
self.asm_hl = NasmLexer()
122-
self.asm_fmt = TerminalFormatter(outencoding="utf-8")
123-
124116
# Prepare the emulator and disassembler
125117
self.emu = uc.Uc(self.UC_ARCH, self.UC_MODE)
126118
self.disasm = cs.Cs(self.CS_ARCH, self.CS_MODE)
@@ -402,15 +394,6 @@ def disassemble_single_detailed(self, addr: int, size: int) -> cs.CsInsn:
402394
insn = self.emu.mem_read(addr, 2 * size)
403395
return self._disassemble_cache(self.disasm.disasm, bytes(insn), addr)
404396

405-
def print_asmline(self, adr, ins, op_str):
406-
""" Pretty-print assembly using pygments syntax highlighting """
407-
line = (
408-
highlight(f"{ins:<6} {op_str:<20}", self.asm_hl, self.asm_fmt)
409-
.decode()
410-
.strip("\n")
411-
)
412-
print("\n" + color("YELLOW", f"{adr:8X} ") + line, end=";")
413-
414397
def hook_prolog(self, name, fn):
415398
"""
416399
Add a call to function 'fn' when 'name' is called during execution.
@@ -569,9 +552,9 @@ def _code_hook(self, uci, address, size, _):
569552
if self.print_config & Print.Code:
570553
if ins is None:
571554
adr, size, _ins, op_str = self.disassemble_single(address, size)
572-
self.print_asmline(adr, _ins, op_str)
555+
highlight_asmline(adr, _ins, op_str)
573556
else:
574-
self.print_asmline(address, ins.mnemonic, ins.op_str)
557+
highlight_asmline(address, ins.mnemonic, ins.op_str)
575558

576559
# Handle the register tracing
577560
event = None

rainbow/utils/color_functions.py

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,39 @@
1515
#
1616
#
1717
# Copyright 2019 Victor Servant, Ledger SAS
18+
import sys
1819

19-
_RST = "\u001b[0m"
20-
FOREGROUND_COLORS = {
21-
"BLACK": "\u001b[30m",
22-
"RED": "\u001b[31m",
23-
"GREEN": "\u001b[32m",
24-
"YELLOW": "\u001b[33m",
25-
"BLUE": "\u001b[34m",
26-
"MAGENTA": "\u001b[35m",
27-
"CYAN": "\u001b[36m",
28-
"WHITE": "\u001b[37m",
29-
}
20+
from pygments import highlight
21+
from pygments.formatters import NullFormatter, TerminalFormatter
22+
from pygments.lexers.asm import NasmLexer
23+
24+
# Use colors only if tty support ANSI colors
25+
ASM_HL = NasmLexer()
26+
ASM_FMT = NullFormatter(outencoding="utf-8")
27+
FOREGROUND_COLORS = {}
28+
if sys.stdout.isatty():
29+
ASM_FMT = TerminalFormatter(outencoding="utf-8")
30+
FOREGROUND_COLORS = {
31+
"BLACK": "\u001b[30m",
32+
"RED": "\u001b[31m",
33+
"GREEN": "\u001b[32m",
34+
"YELLOW": "\u001b[33m",
35+
"BLUE": "\u001b[34m",
36+
"MAGENTA": "\u001b[35m",
37+
"CYAN": "\u001b[36m",
38+
"WHITE": "\u001b[37m",
39+
"_RST": "\u001b[0m",
40+
}
3041

3142

3243
def color(color_name: str, x: str) -> str:
3344
"""Color string `x` with color `color_name`"""
3445
color_code = FOREGROUND_COLORS.get(color_name, "")
35-
return f"{color_code}{x}{_RST}"
46+
rst_code = FOREGROUND_COLORS.get("_RST", "")
47+
return f"{color_code}{x}{rst_code}"
48+
49+
50+
def highlight_asmline(addr: int, ins: str, op_str: str):
51+
"""Pretty-print assembly using pygments syntax highlighting"""
52+
line = highlight(f"{ins:<6} {op_str:<20}", ASM_HL, ASM_FMT).decode().strip("\n")
53+
print("\n" + color("YELLOW", f"{addr:8X} ") + line, end=";")

0 commit comments

Comments
 (0)