From f90ee24e3bfb56ef071c9436c66277482e0bde10 Mon Sep 17 00:00:00 2001
From: Netanel Cohen <netanelc305@protonmail.com>
Date: Thu, 22 Aug 2024 16:07:05 +0300
Subject: [PATCH 1/2] hilda_client: Add `hilda_root` path

---
 hilda/hilda_client.py       | 10 +++++-----
 hilda/objective_c_class.py  |  5 ++---
 hilda/objective_c_symbol.py |  3 +--
 3 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/hilda/hilda_client.py b/hilda/hilda_client.py
index 5a03705..c343fad 100644
--- a/hilda/hilda_client.py
+++ b/hilda/hilda_client.py
@@ -146,6 +146,7 @@ def __init__(self, debugger: lldb.SBDebugger):
         self._dynamic_env_loaded = False
         self._symbols_loaded = False
         self.globals: typing.MutableMapping[str, Any] = globals()
+        self._hilda_root = Path(__file__).parent
 
         # the frame called within the context of the hit BP
         self._bp_frame = None
@@ -168,7 +169,7 @@ def lsof(self) -> dict:
         Get dictionary of all open FDs
         :return: Mapping between open FDs and their paths
         """
-        data = (Path(__file__).parent / 'objective_c' / 'lsof.m').read_text()
+        data = (self._hilda_root / 'objective_c' / 'lsof.m').read_text()
         result = json.loads(self.po(data))
         # convert FDs into int
         return {int(k): v for k, v in result.items()}
@@ -828,8 +829,7 @@ def ns(self, data: CfSerializable) -> Symbol:
             json_data = json.dumps({'root': data}, default=self._to_ns_json_default)
         except TypeError as e:
             raise ConvertingToNsObjectError from e
-
-        obj_c_code = (Path(__file__).parent / 'objective_c' / 'to_ns_from_json.m').read_text()
+        obj_c_code = (self._hilda_root / 'objective_c' / 'to_ns_from_json.m').read_text()
         expression = obj_c_code.replace('__json_object_dump__', json_data.replace('"', r'\"'))
         try:
             return self.evaluate_expression(expression)
@@ -842,7 +842,7 @@ def decode_cf(self, address: Union[int, str]) -> CfSerializable:
         :param address: NS object.
         :return: Python object.
         """
-        obj_c_code = (Path(__file__).parent / 'objective_c' / 'from_ns_to_json.m').read_text()
+        obj_c_code = (self._hilda_root / 'objective_c' / 'from_ns_to_json.m').read_text()
         address = f'0x{address:x}' if isinstance(address, int) else address
         expression = obj_c_code.replace('__ns_object_address__', address)
         try:
@@ -1212,7 +1212,7 @@ def _get_module_class_list(self, module_name: str):
                 continue
             objc_classlist = m.FindSection('__DATA').FindSubSection('__objc_classlist')
             objc_classlist_addr = self.symbol(objc_classlist.GetLoadAddress(self.target))
-            obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_class_by_module.m').read_text()
+            obj_c_code = (self._hilda_root / 'objective_c' / 'get_objectivec_class_by_module.m').read_text()
             obj_c_code = obj_c_code.replace('__count_objc_class', f'{objc_classlist.size // 8}').replace(
                 '__objc_class_list',
                 f'{objc_classlist_addr}')
diff --git a/hilda/objective_c_class.py b/hilda/objective_c_class.py
index b991f68..fa9ea7a 100644
--- a/hilda/objective_c_class.py
+++ b/hilda/objective_c_class.py
@@ -3,7 +3,6 @@
 from collections import namedtuple
 from dataclasses import dataclass, field
 from functools import partial
-from pathlib import Path
 from typing import Any
 from uuid import uuid4
 
@@ -120,7 +119,7 @@ def from_class_name(client, class_name: str):
         :param hilda.hilda_client.HildaClient client: Hilda client.
         :param class_name: Class name.
         """
-        obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_class_description.m').read_text()
+        obj_c_code = (client._hilda_root / 'objective_c' / 'get_objectivec_class_description.m').read_text()
         obj_c_code = obj_c_code.replace('__class_address__', '0').replace('__class_name__', class_name)
         class_symbol = Class(client, class_data=json.loads(client.po(obj_c_code)))
         if class_symbol.name != class_name:
@@ -143,7 +142,7 @@ def reload(self):
         Reload class object data.
         Should be used whenever the class layout changes (for example, during method swizzling)
         """
-        obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_class_description.m').read_text()
+        obj_c_code = (self._client._hilda_root / 'objective_c' / 'get_objectivec_class_description.m').read_text()
         obj_c_code = obj_c_code.replace('__class_address__', f'{self._class_object:d}')
         obj_c_code = obj_c_code.replace('__class_name__', self.name)
         self._load_class_data(json.loads(self._client.po(obj_c_code)))
diff --git a/hilda/objective_c_symbol.py b/hilda/objective_c_symbol.py
index 94e38cf..2b8071b 100644
--- a/hilda/objective_c_symbol.py
+++ b/hilda/objective_c_symbol.py
@@ -2,7 +2,6 @@
 from contextlib import suppress
 from dataclasses import dataclass
 from functools import partial
-from pathlib import Path
 
 from objc_types_decoder.decode import decode as decode_type
 from pygments import highlight
@@ -60,7 +59,7 @@ def reload(self):
         self.methods.clear()
         self.class_ = None
 
-        obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_symbol_data.m').read_text()
+        obj_c_code = (self._client._hilda_root / 'objective_c' / 'get_objectivec_symbol_data.m').read_text()
         obj_c_code = obj_c_code.replace('__symbol_address__', f'{self:d}')
         data = json.loads(self._client.po(obj_c_code))
 

From e457d688e6af21ec7d9c7157ddb6fbc090ec809a Mon Sep 17 00:00:00 2001
From: Netanel Cohen <netanelc305@protonmail.com>
Date: Thu, 22 Aug 2024 16:07:49 +0300
Subject: [PATCH 2/2] hilda_client: Add `run_for`

---
 README.md             |  2 ++
 hilda/hilda_client.py | 10 ++++++++++
 2 files changed, 12 insertions(+)

diff --git a/README.md b/README.md
index 2cbfe53..ea303ae 100644
--- a/README.md
+++ b/README.md
@@ -132,6 +132,8 @@ Here is a gist of methods you can access from `p`:
   - Stop process.
 - `cont`
   - Continue process.
+- `run_for`
+  - Run the process for given interval.
 - `detach`
   - Detach from process.
       Useful in order to exit gracefully so process doesn't get killed
diff --git a/hilda/hilda_client.py b/hilda/hilda_client.py
index c343fad..bb970bc 100644
--- a/hilda/hilda_client.py
+++ b/hilda/hilda_client.py
@@ -348,6 +348,16 @@ def stop(self, *args) -> None:
         if not self.process.Stop().Success():
             self.log_critical('failed to stop process')
 
+    def run_for(self, seconds: float) -> None:
+        """
+        Run the process for a given time
+        :return:
+        """
+        self.cont()
+        self.logger.info(f'Running for {seconds} seconds')
+        time.sleep(seconds)
+        self.stop()
+
     def cont(self, *args) -> None:
         """ Continue process. """
         is_running = self.process.GetState() == lldb.eStateRunning