mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-5511: final review set
GP-5511: post-re-review GP-5511: fix for require_tx bug GP-5511: minor fixes GP-5511: fixups using vscode - something broken GP-5511: finsihing up GP-5511: most things covered GP-5511: commands (first pass) GP-5511: arch
This commit is contained in:
parent
8fcda62c5b
commit
5d4b56b7e4
6 changed files with 526 additions and 554 deletions
|
@ -291,7 +291,7 @@ register_mappers = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def compute_register_mapper(lang):
|
def compute_register_mapper(lang: str)-> DefaultRegisterMapper:
|
||||||
if not lang in register_mappers:
|
if not lang in register_mappers:
|
||||||
if ':BE:' in lang:
|
if ':BE:' in lang:
|
||||||
return DEFAULT_BE_REGISTER_MAPPER
|
return DEFAULT_BE_REGISTER_MAPPER
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
##
|
##
|
||||||
|
from typing import Dict, List, Literal, Optional, Tuple
|
||||||
|
|
||||||
from ghidratrace.client import Address, RegVal
|
from ghidratrace.client import Address, RegVal
|
||||||
import drgn
|
import drgn
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ from . import util
|
||||||
|
|
||||||
|
|
||||||
# NOTE: This map is derived from the ldefs using a script
|
# NOTE: This map is derived from the ldefs using a script
|
||||||
language_map = {
|
language_map: Dict[str, List[str]] = {
|
||||||
'AARCH64': ['AARCH64:BE:64:v8A', 'AARCH64:LE:64:AppleSilicon', 'AARCH64:LE:64:v8A'],
|
'AARCH64': ['AARCH64:BE:64:v8A', 'AARCH64:LE:64:AppleSilicon', 'AARCH64:LE:64:v8A'],
|
||||||
'ARM': ['ARM:BE:32:v8', 'ARM:BE:32:v8T', 'ARM:LE:32:v8', 'ARM:LE:32:v8T'],
|
'ARM': ['ARM:BE:32:v8', 'ARM:BE:32:v8T', 'ARM:LE:32:v8', 'ARM:LE:32:v8T'],
|
||||||
'PPC64': ['PowerPC:BE:64:4xx', 'PowerPC:LE:64:4xx'],
|
'PPC64': ['PowerPC:BE:64:4xx', 'PowerPC:LE:64:4xx'],
|
||||||
|
@ -31,19 +33,19 @@ language_map = {
|
||||||
'UNKNOWN': ['DATA:LE:64:default', 'DATA:LE:64:default'],
|
'UNKNOWN': ['DATA:LE:64:default', 'DATA:LE:64:default'],
|
||||||
}
|
}
|
||||||
|
|
||||||
data64_compiler_map = {
|
data64_compiler_map: Dict[Optional[str], str] = {
|
||||||
None: 'pointer64',
|
None: 'pointer64',
|
||||||
}
|
}
|
||||||
|
|
||||||
default_compiler_map = {
|
default_compiler_map: Dict[Optional[str], str] = {
|
||||||
'Language.C': 'default',
|
'Language.C': 'default',
|
||||||
}
|
}
|
||||||
|
|
||||||
x86_compiler_map = {
|
x86_compiler_map: Dict[Optional[str], str] = {
|
||||||
'Language.C': 'gcc',
|
'Language.C': 'gcc',
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_map = {
|
compiler_map: Dict[str, Dict[Optional[str], str]] = {
|
||||||
'DATA:BE:64:': data64_compiler_map,
|
'DATA:BE:64:': data64_compiler_map,
|
||||||
'DATA:LE:64:': data64_compiler_map,
|
'DATA:LE:64:': data64_compiler_map,
|
||||||
'x86:LE:32:': x86_compiler_map,
|
'x86:LE:32:': x86_compiler_map,
|
||||||
|
@ -56,12 +58,12 @@ compiler_map = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_arch():
|
def get_arch() -> str:
|
||||||
platform = drgn.host_platform
|
platform = drgn.host_platform
|
||||||
return platform.arch.name
|
return platform.arch.name
|
||||||
|
|
||||||
|
|
||||||
def get_endian():
|
def get_endian() -> Literal['little', 'big']:
|
||||||
parm = util.get_convenience_variable('endian')
|
parm = util.get_convenience_variable('endian')
|
||||||
if parm != 'auto':
|
if parm != 'auto':
|
||||||
return parm
|
return parm
|
||||||
|
@ -73,7 +75,7 @@ def get_endian():
|
||||||
return 'big'
|
return 'big'
|
||||||
|
|
||||||
|
|
||||||
def get_size():
|
def get_size() -> str:
|
||||||
parm = util.get_convenience_variable('size')
|
parm = util.get_convenience_variable('size')
|
||||||
if parm != 'auto':
|
if parm != 'auto':
|
||||||
return parm
|
return parm
|
||||||
|
@ -85,11 +87,11 @@ def get_size():
|
||||||
return '32'
|
return '32'
|
||||||
|
|
||||||
|
|
||||||
def get_osabi():
|
def get_osabi() -> str:
|
||||||
return "Language.C"
|
return "Language.C"
|
||||||
|
|
||||||
|
|
||||||
def compute_ghidra_language():
|
def compute_ghidra_language() -> str:
|
||||||
# First, check if the parameter is set
|
# First, check if the parameter is set
|
||||||
lang = util.get_convenience_variable('ghidra-language')
|
lang = util.get_convenience_variable('ghidra-language')
|
||||||
if lang != 'auto':
|
if lang != 'auto':
|
||||||
|
@ -115,7 +117,7 @@ def compute_ghidra_language():
|
||||||
return 'DATA' + lebe + sz + ':default'
|
return 'DATA' + lebe + sz + ':default'
|
||||||
|
|
||||||
|
|
||||||
def compute_ghidra_compiler(lang):
|
def compute_ghidra_compiler(lang: str) -> str:
|
||||||
# First, check if the parameter is set
|
# First, check if the parameter is set
|
||||||
comp = util.get_convenience_variable('ghidra-compiler')
|
comp = util.get_convenience_variable('ghidra-compiler')
|
||||||
if comp != 'auto':
|
if comp != 'auto':
|
||||||
|
@ -145,7 +147,7 @@ def compute_ghidra_compiler(lang):
|
||||||
return 'default'
|
return 'default'
|
||||||
|
|
||||||
|
|
||||||
def compute_ghidra_lcsp():
|
def compute_ghidra_lcsp() -> Tuple[str, str]:
|
||||||
lang = compute_ghidra_language()
|
lang = compute_ghidra_language()
|
||||||
comp = compute_ghidra_compiler(lang)
|
comp = compute_ghidra_compiler(lang)
|
||||||
return lang, comp
|
return lang, comp
|
||||||
|
@ -153,14 +155,14 @@ def compute_ghidra_lcsp():
|
||||||
|
|
||||||
class DefaultMemoryMapper(object):
|
class DefaultMemoryMapper(object):
|
||||||
|
|
||||||
def __init__(self, defaultSpace):
|
def __init__(self, defaultSpace: str) -> None:
|
||||||
self.defaultSpace = defaultSpace
|
self.defaultSpace = defaultSpace
|
||||||
|
|
||||||
def map(self, proc: drgn.Program, offset: int):
|
def map(self, proc: int, offset: int) -> Tuple[str, Address]:
|
||||||
space = self.defaultSpace
|
space = self.defaultSpace
|
||||||
return self.defaultSpace, Address(space, offset)
|
return self.defaultSpace, Address(space, offset)
|
||||||
|
|
||||||
def map_back(self, proc: drgn.Program, address: Address) -> int:
|
def map_back(self, proc: int, address: Address) -> int:
|
||||||
if address.space == self.defaultSpace:
|
if address.space == self.defaultSpace:
|
||||||
return address.offset
|
return address.offset
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -169,10 +171,10 @@ class DefaultMemoryMapper(object):
|
||||||
|
|
||||||
DEFAULT_MEMORY_MAPPER = DefaultMemoryMapper('ram')
|
DEFAULT_MEMORY_MAPPER = DefaultMemoryMapper('ram')
|
||||||
|
|
||||||
memory_mappers = {}
|
memory_mappers: Dict[str, DefaultMemoryMapper] = {}
|
||||||
|
|
||||||
|
|
||||||
def compute_memory_mapper(lang):
|
def compute_memory_mapper(lang: str) -> DefaultMemoryMapper:
|
||||||
if not lang in memory_mappers:
|
if not lang in memory_mappers:
|
||||||
return DEFAULT_MEMORY_MAPPER
|
return DEFAULT_MEMORY_MAPPER
|
||||||
return memory_mappers[lang]
|
return memory_mappers[lang]
|
||||||
|
@ -180,29 +182,29 @@ def compute_memory_mapper(lang):
|
||||||
|
|
||||||
class DefaultRegisterMapper(object):
|
class DefaultRegisterMapper(object):
|
||||||
|
|
||||||
def __init__(self, byte_order):
|
def __init__(self, byte_order: str) -> None:
|
||||||
if not byte_order in ['big', 'little']:
|
if not byte_order in ['big', 'little']:
|
||||||
raise ValueError("Invalid byte_order: {}".format(byte_order))
|
raise ValueError("Invalid byte_order: {}".format(byte_order))
|
||||||
self.byte_order = byte_order
|
self.byte_order = byte_order
|
||||||
self.union_winners = {}
|
|
||||||
|
|
||||||
def map_name(self, proc, name):
|
def map_name(self, proc: int, name: str) -> str:
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def map_value(self, proc, name, value):
|
def map_value(self, proc: int, name: str, value: bytes):
|
||||||
return RegVal(self.map_name(proc, name), value)
|
return RegVal(self.map_name(proc, name), value)
|
||||||
|
|
||||||
def map_name_back(self, proc, name):
|
def map_name_back(self, proc: int, name: str):
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def map_value_back(self, proc, name, value):
|
def map_value_back(self, proc: int, name: str, value: bytes):
|
||||||
return RegVal(self.map_name_back(proc, name), value)
|
return RegVal(self.map_name_back(proc, name), value)
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_BE_REGISTER_MAPPER = DefaultRegisterMapper('big')
|
DEFAULT_BE_REGISTER_MAPPER = DefaultRegisterMapper('big')
|
||||||
DEFAULT_LE_REGISTER_MAPPER = DefaultRegisterMapper('little')
|
DEFAULT_LE_REGISTER_MAPPER = DefaultRegisterMapper('little')
|
||||||
|
|
||||||
def compute_register_mapper(lang):
|
|
||||||
|
def compute_register_mapper(lang: str) -> DefaultRegisterMapper:
|
||||||
if ':BE:' in lang:
|
if ':BE:' in lang:
|
||||||
return DEFAULT_BE_REGISTER_MAPPER
|
return DEFAULT_BE_REGISTER_MAPPER
|
||||||
else:
|
else:
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,45 +13,43 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
##
|
##
|
||||||
|
from dataclasses import dataclass, field
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import drgn
|
import drgn
|
||||||
|
|
||||||
|
from typing import Any, Callable, Collection, Dict, Optional, TypeVar, cast
|
||||||
|
|
||||||
from . import commands, util
|
from . import commands, util
|
||||||
|
|
||||||
|
|
||||||
ALL_EVENTS = 0xFFFF
|
ALL_EVENTS = 0xFFFF
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=False)
|
||||||
class HookState(object):
|
class HookState(object):
|
||||||
__slots__ = ('installed', 'mem_catchpoint')
|
installed = False
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.installed = False
|
|
||||||
self.mem_catchpoint = None
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=False)
|
||||||
class ProcessState(object):
|
class ProcessState(object):
|
||||||
__slots__ = ('first', 'regions', 'modules', 'threads',
|
first = True
|
||||||
'breaks', 'watches', 'visited')
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.first = True
|
|
||||||
# For things we can detect changes to between stops
|
# For things we can detect changes to between stops
|
||||||
self.regions = False
|
regions = False
|
||||||
self.modules = False
|
modules = False
|
||||||
self.threads = False
|
threads = False
|
||||||
self.breaks = False
|
breaks = False
|
||||||
self.watches = False
|
watches = False
|
||||||
# For frames and threads that have already been synced since last stop
|
# For frames and threads that have already been synced since last stop
|
||||||
self.visited = set()
|
visited: set[Any] = field(default_factory=set)
|
||||||
|
|
||||||
def record(self, description=None):
|
def record(self, description: Optional[str] = None) -> None:
|
||||||
first = self.first
|
first = self.first
|
||||||
self.first = False
|
self.first = False
|
||||||
|
trace = commands.STATE.require_trace()
|
||||||
if description is not None:
|
if description is not None:
|
||||||
commands.STATE.trace.snapshot(description)
|
trace.snapshot(description)
|
||||||
if first:
|
if first:
|
||||||
commands.put_processes()
|
commands.put_processes()
|
||||||
commands.put_environment()
|
commands.put_environment()
|
||||||
|
@ -84,51 +82,53 @@ class ProcessState(object):
|
||||||
commands.put_modules()
|
commands.put_modules()
|
||||||
self.modules = False
|
self.modules = False
|
||||||
|
|
||||||
def record_continued(self):
|
def record_continued(self) -> None:
|
||||||
commands.put_processes()
|
commands.put_processes()
|
||||||
commands.put_threads()
|
commands.put_threads()
|
||||||
|
|
||||||
def record_exited(self, exit_code):
|
def record_exited(self, exit_code: int) -> None:
|
||||||
|
trace = commands.STATE.require_trace()
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
ipath = commands.PROCESS_PATTERN.format(procnum=nproc)
|
ipath = commands.PROCESS_PATTERN.format(procnum=nproc)
|
||||||
procobj = commands.STATE.trace.proxy_object_path(ipath)
|
procobj = trace.proxy_object_path(ipath)
|
||||||
procobj.set_value('Exit Code', exit_code)
|
procobj.set_value('Exit Code', exit_code)
|
||||||
procobj.set_value('State', 'TERMINATED')
|
procobj.set_value('State', 'TERMINATED')
|
||||||
|
|
||||||
|
|
||||||
HOOK_STATE = HookState()
|
HOOK_STATE = HookState()
|
||||||
PROC_STATE = {}
|
PROC_STATE: Dict[int, ProcessState] = {}
|
||||||
|
|
||||||
def on_new_process(event):
|
|
||||||
|
def on_new_process(id: int) -> None:
|
||||||
trace = commands.STATE.trace
|
trace = commands.STATE.trace
|
||||||
if trace is None:
|
if trace is None:
|
||||||
return
|
return
|
||||||
with commands.STATE.client.batch():
|
with trace.client.batch():
|
||||||
with trace.open_tx("New Process {}".format(event.process.num)):
|
with trace.open_tx("New Process {}".format(id)):
|
||||||
commands.put_processes() # TODO: Could put just the one....
|
commands.put_processes() # TODO: Could put just the one....
|
||||||
|
|
||||||
|
|
||||||
def on_process_selected():
|
def on_process_selected() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc not in PROC_STATE:
|
if nproc not in PROC_STATE:
|
||||||
return
|
return
|
||||||
trace = commands.STATE.trace
|
trace = commands.STATE.trace
|
||||||
if trace is None:
|
if trace is None:
|
||||||
return
|
return
|
||||||
with commands.STATE.client.batch():
|
with trace.client.batch():
|
||||||
with trace.open_tx("Process {} selected".format(nproc)):
|
with trace.open_tx("Process {} selected".format(nproc)):
|
||||||
PROC_STATE[nproc].record()
|
PROC_STATE[nproc].record()
|
||||||
commands.activate()
|
commands.activate()
|
||||||
|
|
||||||
|
|
||||||
def on_new_thread(event):
|
def on_new_thread() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc not in PROC_STATE:
|
if nproc not in PROC_STATE:
|
||||||
return
|
return
|
||||||
PROC_STATE[nproc].threads = True
|
PROC_STATE[nproc].threads = True
|
||||||
|
|
||||||
|
|
||||||
def on_thread_selected():
|
def on_thread_selected() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc not in PROC_STATE:
|
if nproc not in PROC_STATE:
|
||||||
return
|
return
|
||||||
|
@ -136,14 +136,14 @@ def on_thread_selected():
|
||||||
if trace is None:
|
if trace is None:
|
||||||
return
|
return
|
||||||
nthrd = util.selected_thread()
|
nthrd = util.selected_thread()
|
||||||
with commands.STATE.client.batch():
|
with trace.client.batch():
|
||||||
with trace.open_tx("Thread {}.{} selected".format(nproc, nthrd)):
|
with trace.open_tx("Thread {}.{} selected".format(nproc, nthrd)):
|
||||||
PROC_STATE[nproc].record()
|
PROC_STATE[nproc].record()
|
||||||
commands.put_threads()
|
commands.put_threads()
|
||||||
commands.activate()
|
commands.activate()
|
||||||
|
|
||||||
|
|
||||||
def on_frame_selected():
|
def on_frame_selected() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc not in PROC_STATE:
|
if nproc not in PROC_STATE:
|
||||||
return
|
return
|
||||||
|
@ -152,7 +152,7 @@ def on_frame_selected():
|
||||||
return
|
return
|
||||||
nthrd = util.selected_thread()
|
nthrd = util.selected_thread()
|
||||||
level = util.selected_frame()
|
level = util.selected_frame()
|
||||||
with commands.STATE.client.batch():
|
with trace.client.batch():
|
||||||
with trace.open_tx("Frame {}.{}.{} selected".format(nproc, nthrd, level)):
|
with trace.open_tx("Frame {}.{}.{} selected".format(nproc, nthrd, level)):
|
||||||
PROC_STATE[nproc].record()
|
PROC_STATE[nproc].record()
|
||||||
commands.put_threads()
|
commands.put_threads()
|
||||||
|
@ -160,32 +160,7 @@ def on_frame_selected():
|
||||||
commands.activate()
|
commands.activate()
|
||||||
|
|
||||||
|
|
||||||
def on_memory_changed(event):
|
def on_cont() -> None:
|
||||||
nproc = util.get_process()
|
|
||||||
if nproc not in PROC_STATE:
|
|
||||||
return
|
|
||||||
trace = commands.STATE.trace
|
|
||||||
if trace is None:
|
|
||||||
return
|
|
||||||
with commands.STATE.client.batch():
|
|
||||||
with trace.open_tx("Memory *0x{:08x} changed".format(event.address)):
|
|
||||||
commands.put_bytes(event.address, event.address + event.length,
|
|
||||||
pages=False, is_mi=False, result=None)
|
|
||||||
|
|
||||||
|
|
||||||
def on_register_changed(event):
|
|
||||||
nproc = util.get_process()
|
|
||||||
if nproc not in PROC_STATE:
|
|
||||||
return
|
|
||||||
trace = commands.STATE.trace
|
|
||||||
if trace is None:
|
|
||||||
return
|
|
||||||
with commands.STATE.client.batch():
|
|
||||||
with trace.open_tx("Register {} changed".format(event.regnum)):
|
|
||||||
commands.putreg()
|
|
||||||
|
|
||||||
|
|
||||||
def on_cont(event):
|
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc not in PROC_STATE:
|
if nproc not in PROC_STATE:
|
||||||
return
|
return
|
||||||
|
@ -193,12 +168,12 @@ def on_cont(event):
|
||||||
if trace is None:
|
if trace is None:
|
||||||
return
|
return
|
||||||
state = PROC_STATE[nproc]
|
state = PROC_STATE[nproc]
|
||||||
with commands.STATE.client.batch():
|
with trace.client.batch():
|
||||||
with trace.open_tx("Continued"):
|
with trace.open_tx("Continued"):
|
||||||
state.record_continued()
|
state.record_continued()
|
||||||
|
|
||||||
|
|
||||||
def on_stop(event):
|
def on_stop() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc not in PROC_STATE:
|
if nproc not in PROC_STATE:
|
||||||
PROC_STATE[nproc] = ProcessState()
|
PROC_STATE[nproc] = ProcessState()
|
||||||
|
@ -208,7 +183,7 @@ def on_stop(event):
|
||||||
return
|
return
|
||||||
state = PROC_STATE[nproc]
|
state = PROC_STATE[nproc]
|
||||||
state.visited.clear()
|
state.visited.clear()
|
||||||
with commands.STATE.client.batch():
|
with trace.client.batch():
|
||||||
with trace.open_tx("Stopped"):
|
with trace.open_tx("Stopped"):
|
||||||
state.record("Stopped")
|
state.record("Stopped")
|
||||||
commands.put_threads()
|
commands.put_threads()
|
||||||
|
@ -216,34 +191,31 @@ def on_stop(event):
|
||||||
commands.activate()
|
commands.activate()
|
||||||
|
|
||||||
|
|
||||||
def modules_changed():
|
def modules_changed() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc not in PROC_STATE:
|
if nproc not in PROC_STATE:
|
||||||
return
|
return
|
||||||
PROC_STATE[nproc].modules = True
|
PROC_STATE[nproc].modules = True
|
||||||
|
|
||||||
|
|
||||||
def install_hooks():
|
def install_hooks() -> None:
|
||||||
if HOOK_STATE.installed:
|
if HOOK_STATE.installed:
|
||||||
return
|
return
|
||||||
HOOK_STATE.installed = True
|
HOOK_STATE.installed = True
|
||||||
|
|
||||||
event_thread = EventThread()
|
|
||||||
event_thread.start()
|
|
||||||
|
|
||||||
|
def remove_hooks() -> None:
|
||||||
def remove_hooks():
|
|
||||||
if not HOOK_STATE.installed:
|
if not HOOK_STATE.installed:
|
||||||
return
|
return
|
||||||
HOOK_STATE.installed = False
|
HOOK_STATE.installed = False
|
||||||
|
|
||||||
|
|
||||||
def enable_current_process():
|
def enable_current_process() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
PROC_STATE[nproc] = ProcessState()
|
PROC_STATE[nproc] = ProcessState()
|
||||||
|
|
||||||
|
|
||||||
def disable_current_process():
|
def disable_current_process() -> None:
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
if nproc in PROC_STATE:
|
if nproc in PROC_STATE:
|
||||||
del PROC_STATE[nproc]
|
del PROC_STATE[nproc]
|
||||||
|
|
|
@ -19,10 +19,11 @@ from io import StringIO
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from typing import Annotated, Any, Dict, Optional
|
from typing import Annotated, Any, Dict, Optional, Tuple
|
||||||
|
|
||||||
import drgn
|
import drgn
|
||||||
import drgn.cli
|
import drgn.cli
|
||||||
|
from drgn import Module, StackFrame # type: ignore
|
||||||
|
|
||||||
from ghidratrace import sch
|
from ghidratrace import sch
|
||||||
from ghidratrace.client import (
|
from ghidratrace.client import (
|
||||||
|
@ -35,159 +36,22 @@ REGISTRY = MethodRegistry(ThreadPoolExecutor(
|
||||||
max_workers=1, thread_name_prefix='MethodRegistry'))
|
max_workers=1, thread_name_prefix='MethodRegistry'))
|
||||||
|
|
||||||
|
|
||||||
def extre(base, ext):
|
def extre(base, ext) -> re.Pattern:
|
||||||
return re.compile(base.pattern + ext)
|
return re.compile(base.pattern + ext)
|
||||||
|
|
||||||
|
|
||||||
PROCESSES_PATTERN = re.compile('Processes')
|
PROCESSES_PATTERN = re.compile('Processes')
|
||||||
PROCESS_PATTERN = extre(PROCESSES_PATTERN, '\[(?P<procnum>\\d*)\]')
|
PROCESS_PATTERN = extre(PROCESSES_PATTERN, '\\[(?P<procnum>\\d*)\\]')
|
||||||
ENV_PATTERN = extre(PROCESS_PATTERN, '\.Environment')
|
ENV_PATTERN = extre(PROCESS_PATTERN, '\\.Environment')
|
||||||
THREADS_PATTERN = extre(PROCESS_PATTERN, '\.Threads')
|
THREADS_PATTERN = extre(PROCESS_PATTERN, '\\.Threads')
|
||||||
THREAD_PATTERN = extre(THREADS_PATTERN, '\[(?P<tnum>\\d*)\]')
|
THREAD_PATTERN = extre(THREADS_PATTERN, '\\[(?P<tnum>\\d*)\\]')
|
||||||
STACK_PATTERN = extre(THREAD_PATTERN, '\.Stack')
|
STACK_PATTERN = extre(THREAD_PATTERN, '\\.Stack')
|
||||||
FRAME_PATTERN = extre(STACK_PATTERN, '\[(?P<level>\\d*)\]')
|
FRAME_PATTERN = extre(STACK_PATTERN, '\\[(?P<level>\\d*)\\]')
|
||||||
REGS_PATTERN = extre(FRAME_PATTERN, '.Registers')
|
REGS_PATTERN = extre(FRAME_PATTERN, '.Registers')
|
||||||
LOCALS_PATTERN = extre(FRAME_PATTERN, '.Locals')
|
LOCALS_PATTERN = extre(FRAME_PATTERN, '.Locals')
|
||||||
MEMORY_PATTERN = extre(PROCESS_PATTERN, '\.Memory')
|
MEMORY_PATTERN = extre(PROCESS_PATTERN, '\\.Memory')
|
||||||
MODULES_PATTERN = extre(PROCESS_PATTERN, '\.Modules')
|
MODULES_PATTERN = extre(PROCESS_PATTERN, '\\.Modules')
|
||||||
MODULE_PATTERN = extre(MODULES_PATTERN, '\[(?P<modbase>.*)\]')
|
MODULE_PATTERN = extre(MODULES_PATTERN, '\\[(?P<modbase>.*)\\]')
|
||||||
|
|
||||||
|
|
||||||
def find_availpid_by_pattern(pattern, object, err_msg):
|
|
||||||
mat = pattern.fullmatch(object.path)
|
|
||||||
if mat is None:
|
|
||||||
raise TypeError(f"{object} is not {err_msg}")
|
|
||||||
pid = int(mat['pid'])
|
|
||||||
return pid
|
|
||||||
|
|
||||||
|
|
||||||
def find_availpid_by_obj(object):
|
|
||||||
return find_availpid_by_pattern(AVAILABLE_PATTERN, object, "an Available")
|
|
||||||
|
|
||||||
|
|
||||||
def find_proc_by_num(id):
|
|
||||||
if id != util.selected_process():
|
|
||||||
util.select_process(id)
|
|
||||||
return util.selected_process()
|
|
||||||
|
|
||||||
|
|
||||||
def find_proc_by_pattern(object, pattern, err_msg):
|
|
||||||
mat = pattern.fullmatch(object.path)
|
|
||||||
if mat is None:
|
|
||||||
raise TypeError(f"{object} is not {err_msg}")
|
|
||||||
procnum = int(mat['procnum'])
|
|
||||||
return find_proc_by_num(procnum)
|
|
||||||
|
|
||||||
|
|
||||||
def find_proc_by_obj(object):
|
|
||||||
return find_proc_by_pattern(object, PROCESS_PATTERN, "an Process")
|
|
||||||
|
|
||||||
|
|
||||||
def find_proc_by_env_obj(object):
|
|
||||||
return find_proc_by_pattern(object, ENV_PATTERN, "an Environment")
|
|
||||||
|
|
||||||
|
|
||||||
def find_proc_by_threads_obj(object):
|
|
||||||
return find_proc_by_pattern(object, THREADS_PATTERN, "a ThreadContainer")
|
|
||||||
|
|
||||||
|
|
||||||
def find_proc_by_mem_obj(object):
|
|
||||||
return find_proc_by_pattern(object, MEMORY_PATTERN, "a Memory")
|
|
||||||
|
|
||||||
|
|
||||||
def find_proc_by_modules_obj(object):
|
|
||||||
return find_proc_by_pattern(object, MODULES_PATTERN, "a ModuleContainer")
|
|
||||||
|
|
||||||
|
|
||||||
def find_thread_by_num(id):
|
|
||||||
if id != util.selected_thread():
|
|
||||||
util.select_thread(id)
|
|
||||||
return util.selected_thread()
|
|
||||||
|
|
||||||
|
|
||||||
def find_thread_by_pattern(pattern, object, err_msg):
|
|
||||||
mat = pattern.fullmatch(object.path)
|
|
||||||
if mat is None:
|
|
||||||
raise TypeError(f"{object} is not {err_msg}")
|
|
||||||
pnum = int(mat['procnum'])
|
|
||||||
tnum = int(mat['tnum'])
|
|
||||||
find_proc_by_num(pnum)
|
|
||||||
return find_thread_by_num(tnum)
|
|
||||||
|
|
||||||
|
|
||||||
def find_thread_by_obj(object):
|
|
||||||
return find_thread_by_pattern(THREAD_PATTERN, object, "a Thread")
|
|
||||||
|
|
||||||
|
|
||||||
def find_thread_by_stack_obj(object):
|
|
||||||
return find_thread_by_pattern(STACK_PATTERN, object, "a Stack")
|
|
||||||
|
|
||||||
|
|
||||||
def find_thread_by_regs_obj(object):
|
|
||||||
return find_thread_by_pattern(REGS_PATTERN, object, "a RegisterValueContainer")
|
|
||||||
|
|
||||||
|
|
||||||
def find_frame_by_level(level):
|
|
||||||
tnum = util.selected_thread()
|
|
||||||
thread = commands.prog.thread(tnum)
|
|
||||||
try:
|
|
||||||
frames = thread.stack_trace()
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return
|
|
||||||
|
|
||||||
for i, f in enumerate(frames):
|
|
||||||
if i == level:
|
|
||||||
if i != util.selected_frame():
|
|
||||||
util.select_frame(i)
|
|
||||||
return i, f
|
|
||||||
|
|
||||||
|
|
||||||
def find_frame_by_pattern(pattern, object, err_msg):
|
|
||||||
mat = pattern.fullmatch(object.path)
|
|
||||||
if mat is None:
|
|
||||||
raise TypeError(f"{object} is not {err_msg}")
|
|
||||||
pnum = int(mat['procnum'])
|
|
||||||
tnum = int(mat['tnum'])
|
|
||||||
level = int(mat['level'])
|
|
||||||
find_proc_by_num(pnum)
|
|
||||||
find_thread_by_num(tnum)
|
|
||||||
return find_frame_by_level(level)
|
|
||||||
|
|
||||||
|
|
||||||
def find_frame_by_obj(object):
|
|
||||||
return find_frame_by_pattern(FRAME_PATTERN, object, "a StackFrame")
|
|
||||||
|
|
||||||
|
|
||||||
def find_frame_by_regs_obj(object):
|
|
||||||
return find_frame_by_pattern(REGS_PATTERN, object, "a RegisterValueContainer")
|
|
||||||
|
|
||||||
|
|
||||||
def find_frame_by_locals_obj(object):
|
|
||||||
return find_frame_by_pattern(LOCALS_PATTERN, object, "a LocalsContainer")
|
|
||||||
|
|
||||||
|
|
||||||
def find_module_by_base(modbase):
|
|
||||||
for m in commands.prog.modules():
|
|
||||||
if modbase == str(hex(m.address_range[0])):
|
|
||||||
return m
|
|
||||||
|
|
||||||
|
|
||||||
def find_module_by_pattern(pattern, object, err_msg):
|
|
||||||
mat = pattern.fullmatch(object.path)
|
|
||||||
if mat is None:
|
|
||||||
raise TypeError(f"{object} is not {err_msg}")
|
|
||||||
pnum = int(mat['procnum'])
|
|
||||||
modbase = mat['modbase']
|
|
||||||
find_proc_by_num(pnum)
|
|
||||||
return find_module_by_base(modbase)
|
|
||||||
|
|
||||||
|
|
||||||
def find_module_by_obj(object):
|
|
||||||
return find_module_by_pattern(MODULE_PATTERN, object, "a Module")
|
|
||||||
|
|
||||||
|
|
||||||
shared_globals: Dict[str, Any] = dict()
|
|
||||||
|
|
||||||
|
|
||||||
class Environment(TraceObject):
|
class Environment(TraceObject):
|
||||||
|
@ -222,10 +86,6 @@ class RegisterValueContainer(TraceObject):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StackFrame(TraceObject):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class SymbolContainer(TraceObject):
|
class SymbolContainer(TraceObject):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -238,6 +98,136 @@ class ThreadContainer(TraceObject):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def find_proc_by_num(id: int) -> int:
|
||||||
|
if id != util.selected_process():
|
||||||
|
util.select_process(id)
|
||||||
|
return util.selected_process()
|
||||||
|
|
||||||
|
|
||||||
|
def find_proc_by_pattern(object: TraceObject, pattern: re.Pattern,
|
||||||
|
err_msg: str) -> int:
|
||||||
|
mat = pattern.fullmatch(object.path)
|
||||||
|
if mat is None:
|
||||||
|
raise TypeError(f"{object} is not {err_msg}")
|
||||||
|
procnum = int(mat['procnum'])
|
||||||
|
return find_proc_by_num(procnum)
|
||||||
|
|
||||||
|
|
||||||
|
def find_proc_by_obj(object: TraceObject) -> int:
|
||||||
|
return find_proc_by_pattern(object, PROCESS_PATTERN, "an Process")
|
||||||
|
|
||||||
|
|
||||||
|
def find_proc_by_env_obj(object: TraceObject) -> int:
|
||||||
|
return find_proc_by_pattern(object, ENV_PATTERN, "an Environment")
|
||||||
|
|
||||||
|
|
||||||
|
def find_proc_by_threads_obj(object: TraceObject) -> int:
|
||||||
|
return find_proc_by_pattern(object, THREADS_PATTERN, "a ThreadContainer")
|
||||||
|
|
||||||
|
|
||||||
|
def find_proc_by_mem_obj(object: TraceObject) -> int:
|
||||||
|
return find_proc_by_pattern(object, MEMORY_PATTERN, "a Memory")
|
||||||
|
|
||||||
|
|
||||||
|
def find_proc_by_modules_obj(object: TraceObject) -> int:
|
||||||
|
return find_proc_by_pattern(object, MODULES_PATTERN, "a ModuleContainer")
|
||||||
|
|
||||||
|
|
||||||
|
def find_thread_by_num(id: int) -> Optional[int]:
|
||||||
|
if id != util.selected_thread():
|
||||||
|
util.select_thread(id)
|
||||||
|
return util.selected_thread()
|
||||||
|
|
||||||
|
|
||||||
|
def find_thread_by_pattern(pattern: re.Pattern, object: TraceObject,
|
||||||
|
err_msg: str) -> Optional[int]:
|
||||||
|
mat = pattern.fullmatch(object.path)
|
||||||
|
if mat is None:
|
||||||
|
raise TypeError(f"{object} is not {err_msg}")
|
||||||
|
pnum = int(mat['procnum'])
|
||||||
|
tnum = int(mat['tnum'])
|
||||||
|
find_proc_by_num(pnum)
|
||||||
|
return find_thread_by_num(tnum)
|
||||||
|
|
||||||
|
|
||||||
|
def find_thread_by_obj(object: TraceObject) -> Optional[int]:
|
||||||
|
return find_thread_by_pattern(THREAD_PATTERN, object, "a Thread")
|
||||||
|
|
||||||
|
|
||||||
|
def find_thread_by_stack_obj(object: TraceObject) -> Optional[int]:
|
||||||
|
return find_thread_by_pattern(STACK_PATTERN, object, "a Stack")
|
||||||
|
|
||||||
|
|
||||||
|
def find_thread_by_regs_obj(object: TraceObject) -> Optional[int]:
|
||||||
|
return find_thread_by_pattern(REGS_PATTERN, object, "a RegisterValueContainer")
|
||||||
|
|
||||||
|
|
||||||
|
def find_frame_by_level(level: int) -> Optional[Tuple[int, StackFrame]]:
|
||||||
|
tnum = util.selected_thread()
|
||||||
|
thread = commands.prog.thread(tnum)
|
||||||
|
try:
|
||||||
|
frames = thread.stack_trace()
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
for i, f in enumerate(frames):
|
||||||
|
if i == level:
|
||||||
|
if i != util.selected_frame():
|
||||||
|
util.select_frame(i)
|
||||||
|
return i, f
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def find_frame_by_pattern(pattern: re.Pattern, object: TraceObject,
|
||||||
|
err_msg: str) -> Optional[Tuple[int, StackFrame]]:
|
||||||
|
mat = pattern.fullmatch(object.path)
|
||||||
|
if mat is None:
|
||||||
|
raise TypeError(f"{object} is not {err_msg}")
|
||||||
|
pnum = int(mat['procnum'])
|
||||||
|
tnum = int(mat['tnum'])
|
||||||
|
level = int(mat['level'])
|
||||||
|
find_proc_by_num(pnum)
|
||||||
|
find_thread_by_num(tnum)
|
||||||
|
return find_frame_by_level(level)
|
||||||
|
|
||||||
|
|
||||||
|
def find_frame_by_obj(object: TraceObject) -> Optional[Tuple[int, StackFrame]]:
|
||||||
|
return find_frame_by_pattern(FRAME_PATTERN, object, "a StackFrame")
|
||||||
|
|
||||||
|
|
||||||
|
def find_frame_by_regs_obj(object: TraceObject) -> Optional[Tuple[int, StackFrame]]:
|
||||||
|
return find_frame_by_pattern(REGS_PATTERN, object, "a RegisterValueContainer")
|
||||||
|
|
||||||
|
|
||||||
|
def find_frame_by_locals_obj(object: TraceObject) -> Optional[Tuple[int, StackFrame]]:
|
||||||
|
return find_frame_by_pattern(LOCALS_PATTERN, object, "a LocalsContainer")
|
||||||
|
|
||||||
|
|
||||||
|
def find_module_by_base(modbase: TraceObject) -> Module:
|
||||||
|
for m in commands.prog.modules(): # type: ignore
|
||||||
|
if modbase == str(hex(m.address_range[0])):
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
def find_module_by_pattern(pattern: re.Pattern, object: TraceObject,
|
||||||
|
err_msg: str) -> int:
|
||||||
|
mat = pattern.fullmatch(object.path)
|
||||||
|
if mat is None:
|
||||||
|
raise TypeError(f"{object} is not {err_msg}")
|
||||||
|
pnum = int(mat['procnum'])
|
||||||
|
modbase = mat['modbase']
|
||||||
|
find_proc_by_num(pnum)
|
||||||
|
return find_module_by_base(modbase)
|
||||||
|
|
||||||
|
|
||||||
|
def find_module_by_obj(object: TraceObject) -> int:
|
||||||
|
return find_module_by_pattern(MODULE_PATTERN, object, "a Module")
|
||||||
|
|
||||||
|
|
||||||
|
shared_globals: Dict[str, Any] = dict()
|
||||||
|
|
||||||
|
|
||||||
@REGISTRY.method()
|
@REGISTRY.method()
|
||||||
def execute(cmd: str, to_string: bool = False) -> Optional[str]:
|
def execute(cmd: str, to_string: bool = False) -> Optional[str]:
|
||||||
"""Execute a Python3 command or script."""
|
"""Execute a Python3 command or script."""
|
||||||
|
@ -341,9 +331,12 @@ def activate_thread(thread: Thread) -> None:
|
||||||
|
|
||||||
|
|
||||||
@REGISTRY.method(action='activate')
|
@REGISTRY.method(action='activate')
|
||||||
def activate_frame(frame: StackFrame) -> None:
|
def activate_frame(frame: TraceObject) -> None:
|
||||||
"""Select the frame."""
|
"""Select the frame."""
|
||||||
i, f = find_frame_by_obj(frame)
|
res = find_frame_by_obj(frame)
|
||||||
|
if res is None:
|
||||||
|
return
|
||||||
|
i, f = res
|
||||||
util.select_frame(i)
|
util.select_frame(i)
|
||||||
with commands.open_tracked_tx('Refresh Stack'):
|
with commands.open_tracked_tx('Refresh Stack'):
|
||||||
commands.ghidra_trace_put_frames()
|
commands.ghidra_trace_put_frames()
|
||||||
|
@ -411,7 +404,7 @@ def step_into(thread: Thread,
|
||||||
"""Step one instruction exactly."""
|
"""Step one instruction exactly."""
|
||||||
find_thread_by_obj(thread)
|
find_thread_by_obj(thread)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
hooks.on_stop(None)
|
hooks.on_stop()
|
||||||
|
|
||||||
|
|
||||||
# @REGISTRY.method
|
# @REGISTRY.method
|
||||||
|
|
|
@ -14,9 +14,11 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
##
|
##
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from dataclasses import dataclass
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
|
||||||
|
|
||||||
import drgn
|
import drgn
|
||||||
import drgn.cli
|
import drgn.cli
|
||||||
|
@ -29,7 +31,7 @@ selected_tid = 0
|
||||||
selected_level = 0
|
selected_level = 0
|
||||||
|
|
||||||
|
|
||||||
def _compute_drgn_ver():
|
def _compute_drgn_ver() -> DrgnVersion:
|
||||||
blurb = drgn.cli.version_header()
|
blurb = drgn.cli.version_header()
|
||||||
top = blurb.split('\n')[0]
|
top = blurb.split('\n')[0]
|
||||||
full = top.split()[1] # "drgn x.y.z"
|
full = top.split()[1] # "drgn x.y.z"
|
||||||
|
@ -38,7 +40,17 @@ def _compute_drgn_ver():
|
||||||
|
|
||||||
DRGN_VERSION = _compute_drgn_ver()
|
DRGN_VERSION = _compute_drgn_ver()
|
||||||
|
|
||||||
def full_mem(self):
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Region:
|
||||||
|
start: int
|
||||||
|
end: int
|
||||||
|
offset: int
|
||||||
|
perms: Optional[str]
|
||||||
|
objfile: str
|
||||||
|
|
||||||
|
|
||||||
|
def full_mem(self) -> Region:
|
||||||
return Region(0, 1 << 64, 0, None, 'full memory')
|
return Region(0, 1 << 64, 0, None, 'full memory')
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,48 +58,40 @@ def get_debugger():
|
||||||
return drgn
|
return drgn
|
||||||
|
|
||||||
|
|
||||||
def get_target():
|
def selected_process() -> int:
|
||||||
return commands.prog
|
|
||||||
|
|
||||||
|
|
||||||
def get_process(name):
|
|
||||||
return get_target()[name]
|
|
||||||
|
|
||||||
|
|
||||||
def selected_process():
|
|
||||||
return selected_pid
|
return selected_pid
|
||||||
|
|
||||||
|
|
||||||
def selected_thread():
|
def selected_thread() -> int:
|
||||||
return selected_tid
|
return selected_tid
|
||||||
|
|
||||||
|
|
||||||
def selected_frame():
|
def selected_frame() -> int:
|
||||||
return selected_level
|
return selected_level
|
||||||
|
|
||||||
|
|
||||||
def select_process(id: int):
|
def select_process(id: int) -> int:
|
||||||
global selected_pid
|
global selected_pid
|
||||||
selected_pid = id
|
selected_pid = id
|
||||||
return selected_pid
|
return selected_pid
|
||||||
|
|
||||||
|
|
||||||
def select_thread(id: int):
|
def select_thread(id: int) -> int:
|
||||||
global selected_tid
|
global selected_tid
|
||||||
selected_tid = id
|
selected_tid = id
|
||||||
return selected_tid
|
return selected_tid
|
||||||
|
|
||||||
|
|
||||||
def select_frame(id: int):
|
def select_frame(id: int) -> int:
|
||||||
global selected_level
|
global selected_level
|
||||||
selected_level = id
|
selected_level = id
|
||||||
return selected_level
|
return selected_level
|
||||||
|
|
||||||
|
|
||||||
conv_map = {}
|
conv_map: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
|
||||||
def get_convenience_variable(id):
|
def get_convenience_variable(id: str):
|
||||||
# val = get_target().GetEnvironment().Get(id)
|
# val = get_target().GetEnvironment().Get(id)
|
||||||
if id not in conv_map:
|
if id not in conv_map:
|
||||||
return "auto"
|
return "auto"
|
||||||
|
@ -97,18 +101,18 @@ def get_convenience_variable(id):
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
def set_convenience_variable(id, value):
|
def set_convenience_variable(id: str, value: Any) -> None:
|
||||||
# env = get_target().GetEnvironment()
|
# env = get_target().GetEnvironment()
|
||||||
# return env.Set(id, value, True)
|
# return env.Set(id, value, True)
|
||||||
conv_map[id] = value
|
conv_map[id] = value
|
||||||
|
|
||||||
|
|
||||||
def escape_ansi(line):
|
def escape_ansi(line: str) -> str:
|
||||||
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]')
|
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]')
|
||||||
return ansi_escape.sub('', line)
|
return ansi_escape.sub('', line)
|
||||||
|
|
||||||
|
|
||||||
def debracket(init):
|
def debracket(init: str) -> str:
|
||||||
val = init
|
val = init
|
||||||
val = val.replace("[", "(")
|
val = val.replace("[", "(")
|
||||||
val = val.replace("]", ")")
|
val = val.replace("]", ")")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue