hilda 3.0.1__py3-none-any.whl → 3.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hilda/_version.py CHANGED
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '3.0.1'
21
- __version_tuple__ = version_tuple = (3, 0, 1)
31
+ __version__ = version = '3.2.1'
32
+ __version_tuple__ = version_tuple = (3, 2, 1)
33
+
34
+ __commit_id__ = commit_id = None
hilda/breakpoints.py CHANGED
@@ -124,12 +124,30 @@ class HildaBreakpoint:
124
124
  for name in names_to_add:
125
125
  self.lldb_breakpoint.AddName(name)
126
126
 
127
+ @property
128
+ def enabled(self) -> bool:
129
+ """
130
+ Configures whether this breakpoint is enabled or not.
131
+ """
132
+ return self.lldb_breakpoint.IsEnabled()
133
+
134
+ @enabled.setter
135
+ def enabled(self, value: bool) -> None:
136
+ self.lldb_breakpoint.SetEnabled(value)
137
+
127
138
  def __repr__(self) -> str:
128
- return (f'<{self.__class__.__name__} LLDB:{self.lldb_breakpoint} GUARDED:{self.guarded} '
139
+ enabled_repr = 'ENABLED' if self.enabled else 'DISABLED'
140
+ guarded_repr = 'GUARDED' if self.guarded else 'NOT-GUARDED'
141
+ return (f'<{self.__class__.__name__} LLDB:{self.lldb_breakpoint} {enabled_repr} {guarded_repr} '
129
142
  f'CALLBACK:{self.callback}>')
130
143
 
131
144
  def __str__(self) -> str:
132
- result = f'🚨 Breakpoint #{self.id} (guarded: {self.guarded}):\n'
145
+ emoji = '🚨' if self.enabled else '🔕'
146
+ enabled_str = 'enabled' if self.enabled else 'disabled'
147
+ guarded_str = 'guarded' if self.guarded else 'not-guarded'
148
+
149
+ result = f'{emoji} Breakpoint #{self.id} ({enabled_str}, {guarded_str})\n'
150
+
133
151
  if self.description is not None:
134
152
  result += f'\tDescription: {self.description}\n'
135
153
 
@@ -137,10 +155,13 @@ class HildaBreakpoint:
137
155
  result += f'\tWhere: {self.where}\n'
138
156
 
139
157
  # A single breakpoint may be related to several locations (addresses)
158
+ locations = self.locations
159
+ if len(locations) == 0:
160
+ result += '\tNo locations\n'
140
161
  for location in self.locations:
141
162
  result += f'\tLocation {location}\n'
142
163
 
143
- return result
164
+ return result.strip('\n')
144
165
 
145
166
  def remove(self, remove_guarded: bool = False) -> None:
146
167
  """
@@ -206,6 +227,7 @@ class BreakpointList:
206
227
  if it does not exist.
207
228
 
208
229
  :param id_or_name_or_bp: Breakpoint's ID or name (or the breakpoint itself)
230
+ :return: `HildaBreakpoint` if one exists, or `None` otherwise
209
231
  """
210
232
 
211
233
  if isinstance(id_or_name_or_bp, int):
@@ -341,14 +363,13 @@ class BreakpointList:
341
363
  :param frame: LLDB frame
342
364
  :param bp_loc: LLDB breakpoint location
343
365
  """
344
- nonlocal regs, expr, retval, stop, bt, cmd, force_return, name
366
+ nonlocal name
345
367
  bp = bp_loc.GetBreakpoint()
346
368
  symbol = hilda.symbol(hilda.frame.addr.GetLoadAddress(hilda.target))
347
369
  thread = hilda.thread
348
- printed_name = name if name is not None else str(symbol.lldb_symbol)
370
+ printed_name = name if name is not None else str(symbol.lldb_address)
349
371
 
350
372
  def format_value(fmt: Union[str, Callable], value: Symbol) -> str:
351
- nonlocal hilda
352
373
  if callable(fmt):
353
374
  return fmt(hilda, value)
354
375
  formatters = {
@@ -441,8 +462,10 @@ class BreakpointList:
441
462
 
442
463
  def show(self) -> None:
443
464
  """ Show existing breakpoints. """
465
+ if len(self) == 0:
466
+ self._hilda.log_info('No breakpoints')
444
467
  for bp in self:
445
- print(bp)
468
+ self._hilda.log_info(bp)
446
469
 
447
470
  def items(self):
448
471
  """
hilda/decorators.py ADDED
@@ -0,0 +1,46 @@
1
+ from hilda.breakpoints import WhereType
2
+ from hilda.lldb_importer import lldb
3
+
4
+ p = lldb.hilda_client
5
+
6
+
7
+ def breakpoint(where: WhereType, enable: bool = False):
8
+ """
9
+ A decorator to define a breakpoint, e.g.,
10
+
11
+ ```
12
+ @breakpoint('symbol_name')
13
+ def my_breakpoint(hilda, *args):
14
+ print('Hit!')
15
+ hilda.cont()
16
+
17
+ my_breakpoint.enabled = True
18
+ ```
19
+ """
20
+ def decorator(callback):
21
+ bp = p.breakpoints.add(where, callback=callback)
22
+ bp.enabled = enable
23
+ return bp
24
+
25
+ return decorator
26
+
27
+
28
+ def watchpoint(where: int, enable: bool = False):
29
+ """
30
+ A decorator to define a watchpoint, e.g.,
31
+
32
+ ```
33
+ @watchpoint(0x11223344)
34
+ def my_watchpoint(hilda, *args):
35
+ print('Hit!')
36
+ hilda.cont()
37
+
38
+ my_watchpoint.enabled = True
39
+ ```
40
+ """
41
+ def decorator(callback):
42
+ wp = p.watchpoints.add(where, callback=callback)
43
+ wp.enabled = enable
44
+ return wp
45
+
46
+ return decorator
hilda/exceptions.py CHANGED
@@ -1,7 +1,7 @@
1
1
  __all__ = ['HildaException', 'SymbolAbsentError', 'EvaluatingExpressionError', 'CreatingObjectiveCSymbolError',
2
2
  'ConvertingToNsObjectError', 'ConvertingFromNSObjectError', 'DisableJetsamMemoryChecksError',
3
3
  'GettingObjectiveCClassError', 'AccessingRegisterError', 'AccessingMemoryError',
4
- 'BrokenLocalSymbolsJarError', 'AddingLldbSymbolError', 'LLDBError', 'InvalidThreadIndexError']
4
+ 'AddingLldbSymbolError', 'LLDBError', 'InvalidThreadIndexError']
5
5
 
6
6
 
7
7
  class HildaException(Exception):
@@ -59,11 +59,6 @@ class AccessingMemoryError(HildaException):
59
59
  pass
60
60
 
61
61
 
62
- class BrokenLocalSymbolsJarError(HildaException):
63
- """ Raise when attempt to load an invalid symbols jar pickle """
64
- pass
65
-
66
-
67
62
  class AddingLldbSymbolError(HildaException):
68
63
  """ Raise when failing to convert a LLDB symbol to Hilda's symbol. """
69
64
  pass
hilda/hilda_client.py CHANGED
@@ -10,7 +10,7 @@ import sys
10
10
  import time
11
11
  import typing
12
12
  from collections import namedtuple
13
- from contextlib import contextmanager, suppress
13
+ from contextlib import contextmanager
14
14
  from dataclasses import dataclass, field
15
15
  from datetime import datetime, timezone
16
16
  from functools import cached_property, wraps
@@ -30,17 +30,16 @@ from traitlets.config import Config
30
30
  from hilda import objective_c_class
31
31
  from hilda.breakpoints import BreakpointList, HildaBreakpoint, WhereType
32
32
  from hilda.common import CfSerializable, selection_prompt
33
- from hilda.exceptions import AccessingMemoryError, AccessingRegisterError, AddingLldbSymbolError, \
34
- ConvertingFromNSObjectError, ConvertingToNsObjectError, CreatingObjectiveCSymbolError, \
35
- DisableJetsamMemoryChecksError, EvaluatingExpressionError, HildaException, InvalidThreadIndexError, \
36
- SymbolAbsentError
33
+ from hilda.exceptions import AccessingMemoryError, AccessingRegisterError, ConvertingFromNSObjectError, \
34
+ ConvertingToNsObjectError, CreatingObjectiveCSymbolError, DisableJetsamMemoryChecksError, \
35
+ EvaluatingExpressionError, HildaException, InvalidThreadIndexError, SymbolAbsentError
37
36
  from hilda.ipython_extensions.keybindings import get_keybindings
38
37
  from hilda.lldb_importer import lldb
39
38
  from hilda.objective_c_symbol import ObjectiveCSymbol
40
39
  from hilda.registers import Registers
41
40
  from hilda.snippets.mach import CFRunLoopServiceMachPort_hooks
42
41
  from hilda.symbol import Symbol
43
- from hilda.symbols_jar import SymbolsJar
42
+ from hilda.symbols import SymbolList
44
43
  from hilda.ui.ui_manager import UiManager
45
44
  from hilda.watchpoints import WatchpointList
46
45
 
@@ -127,7 +126,7 @@ class HildaClient:
127
126
  self.debugger = debugger
128
127
  self.target = debugger.GetSelectedTarget()
129
128
  self.process = self.target.GetProcess()
130
- self.symbols = SymbolsJar.create(self)
129
+ self.symbols = SymbolList(self)
131
130
  self.breakpoints = BreakpointList(self)
132
131
  self.watchpoints = WatchpointList(self)
133
132
  self.captured_objects = {}
@@ -201,7 +200,7 @@ class HildaClient:
201
200
  :param address:
202
201
  :return: Hilda's symbol object
203
202
  """
204
- return Symbol.create(address, self)
203
+ return self.symbols.add(address)
205
204
 
206
205
  def objc_symbol(self, address: int) -> ObjectiveCSymbol:
207
206
  """
@@ -214,18 +213,18 @@ class HildaClient:
214
213
  except HildaException as e:
215
214
  raise CreatingObjectiveCSymbolError from e
216
215
 
217
- def inject(self, filename: str) -> SymbolsJar:
216
+ def inject(self, filename: str) -> SymbolList:
218
217
  """
219
218
  Inject a single library into currently running process.
220
219
 
221
220
  :param filename: library to inject (dylib)
222
- :return: SymbolsJar
221
+ :return: SymbolList
223
222
  """
224
223
  module = self.target.FindModule(lldb.SBFileSpec(os.path.basename(filename), False))
225
224
  if module.file.basename is not None:
226
225
  self.log_warning(f'file {filename} has already been loaded')
227
226
 
228
- injected = SymbolsJar.create(self)
227
+ injected = SymbolList(self)
229
228
  handle = self.symbols.dlopen(filename, 10) # RTLD_GLOBAL|RTLD_NOW
230
229
 
231
230
  if handle == 0:
@@ -247,34 +246,9 @@ class HildaClient:
247
246
  # ignore unnamed symbols and those which are not: data, code or objc classes
248
247
  continue
249
248
 
250
- injected[name] = self.symbol(load_addr)
249
+ injected.add(self.symbol(load_addr), name)
251
250
  return injected
252
251
 
253
- def rebind_symbols(self, image_range=None, filename_expr=''):
254
- """
255
- Reparse all loaded images symbols
256
- :param image_range: index range for images to load in the form of [start, end]
257
- :param filename_expr: filter only images containing given expression
258
- """
259
- self.log_debug('mapping symbols')
260
- self._symbols_loaded = False
261
-
262
- for i, module in enumerate(tqdm(self.target.modules)):
263
- filename = module.file.basename
264
-
265
- if filename_expr not in filename:
266
- continue
267
-
268
- if image_range is not None and (i < image_range[0] or i > image_range[1]):
269
- continue
270
-
271
- for symbol in module:
272
- with suppress(AddingLldbSymbolError):
273
- self.add_lldb_symbol(symbol)
274
-
275
- globals()['symbols'] = self.symbols
276
- self._symbols_loaded = True
277
-
278
252
  @stop_is_needed
279
253
  def poke(self, address, buf: bytes):
280
254
  """
@@ -594,7 +568,7 @@ class HildaClient:
594
568
  """ jump to given symbol """
595
569
  self.lldb_handle_command(f'j *{symbol}')
596
570
 
597
- def lldb_handle_command(self, cmd: str) -> None:
571
+ def lldb_handle_command(self, cmd: str, capture_output: bool = False) -> Optional[str]:
598
572
  """
599
573
  Execute an LLDB command
600
574
 
@@ -602,8 +576,15 @@ class HildaClient:
602
576
  lldb_handle_command('register read')
603
577
 
604
578
  :param cmd: LLDB command
579
+ :param capture_output: True if capturing the command output
580
+ :return: The output if capture was requested, None if not or the command failed
605
581
  """
606
- self.debugger.HandleCommand(cmd)
582
+ if capture_output:
583
+ result = lldb.SBCommandReturnObject()
584
+ self.debugger.GetCommandInterpreter().HandleCommand(cmd, result)
585
+ return result.GetOutput() if result.Succeeded() else None
586
+ else:
587
+ self.debugger.HandleCommand(cmd)
607
588
 
608
589
  def objc_get_class(self, name: str, module_name: Optional[str] = None) -> objective_c_class.Class:
609
590
  """
@@ -828,36 +809,6 @@ class HildaClient:
828
809
  """ Log at info level """
829
810
  self.logger.info(message)
830
811
 
831
- def add_lldb_symbol(self, symbol: lldb.SBSymbol) -> Symbol:
832
- """
833
- Convert an LLDB symbol into Hilda's symbol object and insert into `symbols` global
834
- :param symbol: LLDB symbol
835
- :return: converted symbol
836
- :raise AddingLldbSymbolError: Hilda failed to convert the LLDB symbol.
837
- """
838
- load_addr = symbol.addr.GetLoadAddress(self.target)
839
- if load_addr == 0xffffffffffffffff:
840
- # skip those not having a real address
841
- raise AddingLldbSymbolError()
842
-
843
- name = symbol.name
844
- type_ = symbol.GetType()
845
-
846
- if name in ('<redacted>',) or (type_ not in (lldb.eSymbolTypeCode,
847
- lldb.eSymbolTypeRuntime,
848
- lldb.eSymbolTypeData,
849
- lldb.eSymbolTypeObjCMetaClass)):
850
- # ignore unnamed symbols and those which are not in a really used type
851
- raise AddingLldbSymbolError()
852
-
853
- value = self.symbol(load_addr)
854
-
855
- # add it into symbols global
856
- self.symbols[name] = value
857
- self.symbols[f'{name}{{{value.filename}}}'] = value
858
-
859
- return value
860
-
861
812
  def wait_for_module(self, expression: str) -> None:
862
813
  """ Wait for a module to be loaded using `dlopen` by matching given expression """
863
814
  self.log_info(f'Waiting for module name containing "{expression}" to be loaded')
@@ -901,7 +852,7 @@ class HildaClient:
901
852
 
902
853
  # Configure and start IPython shell
903
854
  ipython_config = Config()
904
- ipython_config.IPCompleter.use_jedi = True
855
+ ipython_config.IPCompleter.use_jedi = False
905
856
  ipython_config.BaseIPythonApplication.profile = 'hilda'
906
857
  ipython_config.InteractiveShellApp.extensions = ['hilda.ipython_extensions.magics',
907
858
  'hilda.ipython_extensions.events',
@@ -3,10 +3,9 @@ import builtins
3
3
 
4
4
  from IPython.terminal.interactiveshell import TerminalInteractiveShell
5
5
 
6
- from hilda.exceptions import EvaluatingExpressionError, SymbolAbsentError
6
+ from hilda.exceptions import EvaluatingExpressionError
7
7
  from hilda.hilda_client import HildaClient
8
8
  from hilda.lldb_importer import lldb
9
- from hilda.symbols_jar import SymbolsJar
10
9
 
11
10
 
12
11
  class HIEvents:
@@ -30,22 +29,19 @@ class HIEvents:
30
29
  # That are undefined
31
30
  continue
32
31
 
33
- if not hasattr(SymbolsJar, node.id):
34
- # ignore SymbolsJar properties
35
- try:
36
- symbol = getattr(self.hilda_client.symbols, node.id)
37
- except SymbolAbsentError:
38
- pass
39
- else:
40
- try:
41
- self.hilda_client._add_global(
42
- node.id,
43
- symbol if symbol.type_ != lldb.eSymbolTypeObjCMetaClass else self.hilda_client.objc_get_class(
44
- node.id)
45
- )
46
- except EvaluatingExpressionError:
47
- self.hilda_client.log_warning(
48
- f'Process is running. Pause execution in order to resolve "{node.id}"')
32
+ symbol = self.hilda_client.symbols.get(node.id)
33
+ if symbol is None:
34
+ continue
35
+
36
+ try:
37
+ self.hilda_client._add_global(
38
+ node.id,
39
+ symbol if symbol.type_ != lldb.eSymbolTypeObjCMetaClass else self.hilda_client.objc_get_class(
40
+ node.id)
41
+ )
42
+ except EvaluatingExpressionError:
43
+ self.hilda_client.log_warning(
44
+ f'Process is running. Pause execution in order to resolve "{node.id}"')
49
45
 
50
46
 
51
47
  def load_ipython_extension(ip: TerminalInteractiveShell):
@@ -1,9 +1,9 @@
1
1
  import json
2
2
  import time
3
- from collections import namedtuple
3
+ from collections import UserList, namedtuple
4
4
  from dataclasses import dataclass, field
5
5
  from functools import partial
6
- from typing import Any
6
+ from typing import Any, Optional
7
7
 
8
8
  from objc_types_decoder.decode import decode as decode_type
9
9
  from objc_types_decoder.decode import decode_with_tail
@@ -12,7 +12,6 @@ from pygments.formatters import TerminalTrueColorFormatter
12
12
  from pygments.lexers import ObjectiveCLexer
13
13
 
14
14
  from hilda.exceptions import GettingObjectiveCClassError
15
- from hilda.symbols_jar import SymbolsJar
16
15
 
17
16
  Ivar = namedtuple('Ivar', 'name type_ offset')
18
17
  Property = namedtuple('Property', 'name attributes')
@@ -88,6 +87,86 @@ class Method:
88
87
  return f'{prefix} {name}; // 0x{self.address:x} (returns: {self.return_type})\n'
89
88
 
90
89
 
90
+ class MethodList(UserList):
91
+ def __init__(self, class_name: str, methods: list[Method]) -> None:
92
+ super().__init__()
93
+ self._class_name = class_name
94
+ self.data = methods
95
+
96
+ def get(self, name: str) -> Optional[Method]:
97
+ """
98
+ Get a specific method implementation.
99
+ :param name: Method name.
100
+ :return: Method.
101
+ """
102
+ for method in self.data:
103
+ if method.name == name:
104
+ return method
105
+ return None
106
+
107
+ # Actions
108
+
109
+ def bp(self, callback=None, **kwargs):
110
+ """
111
+ Place a breakpoint on all symbols in the method list.
112
+ Look for the bp command for more details.
113
+ :param callback: callback function to be executed upon an hit
114
+ :param kwargs: optional kwargs for the bp command
115
+ """
116
+ for method in self.data:
117
+ kwargs['name'] = f'[{self._class_name} {method.name}]'
118
+ method.imp.bp(callback, **kwargs)
119
+
120
+ def monitor(self, **kwargs):
121
+ """
122
+ Perform monitor for all symbols in the method list.
123
+ See monitor command for more details.
124
+ :param args: given arguments for monitor command
125
+ """
126
+ for method in self.data:
127
+ method.imp.monitor(**kwargs)
128
+
129
+ # Filters
130
+
131
+ def filter_startswith(self, exp, case_sensitive=True):
132
+ """
133
+ Filter only methods with given prefix
134
+ :param exp: prefix
135
+ :param case_sensitive: is case sensitive
136
+ :return: reduced method list
137
+ """
138
+ if not case_sensitive:
139
+ exp = exp.lower()
140
+
141
+ retval = []
142
+ for v in self.data:
143
+ name = v.name
144
+ if not case_sensitive:
145
+ name = name.lower()
146
+ if name.startswith(exp):
147
+ retval.append(v)
148
+ return MethodList(self._class_name, retval)
149
+
150
+ def filter_name_contains(self, exp, case_sensitive=True):
151
+ """
152
+ Filter methods containing a given expression
153
+ :param exp: given expression
154
+ :param case_sensitive: is case sensitive
155
+ :return: reduced method list
156
+ """
157
+ if not case_sensitive:
158
+ exp = exp.lower()
159
+
160
+ retval = []
161
+ for v in self.data:
162
+ name = v.name
163
+ if not case_sensitive:
164
+ name = name.lower()
165
+ if exp in name:
166
+ retval.append(v)
167
+ return MethodList(self._class_name, retval)
168
+
169
+
91
170
  class Class:
92
171
  """
93
172
  Wrapper for ObjectiveC Class object.
@@ -103,8 +182,8 @@ class Class:
103
182
  self.protocols = []
104
183
  self.ivars = []
105
184
  self.properties = []
106
- self.methods = []
107
185
  self.name = ''
186
+ self.methods = MethodList(self.name, [])
108
187
  self.super = None
109
188
  if class_data is None:
110
189
  self.reload()
@@ -160,16 +239,6 @@ class Class:
160
239
  """
161
240
  return self._class_object.objc_call(sel, *args)
162
241
 
163
- def get_method(self, name: str):
164
- """
165
- Get a specific method implementation.
166
- :param name: Method name.
167
- :return: Method.
168
- """
169
- for method in self.methods:
170
- if method.name == name:
171
- return method
172
-
173
242
  def capture_self(self, sync: bool = False):
174
243
  """
175
244
  Capture the first called `self` from this class.
@@ -210,15 +279,13 @@ class Class:
210
279
  """
211
280
  Proxy for monitor command.
212
281
  """
213
- self.symbols_jar.monitor(**kwargs)
282
+ self.methods.monitor(**kwargs)
214
283
 
215
284
  def bp(self, callback=None, **kwargs):
216
285
  """
217
286
  Proxy for bp command.
218
287
  """
219
- for method in self.methods:
220
- kwargs['name'] = f'[{self.name} {method.name}]'
221
- method.imp.bp(callback, **kwargs)
288
+ self.methods.bp(callback, **kwargs)
222
289
 
223
290
  def iter_supers(self):
224
291
  """
@@ -243,17 +310,7 @@ class Class:
243
310
  Property(name=prop['name'], attributes=convert_encoded_property_attributes(prop['attributes']))
244
311
  for prop in data['properties']
245
312
  ]
246
- self.methods = [Method.from_data(method, self._client) for method in data['methods']]
247
-
248
- @property
249
- def symbols_jar(self) -> SymbolsJar:
250
- """ Get a SymbolsJar object for quick operations on all methods """
251
- jar = SymbolsJar.create(self._client)
252
-
253
- for m in self.methods:
254
- jar[f'[{self.name} {m.name}]'] = m.imp
255
-
256
- return jar
313
+ self.methods = MethodList(self.name, [Method.from_data(method, self._client) for method in data['methods']])
257
314
 
258
315
  def __dir__(self):
259
316
  result = set()
@@ -9,9 +9,8 @@ from pygments.formatters import TerminalTrueColorFormatter
9
9
  from pygments.lexers import ObjectiveCLexer
10
10
 
11
11
  from hilda.exceptions import HildaException
12
- from hilda.objective_c_class import Class, Method, Property, convert_encoded_property_attributes
12
+ from hilda.objective_c_class import Class, Method, MethodList, Property, convert_encoded_property_attributes
13
13
  from hilda.symbol import Symbol
14
- from hilda.symbols_jar import SymbolsJar
15
14
 
16
15
 
17
16
  class SettingIvarError(HildaException):
@@ -45,7 +44,7 @@ class ObjectiveCSymbol(Symbol):
45
44
  symbol = super().create(value, client)
46
45
  symbol.ivars = [] # type: List[Ivar]
47
46
  symbol.properties = [] # type: List[Property]
48
- symbol.methods = [] # type: List[Method]
47
+ symbol.methods = MethodList('', []) # type: MethodList
49
48
  symbol.class_ = None # type: Optional[Class]
50
49
  symbol.reload()
51
50
  return symbol
@@ -56,7 +55,7 @@ class ObjectiveCSymbol(Symbol):
56
55
  """
57
56
  self.ivars.clear()
58
57
  self.properties.clear()
59
- self.methods.clear()
58
+ self.methods = MethodList('', [])
60
59
  self.class_ = None
61
60
 
62
61
  obj_c_code = (self._client._hilda_root / 'objective_c' / 'get_objectivec_symbol_data.m').read_text()
@@ -65,12 +64,12 @@ class ObjectiveCSymbol(Symbol):
65
64
 
66
65
  self._reload_ivars(data['ivars'])
67
66
  self._reload_properties(data['properties'])
68
- self.methods = [Method.from_data(method, self._client) for method in data['methods']]
69
67
 
70
68
  data['name'] = data['class_name']
71
69
  data['address'] = data['class_address']
72
70
  data['super'] = data['class_super']
73
71
  self.class_ = Class(self._client, self._client.symbol(data['class_address']), data)
72
+ self.methods = MethodList(self.class_.name, [Method.from_data(method, self._client) for method in data['methods']])
74
73
 
75
74
  def show(self, recursive: bool = False):
76
75
  """
@@ -141,7 +140,7 @@ class ObjectiveCSymbol(Symbol):
141
140
  buf += f'@synthesize {prop.name} = {attrs.synthesize};\n'
142
141
 
143
142
  # Add methods
144
- methods = self.methods.copy()
143
+ methods = list(self.methods)
145
144
 
146
145
  # Add super methods.
147
146
  if recursive:
@@ -158,16 +157,6 @@ class ObjectiveCSymbol(Symbol):
158
157
  buf += '@end'
159
158
  return buf
160
159
 
161
- @property
162
- def symbols_jar(self) -> SymbolsJar:
163
- """ Get a SymbolsJar object for quick operations on all methods """
164
- jar = SymbolsJar.create(self._client)
165
-
166
- for m in self.methods:
167
- jar[m.name] = m.address
168
-
169
- return jar
170
-
171
160
  def __dir__(self):
172
161
  result = set()
173
162
 
@@ -93,15 +93,15 @@ class NanoV2Arena:
93
93
  def __init__(self, arena_base_addr):
94
94
  self.nanov2_arena_struct = Struct(
95
95
  # Note that this only parses 1 CPU memblock (1MB). Modify it to be 64.
96
- *[\
97
- f"blocks_{idx}" / Array(self.blocks_per_size[idx], \
98
- Struct('content' / \
99
- Array(self.slots_per_size[idx], \
100
- Struct('Q' / Bytes(self.size_per_slot[idx]) \
101
- )\
102
- )\
103
- ))\
104
- for idx in range(len(self.blocks_per_size))\
96
+ *[
97
+ f"blocks_{idx}" / Array(self.blocks_per_size[idx],
98
+ Struct('content' /
99
+ Array(self.slots_per_size[idx],
100
+ Struct('Q' / Bytes(self.size_per_slot[idx])
101
+ )
102
+ )
103
+ ))
104
+ for idx in range(len(self.blocks_per_size))
105
105
  ]
106
106
  )
107
107
  self.arena_struct = self.nanov2_arena_struct.parse_stream(arena_base_addr)