Skip to content

Instantly share code, notes, and snippets.

@stek29
Last active May 1, 2024 15:44
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stek29/cdbbbe018f0aaf0b2a9a58c9173becb8 to your computer and use it in GitHub Desktop.
Save stek29/cdbbbe018f0aaf0b2a9a58c9173becb8 to your computer and use it in GitHub Desktop.
Pretty print x86 (r|e)flags register with lldb script
import lldb
import shlex
FLAGS = [
['CF', 'Carry Flag'],
[None, 'Reserved'],
['PF', 'Parity Flag'],
[None, 'Reserved'],
['AF', 'Adjust Flag'],
[None, 'Reserved'],
['ZF', 'Zero Flag'],
['SF', 'Sign Flag'],
['TF', 'Trap Flag'],
['IF', 'Interrupt Enable Flag'],
['DF', 'Direction Flag'],
['OF', 'Overflow Flag'],
['IOPL_H', 'I/O privilege level High bit'],
['IOPL_L', 'I/O privilege level Low bit'],
['NT', 'Nested Task Flag'],
[None, 'Reserved'],
# eflags
['RF', 'Resume Flag'],
['VM', 'Virtual 8086 mode flag'],
['AC', 'Alignment check'],
['VIF', 'Virtual interrupt flag'],
['VIP', 'Virtual interrupt pending'],
['ID', 'Able to use CPUID instruction'],
# 22-31 reserved
# rflags 32-63 reserved
]
def parse_flags(val):
""" Returns list of set flags """
set_flags = list()
for bit, desc in enumerate(FLAGS):
if val & (1 << bit) and desc[0] is not None:
set_flags.append(desc)
return set_flags
def flag_list_to_str(l):
return ' '.join((desc[0] for desc in l))
def get_flags_reg(frame):
grs = list()
for rs in frame.GetRegisters():
if rs.GetName().lower() == 'general purpose registers':
grs = rs
break
for reg in grs:
if 'flags' in reg.GetName():
return reg
return None
def fmt_lst(fl_reg, lst):
val = fl_reg.GetValueAsUnsigned()
lst = [x.upper() for x in lst]
found = list()
for bit, desc in enumerate(FLAGS):
if desc[0] is not None and desc[0] in lst:
lst.remove(desc[0])
found.append([desc[0], bool(val & (1 << bit))])
ret = list()
# lst must be empty at this point
# anything left wasn't found
if lst:
ret.append('ERROR: Unknown flags: [%s]' % ' '.join(lst))
for x in found:
ret.append('%s: %d'%(x[0], int(x[1])))
return '\n'.join(ret)
def fmt_short(fl_reg):
val = fl_reg.GetValueAsUnsigned()
reg_print_width = fl_reg.GetByteSize() * 2
descs = parse_flags(val)
return ('%s: 0x%.*x [%s]' % (
fl_reg.GetName(), # register name
reg_print_width, # how many hex digits to print
val, # value
flag_list_to_str(descs) # parsed value (list of set flags)
))
def pfl_cmd(debugger, command, result, internal_dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
fl_reg = get_flags_reg(frame)
if fl_reg is None:
print("ERROR: Cant find flags register!")
return
lst = shlex.split(command)
ret = ''
if lst:
# dirty argparse hack
# XXX handle flags and eflags diff for fun? :)
if '-l' in lst:
lst = [desc[0] for desc in FLAGS if desc[0] is not None]
ret = fmt_lst(fl_reg, lst)
else:
ret = fmt_short(fl_reg)
print(ret)
@invokeness
Copy link

how to use it ?

@eihli
Copy link

eihli commented Aug 11, 2022

Save as rflags.py.
Run lldb then run:

(lldb) command script add -f rflags.pfl_cmd pfl
(lldb) pfl
rflags: 0x0000000000000206 [PF IF]

Reference: https://lldb.llvm.org/use/python-reference.html#create-a-new-lldb-command-using-a-python-function

@programmingkidx
Copy link

programmingkidx commented Apr 16, 2024

@eihli I see "error: unable to execute script function" when I enter pfl.
I am using lldb 900.0.64 on Mac OS 10.12.

@therealdreg
Copy link

thx for this code, added to my repo https://github.com/therealdreg/lldb_reversing/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment