mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-09-13 05:37:14 +00:00
GP-4350: more review-related changes
GP-4350: attempted fix for expression-based bpts GP-4350: working for at least 8+ GP-4350: fix for f.level (working for 10+) GP-4350: good for 11+ GP-4350: good for 11+
This commit is contained in:
parent
9a7ab128df
commit
f2319e61be
|
@ -117,7 +117,7 @@ def get_endian():
|
|||
|
||||
def get_osabi():
|
||||
parm = gdb.parameter('osabi')
|
||||
if not parm in ['auto', 'default']:
|
||||
if not parm in ['', 'auto', 'default']:
|
||||
return parm
|
||||
# We have to hack around the fact the GDB won't give us the current OS ABI
|
||||
# via the API if it is "auto" or "default". Using "show", we can get it, but
|
||||
|
|
|
@ -165,21 +165,22 @@ def cmd(cli_name, mi_name, cli_class, cli_repeat):
|
|||
_CLICmd.__doc__ = func.__doc__
|
||||
_CLICmd()
|
||||
|
||||
class _MICmd(gdb.MICommand):
|
||||
if hasattr(gdb, 'MICommand'):
|
||||
class _MICmd(gdb.MICommand):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(mi_name)
|
||||
def __init__(self):
|
||||
super().__init__(mi_name)
|
||||
|
||||
def invoke(self, argv):
|
||||
try:
|
||||
return func(*argv, is_mi=True)
|
||||
except TypeError as e:
|
||||
raise gdb.GdbError(e.args[0].replace(func.__name__ + "()",
|
||||
mi_name))
|
||||
def invoke(self, argv):
|
||||
try:
|
||||
return func(*argv, is_mi=True)
|
||||
except TypeError as e:
|
||||
raise gdb.GdbError(e.args[0].replace(func.__name__ + "()",
|
||||
mi_name))
|
||||
|
||||
_MICmd.__doc__ = func.__doc__
|
||||
_MICmd()
|
||||
return func
|
||||
_MICmd.__doc__ = func.__doc__
|
||||
_MICmd()
|
||||
return func
|
||||
|
||||
return _cmd
|
||||
|
||||
|
@ -586,7 +587,7 @@ def ghidra_trace_delmem(address, length, *, is_mi, **kwargs):
|
|||
def putreg(frame, reg_descs):
|
||||
inf = gdb.selected_inferior()
|
||||
space = REGS_PATTERN.format(infnum=inf.num, tnum=gdb.selected_thread().num,
|
||||
level=frame.level())
|
||||
level=util.get_level(frame))
|
||||
STATE.trace.create_overlay_space('register', space)
|
||||
cobj = STATE.trace.create_object(space)
|
||||
cobj.insert()
|
||||
|
@ -594,12 +595,12 @@ def putreg(frame, reg_descs):
|
|||
keys = []
|
||||
values = []
|
||||
for desc in reg_descs:
|
||||
v = frame.read_register(desc)
|
||||
v = frame.read_register(desc.name)
|
||||
rv = mapper.map_value(inf, desc.name, v)
|
||||
values.append(rv)
|
||||
# TODO: Key by gdb's name or mapped name? I think gdb's.
|
||||
rpath = REG_PATTERN.format(infnum=inf.num, tnum=gdb.selected_thread(
|
||||
).num, level=frame.level(), regname=desc.name)
|
||||
).num, level=util.get_level(frame), regname=desc.name)
|
||||
keys.append(REG_KEY_PATTERN.format(regname=desc.name))
|
||||
robj = STATE.trace.create_object(rpath)
|
||||
robj.set_value('_value', rv.value)
|
||||
|
@ -621,7 +622,7 @@ def ghidra_trace_putreg(group='all', *, is_mi, **kwargs):
|
|||
STATE.require_tx()
|
||||
frame = gdb.selected_frame()
|
||||
with STATE.client.batch() as b:
|
||||
return putreg(frame, frame.architecture().registers(group))
|
||||
return putreg(frame, util.get_register_descs(frame.architecture(), group))
|
||||
|
||||
|
||||
@cmd('ghidra trace delreg', '-ghidra-trace-delreg', gdb.COMMAND_DATA, True)
|
||||
|
@ -636,11 +637,11 @@ def ghidra_trace_delreg(group='all', *, is_mi, **kwargs):
|
|||
inf = gdb.selected_inferior()
|
||||
frame = gdb.selected_frame()
|
||||
space = 'Inferiors[{}].Threads[{}].Stack[{}].Registers'.format(
|
||||
inf.num, gdb.selected_thread().num, frame.level()
|
||||
inf.num, gdb.selected_thread().num, util.get_level(frame)
|
||||
)
|
||||
mapper = STATE.trace.register_mapper
|
||||
names = []
|
||||
for desc in frame.architecture().registers(group):
|
||||
for desc in util.get_register_descs(frame.architecture(), group):
|
||||
names.append(mapper.map_name(inf, desc.name))
|
||||
return STATE.trace.delete_registers(space, names)
|
||||
|
||||
|
@ -962,7 +963,7 @@ def activate(path=None):
|
|||
else:
|
||||
frame = gdb.selected_frame()
|
||||
path = FRAME_PATTERN.format(
|
||||
infnum=inf.num, tnum=t.num, level=frame.level())
|
||||
infnum=inf.num, tnum=t.num, level=util.get_level(frame))
|
||||
trace.proxy_object_path(path).activate()
|
||||
|
||||
|
||||
|
@ -1402,19 +1403,21 @@ def put_frames():
|
|||
bt = gdb.execute('bt', to_string=True).strip().split('\n')
|
||||
f = newest_frame(gdb.selected_frame())
|
||||
keys = []
|
||||
level = 0
|
||||
while f is not None:
|
||||
fpath = FRAME_PATTERN.format(
|
||||
infnum=inf.num, tnum=t.num, level=f.level())
|
||||
infnum=inf.num, tnum=t.num, level=level)
|
||||
fobj = STATE.trace.create_object(fpath)
|
||||
keys.append(FRAME_KEY_PATTERN.format(level=f.level()))
|
||||
keys.append(FRAME_KEY_PATTERN.format(level=level))
|
||||
base, pc = mapper.map(inf, f.pc())
|
||||
if base != pc.space:
|
||||
STATE.trace.create_overlay_space(base, pc.space)
|
||||
fobj.set_value('_pc', pc)
|
||||
fobj.set_value('_func', str(f.function()))
|
||||
fobj.set_value(
|
||||
'_display', bt[f.level()].strip().replace('\\s+', ' '))
|
||||
'_display', bt[level].strip().replace('\\s+', ' '))
|
||||
f = f.older()
|
||||
level += 1
|
||||
fobj.insert()
|
||||
STATE.trace.proxy_object_path(STACK_PATTERN.format(
|
||||
infnum=inf.num, tnum=t.num)).retain_values(keys)
|
||||
|
|
|
@ -19,7 +19,7 @@ import traceback
|
|||
|
||||
import gdb
|
||||
|
||||
from . import commands
|
||||
from . import commands, util
|
||||
|
||||
|
||||
class GhidraHookPrefix(gdb.Command):
|
||||
|
@ -89,10 +89,10 @@ class InferiorState(object):
|
|||
commands.put_frames()
|
||||
self.visited.add(thread)
|
||||
frame = gdb.selected_frame()
|
||||
hashable_frame = (thread, frame.level())
|
||||
hashable_frame = (thread, util.get_level(frame))
|
||||
if first or hashable_frame not in self.visited:
|
||||
commands.putreg(
|
||||
frame, frame.architecture().registers('general'))
|
||||
frame, util.get_register_descs(frame.architecture(), 'general'))
|
||||
commands.putmem("$pc", "1", from_tty=False)
|
||||
commands.putmem("$sp", "1", from_tty=False)
|
||||
self.visited.add(hashable_frame)
|
||||
|
@ -234,7 +234,7 @@ def on_frame_selected():
|
|||
t = gdb.selected_thread()
|
||||
f = gdb.selected_frame()
|
||||
HOOK_STATE.ensure_batch()
|
||||
with trace.open_tx("Frame {}.{}.{} selected".format(inf.num, t.num, f.level())):
|
||||
with trace.open_tx("Frame {}.{}.{} selected".format(inf.num, t.num, util.get_level(f))):
|
||||
INF_STATES[inf.num].record()
|
||||
commands.activate()
|
||||
|
||||
|
@ -274,7 +274,7 @@ def on_register_changed(event):
|
|||
# For now, just record the lot
|
||||
HOOK_STATE.ensure_batch()
|
||||
with trace.open_tx("Register {} changed".format(event.regnum)):
|
||||
commands.putreg(event.frame, event.frame.architecture().registers())
|
||||
commands.putreg(event.frame, util.get_register_descs(event.frame.architecture()))
|
||||
|
||||
|
||||
@log_errors
|
||||
|
@ -549,8 +549,10 @@ def install_hooks():
|
|||
cont
|
||||
end
|
||||
""")
|
||||
HOOK_STATE.mem_catchpoint = (
|
||||
set(gdb.breakpoints()) - breaks_before).pop()
|
||||
bpts = gdb.breakpoints()
|
||||
# NB: this is unnecessary for gdb 11+
|
||||
if len(bpts) > 0:
|
||||
HOOK_STATE.mem_catchpoint = (set(bpts) - breaks_before).pop()
|
||||
|
||||
gdb.events.cont.connect(on_cont)
|
||||
gdb.events.stop.connect(on_stop)
|
||||
|
|
|
@ -28,17 +28,17 @@ from . import commands, hooks, util
|
|||
@contextmanager
|
||||
def no_pagination():
|
||||
before = gdb.parameter('pagination')
|
||||
gdb.set_parameter('pagination', False)
|
||||
util.set_bool_param('pagination', False)
|
||||
yield
|
||||
gdb.set_parameter('pagination', before)
|
||||
util.set_bool_param('pagination', before)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def no_confirm():
|
||||
before = gdb.parameter('confirm')
|
||||
gdb.set_parameter('confirm', False)
|
||||
util.set_bool_param('confirm', False)
|
||||
yield
|
||||
gdb.set_parameter('confirm', before)
|
||||
util.set_bool_param('confirm', before)
|
||||
|
||||
|
||||
class GdbExecutor(Executor):
|
||||
|
@ -175,7 +175,7 @@ def find_frame_by_level(thread, level):
|
|||
f = gdb.selected_frame()
|
||||
|
||||
# Navigate up or down, because I can't just get by level
|
||||
down = level - f.level()
|
||||
down = level - util.get_level(f)
|
||||
while down > 0:
|
||||
f = f.older()
|
||||
if f is None:
|
||||
|
@ -188,7 +188,6 @@ def find_frame_by_level(thread, level):
|
|||
raise KeyError(
|
||||
f"Inferiors[{thread.inferior.num}].Threads[{thread.num}].Stack[{level}] does not exist")
|
||||
down += 1
|
||||
assert f.level() == level
|
||||
return f
|
||||
|
||||
|
||||
|
@ -215,7 +214,7 @@ def find_frame_by_regs_obj(object):
|
|||
|
||||
# Because there's no method to get a register by name....
|
||||
def find_reg_by_name(f, name):
|
||||
for reg in f.architecture().registers():
|
||||
for reg in util.get_register_descs(f.architecture()):
|
||||
# TODO: gdb appears to be case sensitive, but until we encounter a
|
||||
# situation where case matters, we'll be insensitive
|
||||
if reg.name.lower() == name.lower():
|
||||
|
|
|
@ -289,6 +289,33 @@ class BreakpointLocationInfoReaderV8(object):
|
|||
pass
|
||||
|
||||
def get_locations(self, breakpoint):
|
||||
inf = gdb.selected_inferior()
|
||||
thread_groups = [inf.num]
|
||||
if breakpoint.location is not None and breakpoint.location.startswith("*0x"):
|
||||
address = int(breakpoint.location[1:],16)
|
||||
loc = BreakpointLocation(address, breakpoint.enabled, thread_groups)
|
||||
return [loc]
|
||||
return []
|
||||
|
||||
|
||||
class BreakpointLocationInfoReaderV9(object):
|
||||
def breakpoint_from_line(self, line):
|
||||
pass
|
||||
|
||||
def location_from_line(self, line):
|
||||
pass
|
||||
|
||||
def get_locations(self, breakpoint):
|
||||
inf = gdb.selected_inferior()
|
||||
thread_groups = [inf.num]
|
||||
if breakpoint.location is None:
|
||||
return []
|
||||
try:
|
||||
address = gdb.parse_and_eval(breakpoint.location).address
|
||||
loc = BreakpointLocation(address, breakpoint.enabled, thread_groups)
|
||||
return [loc]
|
||||
except Exception as e:
|
||||
print(f"Error parsing bpt location = {breakpoint.location}")
|
||||
return []
|
||||
|
||||
|
||||
|
@ -298,13 +325,62 @@ class BreakpointLocationInfoReaderV13(object):
|
|||
|
||||
|
||||
def _choose_breakpoint_location_info_reader():
|
||||
if 8 <= GDB_VERSION.major < 13:
|
||||
return BreakpointLocationInfoReaderV8()
|
||||
elif GDB_VERSION.major >= 13:
|
||||
if GDB_VERSION.major >= 13:
|
||||
return BreakpointLocationInfoReaderV13()
|
||||
if GDB_VERSION.major >= 9:
|
||||
return BreakpointLocationInfoReaderV9()
|
||||
if GDB_VERSION.major >= 8:
|
||||
return BreakpointLocationInfoReaderV8()
|
||||
else:
|
||||
raise gdb.GdbError(
|
||||
"GDB version not recognized by ghidragdb: " + GDB_VERSION.full)
|
||||
|
||||
|
||||
BREAKPOINT_LOCATION_INFO_READER = _choose_breakpoint_location_info_reader()
|
||||
|
||||
def set_bool_param_by_api(name, value):
|
||||
gdb.set_parameter(name, value)
|
||||
|
||||
|
||||
def set_bool_param_by_cmd(name, value):
|
||||
val = 'on' if value else 'off'
|
||||
gdb.execute(f'set {name} {val}')
|
||||
|
||||
|
||||
def choose_set_parameter():
|
||||
if GDB_VERSION.major >= 13:
|
||||
return set_bool_param_by_api
|
||||
else:
|
||||
return set_bool_param_by_cmd
|
||||
|
||||
set_bool_param = choose_set_parameter()
|
||||
|
||||
|
||||
def get_level(frame):
|
||||
if hasattr(frame, "level"):
|
||||
return frame.level()
|
||||
else:
|
||||
level = -1;
|
||||
f = frame
|
||||
while f is not None:
|
||||
level += 1
|
||||
f = f.newer()
|
||||
return level
|
||||
|
||||
|
||||
class RegisterDesc(namedtuple('BaseRegisterDesc', ['name'])):
|
||||
pass
|
||||
|
||||
def get_register_descs(arch, group='all'):
|
||||
if hasattr(arch, "registers"):
|
||||
return arch.registers(group)
|
||||
else:
|
||||
descs = []
|
||||
regset = gdb.execute(f"info registers {group}", to_string=True).strip().split('\n')
|
||||
for line in regset:
|
||||
if not line.startswith(" "):
|
||||
tokens = line.strip().split()
|
||||
descs.append(RegisterDesc(tokens[0]))
|
||||
return descs
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue