hilda 2.0.12__tar.gz → 2.0.15__tar.gz

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.
Files changed (78) hide show
  1. {hilda-2.0.12 → hilda-2.0.15}/.github/workflows/python-app.yml +1 -1
  2. {hilda-2.0.12 → hilda-2.0.15}/PKG-INFO +4 -4
  3. {hilda-2.0.12 → hilda-2.0.15}/hilda/_version.py +2 -2
  4. {hilda-2.0.12 → hilda-2.0.15}/hilda/cli.py +6 -6
  5. {hilda-2.0.12 → hilda-2.0.15}/hilda/common.py +3 -3
  6. {hilda-2.0.12 → hilda-2.0.15}/hilda/hilda_client.py +32 -13
  7. {hilda-2.0.12 → hilda-2.0.15}/hilda/launch_lldb.py +4 -4
  8. {hilda-2.0.12 → hilda-2.0.15}/hilda/lldb_importer.py +1 -1
  9. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c_class.py +2 -2
  10. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c_symbol.py +5 -5
  11. {hilda-2.0.12 → hilda-2.0.15}/hilda/registers.py +1 -1
  12. hilda-2.0.15/hilda/snippets/libmalloc.py +285 -0
  13. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/macho/all_image_infos.py +2 -2
  14. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/macho/image_info.py +1 -1
  15. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/macho/macho_load_commands.py +9 -11
  16. {hilda-2.0.12 → hilda-2.0.15}/hilda/symbol.py +4 -4
  17. {hilda-2.0.12 → hilda-2.0.15}/hilda/ui/views.py +5 -6
  18. {hilda-2.0.12 → hilda-2.0.15}/hilda.egg-info/PKG-INFO +4 -4
  19. {hilda-2.0.12 → hilda-2.0.15}/hilda.egg-info/SOURCES.txt +1 -0
  20. {hilda-2.0.12 → hilda-2.0.15}/pyproject.toml +2 -2
  21. {hilda-2.0.12 → hilda-2.0.15}/.github/workflows/python-publish.yml +0 -0
  22. {hilda-2.0.12 → hilda-2.0.15}/.gitignore +0 -0
  23. {hilda-2.0.12 → hilda-2.0.15}/.pre-commit-config.yaml +0 -0
  24. {hilda-2.0.12 → hilda-2.0.15}/LICENSE +0 -0
  25. {hilda-2.0.12 → hilda-2.0.15}/README.md +0 -0
  26. {hilda-2.0.12 → hilda-2.0.15}/gifs/.gitattributes +0 -0
  27. {hilda-2.0.12 → hilda-2.0.15}/gifs/ui.png +0 -0
  28. {hilda-2.0.12 → hilda-2.0.15}/gifs/xpc_print_message.gif +0 -0
  29. {hilda-2.0.12 → hilda-2.0.15}/hilda/__init__.py +0 -0
  30. {hilda-2.0.12 → hilda-2.0.15}/hilda/__main__.py +0 -0
  31. {hilda-2.0.12 → hilda-2.0.15}/hilda/exceptions.py +0 -0
  32. {hilda-2.0.12 → hilda-2.0.15}/hilda/hilda_ascii_art.html +0 -0
  33. {hilda-2.0.12 → hilda-2.0.15}/hilda/ipython_extensions/events.py +0 -0
  34. {hilda-2.0.12 → hilda-2.0.15}/hilda/ipython_extensions/keybindings.py +0 -0
  35. {hilda-2.0.12 → hilda-2.0.15}/hilda/ipython_extensions/magics.py +0 -0
  36. {hilda-2.0.12 → hilda-2.0.15}/hilda/lldb_entrypoint.py +0 -0
  37. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c/from_ns_to_json.m +0 -0
  38. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c/get_objectivec_class_by_module.m +0 -0
  39. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c/get_objectivec_class_description.m +0 -0
  40. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c/get_objectivec_symbol_data.m +0 -0
  41. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c/lsof.m +0 -0
  42. {hilda-2.0.12 → hilda-2.0.15}/hilda/objective_c/to_ns_from_json.m +0 -0
  43. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/__init__.py +0 -0
  44. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/boringssl.py +0 -0
  45. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/collections.py +0 -0
  46. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/dyld.py +0 -0
  47. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/fs_utils.py +0 -0
  48. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/mach/CFRunLoopServiceMachPort_hooks.py +0 -0
  49. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/mach/__init__.py +0 -0
  50. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/macho/__init__.py +0 -0
  51. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/macho/apple_version.py +0 -0
  52. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/macho/macho.py +0 -0
  53. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/remotepairingd.py +0 -0
  54. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/syslog.py +0 -0
  55. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/uuid.py +0 -0
  56. {hilda-2.0.12 → hilda-2.0.15}/hilda/snippets/xpc.py +0 -0
  57. {hilda-2.0.12 → hilda-2.0.15}/hilda/symbols_jar.py +0 -0
  58. {hilda-2.0.12 → hilda-2.0.15}/hilda/ui/colors.json +0 -0
  59. {hilda-2.0.12 → hilda-2.0.15}/hilda/ui/ui_manager.py +0 -0
  60. {hilda-2.0.12 → hilda-2.0.15}/hilda.egg-info/dependency_links.txt +0 -0
  61. {hilda-2.0.12 → hilda-2.0.15}/hilda.egg-info/entry_points.txt +0 -0
  62. {hilda-2.0.12 → hilda-2.0.15}/hilda.egg-info/requires.txt +0 -0
  63. {hilda-2.0.12 → hilda-2.0.15}/hilda.egg-info/top_level.txt +0 -0
  64. {hilda-2.0.12 → hilda-2.0.15}/requirements.txt +0 -0
  65. {hilda-2.0.12 → hilda-2.0.15}/setup.cfg +0 -0
  66. {hilda-2.0.12 → hilda-2.0.15}/tests/__init__.py +0 -0
  67. {hilda-2.0.12 → hilda-2.0.15}/tests/conftest.py +0 -0
  68. {hilda-2.0.12 → hilda-2.0.15}/tests/test_hilda_client/test_from_ns.py +0 -0
  69. {hilda-2.0.12 → hilda-2.0.15}/tests/test_hilda_client/test_hilda_client.py +0 -0
  70. {hilda-2.0.12 → hilda-2.0.15}/tests/test_hilda_client/test_monitor.py +0 -0
  71. {hilda-2.0.12 → hilda-2.0.15}/tests/test_hilda_client/test_ns.py +0 -0
  72. {hilda-2.0.12 → hilda-2.0.15}/tests/test_hilda_client/test_rebind_symbols.py +0 -0
  73. {hilda-2.0.12 → hilda-2.0.15}/tests/test_hilda_client/test_registers.py +0 -0
  74. {hilda-2.0.12 → hilda-2.0.15}/tests/test_snippets/test_xpc.py +0 -0
  75. {hilda-2.0.12 → hilda-2.0.15}/tests/test_symbols/test_objective_c_class.py +0 -0
  76. {hilda-2.0.12 → hilda-2.0.15}/tests/test_symbols/test_objective_c_symbol.py +0 -0
  77. {hilda-2.0.12 → hilda-2.0.15}/tests/test_symbols/test_symbol.py +0 -0
  78. {hilda-2.0.12 → hilda-2.0.15}/tests/test_symbols/test_symbols_jar.py +0 -0
@@ -16,7 +16,7 @@ jobs:
16
16
 
17
17
  strategy:
18
18
  matrix:
19
- python-version: [ 3.8, 3.9, "3.10", "3.11", "3.12" ]
19
+ python-version: [ 3.9, "3.10", "3.11", "3.12", "3.13" ]
20
20
  os: [ macos-latest ]
21
21
 
22
22
  steps:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: hilda
3
- Version: 2.0.12
3
+ Version: 2.0.15
4
4
  Summary: LLDB wrapped and empowered by iPython's features
5
5
  Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>, netanel cohen <netanelc305@protonmail.com>
6
6
  Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>, netanel cohen <netanelc305@protonmail.com>
@@ -31,13 +31,13 @@ Classifier: Operating System :: MacOS
31
31
  Classifier: Development Status :: 5 - Production/Stable
32
32
  Classifier: License :: OSI Approved :: MIT License
33
33
  Classifier: Programming Language :: Python :: 3
34
- Classifier: Programming Language :: Python :: 3.8
35
34
  Classifier: Programming Language :: Python :: 3.9
36
35
  Classifier: Programming Language :: Python :: 3.10
37
36
  Classifier: Programming Language :: Python :: 3.11
38
37
  Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
39
  Classifier: Programming Language :: Python :: 3 :: Only
40
- Requires-Python: >=3.8
40
+ Requires-Python: >=3.9
41
41
  Description-Content-Type: text/markdown
42
42
  License-File: LICENSE
43
43
  Requires-Dist: tqdm
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '2.0.12'
16
- __version_tuple__ = version_tuple = (2, 0, 12)
15
+ __version__ = version = '2.0.15'
16
+ __version_tuple__ = version_tuple = (2, 0, 15)
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from pathlib import Path
3
- from typing import List, Optional
3
+ from typing import Optional
4
4
 
5
5
  import click
6
6
  import coloredlogs
@@ -23,7 +23,7 @@ def cli():
23
23
  startup_files_option = click.option('-f', '--startup_files', multiple=True, help='Files to run on start')
24
24
 
25
25
 
26
- def parse_envp(ctx: click.Context, param: click.Parameter, value: List[str]) -> List[str]:
26
+ def parse_envp(ctx: click.Context, param: click.Parameter, value: list[str]) -> list[str]:
27
27
  env_list = []
28
28
  for item in value:
29
29
  try:
@@ -38,7 +38,7 @@ def parse_envp(ctx: click.Context, param: click.Parameter, value: List[str]) ->
38
38
  @click.argument('hostname', default='localhost')
39
39
  @click.argument('port', type=click.INT, default=DEFAULT_HILDA_PORT)
40
40
  @startup_files_option
41
- def remote(hostname: str, port: int, startup_files: List[str]) -> None:
41
+ def remote(hostname: str, port: int, startup_files: list[str]) -> None:
42
42
  """ Connect to remote debugserver at given address """
43
43
  with create_hilda_client_using_remote_attach(hostname, port) as hilda_client:
44
44
  hilda_client.interact(startup_files=startup_files)
@@ -48,7 +48,7 @@ def remote(hostname: str, port: int, startup_files: List[str]) -> None:
48
48
  @click.option('-n', '--name', help='process name to attach')
49
49
  @click.option('-p', '--pid', type=click.INT, help='pid to attach')
50
50
  @startup_files_option
51
- def attach(name: Optional[str], pid: Optional[int], startup_files: List[str]) -> None:
51
+ def attach(name: Optional[str], pid: Optional[int], startup_files: list[str]) -> None:
52
52
  """ Attach to given process and start a lldb shell """
53
53
  if name is not None:
54
54
  hilda_client = create_hilda_client_using_attach_by_name(name)
@@ -78,9 +78,9 @@ def cli_bare() -> None:
78
78
  @click.option('--cwd', help='Set the working directory for the process')
79
79
  @click.option('--flags', type=click.INT, default=0, help='Launch flags (bitmask)')
80
80
  @startup_files_option
81
- def launch(exec_path: str, argv: List[str], envp: List[str], stdin: Optional[Path],
81
+ def launch(exec_path: str, argv: list[str], envp: list[str], stdin: Optional[Path],
82
82
  stdout: Optional[Path], stderr: Optional[Path], cwd: Optional[Path], flags: Optional[int],
83
- startup_files: List[str]) -> None:
83
+ startup_files: list[str]) -> None:
84
84
  """ Attach to a given process and start a lldb shell """
85
85
  argv = list(argv)
86
86
  envp = list(envp)
@@ -1,14 +1,14 @@
1
1
  from datetime import datetime
2
- from typing import Any, List, Mapping, Tuple, Union
2
+ from typing import Any, Union
3
3
 
4
4
  import inquirer3
5
5
  from inquirer3.themes import GreenPassion
6
6
 
7
7
  CfSerializable = Union[
8
- Mapping[str, Any], List, Tuple[Any, ...], str, bool, float, bytes, datetime, None]
8
+ dict[str, Any], list, tuple[Any, ...], str, bool, float, bytes, datetime, None]
9
9
 
10
10
 
11
- def selection_prompt(options_list: List):
11
+ def selection_prompt(options_list: list):
12
12
  question = [inquirer3.List('choice', message='choose device', choices=options_list, carousel=True)]
13
13
  result = inquirer3.prompt(question, theme=GreenPassion(), raise_keyboard_interrupt=True)
14
14
  return result['choice']
@@ -16,7 +16,7 @@ from dataclasses import dataclass, field
16
16
  from datetime import datetime, timezone
17
17
  from functools import cached_property, wraps
18
18
  from pathlib import Path
19
- from typing import Any, Callable, List, Optional, Union
19
+ from typing import Any, Callable, Optional, Union
20
20
 
21
21
  import hexdump
22
22
  import IPython
@@ -125,9 +125,29 @@ def stop_is_needed(func: Callable):
125
125
  return wrapper
126
126
 
127
127
 
128
- class HildaClient:
129
- Breakpoint = namedtuple('Breakpoint', 'address options forced callback')
128
+ class HildaBreakpoint:
129
+ def __init__(self, hilda_client: 'HildaClient', lldb_breakpoint: lldb.SBBreakpoint,
130
+ address: Union[str, int], forced: bool = False, options: Optional[typing.Mapping] = None,
131
+ callback: Optional[Callable] = None) -> None:
132
+ self._hilda_client = hilda_client
133
+ self.address = address
134
+ self.forced = forced
135
+ self.options = options
136
+ self.callback = callback
137
+ self.lldb_breakpoint = lldb_breakpoint
138
+
139
+ def __repr__(self) -> str:
140
+ return (f'<{self.__class__.__name__} LLDB:{self.lldb_breakpoint} FORCED:{self.forced} OPTIONS:{self.options} '
141
+ f'CALLBACK:{self.callback}>')
142
+
143
+ def __str__(self) -> str:
144
+ return repr(self)
130
145
 
146
+ def remove(self) -> None:
147
+ self._hilda_client.remove_hilda_breakpoint(self.lldb_breakpoint.id)
148
+
149
+
150
+ class HildaClient:
131
151
  RETVAL_BIT_COUNT = 64
132
152
 
133
153
  def __init__(self, debugger: lldb.SBDebugger):
@@ -174,7 +194,7 @@ class HildaClient:
174
194
  # convert FDs into int
175
195
  return {int(k): v for k, v in result.items()}
176
196
 
177
- def bt(self, should_print: bool = False, depth: Optional[int] = None) -> List[Union[str, lldb.SBFrame]]:
197
+ def bt(self, should_print: bool = False, depth: Optional[int] = None) -> list[Union[str, lldb.SBFrame]]:
178
198
  """ Print an improved backtrace. """
179
199
  backtrace = []
180
200
  for i, frame in enumerate(self.thread.frames):
@@ -473,7 +493,7 @@ class HildaClient:
473
493
  with self.stopped():
474
494
  return self.evaluate_expression(call_expression)
475
495
 
476
- def monitor(self, address, condition: str = None, **options) -> lldb.SBBreakpoint:
496
+ def monitor(self, address, condition: str = None, **options) -> HildaBreakpoint:
477
497
  """
478
498
  Monitor every time a given address is called
479
499
 
@@ -613,7 +633,7 @@ class HildaClient:
613
633
  if remove_forced or not bp.forced:
614
634
  self.remove_hilda_breakpoint(bp_id)
615
635
 
616
- def remove_hilda_breakpoint(self, bp_id):
636
+ def remove_hilda_breakpoint(self, bp_id: int) -> None:
617
637
  """
618
638
  Remove a single breakpoint placed by Hilda
619
639
  :param bp_id: Breakpoint's ID
@@ -647,7 +667,7 @@ class HildaClient:
647
667
  print(highlight(entitlements, XmlLexer(), TerminalTrueColorFormatter()))
648
668
 
649
669
  def bp(self, address_or_name: Union[int, str], callback: Optional[Callable] = None, condition: str = None,
650
- forced=False, module_name: Optional[str] = None, **options) -> lldb.SBBreakpoint:
670
+ forced=False, module_name: Optional[str] = None, **options) -> HildaBreakpoint:
651
671
  """
652
672
  Add a breakpoint
653
673
  :param address_or_name:
@@ -676,15 +696,14 @@ class HildaClient:
676
696
  bp.SetCondition(condition)
677
697
 
678
698
  # add into Hilda's internal list of breakpoints
679
- self.breakpoints[bp.id] = HildaClient.Breakpoint(
680
- address=address_or_name, options=options, forced=forced, callback=callback
681
- )
699
+ self.breakpoints[bp.id] = HildaBreakpoint(self, bp, address=address_or_name, forced=forced, options=options,
700
+ callback=callback)
682
701
 
683
702
  if callback is not None:
684
703
  bp.SetScriptCallbackFunction('lldb.hilda_client.bp_callback_router')
685
704
 
686
705
  self.log_info(f'Breakpoint #{bp.id} has been set')
687
- return bp
706
+ return self.breakpoints[bp.id]
688
707
 
689
708
  def bp_callback_router(self, frame, bp_loc, *_):
690
709
  """
@@ -968,7 +987,7 @@ class HildaClient:
968
987
  """
969
988
  block = self.symbols.malloc(size)
970
989
  if block == 0:
971
- raise IOError(f'failed to allocate memory of size: {size} bytes')
990
+ raise OSError(f'failed to allocate memory of size: {size} bytes')
972
991
 
973
992
  try:
974
993
  yield block
@@ -1076,7 +1095,7 @@ class HildaClient:
1076
1095
  self.cont()
1077
1096
 
1078
1097
  def interact(self, additional_namespace: Optional[typing.Mapping] = None,
1079
- startup_files: Optional[List[str]] = None) -> None:
1098
+ startup_files: Optional[list[str]] = None) -> None:
1080
1099
  """ Start an interactive Hilda shell """
1081
1100
  if not self._dynamic_env_loaded:
1082
1101
  self.init_dynamic_environment()
@@ -3,7 +3,7 @@ import os
3
3
  import sys
4
4
  from abc import ABC, abstractmethod
5
5
  from threading import Thread
6
- from typing import List, Optional
6
+ from typing import Optional
7
7
 
8
8
  from hilda.exceptions import LLDBError
9
9
  from hilda.hilda_client import HildaClient
@@ -146,7 +146,7 @@ class LLDBAttachName(LLDBListenerThread):
146
146
 
147
147
 
148
148
  class LLDBLaunch(LLDBListenerThread):
149
- def __init__(self, exec_path: str, argv: Optional[List[str]] = None, envp: Optional[List[str]] = None,
149
+ def __init__(self, exec_path: str, argv: Optional[list[str]] = None, envp: Optional[list[str]] = None,
150
150
  stdin: Optional[str] = None,
151
151
  stdout: Optional[str] = None, stderr: Optional[str] = None, wd: Optional[str] = None,
152
152
  flags: Optional[int] = 0):
@@ -167,7 +167,7 @@ class LLDBLaunch(LLDBListenerThread):
167
167
  # Launch(SBTarget self, SBListener listener, char const ** argv, char const ** envp,
168
168
  # char const * stdin_path, char const * stdout_path, char const * stderr_path, char const * working_directory,
169
169
  # uint32_t launch_flags, bool stop_at_entry, SBError error) -> SBProcess
170
- logger.debug(f'Lunching process {self.exec_path}')
170
+ logger.debug(f'Launching process {self.exec_path}')
171
171
  return self.target.Launch(self.listener, self.argv, self.envp,
172
172
  self.stdin, self.stdout, self.stderr, self.working_directory,
173
173
  self.flags, True,
@@ -189,7 +189,7 @@ def create_hilda_client_using_remote_attach(
189
189
 
190
190
 
191
191
  def create_hilda_client_using_launch(
192
- exec_path: str, argv: Optional[List] = None, envp: Optional[List] = None, stdin: Optional[str] = None,
192
+ exec_path: str, argv: Optional[list] = None, envp: Optional[list] = None, stdin: Optional[str] = None,
193
193
  stdout: Optional[str] = None, stderr: Optional[str] = None, wd: Optional[str] = None,
194
194
  flags: Optional[int] = 0) -> HildaClient:
195
195
  lldb_t = LLDBLaunch(exec_path, argv, envp, stdin, stdout, stderr, wd, flags)
@@ -8,7 +8,7 @@ logger = logging.getLogger(__name__)
8
8
 
9
9
 
10
10
  def get_lldb_python_path() -> str:
11
- result = subprocess.run(['lldb', '-P'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
11
+ result = subprocess.run(['lldb', '-P'], capture_output=True, text=True, check=True)
12
12
  return result.stdout.strip()
13
13
 
14
14
 
@@ -89,7 +89,7 @@ class Method:
89
89
  return f'{prefix} {name}; // 0x{self.address:x} (returns: {self.return_type})\n'
90
90
 
91
91
 
92
- class Class(object):
92
+ class Class:
93
93
  """
94
94
  Wrapper for ObjectiveC Class object.
95
95
  """
@@ -273,7 +273,7 @@ class Class(object):
273
273
  if method.is_class:
274
274
  result.add(method.name.replace(':', '_'))
275
275
 
276
- result.update(list(super(Class, self).__dir__()))
276
+ result.update(list(super().__dir__()))
277
277
  return list(result)
278
278
 
279
279
  def __str__(self):
@@ -42,7 +42,7 @@ class ObjectiveCSymbol(Symbol):
42
42
  :return: ObjectiveCSymbol object.
43
43
  :rtype: ObjectiveCSymbol
44
44
  """
45
- symbol = super(ObjectiveCSymbol, cls).create(value, client)
45
+ symbol = super().create(value, client)
46
46
  symbol.ivars = [] # type: List[Ivar]
47
47
  symbol.properties = [] # type: List[Property]
48
48
  symbol.methods = [] # type: List[Method]
@@ -183,12 +183,12 @@ class ObjectiveCSymbol(Symbol):
183
183
  for method in sup.methods:
184
184
  result.add(method.name.replace(':', '_'))
185
185
 
186
- result.update(list(super(ObjectiveCSymbol, self).__dir__()))
186
+ result.update(list(super().__dir__()))
187
187
  return list(result)
188
188
 
189
189
  def __getitem__(self, item):
190
190
  if isinstance(item, int):
191
- return super(ObjectiveCSymbol, self).__getitem__(item)
191
+ return super().__getitem__(item)
192
192
 
193
193
  # Ivars
194
194
  for ivar in self.ivars:
@@ -217,7 +217,7 @@ class ObjectiveCSymbol(Symbol):
217
217
 
218
218
  def __setitem__(self, key, value):
219
219
  if isinstance(key, int):
220
- super(ObjectiveCSymbol, self).__setitem__(key, value)
220
+ super().__setitem__(key, value)
221
221
  return
222
222
 
223
223
  with suppress(SettingIvarError):
@@ -232,7 +232,7 @@ class ObjectiveCSymbol(Symbol):
232
232
  try:
233
233
  self._set_ivar(key, value)
234
234
  except SettingIvarError:
235
- super(ObjectiveCSymbol, self).__setattr__(key, value)
235
+ super().__setattr__(key, value)
236
236
 
237
237
  def __str__(self):
238
238
  return self._to_str(False)
@@ -1,4 +1,4 @@
1
- class Registers(object):
1
+ class Registers:
2
2
  """
3
3
  Wrapper for more convenient access to modify current frame's registers
4
4
  """
@@ -0,0 +1,285 @@
1
+ from construct import Array, BitsInteger, BitStruct, Bytes, Enum, Flag, Hex, Int32ul, Int64ul, Padding, Struct, Tell
2
+
3
+ from hilda.lldb_importer import lldb
4
+ from hilda.symbol import SymbolFormatField
5
+
6
+ malloc_zone_t = Struct(
7
+ 'RESERVED_1_CFALLOCATOR' / Hex(Int64ul),
8
+ 'RESERVED_2_CFALLOCATOR' / Hex(Int64ul),
9
+ 'size' / SymbolFormatField(lldb.hilda_client),
10
+ 'malloc' / SymbolFormatField(lldb.hilda_client),
11
+ 'calloc' / SymbolFormatField(lldb.hilda_client),
12
+ 'valloc' / SymbolFormatField(lldb.hilda_client),
13
+ 'free' / SymbolFormatField(lldb.hilda_client),
14
+ 'realloc' / SymbolFormatField(lldb.hilda_client),
15
+ 'destroy' / SymbolFormatField(lldb.hilda_client),
16
+ 'zone_name' / SymbolFormatField(lldb.hilda_client),
17
+ 'batch_malloc' / SymbolFormatField(lldb.hilda_client),
18
+ 'batch_free' / SymbolFormatField(lldb.hilda_client),
19
+ 'introspect' / SymbolFormatField(lldb.hilda_client),
20
+ 'version' / SymbolFormatField(lldb.hilda_client),
21
+ 'memalign' / SymbolFormatField(lldb.hilda_client),
22
+ 'free_definite_size' / SymbolFormatField(lldb.hilda_client),
23
+ 'pressure_relief' / SymbolFormatField(lldb.hilda_client),
24
+ 'claimed_address' / SymbolFormatField(lldb.hilda_client),
25
+ 'try_free_default' / SymbolFormatField(lldb.hilda_client),
26
+ 'malloc_with_options' / SymbolFormatField(lldb.hilda_client),
27
+ 'malloc_type_malloc' / SymbolFormatField(lldb.hilda_client),
28
+ 'malloc_type_calloc' / SymbolFormatField(lldb.hilda_client),
29
+ 'malloc_type_realloc' / SymbolFormatField(lldb.hilda_client),
30
+ 'malloc_type_memalign' / SymbolFormatField(lldb.hilda_client),
31
+ 'malloc_type_malloc_with_options' / SymbolFormatField(lldb.hilda_client),
32
+ )
33
+
34
+ nanov2_statistics_t = Struct(
35
+ 'allocated_regions' / Hex(Int32ul),
36
+ 'region_addresses_clhashes' / Hex(Int32ul),
37
+ # 'size_class_statistics' / Array(16, nanov2_size_class_statistics)
38
+ )
39
+
40
+ nanozonev2_s = Struct(
41
+ 'address' / Tell,
42
+ 'basic_zone' / malloc_zone_t,
43
+ # pad used to mprotect the first page
44
+ Padding(0x4000 - malloc_zone_t.sizeof()+32),
45
+ # metadata of arena blocks
46
+ 'current_block' / Hex(Int64ul),
47
+ # current_block_lock omitted
48
+ Padding(0x2fd4),
49
+ 'delegate_allocations' / Hex(Int32ul),
50
+ 'debug_flags' / Hex(Int64ul),
51
+ 'aslr_cookie' / Hex(Int64ul),
52
+ 'aslr_cookie_aligned' / Hex(Int64ul),
53
+ 'slot_freelist_cookies' / Hex(Int64ul),
54
+ 'helper_zone' / Hex(Int64ul),
55
+ 'block_lock' / Hex(Int32ul),
56
+ 'regions_lock' / Hex(Int32ul),
57
+ 'first_region_base_ptr' / Hex(Int64ul),
58
+ 'current_region_next_arena' / Hex(Int64ul),
59
+ 'madvise_lock' / Hex(Int64ul),
60
+ 'nanov2_statistics_t' / nanov2_statistics_t
61
+ )
62
+
63
+ nanov2_size_class_statistics = Struct(
64
+ 'total_allocations' / Hex(Int64ul),
65
+ 'total_frees' / Hex(Int64ul),
66
+ 'madvised_blocks' / Hex(Int64ul),
67
+ 'madvise_races' / Hex(Int64ul),
68
+ )
69
+
70
+
71
+ class NanoV2Zone:
72
+
73
+ def __init__(self, nanov2_base_addr, helper_zone_ptr):
74
+ self.nanov2_base_addr = nanov2_base_addr
75
+ self.nanov2_struct = nanozonev2_s.parse_stream(self.nanov2_base_addr)
76
+ if not self._sanity_check(helper_zone_ptr):
77
+ self.nanov2_struct = None
78
+
79
+ def _sanity_check(self, helper_zone_ptr):
80
+ return helper_zone_ptr == int(str(self.nanov2_struct.helper_zone), 16)
81
+
82
+ def get_nanov2_struct(self):
83
+ return self.nanov2_struct
84
+
85
+
86
+ class NanoV2Arena:
87
+ # You would have to iterate for 64 times to dump everything. But not going to dump 64MB...
88
+ # Found at nanov2_malloc.c
89
+ size_per_slot = [16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256]
90
+ blocks_per_size = [2, 10, 11, 10, 5, 3, 3, 4, 3, 2, 2, 2, 2, 2, 1, 2]
91
+ slots_per_size = [1024, 512, 341, 256, 204, 170, 146, 128, 113, 102, 93, 85, 78, 73, 68, 64]
92
+
93
+ def __init__(self, arena_base_addr):
94
+ self.nanov2_arena_struct = Struct(
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))\
105
+ ]
106
+ )
107
+ self.arena_struct = self.nanov2_arena_struct.parse_stream(arena_base_addr)
108
+
109
+ def get_arena_struct(self):
110
+ return self.arena_struct
111
+
112
+
113
+ class NanoV2ArenaMetadataBlock:
114
+ # This is used by libmalloc to store the metadata of the arena blocks which is used during allocations.
115
+ # It is a matrix because we have a list of block sizes * CPU_NUMBER.
116
+
117
+ NEXT_SLOT = Enum(BitsInteger(11),
118
+ SLOT_NULL=0,
119
+ SLOT_GUARD=0x7fa,
120
+ SLOT_BUMP=0x7fb,
121
+ SLOT_FULL=0x7fc,
122
+ SLOT_CAN_MADVISE=0x7fd,
123
+ SLOT_MADVISING=0x7fe,
124
+ SLOT_MADVISED=0x7ff
125
+ )
126
+
127
+ block_meta_t = BitStruct(
128
+ 'in_use' / Flag,
129
+ 'gen_count' / Hex(BitsInteger(10)),
130
+ 'free_count' / Hex(BitsInteger(10)),
131
+ 'next_slot' / NEXT_SLOT,
132
+ )
133
+
134
+ def __init__(self, curr_block_addr):
135
+ self.nanov2_arena_metablock_t = Struct(
136
+ # We can't directly parse the block_meta with the CStruct.
137
+ # It has to be Int32ul first because BitStruct does not handle unalignment properly.
138
+ "arena_block_meta" / Array(4096, Hex(Int32ul))
139
+ )
140
+ self.curr_block_addr = curr_block_addr
141
+ self.arena_metadata_block = self.nanov2_arena_metablock_t.parse_stream(curr_block_addr)
142
+
143
+ def dump_arena_metadata_block(self):
144
+ block_idx = 0
145
+ for meta_block in self.arena_metadata_block.arena_block_meta:
146
+ hex_meta_contents = str(meta_block)[2:]
147
+ block_meta_struct = self.block_meta_t.parse(bytes.fromhex(hex_meta_contents))
148
+ if block_meta_struct.in_use:
149
+ print(f"Arena block index {block_idx} (CPU {int(block_idx / 64) - 1}): next: {block_meta_struct.next_slot}")
150
+ block_idx = block_idx + 1
151
+
152
+
153
+ RACK_TYPE = Enum(Int32ul,
154
+ RACK_TYPE_NONE=0,
155
+ RACK_TYPE_TINY=1,
156
+ RACK_TYPE_SMALL=2,
157
+ RACK_TYPE_MEDIUM=3
158
+ )
159
+
160
+ region_hash_generation_t = Struct(
161
+ 'num_regions_allocated' / Hex(Int64ul),
162
+ 'num_regions_allocated_shift' / Hex(Int64ul),
163
+ 'hashed_regions_ptr' / Hex(Int64ul),
164
+ 'nextgen_ptr' / Hex(Int64ul),
165
+ )
166
+
167
+ rack_s = Struct(
168
+ # Keep in mind this struct is MALLOC_CACHE_ALIGN(128) aligned.
169
+ 'address' / Tell,
170
+ 'region_lock' / Hex(Int32ul),
171
+ 'type' / RACK_TYPE,
172
+ 'num_regions' / Hex(Int64ul),
173
+ 'num_regions_dealloc' / Hex(Int64ul),
174
+ 'region_generation_ptr' / Hex(Int64ul),
175
+ 'rg' / Array(2, region_hash_generation_t),
176
+ 'initial_regions' / Array(64, Hex(Int64ul)),
177
+ 'num_magazines' / Hex(Int32ul),
178
+ 'num_magazines_mask' / Hex(Int32ul),
179
+ 'num_magazines_mask_shift' / Hex(Int32ul),
180
+ 'debug_flags' / Hex(Int32ul),
181
+ 'magazines' / Hex(Int64ul),
182
+ 'cookie' / Hex(Int64ul),
183
+ 'last_madvise' / Hex(Int64ul),
184
+ )
185
+
186
+ szone_t = Struct(
187
+ 'address' / Tell,
188
+ 'basic_zone' / malloc_zone_t,
189
+ # it seems like the offset is 0x4068 from the start of the basic_zone to the tiny rack
190
+ Padding(0x4000 - malloc_zone_t.sizeof() + 0x68),
191
+ 'cpu_id_key' / Hex(Int64ul),
192
+ 'debug_flags' / Hex(Int64ul),
193
+ 'log_address' / Hex(Int64ul),
194
+ 'tiny_rack' / rack_s,
195
+ Padding(0x78),
196
+ 'small_rack' / rack_s,
197
+ Padding(0x78),
198
+ 'medium_rack' / rack_s,
199
+ 'large_szone_lock' / Hex(Int32ul),
200
+ 'num_large_objects_in_use' / Hex(Int32ul),
201
+ 'num_large_entries' / Hex(Int32ul),
202
+ 'large_entries' / Hex(Int64ul),
203
+ 'num_bytes_in_large_objects' / Hex(Int64ul),
204
+ # for macOS, CONFIG_LARGE_CACHE is True. For iOS is False (TODO)
205
+ )
206
+
207
+
208
+ class HelperZone:
209
+ def __init__(self, helper_zone_ptr):
210
+ self.szone_struct = szone_t.parse_stream(helper_zone_ptr)
211
+
212
+ def get_helper_zone(self):
213
+ return self.szone_struct
214
+
215
+
216
+ def _get_nanov2_zone():
217
+ hilda = lldb.hilda_client
218
+ default_nanozone_ptr = hilda.symbols.malloc_zones[0][0]
219
+ # we need the helper_zone_ptr to perform a sanity check on the parsing.
220
+ helper_zone_ptr = hilda.symbols.malloc_zones[0][1]
221
+ return NanoV2Zone(default_nanozone_ptr, helper_zone_ptr)
222
+
223
+
224
+ def dump_helper_zone():
225
+ hilda = lldb.hilda_client
226
+ helper_zone_ptr = hilda.symbols.malloc_zones[0][1]
227
+ helper_zone = HelperZone(helper_zone_ptr)
228
+ print(helper_zone.get_helper_zone())
229
+
230
+
231
+ def dump_nanov2_zone():
232
+ nano_zone_class = _get_nanov2_zone()
233
+ print(nano_zone_class.get_nanov2_struct())
234
+
235
+
236
+ def dump_used_arena():
237
+ """
238
+ Arena first block is the metadata
239
+ Afterwards, arena consists of 64 logical blocks (1 per each CPU) that each of them is 1MB.
240
+ Each CPU mem block is -> blocks_per_size = [2,10,11,10,5,3,3,4,3,2,2,2,2,2,1,2] -> 64 blocks
241
+ Something like this:
242
+
243
+ (remember, 1 block is 16k)
244
+ ----------------------------------
245
+ ARENA_METADATA_BLOCK - 16K
246
+ ----------------------------------
247
+ (it is inline, this arrow is not a ptr. just drawing purposes.)
248
+ CPU_0_MEM_BLOCK - 1MB -----------> | BLOCK_16 * 2
249
+ BLOCK_32 * 10
250
+ BLOCK_48 * 11
251
+ .... (check blocks_per_size)
252
+ ----------------------------------
253
+ CPU_1_MEM_BLOCK - 1MB
254
+ ----------------------------------
255
+ CPU_X_MEM_BLOCK - 1MB (There are up to 64!)
256
+ ----------------------------------
257
+
258
+ Which makes an arena 64CPU mem blocks * 1 mb = 64mb + arena metadata block = 65mb.
259
+ A region consists of 8 arenas which results in 64mb * 8 = 512mb (no metadata accounted)
260
+ """
261
+
262
+ # Note there can be up to NANOV2_ARENAS_PER_REGION arenas (8). We will only dump 1 of them.
263
+ hilda = lldb.hilda_client
264
+ nano_zone_class = _get_nanov2_zone()
265
+ # arena base addr is always 0x0000600000000000 + aslr_cookie_enabled + 0x4000 (first block is the arena metablock)
266
+ first_region_base_ptr_int = int(str(nano_zone_class.get_nanov2_struct().first_region_base_ptr), 16)
267
+ aslr_cookie_aligned_int = int(str(nano_zone_class.get_nanov2_struct().aslr_cookie_aligned), 16)
268
+ arena_addr = first_region_base_ptr_int + aslr_cookie_aligned_int + 0x4000
269
+ nanov2_arena_struct = NanoV2Arena(hilda.symbol(arena_addr))
270
+ with open('/tmp/arena_contents.txt', 'w') as arena_dump_file:
271
+ print("Dumping 1MB of arena (CPU_0 mem block) contents into /tmp/arena_contents.txt.")
272
+ arena_dump_file.write(str(nanov2_arena_struct.get_arena_struct()))
273
+
274
+
275
+ def dump_nanov2_block_metadata():
276
+ # The metadata block is the first logical block in the arena. Arena metadata is at arena_addr + aslr_cookie_aligned
277
+ hilda = lldb.hilda_client
278
+ nano_zone_class = _get_nanov2_zone()
279
+ first_region_base_ptr_int = int(str(nano_zone_class.get_nanov2_struct().first_region_base_ptr), 16)
280
+ aslr_cookie_aligned_int = int(str(nano_zone_class.get_nanov2_struct().aslr_cookie_aligned), 16)
281
+ metadata_addr = first_region_base_ptr_int + aslr_cookie_aligned_int
282
+ print(f"Arena metadata can be found at {metadata_addr:x}")
283
+ current_block_symbol = hilda.symbol(metadata_addr)
284
+ meta_block_class = NanoV2ArenaMetadataBlock(current_block_symbol)
285
+ meta_block_class.dump_arena_metadata_block()
@@ -47,7 +47,7 @@ all_image_infos_t = Struct(
47
47
  )
48
48
 
49
49
 
50
- class AllImageInfos(object):
50
+ class AllImageInfos:
51
51
  def reload(self):
52
52
  with lldb.hilda_client.stopped(1):
53
53
  all_image_infos_symbol = lldb.hilda_client.symbol(lldb.hilda_client.symbols.dyld_all_image_infos)
@@ -98,7 +98,7 @@ class AllImageInfos(object):
98
98
  if len(unique_images) > 1:
99
99
  image = AllImageInfos.__select_specific_image(unique_images)
100
100
 
101
- dependencies = set([image_name.path for image_name in image.load_commands.dylib_commands])
101
+ dependencies = {image_name.path for image_name in image.load_commands.dylib_commands}
102
102
 
103
103
  return dependencies
104
104
 
@@ -22,7 +22,7 @@ dyld_uuid_info_t = Struct(
22
22
  )
23
23
 
24
24
 
25
- class ImageInfo(object):
25
+ class ImageInfo:
26
26
  def __init__(self, image_info_data):
27
27
  self.__image_info_data = image_info_data
28
28
  self.__file_path = image_info_data.imageFilePath
@@ -1,5 +1,3 @@
1
- from typing import List
2
-
3
1
  from construct import Array, Bytes, Enum, Hex, Int8ul, Int32ul, Int64ul, PaddedString, Pointer, Seek, Struct, Switch, \
4
2
  Tell, this
5
3
 
@@ -142,7 +140,7 @@ load_command_t = Struct(
142
140
  )
143
141
 
144
142
 
145
- class LoadCommand(object):
143
+ class LoadCommand:
146
144
  def __init__(self, load_command_data):
147
145
  self.__load_command_data = load_command_data
148
146
  self.__cmd = load_command_data.cmd
@@ -160,7 +158,7 @@ class LoadCommand(object):
160
158
 
161
159
  class DylibCommand(LoadCommand):
162
160
  def __init__(self, load_command_data):
163
- super(DylibCommand, self).__init__(load_command_data)
161
+ super().__init__(load_command_data)
164
162
  dylib_data = load_command_data.data.dylib
165
163
 
166
164
  self.__path = dylib_data.lc_str.name
@@ -181,7 +179,7 @@ class DylibCommand(LoadCommand):
181
179
 
182
180
  class Segment64Command(LoadCommand):
183
181
  def __init__(self, load_command_data):
184
- super(Segment64Command, self).__init__(load_command_data)
182
+ super().__init__(load_command_data)
185
183
 
186
184
  self.__segname = load_command_data.data.segname
187
185
  self.__vmaddr = load_command_data.data.vmaddr
@@ -210,7 +208,7 @@ class Segment64Command(LoadCommand):
210
208
 
211
209
  class UUIDCommand(LoadCommand):
212
210
  def __init__(self, load_command_data):
213
- super(UUIDCommand, self).__init__(load_command_data)
211
+ super().__init__(load_command_data)
214
212
 
215
213
  self.__uuid = load_command_data.data.uuid
216
214
 
@@ -223,7 +221,7 @@ class UUIDCommand(LoadCommand):
223
221
 
224
222
  class BuildVersionCommand(LoadCommand):
225
223
  def __init__(self, load_command_data):
226
- super(BuildVersionCommand, self).__init__(load_command_data)
224
+ super().__init__(load_command_data)
227
225
 
228
226
  self.__platform = load_command_data.data.platform
229
227
  self.__minos = load_command_data.data.platform
@@ -252,7 +250,7 @@ class BuildVersionCommand(LoadCommand):
252
250
 
253
251
  class UnimplementedCommand(LoadCommand):
254
252
  def __init__(self, load_command_data):
255
- super(UnimplementedCommand, self).__init__(load_command_data)
253
+ super().__init__(load_command_data)
256
254
 
257
255
  self.__bytes = load_command_data.data
258
256
 
@@ -287,15 +285,15 @@ class LoadCommands:
287
285
  return self.__load_commands
288
286
 
289
287
  @property
290
- def segment_commands(self) -> List[Segment64Command]:
288
+ def segment_commands(self) -> list[Segment64Command]:
291
289
  return [segment_command for segment_command in self.__load_commands if
292
290
  isinstance(segment_command, Segment64Command)]
293
291
 
294
292
  @property
295
- def dylib_commands(self) -> List[DylibCommand]:
293
+ def dylib_commands(self) -> list[DylibCommand]:
296
294
  return [dylib_command for dylib_command in self.__load_commands if isinstance(dylib_command, DylibCommand)]
297
295
 
298
- def find(self, predicate=None) -> List[LoadCommand]:
296
+ def find(self, predicate=None) -> list[LoadCommand]:
299
297
  if predicate is None:
300
298
  return self.__load_commands
301
299
 
@@ -18,7 +18,7 @@ class SymbolFormatField(FormatField):
18
18
  """
19
19
 
20
20
  def __init__(self, client):
21
- super(SymbolFormatField, self).__init__('<', 'Q')
21
+ super().__init__('<', 'Q')
22
22
  self._client = client
23
23
 
24
24
  def _parse(self, stream, context, path):
@@ -139,10 +139,10 @@ class Symbol(int):
139
139
  def peek_str(self) -> str:
140
140
  return self._client.peek_str(self)
141
141
 
142
- def monitor(self, **args) -> lldb.SBBreakpoint:
142
+ def monitor(self, **args):
143
143
  return self._client.monitor(self, **args)
144
144
 
145
- def bp(self, callback=None, **args) -> lldb.SBBreakpoint:
145
+ def bp(self, callback=None, **args):
146
146
  return self._client.bp(self, callback, **args)
147
147
 
148
148
  def disass(self, size, **args) -> lldb.SBInstructionList:
@@ -165,7 +165,7 @@ class Symbol(int):
165
165
  elif whence == os.SEEK_SET:
166
166
  self._offset = offset - self
167
167
  else:
168
- raise IOError('Unsupported whence')
168
+ raise OSError('Unsupported whence')
169
169
 
170
170
  def read(self, count: int) -> bytes:
171
171
  """ Construct compliance. """
@@ -1,6 +1,5 @@
1
1
  import shutil
2
2
  from abc import abstractmethod
3
- from typing import List, Mapping
4
3
 
5
4
  from click import style
6
5
  from lldb import SBAddress
@@ -9,7 +8,7 @@ from tabulate import tabulate
9
8
  WORD_SIZE = 8
10
9
 
11
10
 
12
- def dict_diff(d1: Mapping, d2: Mapping) -> List[str]:
11
+ def dict_diff(d1: dict, d2: dict) -> list[str]:
13
12
  """ Returns a list of keys whose values have changed """
14
13
  changed_keys = []
15
14
  if d1 is None or d2 is None:
@@ -59,7 +58,7 @@ class StackView(View):
59
58
  """
60
59
  super().__init__(hilda_client, 'Stack', color_scheme)
61
60
  self.depth = depth
62
- self.prev: Mapping[int, str] = None
61
+ self.prev: dict[int, str] = None
63
62
 
64
63
  def __str__(self) -> str:
65
64
  """ Format stack view for printing """
@@ -80,7 +79,7 @@ class StackView(View):
80
79
 
81
80
  return super().__str__() + '\n'.join(fmt_parts)
82
81
 
83
- def _create_mapping(self) -> Mapping[int, str]:
82
+ def _create_mapping(self) -> dict[int, str]:
84
83
  """ Generate mapping of stack address:data"""
85
84
  base_addr = self.hilda.frame.sp
86
85
  stack_mapping = {}
@@ -103,7 +102,7 @@ class RegistersView(View):
103
102
  `prev` saves the last registers stats inorder to perform diff check.
104
103
  """
105
104
  super().__init__(hilda_client, 'Registers', color_scheme)
106
- self.prev: Mapping[str, str] = None
105
+ self.prev: dict[str, str] = None
107
106
  self.rtype = rtype
108
107
 
109
108
  def __str__(self) -> str:
@@ -133,7 +132,7 @@ class RegistersView(View):
133
132
 
134
133
  return super().__str__() + tabulate(list(zip(*list_of_lists)), tablefmt='plain', numalign='left')
135
134
 
136
- def _create_mapping(self) -> Mapping[str, str]:
135
+ def _create_mapping(self) -> dict[str, str]:
137
136
  """ Generate mapping of registers name:data"""
138
137
  regs = self._get_registers()
139
138
  regs_mapping = {}
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: hilda
3
- Version: 2.0.12
3
+ Version: 2.0.15
4
4
  Summary: LLDB wrapped and empowered by iPython's features
5
5
  Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>, netanel cohen <netanelc305@protonmail.com>
6
6
  Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>, netanel cohen <netanelc305@protonmail.com>
@@ -31,13 +31,13 @@ Classifier: Operating System :: MacOS
31
31
  Classifier: Development Status :: 5 - Production/Stable
32
32
  Classifier: License :: OSI Approved :: MIT License
33
33
  Classifier: Programming Language :: Python :: 3
34
- Classifier: Programming Language :: Python :: 3.8
35
34
  Classifier: Programming Language :: Python :: 3.9
36
35
  Classifier: Programming Language :: Python :: 3.10
37
36
  Classifier: Programming Language :: Python :: 3.11
38
37
  Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
39
  Classifier: Programming Language :: Python :: 3 :: Only
40
- Requires-Python: >=3.8
40
+ Requires-Python: >=3.9
41
41
  Description-Content-Type: text/markdown
42
42
  License-File: LICENSE
43
43
  Requires-Dist: tqdm
@@ -45,6 +45,7 @@ hilda/snippets/boringssl.py
45
45
  hilda/snippets/collections.py
46
46
  hilda/snippets/dyld.py
47
47
  hilda/snippets/fs_utils.py
48
+ hilda/snippets/libmalloc.py
48
49
  hilda/snippets/remotepairingd.py
49
50
  hilda/snippets/syslog.py
50
51
  hilda/snippets/uuid.py
@@ -2,7 +2,7 @@
2
2
  name = "hilda"
3
3
  description = "LLDB wrapped and empowered by iPython's features"
4
4
  readme = "README.md"
5
- requires-python = ">=3.8"
5
+ requires-python = ">=3.9"
6
6
  license = { file = "LICENSE" }
7
7
  keywords = ["python", "debugger", "lldb", "ipython", "ios", "debug"]
8
8
  authors = [
@@ -20,11 +20,11 @@ classifiers = [
20
20
  "Development Status :: 5 - Production/Stable",
21
21
  "License :: OSI Approved :: MIT License",
22
22
  "Programming Language :: Python :: 3",
23
- "Programming Language :: Python :: 3.8",
24
23
  "Programming Language :: Python :: 3.9",
25
24
  "Programming Language :: Python :: 3.10",
26
25
  "Programming Language :: Python :: 3.11",
27
26
  "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
28
  "Programming Language :: Python :: 3 :: Only",
29
29
  ]
30
30
  dynamic = ["dependencies", "version"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes