hilda 3.0.0__tar.gz → 3.0.1__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.
- {hilda-3.0.0 → hilda-3.0.1}/PKG-INFO +1 -1
- {hilda-3.0.0 → hilda-3.0.1}/hilda/_version.py +2 -2
- {hilda-3.0.0 → hilda-3.0.1}/hilda/hilda_client.py +2 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/launch_lldb.py +29 -12
- {hilda-3.0.0 → hilda-3.0.1}/hilda/symbol.py +3 -0
- hilda-3.0.1/hilda/watchpoints.py +237 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda.egg-info/PKG-INFO +1 -1
- {hilda-3.0.0 → hilda-3.0.1}/hilda.egg-info/SOURCES.txt +1 -0
- {hilda-3.0.0 → hilda-3.0.1}/.github/workflows/python-app.yml +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/.github/workflows/python-publish.yml +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/.gitignore +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/.pre-commit-config.yaml +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/LICENSE +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/README.md +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/gifs/.gitattributes +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/gifs/ui.png +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/gifs/xpc_print_message.gif +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/__init__.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/__main__.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/breakpoints.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/cli.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/common.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/exceptions.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/hilda_ascii_art.html +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/ipython_extensions/events.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/ipython_extensions/keybindings.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/ipython_extensions/magics.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/lldb_entrypoint.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/lldb_importer.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c/from_ns_to_json.m +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c/get_objectivec_class_by_module.m +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c/get_objectivec_class_description.m +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c/get_objectivec_symbol_data.m +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c/lsof.m +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c/to_ns_from_json.m +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c_class.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/objective_c_symbol.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/registers.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/__init__.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/boringssl.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/collections.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/dyld.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/fs_utils.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/libmalloc.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/mach/CFRunLoopServiceMachPort_hooks.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/mach/__init__.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/macho/__init__.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/macho/all_image_infos.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/macho/apple_version.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/macho/image_info.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/macho/macho.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/macho/macho_load_commands.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/remotepairingd.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/syslog.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/uuid.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/snippets/xpc.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/symbols_jar.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/ui/colors.json +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/ui/ui_manager.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda/ui/views.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda.egg-info/dependency_links.txt +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda.egg-info/entry_points.txt +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda.egg-info/requires.txt +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/hilda.egg-info/top_level.txt +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/pyproject.toml +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/requirements.txt +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/setup.cfg +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/__init__.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/conftest.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_hilda_client/test_from_ns.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_hilda_client/test_hilda_client.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_hilda_client/test_monitor.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_hilda_client/test_ns.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_hilda_client/test_rebind_symbols.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_hilda_client/test_registers.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_snippets/test_xpc.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_symbols/test_objective_c_class.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_symbols/test_objective_c_symbol.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_symbols/test_symbol.py +0 -0
- {hilda-3.0.0 → hilda-3.0.1}/tests/test_symbols/test_symbols_jar.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: hilda
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.1
|
|
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>
|
|
@@ -42,6 +42,7 @@ from hilda.snippets.mach import CFRunLoopServiceMachPort_hooks
|
|
|
42
42
|
from hilda.symbol import Symbol
|
|
43
43
|
from hilda.symbols_jar import SymbolsJar
|
|
44
44
|
from hilda.ui.ui_manager import UiManager
|
|
45
|
+
from hilda.watchpoints import WatchpointList
|
|
45
46
|
|
|
46
47
|
lldb.KEYSTONE_SUPPORT = True
|
|
47
48
|
try:
|
|
@@ -128,6 +129,7 @@ class HildaClient:
|
|
|
128
129
|
self.process = self.target.GetProcess()
|
|
129
130
|
self.symbols = SymbolsJar.create(self)
|
|
130
131
|
self.breakpoints = BreakpointList(self)
|
|
132
|
+
self.watchpoints = WatchpointList(self)
|
|
131
133
|
self.captured_objects = {}
|
|
132
134
|
self.registers = Registers(self)
|
|
133
135
|
self.arch = self.target.GetTriple().split('-')[0]
|
|
@@ -61,6 +61,33 @@ class LLDBListenerThread(Thread, ABC):
|
|
|
61
61
|
sys.stderr.write(stderr)
|
|
62
62
|
stderr = self.process.GetSTDERR(1024)
|
|
63
63
|
|
|
64
|
+
def _process_potential_watchpoint_event(self) -> None:
|
|
65
|
+
stopped_threads = self._get_stopped_threads(lldb.eStopReasonWatchpoint)
|
|
66
|
+
for thread in stopped_threads:
|
|
67
|
+
watchpoint_id = thread.GetStopReasonDataAtIndex(0)
|
|
68
|
+
frame = thread.GetFrameAtIndex(0)
|
|
69
|
+
if lldb.hilda_client is not None:
|
|
70
|
+
lldb.hilda_client.watchpoints._dispatch_watchpoint_callback(watchpoint_id, thread, frame)
|
|
71
|
+
|
|
72
|
+
def _get_stopped_threads(self, reason: Optional[int] = None) -> list[lldb.SBThread]:
|
|
73
|
+
if reason is None:
|
|
74
|
+
stop_reasons = [
|
|
75
|
+
lldb.eStopReasonSignal, lldb.eStopReasonException,
|
|
76
|
+
lldb.eStopReasonBreakpoint, lldb.eStopReasonWatchpoint,
|
|
77
|
+
lldb.eStopReasonPlanComplete, lldb.eStopReasonTrace,
|
|
78
|
+
]
|
|
79
|
+
else:
|
|
80
|
+
stop_reasons = [reason]
|
|
81
|
+
|
|
82
|
+
return [thread for thread in self.process if thread.GetStopReason() in stop_reasons]
|
|
83
|
+
|
|
84
|
+
def _set_selected_thread_to_stopped_thread(self) -> None:
|
|
85
|
+
stopped_threads = self._get_stopped_threads()
|
|
86
|
+
if len(stopped_threads) < 1:
|
|
87
|
+
return
|
|
88
|
+
thread = stopped_threads[0]
|
|
89
|
+
self.process.SetSelectedThread(thread)
|
|
90
|
+
|
|
64
91
|
def run(self):
|
|
65
92
|
event = lldb.SBEvent()
|
|
66
93
|
last_state = lldb.eStateStopped
|
|
@@ -87,18 +114,8 @@ class LLDBListenerThread(Thread, ABC):
|
|
|
87
114
|
logger.debug('Process Continued')
|
|
88
115
|
elif state == lldb.eStateStopped and last_state == lldb.eStateRunning:
|
|
89
116
|
logger.debug('Process Stopped')
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
stop_reason = thread.GetStopReason()
|
|
93
|
-
logger.debug(f'tid = {hex(thread.GetThreadID())} pc = {frame.GetPC()}')
|
|
94
|
-
if stop_reason not in [lldb.eStopReasonSignal, lldb.eStopReasonException,
|
|
95
|
-
lldb.eStopReasonBreakpoint,
|
|
96
|
-
lldb.eStopReasonWatchpoint, lldb.eStopReasonPlanComplete,
|
|
97
|
-
lldb.eStopReasonTrace,
|
|
98
|
-
lldb.eStopReasonSignal]:
|
|
99
|
-
continue
|
|
100
|
-
self.process.SetSelectedThread(thread)
|
|
101
|
-
break
|
|
117
|
+
self._set_selected_thread_to_stopped_thread()
|
|
118
|
+
self._process_potential_watchpoint_event()
|
|
102
119
|
|
|
103
120
|
last_state = state
|
|
104
121
|
|
|
@@ -145,6 +145,9 @@ class Symbol(int):
|
|
|
145
145
|
def monitor(self, **args):
|
|
146
146
|
return self._client.monitor(self, **args)
|
|
147
147
|
|
|
148
|
+
def watch(self, **args):
|
|
149
|
+
return self._client.watchpoints.add(self, **args)
|
|
150
|
+
|
|
148
151
|
def bp(self, callback=None, **args):
|
|
149
152
|
return self._client.bp(self, callback, **args)
|
|
150
153
|
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
from typing import Callable, Generator, Optional, Union
|
|
2
|
+
|
|
3
|
+
from hilda.lldb_importer import lldb
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class HildaWatchpoint:
|
|
7
|
+
"""
|
|
8
|
+
Hilda's class representing an LLDB watchpoint, with some optional additional properties
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, hilda, lldb_watchpoint: lldb.SBWatchpoint, where: Optional[int] = None) -> None:
|
|
12
|
+
"""
|
|
13
|
+
Initialize a watchpoint list.
|
|
14
|
+
|
|
15
|
+
:param hilda.hilda_client.HildaClient hilda: Hilda client
|
|
16
|
+
"""
|
|
17
|
+
self._hilda = hilda
|
|
18
|
+
self._where = where
|
|
19
|
+
self._callback = None
|
|
20
|
+
|
|
21
|
+
# Actual watchpoint from LLDB API
|
|
22
|
+
self.lldb_watchpoint = lldb_watchpoint
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def where(self) -> Optional[int]:
|
|
26
|
+
"""
|
|
27
|
+
A value identifying where the watchpoint was set (when it was created).
|
|
28
|
+
|
|
29
|
+
It could be either an address (int) or a Hilda symbol object (Symbol, that inherits from int).
|
|
30
|
+
"""
|
|
31
|
+
return self._where
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def id(self) -> int:
|
|
35
|
+
""" A number identifying the watchpoint. """
|
|
36
|
+
return self.lldb_watchpoint.GetID()
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def callback(self) -> Optional[Callable]:
|
|
40
|
+
"""
|
|
41
|
+
A callback that will be executed when the watchpoint is hit.
|
|
42
|
+
|
|
43
|
+
Note that unless the callback explicitly continues (by calling `cont()`), the program will not continue.
|
|
44
|
+
The callback will be invoked as callback(hilda, *args), where hilda is the 'HildaClient'.
|
|
45
|
+
"""
|
|
46
|
+
return self._callback
|
|
47
|
+
|
|
48
|
+
@callback.setter
|
|
49
|
+
def callback(self, callback: Optional[Callable]) -> None:
|
|
50
|
+
self._callback = callback
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def condition(self) -> Optional[str]:
|
|
54
|
+
"""
|
|
55
|
+
An LLDB expression to make this a conditional watchpoint.
|
|
56
|
+
"""
|
|
57
|
+
return self.lldb_watchpoint.GetCondition()
|
|
58
|
+
|
|
59
|
+
@condition.setter
|
|
60
|
+
def condition(self, condition: Optional[str]) -> None:
|
|
61
|
+
self.lldb_watchpoint.SetCondition(condition)
|
|
62
|
+
|
|
63
|
+
def __repr__(self) -> str:
|
|
64
|
+
return f'<{self.__class__.__name__} LLDB:{self.lldb_watchpoint} CALLBACK:{self.callback}>'
|
|
65
|
+
|
|
66
|
+
def __str__(self) -> str:
|
|
67
|
+
return repr(self)
|
|
68
|
+
|
|
69
|
+
def remove(self) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Remove the watchpoint.
|
|
72
|
+
"""
|
|
73
|
+
self._hilda.watchpoints.remove(self)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class WatchpointList:
|
|
77
|
+
"""
|
|
78
|
+
Manager for `HildaWatchpoint` objects, each one wrapping another native LLDB watchpoint.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(self, hilda) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Initialize a watchpoint list.
|
|
84
|
+
|
|
85
|
+
:param hilda.hilda_client.HildaClient hilda: Hilda client
|
|
86
|
+
"""
|
|
87
|
+
self._hilda = hilda
|
|
88
|
+
self._watchpoints = {}
|
|
89
|
+
|
|
90
|
+
def __contains__(self, id_or_wp: Union[int, HildaWatchpoint]) -> bool:
|
|
91
|
+
return self.get(id_or_wp) is not None
|
|
92
|
+
|
|
93
|
+
def __iter__(self) -> Generator[HildaWatchpoint, None, None]:
|
|
94
|
+
for wp in self._hilda.target.watchpoint_iter():
|
|
95
|
+
yield self[wp.GetID()]
|
|
96
|
+
|
|
97
|
+
def __len__(self) -> int:
|
|
98
|
+
return self._hilda.target.GetNumWatchpoints()
|
|
99
|
+
|
|
100
|
+
def __getitem__(self, id_or_wp: Union[int, HildaWatchpoint]) -> HildaWatchpoint:
|
|
101
|
+
"""
|
|
102
|
+
Get a watchpoint by ID (or the watchpoint itself, though it usually makes little sense)
|
|
103
|
+
|
|
104
|
+
:param id_or_wp: Watchpoint's ID (or the watchpoint itself)
|
|
105
|
+
"""
|
|
106
|
+
wp = self.get(id_or_wp)
|
|
107
|
+
if wp is None:
|
|
108
|
+
raise KeyError(id_or_wp)
|
|
109
|
+
|
|
110
|
+
return wp
|
|
111
|
+
|
|
112
|
+
def __delitem__(self, id_or_wp: Union[int, HildaWatchpoint]):
|
|
113
|
+
"""
|
|
114
|
+
Remove a watchpoint.
|
|
115
|
+
|
|
116
|
+
:param id_or_wp: Watchpoint's ID (or the watchpoint itself)
|
|
117
|
+
"""
|
|
118
|
+
self.remove(id_or_wp)
|
|
119
|
+
|
|
120
|
+
def __repr__(self) -> str:
|
|
121
|
+
return repr(dict(self.items()))
|
|
122
|
+
|
|
123
|
+
def __str__(self) -> str:
|
|
124
|
+
return repr(self)
|
|
125
|
+
|
|
126
|
+
def get(self, id_or_wp: Union[int, HildaWatchpoint]) -> Optional[HildaWatchpoint]:
|
|
127
|
+
"""
|
|
128
|
+
Get a watchpoint by ID or the watchpoint itself.
|
|
129
|
+
|
|
130
|
+
:param id_or_wp: Watchpoint's ID (or the watchpoint itself)
|
|
131
|
+
:return: `HildaWatchpoint` is one exists, or `None` otherwise
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
if isinstance(id_or_wp, int):
|
|
135
|
+
wp = self._hilda.target.FindWatchpointByID(id_or_wp)
|
|
136
|
+
elif isinstance(id_or_wp, HildaWatchpoint):
|
|
137
|
+
wp = id_or_wp.lldb_watchpoint
|
|
138
|
+
else:
|
|
139
|
+
raise KeyError(f'Watchpoint "{id_or_wp}" could not be found')
|
|
140
|
+
|
|
141
|
+
if not wp.IsValid():
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
wp_id = wp.GetID()
|
|
145
|
+
if wp_id not in self._watchpoints:
|
|
146
|
+
self._hilda.log_debug(f'Found a watchpoint added outside of the Hilda API {wp}')
|
|
147
|
+
self._watchpoints[wp_id] = HildaWatchpoint(self._hilda, wp)
|
|
148
|
+
|
|
149
|
+
return self._watchpoints[wp_id]
|
|
150
|
+
|
|
151
|
+
def add(self, where: int, size: int = 8, read: bool = True, write: bool = True,
|
|
152
|
+
callback: Optional[Callable] = None, condition: str = None) -> HildaWatchpoint:
|
|
153
|
+
"""
|
|
154
|
+
Add a watchpoint.
|
|
155
|
+
|
|
156
|
+
:param where: The address of the watchpoint.
|
|
157
|
+
:param size: The size of the watchpoint (the address span to watch).
|
|
158
|
+
:param read: The watchpoint should monitor reads from memory in the specified address (and size).
|
|
159
|
+
:param write: The watchpoint should monitor writes to memory in the specified address (and size).
|
|
160
|
+
:param callback: A callback that will be executed when the watchpoint is hit.
|
|
161
|
+
Note that unless the callback explicitly continues (by calling cont()), the program will not continue.
|
|
162
|
+
The callback will be invoked as callback(hilda, *args), where hilda is the 'HildaClient'.
|
|
163
|
+
:param condition: An LLDB expression to make this a conditional watchpoint.
|
|
164
|
+
:return: The new watchpoint
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
error = lldb.SBError()
|
|
168
|
+
wp = self._hilda.target.WatchAddress(where, size, read, write, error)
|
|
169
|
+
if not wp.IsValid():
|
|
170
|
+
raise Exception(f'Failed to create watchpoint at {where} ({error})')
|
|
171
|
+
|
|
172
|
+
wp = HildaWatchpoint(self._hilda, wp, where)
|
|
173
|
+
wp.callback = callback
|
|
174
|
+
wp.condition = condition
|
|
175
|
+
|
|
176
|
+
self._watchpoints[wp.id] = wp
|
|
177
|
+
|
|
178
|
+
self._hilda.log_info(f'Watchpoint #{wp.id} has been set')
|
|
179
|
+
return wp
|
|
180
|
+
|
|
181
|
+
def remove(self, id_or_wp: Union[int, HildaWatchpoint]) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Remove a watchpoint.
|
|
184
|
+
|
|
185
|
+
:param id_or_wp: Watchpoint's ID (or the watchpoint itself)
|
|
186
|
+
"""
|
|
187
|
+
wp = self[id_or_wp]
|
|
188
|
+
watchpoint_id = wp.id
|
|
189
|
+
self._hilda.target.DeleteWatchpoint(watchpoint_id)
|
|
190
|
+
self._hilda.log_debug(f'Watchpoint #{watchpoint_id} has been removed')
|
|
191
|
+
|
|
192
|
+
def clear(self) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Remove all watchpoints
|
|
195
|
+
"""
|
|
196
|
+
for wp in list(self):
|
|
197
|
+
self.remove(wp)
|
|
198
|
+
|
|
199
|
+
def show(self) -> None:
|
|
200
|
+
""" Show existing watchpoints. """
|
|
201
|
+
for wp in self:
|
|
202
|
+
message = f'🚨 Watchpoint #{wp.id}'
|
|
203
|
+
|
|
204
|
+
if wp.where is not None:
|
|
205
|
+
message += f'\n\tWhere: {wp.where}'
|
|
206
|
+
|
|
207
|
+
self._hilda.log_info(message)
|
|
208
|
+
|
|
209
|
+
def items(self) -> Generator[tuple[int, HildaWatchpoint], None, None]:
|
|
210
|
+
"""
|
|
211
|
+
Get a watchpoint ID and watchpoint object tuple for every watchpoint.
|
|
212
|
+
"""
|
|
213
|
+
return ((wp.id, wp) for wp in self)
|
|
214
|
+
|
|
215
|
+
def keys(self) -> Generator[int, None, None]:
|
|
216
|
+
"""
|
|
217
|
+
Get the watchpoint ID for every watchpoint.
|
|
218
|
+
"""
|
|
219
|
+
return (wp.id for wp in self)
|
|
220
|
+
|
|
221
|
+
def values(self) -> Generator[HildaWatchpoint, None, None]:
|
|
222
|
+
"""
|
|
223
|
+
Get the watchpoint object for every watchpoint.
|
|
224
|
+
"""
|
|
225
|
+
return (wp for wp in self)
|
|
226
|
+
|
|
227
|
+
def _dispatch_watchpoint_callback(self, watchpoint_id: int, _, frame) -> None:
|
|
228
|
+
"""
|
|
229
|
+
Route the watchpoint callback the specific watchpoint callback.
|
|
230
|
+
"""
|
|
231
|
+
self._hilda._bp_frame = frame
|
|
232
|
+
try:
|
|
233
|
+
callback = self[watchpoint_id].callback
|
|
234
|
+
if callback is not None:
|
|
235
|
+
callback(self._hilda, frame, None, self[watchpoint_id])
|
|
236
|
+
finally:
|
|
237
|
+
self._hilda._bp_frame = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: hilda
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.1
|
|
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>
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|