mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-27 21:55:32 +08:00
Merge remote-tracking branch 'origin/GP-4350_d-millar_backport_gdb_traceRMI--SQUASHED'
This commit is contained in:
@@ -117,7 +117,7 @@ def get_endian():
|
|||||||
|
|
||||||
def get_osabi():
|
def get_osabi():
|
||||||
parm = gdb.parameter('osabi')
|
parm = gdb.parameter('osabi')
|
||||||
if not parm in ['auto', 'default']:
|
if not parm in ['', 'auto', 'default']:
|
||||||
return parm
|
return parm
|
||||||
# We have to hack around the fact the GDB won't give us the current OS ABI
|
# 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
|
# 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.__doc__ = func.__doc__
|
||||||
_CLICmd()
|
_CLICmd()
|
||||||
|
|
||||||
class _MICmd(gdb.MICommand):
|
if hasattr(gdb, 'MICommand'):
|
||||||
|
class _MICmd(gdb.MICommand):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(mi_name)
|
super().__init__(mi_name)
|
||||||
|
|
||||||
def invoke(self, argv):
|
def invoke(self, argv):
|
||||||
try:
|
try:
|
||||||
return func(*argv, is_mi=True)
|
return func(*argv, is_mi=True)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
raise gdb.GdbError(e.args[0].replace(func.__name__ + "()",
|
raise gdb.GdbError(e.args[0].replace(func.__name__ + "()",
|
||||||
mi_name))
|
mi_name))
|
||||||
|
|
||||||
_MICmd.__doc__ = func.__doc__
|
_MICmd.__doc__ = func.__doc__
|
||||||
_MICmd()
|
_MICmd()
|
||||||
return func
|
return func
|
||||||
|
|
||||||
return _cmd
|
return _cmd
|
||||||
|
|
||||||
@@ -586,7 +587,7 @@ def ghidra_trace_delmem(address, length, *, is_mi, **kwargs):
|
|||||||
def putreg(frame, reg_descs):
|
def putreg(frame, reg_descs):
|
||||||
inf = gdb.selected_inferior()
|
inf = gdb.selected_inferior()
|
||||||
space = REGS_PATTERN.format(infnum=inf.num, tnum=gdb.selected_thread().num,
|
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)
|
STATE.trace.create_overlay_space('register', space)
|
||||||
cobj = STATE.trace.create_object(space)
|
cobj = STATE.trace.create_object(space)
|
||||||
cobj.insert()
|
cobj.insert()
|
||||||
@@ -594,12 +595,12 @@ def putreg(frame, reg_descs):
|
|||||||
keys = []
|
keys = []
|
||||||
values = []
|
values = []
|
||||||
for desc in reg_descs:
|
for desc in reg_descs:
|
||||||
v = frame.read_register(desc)
|
v = frame.read_register(desc.name)
|
||||||
rv = mapper.map_value(inf, desc.name, v)
|
rv = mapper.map_value(inf, desc.name, v)
|
||||||
values.append(rv)
|
values.append(rv)
|
||||||
# TODO: Key by gdb's name or mapped name? I think gdb's.
|
# TODO: Key by gdb's name or mapped name? I think gdb's.
|
||||||
rpath = REG_PATTERN.format(infnum=inf.num, tnum=gdb.selected_thread(
|
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))
|
keys.append(REG_KEY_PATTERN.format(regname=desc.name))
|
||||||
robj = STATE.trace.create_object(rpath)
|
robj = STATE.trace.create_object(rpath)
|
||||||
robj.set_value('_value', rv.value)
|
robj.set_value('_value', rv.value)
|
||||||
@@ -621,7 +622,7 @@ def ghidra_trace_putreg(group='all', *, is_mi, **kwargs):
|
|||||||
STATE.require_tx()
|
STATE.require_tx()
|
||||||
frame = gdb.selected_frame()
|
frame = gdb.selected_frame()
|
||||||
with STATE.client.batch() as b:
|
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)
|
@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()
|
inf = gdb.selected_inferior()
|
||||||
frame = gdb.selected_frame()
|
frame = gdb.selected_frame()
|
||||||
space = 'Inferiors[{}].Threads[{}].Stack[{}].Registers'.format(
|
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
|
mapper = STATE.trace.register_mapper
|
||||||
names = []
|
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))
|
names.append(mapper.map_name(inf, desc.name))
|
||||||
return STATE.trace.delete_registers(space, names)
|
return STATE.trace.delete_registers(space, names)
|
||||||
|
|
||||||
@@ -962,7 +963,7 @@ def activate(path=None):
|
|||||||
else:
|
else:
|
||||||
frame = gdb.selected_frame()
|
frame = gdb.selected_frame()
|
||||||
path = FRAME_PATTERN.format(
|
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()
|
trace.proxy_object_path(path).activate()
|
||||||
|
|
||||||
|
|
||||||
@@ -1402,19 +1403,21 @@ def put_frames():
|
|||||||
bt = gdb.execute('bt', to_string=True).strip().split('\n')
|
bt = gdb.execute('bt', to_string=True).strip().split('\n')
|
||||||
f = newest_frame(gdb.selected_frame())
|
f = newest_frame(gdb.selected_frame())
|
||||||
keys = []
|
keys = []
|
||||||
|
level = 0
|
||||||
while f is not None:
|
while f is not None:
|
||||||
fpath = FRAME_PATTERN.format(
|
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)
|
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())
|
base, pc = mapper.map(inf, f.pc())
|
||||||
if base != pc.space:
|
if base != pc.space:
|
||||||
STATE.trace.create_overlay_space(base, pc.space)
|
STATE.trace.create_overlay_space(base, pc.space)
|
||||||
fobj.set_value('_pc', pc)
|
fobj.set_value('_pc', pc)
|
||||||
fobj.set_value('_func', str(f.function()))
|
fobj.set_value('_func', str(f.function()))
|
||||||
fobj.set_value(
|
fobj.set_value(
|
||||||
'_display', bt[f.level()].strip().replace('\\s+', ' '))
|
'_display', bt[level].strip().replace('\\s+', ' '))
|
||||||
f = f.older()
|
f = f.older()
|
||||||
|
level += 1
|
||||||
fobj.insert()
|
fobj.insert()
|
||||||
STATE.trace.proxy_object_path(STACK_PATTERN.format(
|
STATE.trace.proxy_object_path(STACK_PATTERN.format(
|
||||||
infnum=inf.num, tnum=t.num)).retain_values(keys)
|
infnum=inf.num, tnum=t.num)).retain_values(keys)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import traceback
|
|||||||
|
|
||||||
import gdb
|
import gdb
|
||||||
|
|
||||||
from . import commands
|
from . import commands, util
|
||||||
|
|
||||||
|
|
||||||
class GhidraHookPrefix(gdb.Command):
|
class GhidraHookPrefix(gdb.Command):
|
||||||
@@ -89,10 +89,10 @@ class InferiorState(object):
|
|||||||
commands.put_frames()
|
commands.put_frames()
|
||||||
self.visited.add(thread)
|
self.visited.add(thread)
|
||||||
frame = gdb.selected_frame()
|
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:
|
if first or hashable_frame not in self.visited:
|
||||||
commands.putreg(
|
commands.putreg(
|
||||||
frame, frame.architecture().registers('general'))
|
frame, util.get_register_descs(frame.architecture(), 'general'))
|
||||||
commands.putmem("$pc", "1", from_tty=False)
|
commands.putmem("$pc", "1", from_tty=False)
|
||||||
commands.putmem("$sp", "1", from_tty=False)
|
commands.putmem("$sp", "1", from_tty=False)
|
||||||
self.visited.add(hashable_frame)
|
self.visited.add(hashable_frame)
|
||||||
@@ -234,7 +234,7 @@ def on_frame_selected():
|
|||||||
t = gdb.selected_thread()
|
t = gdb.selected_thread()
|
||||||
f = gdb.selected_frame()
|
f = gdb.selected_frame()
|
||||||
HOOK_STATE.ensure_batch()
|
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()
|
INF_STATES[inf.num].record()
|
||||||
commands.activate()
|
commands.activate()
|
||||||
|
|
||||||
@@ -274,7 +274,7 @@ def on_register_changed(event):
|
|||||||
# For now, just record the lot
|
# For now, just record the lot
|
||||||
HOOK_STATE.ensure_batch()
|
HOOK_STATE.ensure_batch()
|
||||||
with trace.open_tx("Register {} changed".format(event.regnum)):
|
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
|
@log_errors
|
||||||
@@ -549,8 +549,10 @@ def install_hooks():
|
|||||||
cont
|
cont
|
||||||
end
|
end
|
||||||
""")
|
""")
|
||||||
HOOK_STATE.mem_catchpoint = (
|
bpts = gdb.breakpoints()
|
||||||
set(gdb.breakpoints()) - breaks_before).pop()
|
# 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.cont.connect(on_cont)
|
||||||
gdb.events.stop.connect(on_stop)
|
gdb.events.stop.connect(on_stop)
|
||||||
|
|||||||
@@ -28,17 +28,17 @@ from . import commands, hooks, util
|
|||||||
@contextmanager
|
@contextmanager
|
||||||
def no_pagination():
|
def no_pagination():
|
||||||
before = gdb.parameter('pagination')
|
before = gdb.parameter('pagination')
|
||||||
gdb.set_parameter('pagination', False)
|
util.set_bool_param('pagination', False)
|
||||||
yield
|
yield
|
||||||
gdb.set_parameter('pagination', before)
|
util.set_bool_param('pagination', before)
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def no_confirm():
|
def no_confirm():
|
||||||
before = gdb.parameter('confirm')
|
before = gdb.parameter('confirm')
|
||||||
gdb.set_parameter('confirm', False)
|
util.set_bool_param('confirm', False)
|
||||||
yield
|
yield
|
||||||
gdb.set_parameter('confirm', before)
|
util.set_bool_param('confirm', before)
|
||||||
|
|
||||||
|
|
||||||
class GdbExecutor(Executor):
|
class GdbExecutor(Executor):
|
||||||
@@ -175,7 +175,7 @@ def find_frame_by_level(thread, level):
|
|||||||
f = gdb.selected_frame()
|
f = gdb.selected_frame()
|
||||||
|
|
||||||
# Navigate up or down, because I can't just get by level
|
# 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:
|
while down > 0:
|
||||||
f = f.older()
|
f = f.older()
|
||||||
if f is None:
|
if f is None:
|
||||||
@@ -188,7 +188,6 @@ def find_frame_by_level(thread, level):
|
|||||||
raise KeyError(
|
raise KeyError(
|
||||||
f"Inferiors[{thread.inferior.num}].Threads[{thread.num}].Stack[{level}] does not exist")
|
f"Inferiors[{thread.inferior.num}].Threads[{thread.num}].Stack[{level}] does not exist")
|
||||||
down += 1
|
down += 1
|
||||||
assert f.level() == level
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
@@ -215,7 +214,7 @@ def find_frame_by_regs_obj(object):
|
|||||||
|
|
||||||
# Because there's no method to get a register by name....
|
# Because there's no method to get a register by name....
|
||||||
def find_reg_by_name(f, 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
|
# TODO: gdb appears to be case sensitive, but until we encounter a
|
||||||
# situation where case matters, we'll be insensitive
|
# situation where case matters, we'll be insensitive
|
||||||
if reg.name.lower() == name.lower():
|
if reg.name.lower() == name.lower():
|
||||||
|
|||||||
@@ -289,6 +289,33 @@ class BreakpointLocationInfoReaderV8(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def get_locations(self, breakpoint):
|
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 []
|
return []
|
||||||
|
|
||||||
|
|
||||||
@@ -298,13 +325,62 @@ class BreakpointLocationInfoReaderV13(object):
|
|||||||
|
|
||||||
|
|
||||||
def _choose_breakpoint_location_info_reader():
|
def _choose_breakpoint_location_info_reader():
|
||||||
if 8 <= GDB_VERSION.major < 13:
|
if GDB_VERSION.major >= 13:
|
||||||
return BreakpointLocationInfoReaderV8()
|
|
||||||
elif GDB_VERSION.major >= 13:
|
|
||||||
return BreakpointLocationInfoReaderV13()
|
return BreakpointLocationInfoReaderV13()
|
||||||
|
if GDB_VERSION.major >= 9:
|
||||||
|
return BreakpointLocationInfoReaderV9()
|
||||||
|
if GDB_VERSION.major >= 8:
|
||||||
|
return BreakpointLocationInfoReaderV8()
|
||||||
else:
|
else:
|
||||||
raise gdb.GdbError(
|
raise gdb.GdbError(
|
||||||
"GDB version not recognized by ghidragdb: " + GDB_VERSION.full)
|
"GDB version not recognized by ghidragdb: " + GDB_VERSION.full)
|
||||||
|
|
||||||
|
|
||||||
BREAKPOINT_LOCATION_INFO_READER = _choose_breakpoint_location_info_reader()
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user