hilda 2.0.11__py3-none-any.whl → 2.0.14__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 +2 -2
- hilda/cli.py +6 -6
- hilda/common.py +3 -3
- hilda/hilda_client.py +47 -18
- hilda/launch_lldb.py +3 -3
- hilda/lldb_importer.py +1 -1
- hilda/objective_c_class.py +4 -5
- hilda/objective_c_symbol.py +6 -7
- hilda/registers.py +1 -1
- hilda/snippets/macho/all_image_infos.py +2 -2
- hilda/snippets/macho/image_info.py +1 -1
- hilda/snippets/macho/macho_load_commands.py +9 -11
- hilda/symbol.py +4 -4
- hilda/ui/views.py +5 -6
- {hilda-2.0.11.dist-info → hilda-2.0.14.dist-info}/METADATA +6 -4
- {hilda-2.0.11.dist-info → hilda-2.0.14.dist-info}/RECORD +20 -20
- {hilda-2.0.11.dist-info → hilda-2.0.14.dist-info}/WHEEL +1 -1
- {hilda-2.0.11.dist-info → hilda-2.0.14.dist-info}/LICENSE +0 -0
- {hilda-2.0.11.dist-info → hilda-2.0.14.dist-info}/entry_points.txt +0 -0
- {hilda-2.0.11.dist-info → hilda-2.0.14.dist-info}/top_level.txt +0 -0
hilda/_version.py
CHANGED
hilda/cli.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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)
|
hilda/common.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from typing import Any,
|
|
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
|
-
|
|
8
|
+
dict[str, Any], list, tuple[Any, ...], str, bool, float, bytes, datetime, None]
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def selection_prompt(options_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']
|
hilda/hilda_client.py
CHANGED
|
@@ -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,
|
|
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
|
|
129
|
-
|
|
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):
|
|
@@ -146,6 +166,7 @@ class HildaClient:
|
|
|
146
166
|
self._dynamic_env_loaded = False
|
|
147
167
|
self._symbols_loaded = False
|
|
148
168
|
self.globals: typing.MutableMapping[str, Any] = globals()
|
|
169
|
+
self._hilda_root = Path(__file__).parent
|
|
149
170
|
|
|
150
171
|
# the frame called within the context of the hit BP
|
|
151
172
|
self._bp_frame = None
|
|
@@ -168,12 +189,12 @@ class HildaClient:
|
|
|
168
189
|
Get dictionary of all open FDs
|
|
169
190
|
:return: Mapping between open FDs and their paths
|
|
170
191
|
"""
|
|
171
|
-
data = (
|
|
192
|
+
data = (self._hilda_root / 'objective_c' / 'lsof.m').read_text()
|
|
172
193
|
result = json.loads(self.po(data))
|
|
173
194
|
# convert FDs into int
|
|
174
195
|
return {int(k): v for k, v in result.items()}
|
|
175
196
|
|
|
176
|
-
def bt(self, should_print: bool = False, depth: Optional[int] = None) ->
|
|
197
|
+
def bt(self, should_print: bool = False, depth: Optional[int] = None) -> list[Union[str, lldb.SBFrame]]:
|
|
177
198
|
""" Print an improved backtrace. """
|
|
178
199
|
backtrace = []
|
|
179
200
|
for i, frame in enumerate(self.thread.frames):
|
|
@@ -347,6 +368,16 @@ class HildaClient:
|
|
|
347
368
|
if not self.process.Stop().Success():
|
|
348
369
|
self.log_critical('failed to stop process')
|
|
349
370
|
|
|
371
|
+
def run_for(self, seconds: float) -> None:
|
|
372
|
+
"""
|
|
373
|
+
Run the process for a given time
|
|
374
|
+
:return:
|
|
375
|
+
"""
|
|
376
|
+
self.cont()
|
|
377
|
+
self.logger.info(f'Running for {seconds} seconds')
|
|
378
|
+
time.sleep(seconds)
|
|
379
|
+
self.stop()
|
|
380
|
+
|
|
350
381
|
def cont(self, *args) -> None:
|
|
351
382
|
""" Continue process. """
|
|
352
383
|
is_running = self.process.GetState() == lldb.eStateRunning
|
|
@@ -462,7 +493,7 @@ class HildaClient:
|
|
|
462
493
|
with self.stopped():
|
|
463
494
|
return self.evaluate_expression(call_expression)
|
|
464
495
|
|
|
465
|
-
def monitor(self, address, condition: str = None, **options) ->
|
|
496
|
+
def monitor(self, address, condition: str = None, **options) -> HildaBreakpoint:
|
|
466
497
|
"""
|
|
467
498
|
Monitor every time a given address is called
|
|
468
499
|
|
|
@@ -602,7 +633,7 @@ class HildaClient:
|
|
|
602
633
|
if remove_forced or not bp.forced:
|
|
603
634
|
self.remove_hilda_breakpoint(bp_id)
|
|
604
635
|
|
|
605
|
-
def remove_hilda_breakpoint(self, bp_id):
|
|
636
|
+
def remove_hilda_breakpoint(self, bp_id: int) -> None:
|
|
606
637
|
"""
|
|
607
638
|
Remove a single breakpoint placed by Hilda
|
|
608
639
|
:param bp_id: Breakpoint's ID
|
|
@@ -636,7 +667,7 @@ class HildaClient:
|
|
|
636
667
|
print(highlight(entitlements, XmlLexer(), TerminalTrueColorFormatter()))
|
|
637
668
|
|
|
638
669
|
def bp(self, address_or_name: Union[int, str], callback: Optional[Callable] = None, condition: str = None,
|
|
639
|
-
forced=False, module_name: Optional[str] = None, **options) ->
|
|
670
|
+
forced=False, module_name: Optional[str] = None, **options) -> HildaBreakpoint:
|
|
640
671
|
"""
|
|
641
672
|
Add a breakpoint
|
|
642
673
|
:param address_or_name:
|
|
@@ -665,15 +696,14 @@ class HildaClient:
|
|
|
665
696
|
bp.SetCondition(condition)
|
|
666
697
|
|
|
667
698
|
# add into Hilda's internal list of breakpoints
|
|
668
|
-
self.breakpoints[bp.id] =
|
|
669
|
-
|
|
670
|
-
)
|
|
699
|
+
self.breakpoints[bp.id] = HildaBreakpoint(self, bp, address=address_or_name, forced=forced, options=options,
|
|
700
|
+
callback=callback)
|
|
671
701
|
|
|
672
702
|
if callback is not None:
|
|
673
703
|
bp.SetScriptCallbackFunction('lldb.hilda_client.bp_callback_router')
|
|
674
704
|
|
|
675
705
|
self.log_info(f'Breakpoint #{bp.id} has been set')
|
|
676
|
-
return bp
|
|
706
|
+
return self.breakpoints[bp.id]
|
|
677
707
|
|
|
678
708
|
def bp_callback_router(self, frame, bp_loc, *_):
|
|
679
709
|
"""
|
|
@@ -828,8 +858,7 @@ class HildaClient:
|
|
|
828
858
|
json_data = json.dumps({'root': data}, default=self._to_ns_json_default)
|
|
829
859
|
except TypeError as e:
|
|
830
860
|
raise ConvertingToNsObjectError from e
|
|
831
|
-
|
|
832
|
-
obj_c_code = (Path(__file__).parent / 'objective_c' / 'to_ns_from_json.m').read_text()
|
|
861
|
+
obj_c_code = (self._hilda_root / 'objective_c' / 'to_ns_from_json.m').read_text()
|
|
833
862
|
expression = obj_c_code.replace('__json_object_dump__', json_data.replace('"', r'\"'))
|
|
834
863
|
try:
|
|
835
864
|
return self.evaluate_expression(expression)
|
|
@@ -842,7 +871,7 @@ class HildaClient:
|
|
|
842
871
|
:param address: NS object.
|
|
843
872
|
:return: Python object.
|
|
844
873
|
"""
|
|
845
|
-
obj_c_code = (
|
|
874
|
+
obj_c_code = (self._hilda_root / 'objective_c' / 'from_ns_to_json.m').read_text()
|
|
846
875
|
address = f'0x{address:x}' if isinstance(address, int) else address
|
|
847
876
|
expression = obj_c_code.replace('__ns_object_address__', address)
|
|
848
877
|
try:
|
|
@@ -958,7 +987,7 @@ class HildaClient:
|
|
|
958
987
|
"""
|
|
959
988
|
block = self.symbols.malloc(size)
|
|
960
989
|
if block == 0:
|
|
961
|
-
raise
|
|
990
|
+
raise OSError(f'failed to allocate memory of size: {size} bytes')
|
|
962
991
|
|
|
963
992
|
try:
|
|
964
993
|
yield block
|
|
@@ -1066,7 +1095,7 @@ class HildaClient:
|
|
|
1066
1095
|
self.cont()
|
|
1067
1096
|
|
|
1068
1097
|
def interact(self, additional_namespace: Optional[typing.Mapping] = None,
|
|
1069
|
-
startup_files: Optional[
|
|
1098
|
+
startup_files: Optional[list[str]] = None) -> None:
|
|
1070
1099
|
""" Start an interactive Hilda shell """
|
|
1071
1100
|
if not self._dynamic_env_loaded:
|
|
1072
1101
|
self.init_dynamic_environment()
|
|
@@ -1212,7 +1241,7 @@ class HildaClient:
|
|
|
1212
1241
|
continue
|
|
1213
1242
|
objc_classlist = m.FindSection('__DATA').FindSubSection('__objc_classlist')
|
|
1214
1243
|
objc_classlist_addr = self.symbol(objc_classlist.GetLoadAddress(self.target))
|
|
1215
|
-
obj_c_code = (
|
|
1244
|
+
obj_c_code = (self._hilda_root / 'objective_c' / 'get_objectivec_class_by_module.m').read_text()
|
|
1216
1245
|
obj_c_code = obj_c_code.replace('__count_objc_class', f'{objc_classlist.size // 8}').replace(
|
|
1217
1246
|
'__objc_class_list',
|
|
1218
1247
|
f'{objc_classlist_addr}')
|
hilda/launch_lldb.py
CHANGED
|
@@ -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
|
|
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[
|
|
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):
|
|
@@ -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[
|
|
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)
|
hilda/lldb_importer.py
CHANGED
|
@@ -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'],
|
|
11
|
+
result = subprocess.run(['lldb', '-P'], capture_output=True, text=True, check=True)
|
|
12
12
|
return result.stdout.strip()
|
|
13
13
|
|
|
14
14
|
|
hilda/objective_c_class.py
CHANGED
|
@@ -3,7 +3,6 @@ import time
|
|
|
3
3
|
from collections import namedtuple
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import partial
|
|
6
|
-
from pathlib import Path
|
|
7
6
|
from typing import Any
|
|
8
7
|
from uuid import uuid4
|
|
9
8
|
|
|
@@ -90,7 +89,7 @@ class Method:
|
|
|
90
89
|
return f'{prefix} {name}; // 0x{self.address:x} (returns: {self.return_type})\n'
|
|
91
90
|
|
|
92
91
|
|
|
93
|
-
class Class
|
|
92
|
+
class Class:
|
|
94
93
|
"""
|
|
95
94
|
Wrapper for ObjectiveC Class object.
|
|
96
95
|
"""
|
|
@@ -120,7 +119,7 @@ class Class(object):
|
|
|
120
119
|
:param hilda.hilda_client.HildaClient client: Hilda client.
|
|
121
120
|
:param class_name: Class name.
|
|
122
121
|
"""
|
|
123
|
-
obj_c_code = (
|
|
122
|
+
obj_c_code = (client._hilda_root / 'objective_c' / 'get_objectivec_class_description.m').read_text()
|
|
124
123
|
obj_c_code = obj_c_code.replace('__class_address__', '0').replace('__class_name__', class_name)
|
|
125
124
|
class_symbol = Class(client, class_data=json.loads(client.po(obj_c_code)))
|
|
126
125
|
if class_symbol.name != class_name:
|
|
@@ -143,7 +142,7 @@ class Class(object):
|
|
|
143
142
|
Reload class object data.
|
|
144
143
|
Should be used whenever the class layout changes (for example, during method swizzling)
|
|
145
144
|
"""
|
|
146
|
-
obj_c_code = (
|
|
145
|
+
obj_c_code = (self._client._hilda_root / 'objective_c' / 'get_objectivec_class_description.m').read_text()
|
|
147
146
|
obj_c_code = obj_c_code.replace('__class_address__', f'{self._class_object:d}')
|
|
148
147
|
obj_c_code = obj_c_code.replace('__class_name__', self.name)
|
|
149
148
|
self._load_class_data(json.loads(self._client.po(obj_c_code)))
|
|
@@ -274,7 +273,7 @@ class Class(object):
|
|
|
274
273
|
if method.is_class:
|
|
275
274
|
result.add(method.name.replace(':', '_'))
|
|
276
275
|
|
|
277
|
-
result.update(list(super(
|
|
276
|
+
result.update(list(super().__dir__()))
|
|
278
277
|
return list(result)
|
|
279
278
|
|
|
280
279
|
def __str__(self):
|
hilda/objective_c_symbol.py
CHANGED
|
@@ -2,7 +2,6 @@ import json
|
|
|
2
2
|
from contextlib import suppress
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from functools import partial
|
|
5
|
-
from pathlib import Path
|
|
6
5
|
|
|
7
6
|
from objc_types_decoder.decode import decode as decode_type
|
|
8
7
|
from pygments import highlight
|
|
@@ -43,7 +42,7 @@ class ObjectiveCSymbol(Symbol):
|
|
|
43
42
|
:return: ObjectiveCSymbol object.
|
|
44
43
|
:rtype: ObjectiveCSymbol
|
|
45
44
|
"""
|
|
46
|
-
symbol = super(
|
|
45
|
+
symbol = super().create(value, client)
|
|
47
46
|
symbol.ivars = [] # type: List[Ivar]
|
|
48
47
|
symbol.properties = [] # type: List[Property]
|
|
49
48
|
symbol.methods = [] # type: List[Method]
|
|
@@ -60,7 +59,7 @@ class ObjectiveCSymbol(Symbol):
|
|
|
60
59
|
self.methods.clear()
|
|
61
60
|
self.class_ = None
|
|
62
61
|
|
|
63
|
-
obj_c_code = (
|
|
62
|
+
obj_c_code = (self._client._hilda_root / 'objective_c' / 'get_objectivec_symbol_data.m').read_text()
|
|
64
63
|
obj_c_code = obj_c_code.replace('__symbol_address__', f'{self:d}')
|
|
65
64
|
data = json.loads(self._client.po(obj_c_code))
|
|
66
65
|
|
|
@@ -184,12 +183,12 @@ class ObjectiveCSymbol(Symbol):
|
|
|
184
183
|
for method in sup.methods:
|
|
185
184
|
result.add(method.name.replace(':', '_'))
|
|
186
185
|
|
|
187
|
-
result.update(list(super(
|
|
186
|
+
result.update(list(super().__dir__()))
|
|
188
187
|
return list(result)
|
|
189
188
|
|
|
190
189
|
def __getitem__(self, item):
|
|
191
190
|
if isinstance(item, int):
|
|
192
|
-
return super(
|
|
191
|
+
return super().__getitem__(item)
|
|
193
192
|
|
|
194
193
|
# Ivars
|
|
195
194
|
for ivar in self.ivars:
|
|
@@ -218,7 +217,7 @@ class ObjectiveCSymbol(Symbol):
|
|
|
218
217
|
|
|
219
218
|
def __setitem__(self, key, value):
|
|
220
219
|
if isinstance(key, int):
|
|
221
|
-
super(
|
|
220
|
+
super().__setitem__(key, value)
|
|
222
221
|
return
|
|
223
222
|
|
|
224
223
|
with suppress(SettingIvarError):
|
|
@@ -233,7 +232,7 @@ class ObjectiveCSymbol(Symbol):
|
|
|
233
232
|
try:
|
|
234
233
|
self._set_ivar(key, value)
|
|
235
234
|
except SettingIvarError:
|
|
236
|
-
super(
|
|
235
|
+
super().__setattr__(key, value)
|
|
237
236
|
|
|
238
237
|
def __str__(self):
|
|
239
238
|
return self._to_str(False)
|
hilda/registers.py
CHANGED
|
@@ -47,7 +47,7 @@ all_image_infos_t = Struct(
|
|
|
47
47
|
)
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
class AllImageInfos
|
|
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 =
|
|
101
|
+
dependencies = {image_name.path for image_name in image.load_commands.dylib_commands}
|
|
102
102
|
|
|
103
103
|
return dependencies
|
|
104
104
|
|
|
@@ -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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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) ->
|
|
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) ->
|
|
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) ->
|
|
296
|
+
def find(self, predicate=None) -> list[LoadCommand]:
|
|
299
297
|
if predicate is None:
|
|
300
298
|
return self.__load_commands
|
|
301
299
|
|
hilda/symbol.py
CHANGED
|
@@ -18,7 +18,7 @@ class SymbolFormatField(FormatField):
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
def __init__(self, client):
|
|
21
|
-
super(
|
|
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)
|
|
142
|
+
def monitor(self, **args):
|
|
143
143
|
return self._client.monitor(self, **args)
|
|
144
144
|
|
|
145
|
-
def bp(self, callback=None, **args)
|
|
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
|
|
168
|
+
raise OSError('Unsupported whence')
|
|
169
169
|
|
|
170
170
|
def read(self, count: int) -> bytes:
|
|
171
171
|
""" Construct compliance. """
|
hilda/ui/views.py
CHANGED
|
@@ -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:
|
|
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:
|
|
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) ->
|
|
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:
|
|
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) ->
|
|
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
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hilda
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.14
|
|
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.
|
|
40
|
+
Requires-Python: >=3.9
|
|
41
41
|
Description-Content-Type: text/markdown
|
|
42
42
|
License-File: LICENSE
|
|
43
43
|
Requires-Dist: tqdm
|
|
@@ -53,7 +53,7 @@ Requires-Dist: keystone-engine
|
|
|
53
53
|
Requires-Dist: tabulate
|
|
54
54
|
Requires-Dist: inquirer3
|
|
55
55
|
Provides-Extra: test
|
|
56
|
-
Requires-Dist: pytest
|
|
56
|
+
Requires-Dist: pytest; extra == "test"
|
|
57
57
|
|
|
58
58
|
# Hilda
|
|
59
59
|
|
|
@@ -189,6 +189,8 @@ Here is a gist of methods you can access from `p`:
|
|
|
189
189
|
- Stop process.
|
|
190
190
|
- `cont`
|
|
191
191
|
- Continue process.
|
|
192
|
+
- `run_for`
|
|
193
|
+
- Run the process for given interval.
|
|
192
194
|
- `detach`
|
|
193
195
|
- Detach from process.
|
|
194
196
|
Useful in order to exit gracefully so process doesn't get killed
|
|
@@ -3,19 +3,19 @@ gifs/ui.png,sha256=iaRwNZ9qVWUkUe2TJb_6VPsTu--7HrElA2duWiyZ-Oc,131
|
|
|
3
3
|
gifs/xpc_print_message.gif,sha256=i5S8Y9bJm9n-NtOipFTAC8_jUR4uZCM4sOap_ccJX0k,939935
|
|
4
4
|
hilda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
hilda/__main__.py,sha256=KWRqvukK4wraxCMtvH5nO25mFXLO5aWXa7z_VfAtbO8,90
|
|
6
|
-
hilda/_version.py,sha256=
|
|
7
|
-
hilda/cli.py,sha256=
|
|
8
|
-
hilda/common.py,sha256=
|
|
6
|
+
hilda/_version.py,sha256=m1KQwr9BxzbCkMceuLAJj8OgCTUeNFGjPpEMFS8xjSA,413
|
|
7
|
+
hilda/cli.py,sha256=PCjrI7GrERIrZCODJYmPt6eyl-nPYZviTS8fBG3oIjM,3618
|
|
8
|
+
hilda/common.py,sha256=El-ih7cvCv9PJ5OWb1jkCbh4GuaRD6gqlrFC5gyY-TE,498
|
|
9
9
|
hilda/exceptions.py,sha256=8L1OvOqns4O4ieiH4YlrMbZkk_PvuyCq4UyqFAodkF8,2042
|
|
10
10
|
hilda/hilda_ascii_art.html,sha256=-9YCjAKdGbjtdd6uoKrxkkcJq7j16r4dGka2bZ27b4o,120119
|
|
11
|
-
hilda/hilda_client.py,sha256=
|
|
12
|
-
hilda/launch_lldb.py,sha256=
|
|
11
|
+
hilda/hilda_client.py,sha256=7HCMl1zColMaqBwyZJ4AY8J1ON7wqEhN7ALhF8qcSlg,48021
|
|
12
|
+
hilda/launch_lldb.py,sha256=SKUdUDvFn5riARHzlRScAztgn4zz0piqgdaAdA2drHs,8032
|
|
13
13
|
hilda/lldb_entrypoint.py,sha256=vTiClzfiTtjorlxEfIsI-W657KEGobx74qDhaZ8nPhM,1007
|
|
14
|
-
hilda/lldb_importer.py,sha256=
|
|
15
|
-
hilda/objective_c_class.py,sha256=
|
|
16
|
-
hilda/objective_c_symbol.py,sha256=
|
|
17
|
-
hilda/registers.py,sha256
|
|
18
|
-
hilda/symbol.py,sha256=
|
|
14
|
+
hilda/lldb_importer.py,sha256=TCGpAWwiBuyNRsbgcYawiqm35t8XQLCJwoOfEqyBeik,526
|
|
15
|
+
hilda/objective_c_class.py,sha256=arIgABZxqsLyo9Q6kyw-Sujm5j-89QUOjS0njjBcGo8,11716
|
|
16
|
+
hilda/objective_c_symbol.py,sha256=lIZHef5iZe3AeUsK0uIsDtFnzSM-Ad6i2wfdj9DwLUM,8269
|
|
17
|
+
hilda/registers.py,sha256=-9kk1MuKnWlJ0Z8zZ2RPV9nGRDtX1GXhCSkEvfnCktA,848
|
|
18
|
+
hilda/symbol.py,sha256=4309OwrnA7JQA3V3lfR_u8NAEdjkU6cEca9lxwioX3U,7452
|
|
19
19
|
hilda/symbols_jar.py,sha256=Vqdv6iH92P6aSfcz5XiR0FbNRqKuUu48mi-GxvPr32w,6504
|
|
20
20
|
hilda/ipython_extensions/events.py,sha256=w_4V8FoJJMarWArEE8uzb2UXk1mqfslmI7XCyVb_XuE,1976
|
|
21
21
|
hilda/ipython_extensions/keybindings.py,sha256=Ai9wHCla6HhgZGGxc0UEOCYODcavyef_zzUC9A9GcTE,1081
|
|
@@ -38,17 +38,17 @@ hilda/snippets/xpc.py,sha256=Z0e4b1lIScZg7fsSwGK43v363qp25fdzYcc7ajJsyhU,3960
|
|
|
38
38
|
hilda/snippets/mach/CFRunLoopServiceMachPort_hooks.py,sha256=gAJD0Qi2w0IxkPnHMbF5webODwot9PPChMRHVNQ6zSg,4230
|
|
39
39
|
hilda/snippets/mach/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
40
|
hilda/snippets/macho/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
|
-
hilda/snippets/macho/all_image_infos.py,sha256=
|
|
41
|
+
hilda/snippets/macho/all_image_infos.py,sha256=HdaFHhOM_AoXX_YTo9L7eEoX5MvMLTw4DZ_JZiTjdAs,4780
|
|
42
42
|
hilda/snippets/macho/apple_version.py,sha256=TTaqZKMviXJoU1o3OYeUskmxSkhVhh3UG1VbdJ6N-LE,148
|
|
43
|
-
hilda/snippets/macho/image_info.py,sha256=
|
|
43
|
+
hilda/snippets/macho/image_info.py,sha256=Onu6u61TwFOwAfENpZIQA9N-Ba3b_M0gr8r6THNdIR4,1605
|
|
44
44
|
hilda/snippets/macho/macho.py,sha256=X4NQZkO7VCcIMNuPs25ukiBrHM5Kj3UPMJzzeILfuyg,839
|
|
45
|
-
hilda/snippets/macho/macho_load_commands.py,sha256=
|
|
45
|
+
hilda/snippets/macho/macho_load_commands.py,sha256=vUWfFM2H6o8dMglXV7rHgh-EMTzS0IgbjO8v8_5o8Mw,10624
|
|
46
46
|
hilda/ui/colors.json,sha256=f-ITquY3IInQreviTy23JfmxfJrGM1_MivACf1GKGqM,262
|
|
47
47
|
hilda/ui/ui_manager.py,sha256=BmzI1sBx0PYCQDlB9Al7wsTEAMJxaJ7NW0DS4C7g5-0,2265
|
|
48
|
-
hilda/ui/views.py,sha256=
|
|
49
|
-
hilda-2.0.
|
|
50
|
-
hilda-2.0.
|
|
51
|
-
hilda-2.0.
|
|
52
|
-
hilda-2.0.
|
|
53
|
-
hilda-2.0.
|
|
54
|
-
hilda-2.0.
|
|
48
|
+
hilda/ui/views.py,sha256=bzClOgKirKYs6nhsNRXpkGNIg3oIOmFb659GLWrlTdo,7792
|
|
49
|
+
hilda-2.0.14.dist-info/LICENSE,sha256=M-LVJ0AFAYB82eueyl8brh-QLPe-iLNVgbCi79-3TDo,1078
|
|
50
|
+
hilda-2.0.14.dist-info/METADATA,sha256=N_-aSr6ezU8eTTyYzq2UgYbqlwMKaAj3r_bV55Zefgg,23378
|
|
51
|
+
hilda-2.0.14.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
52
|
+
hilda-2.0.14.dist-info/entry_points.txt,sha256=9n3O3j6V3XnVR_GcFqCWNgRAbalfukTSW2WvghsLVmA,46
|
|
53
|
+
hilda-2.0.14.dist-info/top_level.txt,sha256=TVD7l1WkE1noT866YqPFhiQnjYCYZM5Xz54v_3EYpnI,11
|
|
54
|
+
hilda-2.0.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|