2018-06-04 18:10:57 +00:00
|
|
|
import gdb
|
|
|
|
import re
|
|
|
|
import gdb.printing
|
|
|
|
|
|
|
|
class PuTTYBignumPrettyPrinter(gdb.printing.PrettyPrinter):
|
|
|
|
"Pretty-print PuTTY's Bignum type."
|
|
|
|
name = "Bignum"
|
|
|
|
|
|
|
|
def __init__(self, val):
|
|
|
|
super(PuTTYBignumPrettyPrinter, self).__init__(self.name)
|
|
|
|
self.val = val
|
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
type_BignumInt = gdb.lookup_type("BignumInt")
|
|
|
|
type_BignumIntPtr = type_BignumInt.pointer()
|
|
|
|
BIGNUM_INT_BITS = 8 * type_BignumInt.sizeof
|
|
|
|
array = self.val.cast(type_BignumIntPtr)
|
|
|
|
aget = lambda i: int(array[i]) & ((1 << BIGNUM_INT_BITS)-1)
|
|
|
|
|
|
|
|
try:
|
|
|
|
length = aget(0)
|
|
|
|
value = 0
|
|
|
|
for i in range(length):
|
|
|
|
value |= aget(i+1) << (BIGNUM_INT_BITS * i)
|
|
|
|
return "Bignum({:#x})".format(value)
|
|
|
|
|
|
|
|
except gdb.MemoryError:
|
|
|
|
address = int(array)
|
|
|
|
if address == 0:
|
|
|
|
return "Bignum(NULL)".format(address)
|
|
|
|
return "Bignum(invalid @ {:#x})".format(address)
|
|
|
|
|
|
|
|
rcpp = gdb.printing.RegexpCollectionPrettyPrinter("PuTTY")
|
|
|
|
rcpp.add_printer(PuTTYBignumPrettyPrinter.name, "^Bignum$",
|
|
|
|
PuTTYBignumPrettyPrinter)
|
|
|
|
|
|
|
|
gdb.printing.register_pretty_printer(None, rcpp)
|
2018-06-09 06:52:28 +00:00
|
|
|
|
|
|
|
class MemDumpCommand(gdb.Command):
|
|
|
|
"""Print a hex+ASCII dump of object EXP.
|
|
|
|
|
|
|
|
EXP must be an expression whose value resides in memory. The
|
|
|
|
contents of the memory it occupies are printed in a standard hex
|
|
|
|
dump format, with each line showing an offset relative to the
|
|
|
|
address of EXP, then the hex byte values of the memory at that
|
|
|
|
offset, and then a translation into ASCII of the same bytes (with
|
|
|
|
values outside the printable ASCII range translated as '.').
|
|
|
|
|
|
|
|
To dump a number of bytes from a particular address, it's useful
|
|
|
|
to use the gdb expression extensions {TYPE} and @LENGTH. For
|
|
|
|
example, if 'ptr' and 'len' are variables giving an address and a
|
|
|
|
length in bytes, then the command
|
|
|
|
|
|
|
|
memdump {char} ptr @ len
|
|
|
|
|
|
|
|
will dump the range of memory described by those two variables."""
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
super(MemDumpCommand, self).__init__(
|
|
|
|
"memdump", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION)
|
|
|
|
|
|
|
|
def invoke(self, cmdline, from_tty):
|
|
|
|
expr = gdb.parse_and_eval(cmdline)
|
|
|
|
try:
|
|
|
|
start, size = int(expr.address), expr.type.sizeof
|
|
|
|
except gdb.error as e:
|
|
|
|
sys.stderr.write(str(e))
|
|
|
|
return
|
|
|
|
except (TypeError, AttributeError):
|
|
|
|
sys.stderr.write("expression must identify an object in memory")
|
|
|
|
return
|
|
|
|
|
|
|
|
width = 16
|
|
|
|
line_ptr_type = gdb.lookup_type(
|
|
|
|
"unsigned char").const().array(width).pointer()
|
|
|
|
|
|
|
|
dumpaddr = 0
|
|
|
|
while size > 0:
|
|
|
|
line = gdb.Value(start).cast(line_ptr_type).dereference()
|
|
|
|
thislinelen = min(size, width)
|
|
|
|
start += thislinelen
|
|
|
|
size -= thislinelen
|
|
|
|
|
|
|
|
dumpline = [None, " "] + [" "] * width + [" "] + [""] * width
|
|
|
|
|
|
|
|
dumpline[0] = "{:08x}".format(dumpaddr)
|
|
|
|
dumpaddr += thislinelen
|
|
|
|
|
|
|
|
for i in range(thislinelen):
|
|
|
|
ch = int(line[i]) & 0xFF
|
|
|
|
dumpline[2+i] = " {:02x}".format(ch)
|
|
|
|
dumpline[3+width+i] = chr(ch) if 0x20 <= ch < 0x7F else "."
|
|
|
|
|
|
|
|
sys.stdout.write("".join(dumpline) + "\n")
|
|
|
|
|
|
|
|
MemDumpCommand()
|