about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/focaccia/lldb_target.py120
-rw-r--r--src/focaccia/symbolic.py6
2 files changed, 70 insertions, 56 deletions
diff --git a/src/focaccia/lldb_target.py b/src/focaccia/lldb_target.py
index 5823d62..a6f7d6d 100644
--- a/src/focaccia/lldb_target.py
+++ b/src/focaccia/lldb_target.py
@@ -45,74 +45,29 @@ class LLDBConcreteTarget:
     }
 
     def __init__(self,
-                 executable: str,
-                 argv: list[str] = [],
-                 envp: list[str] | None = None):
+                 debugger: lldb.SBDebugger,
+                 target: lldb.SBTarget,
+                 process: lldb.SBProcess):
         """Construct an LLDB concrete target. Stop at entry.
 
-        :param argv: List of arguements. Does NOT include the conventional
-                     executable name as the first entry.
-        :param envp: List of environment entries. Defaults to current
-                     `os.environ` if `None`.
-        :raises RuntimeError: If the process is unable to launch.
+        :param debugger: LLDB SBDebugger object representing an initialized debug session.
+        :param target: LLDB SBTarget object representing an initialized target for the debugger.
+        :param process: LLDB SBProcess object representing an initialized process (either local or remote).
         """
-        if envp is None:
-            envp = [f'{k}={v}' for k, v in os.environ.items()]
+        self.debugger = debugger
+        self.target = target
+        self.process = process
 
-        self.debugger = lldb.SBDebugger.Create()
-        self.debugger.SetAsync(False)
-        self.target = self.debugger.CreateTargetWithFileAndArch(executable, lldb.LLDB_ARCH_DEFAULT)
-        
         self.module = self.target.FindModule(self.target.GetExecutable())
         self.interpreter = self.debugger.GetCommandInterpreter()
 
         # Set up objects for process execution
-        self.error = lldb.SBError()
         self.listener = self.debugger.GetListener()
 
         # Determine current arch
         self.archname = self.determine_arch()
         self.arch = supported_architectures[self.archname]
 
-    @classmethod
-    def from_executable(cls, 
-                        executable: str,
-                        argv: list[str] = [],
-                        envp: list[str] | None = None):
-        """Construct an LLDB concrete target. Stop at entry.
-
-        :param argv: List of arguements. Does NOT include the conventional
-                     executable name as the first entry.
-        :param envp: List of environment entries. Defaults to current
-                     `os.environ` if `None`.
-        :raises RuntimeError: If the process is unable to launch.
-        """
-        obj = cls(executable, argv, envp)
-        obj.process = obj.target.Launch(obj.listener,
-                                        argv, envp,        # argv, envp
-                                        None, None, None,  # stdin, stdout, stderr
-                                        None,              # working directory
-                                        0,
-                                        True, obj.error)
-        if not obj.target.process.IsValid():
-            raise RuntimeError(f'Failed to launch LLDB target')
-        return obj
-
-    @classmethod
-    def with_remote(cls, 
-                    remote: str,
-                    executable: str, 
-                    argv: list[str] = [],
-                    envp: list[str] | None = None):
-        obj = cls(executable, argv, envp)
-        obj.process = obj.target.ConnectRemote(obj.listener,
-                                               f'connect://{remote}',
-                                               None,
-                                               obj.error)
-        if not obj.target.process.IsValid():
-            raise RuntimeError('Failed to connect via LLDB to remote target')
-        return obj
-
     def determine_arch(self):
         archname = self.target.GetPlatform().GetTriple().split('-')[0]
         if archname not in supported_architectures:
@@ -355,3 +310,60 @@ class LLDBConcreteTarget:
         inst = self.target.ReadInstructions(lldb.SBAddress(addr, self.target), 1)[0]
         return f'{inst.GetMnemonic(self.target)} {inst.GetOperands(self.target)}'
 
+class LLDBLocalTarget(LLDBConcreteTarget):
+    def __init__(self,
+                 executable: str,
+                 argv: list[str] = [],
+                 envp: list[str] | None = None):
+        """Construct an LLDB local target. Stop at entry.
+
+        :param executable: Name of executable to run under LLDB.
+        :param argv: List of arguements. Does NOT include the conventional
+                     executable name as the first entry.
+        :param envp: List of environment entries. Defaults to current
+                     `os.environ` if `None`.
+        :raises RuntimeError: If the process is unable to launch.
+        """
+        if envp is None:
+            envp = [f'{k}={v}' for k, v in os.environ.items()]
+
+        debugger = lldb.SBDebugger.Create()
+        debugger.SetAsync(False)
+        target = debugger.CreateTargetWithFileAndArch(executable, lldb.LLDB_ARCH_DEFAULT)
+        
+        # Set up objects for process execution
+        error = lldb.SBError()
+        process = target.Launch(debugger.GetListener(),
+                                argv, envp,        # argv, envp
+                                None, None, None,  # stdin, stdout, stderr
+                                None,              # working directory
+                                0,
+                                True, error)
+
+        if not target.process.IsValid():
+            raise RuntimeError(f'Failed to launch LLDB target: {error.GetCString()}')
+
+        super().__init__(debugger, target, process)
+
+class LLDBRemoteTarget(LLDBConcreteTarget):
+    def __init__(self, remote: str):
+        """Construct an LLDB remote target. Stop at entry.
+
+        :param remote: String of the form <remote_name>:<port> (e.g. localhost:12345).
+        :raises RuntimeError: If failing to attach to a remote debug session.
+        """
+        debugger = lldb.SBDebugger.Create()
+        debugger.SetAsync(False)
+        target = debugger.CreateTarget(None)
+        
+        # Set up objects for process execution
+        error = lldb.SBError()
+        process = target.ConnectRemote(debugger.GetListener(),
+                                       f'connect://{remote}',
+                                       None,
+                                       error)
+        if not target.process.IsValid():
+            raise RuntimeError(f'Failed to connect via LLDB to remote target: {error.GetCString()}')
+        
+        super().__init__(debugger, target, process)
+
diff --git a/src/focaccia/symbolic.py b/src/focaccia/symbolic.py
index da8ffc8..aa6ab5e 100644
--- a/src/focaccia/symbolic.py
+++ b/src/focaccia/symbolic.py
@@ -15,6 +15,8 @@ from miasm.ir.symbexec import SymbolicExecutionEngine
 
 from .arch import Arch, supported_architectures
 from .lldb_target import LLDBConcreteTarget, \
+                         LLDBLocalTarget, \
+                         LLDBRemoteTarget, \
                          ConcreteRegisterError, \
                          ConcreteMemoryError
 from .miasm_util import MiasmSymbolResolver, eval_expr, make_machine
@@ -631,9 +633,9 @@ def collect_symbolic_trace(env: TraceEnvironment,
     # Set up concrete reference state
     target = None
     if remote:
-        target = LLDBConcreteTarget.with_remote(remote, binary, env.argv, env.envp)
+        target = LLDBRemoteTarget(remote)
     else:
-        target = LLDBConcreteTarget.from_executable(binary, env.argv, env.envp)
+        target = LLDBLocalTarget(binary, env.argv, env.envp)
 
     if start_addr is not None:
         target.run_until(start_addr)