You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pwndbg/pwndbg/commands/context.py

192 lines
5.1 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import gdb
import pwndbg.arguments
import pwndbg.chain
import pwndbg.color
import pwndbg.commands
import pwndbg.commands.nearpc
import pwndbg.commands.telescope
import pwndbg.disasm
import pwndbg.events
import pwndbg.ida
import pwndbg.regs
import pwndbg.symbol
import pwndbg.ui
import pwndbg.vmmap
# @pwndbg.events.stop
@pwndbg.commands.Command
@pwndbg.commands.OnlyWhenRunning
def context(*args):
"""
Print out the current register, instruction, and stack context.
"""
if len(args) == 0:
args = ['reg','code','stack','backtrace','args']
args = [a[0] for a in args]
result = []
result.append(pwndbg.color.legend())
if 'r' in args: result.extend(context_regs())
if 'c' in args: result.extend(context_code())
if 'a' in args: result.extend(context_args())
if 's' in args: result.extend(context_stack())
if 'b' in args: result.extend(context_backtrace())
result.extend(context_signal())
for line in result:
print(line)
def context_regs():
result = []
result.append(pwndbg.color.blue(pwndbg.ui.banner("registers")))
result.extend(get_regs())
return result
@pwndbg.commands.Command
@pwndbg.commands.OnlyWhenRunning
def regs(*regs):
print('\n'.join(get_regs(*regs)))
def get_regs(*regs):
result = []
if not regs:
regs = pwndbg.regs.gpr + (pwndbg.regs.frame, pwndbg.regs.current.stack, pwndbg.regs.current.pc)
changed = pwndbg.regs.changed
for reg in regs:
if reg is None:
continue
if reg not in pwndbg.regs:
print("Unknown register: %r" % reg)
continue
value = pwndbg.regs[reg]
# Make the register stand out
regname = pwndbg.color.bold(reg.ljust(4).upper())
# Show a dot next to the register if it changed
m = ' ' if reg not in changed else '*'
result.append("%s%s %s" % (m, regname, pwndbg.chain.format(value)))
return result
def context_code():
banner = [pwndbg.color.blue(pwndbg.ui.banner("code"))]
result = pwndbg.commands.nearpc.nearpc(to_string=True)
# If we didn't disassemble backward, try to make sure
# that the amount of screen space taken is roughly constant.
while len(result) < 11:
result.insert(0, '')
return banner + result
def context_stack():
result = []
result.append(pwndbg.color.blue(pwndbg.ui.banner("stack")))
telescope = pwndbg.commands.telescope.telescope(pwndbg.regs.sp, to_string=True)
if telescope:
result.extend(telescope)
return result
def context_backtrace(frame_count=10, with_banner=True):
result = []
if with_banner:
result.append(pwndbg.color.blue(pwndbg.ui.banner("backtrace")))
this_frame = gdb.selected_frame()
newest_frame = this_frame
oldest_frame = this_frame
for i in range(frame_count):
try:
candidate = oldest_frame.older()
except gdb.MemoryError:
break
if not candidate:
break
oldest_frame = candidate
for i in range(frame_count):
candidate = newest_frame.newer()
if not candidate:
break
newest_frame = candidate
frame = newest_frame
i = 0
while True:
prefix = '> ' if frame == this_frame else ' '
addrsz = pwndbg.ui.addrsz(frame.pc())
symbol = pwndbg.symbol.get(frame.pc())
if symbol:
addrsz = addrsz + ' ' + symbol
line = map(str, (prefix, 'f', i, addrsz))
line = ' '.join(line)
result.append(line)
if frame == oldest_frame:
break
frame = frame.older()
i += 1
return result
def context_args():
result = []
##################################################
# DISABLED FOR NOW, I LIKE INLINE DISPLAY BETTER
##################################################
# # For call instructions, attempt to resolve the target and
# # determine the number of arguments.
# for arg, value in pwndbg.arguments.arguments(pwndbg.disasm.one()):
# code = False if arg.type == 'char' else True
# pretty = pwndbg.chain.format(value, code=code)
# result.append('%-10s %s' % (arg.name+':', pretty))
# if not result:
# return []
# result.insert(0, pwndbg.color.blue(pwndbg.ui.banner("arguments")))
return result
last_signal = []
def save_signal(signal):
global last_signal
last_signal = result = []
if isinstance(signal, gdb.ExitedEvent):
# Booooo old gdb
if hasattr(signal, 'exit_code'):
result.append(pwndbg.color.red('Exited: %r' % signal.exit_code))
elif isinstance(signal, gdb.SignalEvent):
msg = 'Program received signal %s' % signal.stop_signal
msg = pwndbg.color.red(msg)
msg = pwndbg.color.bold(msg)
result.append(msg)
elif isinstance(signal, gdb.BreakpointEvent):
for bkpt in signal.breakpoints:
result.append(pwndbg.color.yellow('Breakpoint %s' % (bkpt.location)))
gdb.events.cont.connect(save_signal)
gdb.events.stop.connect(save_signal)
gdb.events.exited.connect(save_signal)
def context_signal():
return last_signal