from __future__ import print_function
import gdb
import os
import traceback
import re
if sys.version_info > (3,):
long = int
print('Loading gdb scripts for debugging DynamoRIO...')
try:
DR_LIBDIR = os.path.dirname(os.path.abspath(__file__))
except:
DR_LIBDIR = None
class DROption(gdb.Parameter):
def __init__(self, dr_option, param_class):
super(DROption, self).__init__("dr-" + dr_option, gdb.COMMAND_OBSCURE,
param_class)
self.dr_option = dr_option
set_doc = ("DynamoRIO option of the same name.")
show_doc = set_doc
def get_set_string(self):
return str(self.value)
def get_show_string(self, svalue):
return svalue
class DRClient(DROption):
def __init__(self):
super(DRClient, self).__init__("client", gdb.PARAM_OPTIONAL_FILENAME)
set_doc = ("Path to DynamoRIO client to run when invoking DR. "
"Leave blank to run without a client.")
show_doc = set_doc
class DRClientArgs(DROption):
def __init__(self):
super(DRClientArgs, self).__init__("client-args", gdb.PARAM_STRING)
set_doc = ("DynamoRIO client arguments.")
show_doc = set_doc
dr_client = DRClient()
dr_client_args = DRClientArgs()
dr_options = [
DROption('msgbox_mask', gdb.PARAM_ZINTEGER),
DROption('loglevel', gdb.PARAM_ZINTEGER),
DROption('logmask', gdb.PARAM_ZINTEGER),
]
class RunDR(gdb.Command):
"""Run the application under DynamoRIO with the current options.
Goes through the drrun script to avoid depending on the config file format.
"""
def __init__(self):
super(RunDR, self).__init__("rundr", gdb.COMMAND_OBSCURE)
def invoke(self, arg, from_tty):
parts = DR_LIBDIR.split(os.sep)
build_mode = parts[-1]
arch = parts[-2][-2:]
if build_mode not in ('debug', 'release'):
print("Unrecognized build_mode {0}.".format(build_mode))
return
if arch not in ('32', '64'):
print("Unable to find drrun using libdir {0}, unrecognized arch {1}.".format(
DR_LIBDIR, arch))
return
drrun_path = os.sep.join(parts[:-2])
drrun_path = os.path.join(drrun_path, 'bin{0}/drrun'.format(arch))
gdb.execute("set exec-wrapper {0} -{1}".format(drrun_path, build_mode))
env_opts = os.environ.get('DYNAMORIO_OPTIONS', '')
param_opts = ' '.join("-{0} {1}".format(p.dr_option, p.value)
for p in dr_options)
client_opts = ''
if dr_client.value:
client_opts = ('-code_api -client_lib {0};0;{1}'.format(
dr_client.value, dr_client_args.value))
dr_opts = ' '.join([env_opts, param_opts, client_opts])
gdb.execute("set env DYNAMORIO_OPTIONS " + dr_opts)
gdb.execute("run " + arg)
RunDR()
def gdb_has_breakpoints():
match = re.match(r'^(\d+)\.(\d+)', gdb.VERSION)
if not match:
match = re.match(r'.*\s+(\d+)\.(\d+)', gdb.VERSION)
if not match:
print("Error parsing gdb version ({0})".format(gdb.VERSION))
return False
major = int(match.group(1))
minor = int(match.group(2))
if major > 7:
return True
elif major == 7 and minor >= 3:
return True
return False
if gdb_has_breakpoints():
class PrivloadBP(gdb.Breakpoint):
DEBUG = False
DYNAMORIO_BP = True
def __init__(self):
super(PrivloadBP, self).__init__("dr_gdb_add_symbol_file",
internal=not self.DEBUG)
def stop(self):
try:
frame = gdb.newest_frame()
filename = frame.read_var("filename").string()
textaddr = long(frame.read_var("textaddr"))
cmd = "add-symbol-file '{0}' {1}".format(filename, hex(textaddr))
print("Executing gdb command:", cmd)
gdb.execute(cmd, to_string=not self.DEBUG)
return self.DEBUG
except:
traceback.print_exc()
return True
def remove_old_bps():
bps = gdb.breakpoints()
if not bps:
return
for bp in bps:
if getattr(bp, 'DYNAMORIO_BP', False):
bp.delete()
remove_old_bps()
gdb.execute("set breakpoint pending on")
PrivloadBP()
else:
print("This version of gdb does not support breakpoints from Python. "
"Libraries loaded by DynamoRIO will not be automatically "
"registered with gdb.")