about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/focaccia/lldb_target.py68
-rw-r--r--src/focaccia/symbolic.py10
-rwxr-xr-xsrc/focaccia/tools/capture_transforms.py5
3 files changed, 63 insertions, 20 deletions
diff --git a/src/focaccia/lldb_target.py b/src/focaccia/lldb_target.py
index 8d3dbd9..5823d62 100644
--- a/src/focaccia/lldb_target.py
+++ b/src/focaccia/lldb_target.py
@@ -61,32 +61,66 @@ class LLDBConcreteTarget:
 
         self.debugger = lldb.SBDebugger.Create()
         self.debugger.SetAsync(False)
-        self.target = self.debugger.CreateTargetWithFileAndArch(executable,
-                                                                lldb.LLDB_ARCH_DEFAULT)
+        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()
-        self.process = self.target.Launch(self.listener,
-                                          argv, envp,        # argv, envp
-                                          None, None, None,  # stdin, stdout, stderr
-                                          None,              # working directory
-                                          0,
-                                          True, self.error)
-        if not self.process.IsValid():
-            raise RuntimeError(f'[In LLDBConcreteTarget.__init__]: Failed to'
-                               f' launch process.')
 
         # Determine current arch
-        self.archname = self.target.GetPlatform().GetTriple().split('-')[0]
-        if self.archname not in supported_architectures:
-            err = f'LLDBConcreteTarget: Architecture {self.archname} is not' \
+        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:
+            err = f'LLDBConcreteTarget: Architecture {archname} is not' \
                   f' supported by Focaccia.'
             print(f'[ERROR] {err}')
             raise NotImplementedError(err)
-        self.arch = supported_architectures[self.archname]
+        return archname
 
     def is_exited(self):
         """Signals whether the concrete process has exited.
@@ -99,8 +133,8 @@ class LLDBConcreteTarget:
         """Continue execution of the concrete process."""
         state = self.process.GetState()
         if state == lldb.eStateExited:
-            raise RuntimeError(f'Tried to resume process execution, but the'
-                               f' process has already exited.')
+            raise RuntimeError('Tried to resume process execution, but the'
+                               ' process has already exited.')
         assert(state == lldb.eStateStopped)
         self.process.Continue()
 
diff --git a/src/focaccia/symbolic.py b/src/focaccia/symbolic.py
index c02adfc..816a2e1 100644
--- a/src/focaccia/symbolic.py
+++ b/src/focaccia/symbolic.py
@@ -617,7 +617,8 @@ class _LLDBConcreteState(ReadableProgramState):
             raise MemoryAccessError(addr, size, 'Unable to read memory from LLDB.')
 
 def collect_symbolic_trace(env: TraceEnvironment,
-                           start_addr: int | None = None
+                           start_addr: int | None = None,
+                           remote: str | None = None,
                            ) -> Trace[SymbolicTransform]:
     """Execute a program and compute state transformations between executed
     instructions.
@@ -628,7 +629,12 @@ def collect_symbolic_trace(env: TraceEnvironment,
     binary = env.binary_name
 
     # Set up concrete reference state
-    target = LLDBConcreteTarget(binary, env.argv, env.envp)
+    target = None
+    if remote:
+        target = LLDBConcreteTarget.with_remote(remote, binary, env.argv, env.envp)
+    else:
+        target = LLDBConcreteTarget.from_executable(binary, env.argv, env.envp)
+
     if start_addr is not None:
         target.run_until(start_addr)
     lldb_state = _LLDBConcreteState(target)
diff --git a/src/focaccia/tools/capture_transforms.py b/src/focaccia/tools/capture_transforms.py
index 6ef0eaa..da34e0f 100755
--- a/src/focaccia/tools/capture_transforms.py
+++ b/src/focaccia/tools/capture_transforms.py
@@ -20,10 +20,13 @@ def main():
                       default=False,
                       action='store_true',
                       help='Cross-validate symbolic equations with concrete values')
+    prog.add_argument('-r', '--remote',
+                      default=False,
+                      help='Remote target to trace (e.g. 127.0.0.1:12345)')
     args = prog.parse_args()
 
     env = TraceEnvironment(args.binary, args.args, args.cross_validate, utils.get_envp())
-    trace = collect_symbolic_trace(env, None)
+    trace = collect_symbolic_trace(env, None, remote=args.remote)
     with open(args.output, 'w') as file:
         parser.serialize_transformations(trace, file)