hilda 2.0.1__py3-none-any.whl → 2.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hilda/_version.py CHANGED
@@ -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.1'
16
- __version_tuple__ = version_tuple = (2, 0, 1)
15
+ __version__ = version = '2.0.3'
16
+ __version_tuple__ = version_tuple = (2, 0, 3)
hilda/cli.py CHANGED
@@ -1,12 +1,14 @@
1
1
  import logging
2
2
  from pathlib import Path
3
- from typing import List, Mapping, Optional
3
+ from typing import List, Optional
4
4
 
5
5
  import click
6
6
  import coloredlogs
7
7
 
8
8
  from hilda import launch_lldb
9
9
  from hilda._version import version
10
+ from hilda.launch_lldb import create_hilda_client_using_attach_by_name, create_hilda_client_using_attach_by_pid, \
11
+ create_hilda_client_using_launch, create_hilda_client_using_remote_attach
10
12
 
11
13
  DEFAULT_HILDA_PORT = 1234
12
14
 
@@ -18,7 +20,7 @@ def cli():
18
20
  pass
19
21
 
20
22
 
21
- startup_files_option = click.option('-f', '--startup_files', multiple=True, default=None, help='Files to run on start')
23
+ startup_files_option = click.option('-f', '--startup_files', multiple=True, help='Files to run on start')
22
24
 
23
25
 
24
26
  def parse_envp(ctx: click.Context, param: click.Parameter, value: List[str]) -> List[str]:
@@ -36,54 +38,59 @@ def parse_envp(ctx: click.Context, param: click.Parameter, value: List[str]) ->
36
38
  @click.argument('hostname', default='localhost')
37
39
  @click.argument('port', type=click.INT, default=DEFAULT_HILDA_PORT)
38
40
  @startup_files_option
39
- def remote(hostname: str, port: int, startup_files: Optional[List[str]] = None) -> None:
41
+ def remote(hostname: str, port: int, startup_files: List[str]) -> None:
40
42
  """ Connect to remote debugserver at given address """
41
- launch_lldb.remote(hostname, port, startup_files)
43
+ with create_hilda_client_using_remote_attach(hostname, port) as hilda_client:
44
+ hilda_client.interact(startup_files=startup_files)
42
45
 
43
46
 
44
47
  @cli.command('attach')
45
48
  @click.option('-n', '--name', help='process name to attach')
46
49
  @click.option('-p', '--pid', type=click.INT, help='pid to attach')
47
50
  @startup_files_option
48
- def attach(name: str, pid: int, startup_files: Optional[List[str]] = None) -> None:
51
+ def attach(name: Optional[str], pid: Optional[int], startup_files: List[str]) -> None:
49
52
  """ Attach to given process and start a lldb shell """
50
- launch_lldb.attach(name=name, pid=pid, startup_files=startup_files)
53
+ if name is not None:
54
+ hilda_client = create_hilda_client_using_attach_by_name(name)
55
+ elif pid is not None:
56
+ hilda_client = create_hilda_client_using_attach_by_pid(name)
57
+ else:
58
+ raise click.UsageError('You must specify a process name or pid')
59
+ hilda_client.interact(startup_files=startup_files)
60
+ hilda_client.detach()
61
+
62
+
63
+ @cli.command('bare')
64
+ def cli_bare() -> None:
65
+ """ Just start a lldb shell """
66
+ commands = [f'command script import {Path(__file__).resolve().parent / "lldb_entrypoint.py"}']
67
+ commands = '\n'.join(commands)
68
+ launch_lldb.execute(f'lldb --one-line "{commands}"')
51
69
 
52
70
 
53
71
  @cli.command('launch')
54
72
  @click.argument('exec_path')
55
73
  @click.option('--argv', multiple=True, help='Command line arguments to pass to the process')
56
74
  @click.option('--envp', multiple=True, callback=parse_envp, help='Environment variables in the form KEY=VALUE')
57
- @click.option('--stdin', type=Path, help='Redirect stdin from this file path')
58
- @click.option('--stdout', type=Path, help='Redirect stdout to this file path')
59
- @click.option('--stderr', type=Path, help='Redirect stderr to this file path')
60
- @click.option('--cwd', type=Path, help='Set the working directory for the process')
75
+ @click.option('--stdin', help='Redirect stdin from this file path')
76
+ @click.option('--stdout', help='Redirect stdout to this file path')
77
+ @click.option('--stderr', help='Redirect stderr to this file path')
78
+ @click.option('--cwd', help='Set the working directory for the process')
61
79
  @click.option('--flags', type=click.INT, default=0, help='Launch flags (bitmask)')
62
80
  @click.option('--stop-at-entry', is_flag=True, help='Stop the process at the entry point')
63
81
  @startup_files_option
64
- def launch(exec_path: str, argv: Optional[List] = None, envp: Optional[Mapping] = None,
65
- stdin: Optional[Path] = None,
66
- stdout: Optional[Path] = None, stderr: Optional[Path] = None, cwd: Optional[Path] = None,
67
- flags: Optional[int] = 0, stop_at_entry: Optional[bool] = False,
68
- startup_files: Optional[List[str]] = None) -> None:
82
+ def launch(exec_path: str, argv: List[str], envp: List[str], stdin: Optional[Path],
83
+ stdout: Optional[Path], stderr: Optional[Path], cwd: Optional[Path], flags: Optional[int],
84
+ stop_at_entry: Optional[bool], startup_files: List[str]) -> None:
69
85
  """ Attach to given process and start a lldb shell """
70
- if not argv:
71
- argv = None
72
- if not envp:
73
- envp = None
74
- launch_lldb.launch(exec_path, argv, envp, stdin, stdout, stderr, cwd, flags, stop_at_entry,
75
- startup_files)
76
-
77
-
78
- @cli.command('bare')
79
- def cli_bare():
80
- """ Just start a lldb shell """
81
- commands = [f'command script import {Path(__file__).resolve().parent / "lldb_entrypoint.py"}']
82
- commands = '\n'.join(commands)
83
- launch_lldb.execute(f'lldb --one-line "{commands}"')
86
+ argv = list(argv)
87
+ envp = list(envp)
88
+ with create_hilda_client_using_launch(
89
+ exec_path, argv, envp, stdin, stdout, stderr, cwd, flags, stop_at_entry) as hilda_client:
90
+ hilda_client.interact(startup_files=startup_files)
84
91
 
85
92
 
86
93
  @cli.command('version')
87
- def cli_version():
94
+ def cli_version() -> None:
88
95
  """Show the version information."""
89
96
  click.echo(version)
hilda/common.py CHANGED
@@ -1,5 +1,14 @@
1
1
  from datetime import datetime
2
2
  from typing import Any, List, Mapping, Tuple, Union
3
3
 
4
+ import inquirer3
5
+ from inquirer3.themes import GreenPassion
6
+
4
7
  CfSerializable = Union[
5
8
  Mapping[str, Any], List, Tuple[Any, ...], str, bool, float, bytes, datetime, None]
9
+
10
+
11
+ def selection_prompt(options_list: List):
12
+ question = [inquirer3.List('choice', message='choose device', choices=options_list, carousel=True)]
13
+ result = inquirer3.prompt(question, theme=GreenPassion(), raise_keyboard_interrupt=True)
14
+ return result['choice']
hilda/exceptions.py CHANGED
@@ -1,7 +1,7 @@
1
1
  __all__ = ['HildaException', 'SymbolAbsentError', 'EvaluatingExpressionError', 'CreatingObjectiveCSymbolError',
2
2
  'ConvertingToNsObjectError', 'ConvertingFromNSObjectError', 'DisableJetsamMemoryChecksError',
3
3
  'GettingObjectiveCClassError', 'AccessingRegisterError', 'AccessingMemoryError',
4
- 'BrokenLocalSymbolsJarError', 'AddingLldbSymbolError', 'LLDBException']
4
+ 'BrokenLocalSymbolsJarError', 'AddingLldbSymbolError', 'LLDBError', 'InvalidThreadIndexError']
5
5
 
6
6
 
7
7
  class HildaException(Exception):
@@ -9,12 +9,9 @@ class HildaException(Exception):
9
9
  pass
10
10
 
11
11
 
12
- class LLDBException(Exception):
13
- """ A domain exception for lldb errors. """
14
-
15
- def __init__(self, message: str):
16
- super().__init__()
17
- self.message = message
12
+ class LLDBError(HildaException):
13
+ """ Wrapper for RAW LLDB errors """
14
+ pass
18
15
 
19
16
 
20
17
  class SymbolAbsentError(HildaException):
@@ -70,3 +67,8 @@ class BrokenLocalSymbolsJarError(HildaException):
70
67
  class AddingLldbSymbolError(HildaException):
71
68
  """ Raise when failing to convert a LLDB symbol to Hilda's symbol. """
72
69
  pass
70
+
71
+
72
+ class InvalidThreadIndexError(HildaException):
73
+ """ Raise when thread idx invalid """
74
+ pass
hilda/hilda_client.py CHANGED
@@ -30,10 +30,11 @@ from tqdm import tqdm
30
30
  from traitlets.config import Config
31
31
 
32
32
  from hilda import objective_c_class
33
- from hilda.common import CfSerializable
33
+ from hilda.common import CfSerializable, selection_prompt
34
34
  from hilda.exceptions import AccessingMemoryError, AccessingRegisterError, AddingLldbSymbolError, \
35
35
  BrokenLocalSymbolsJarError, ConvertingFromNSObjectError, ConvertingToNsObjectError, CreatingObjectiveCSymbolError, \
36
- DisableJetsamMemoryChecksError, EvaluatingExpressionError, HildaException, SymbolAbsentError
36
+ DisableJetsamMemoryChecksError, EvaluatingExpressionError, HildaException, InvalidThreadIndexError, \
37
+ SymbolAbsentError
37
38
  from hilda.lldb_importer import lldb
38
39
  from hilda.objective_c_symbol import ObjectiveCSymbol
39
40
  from hilda.registers import Registers
@@ -73,7 +74,7 @@ def disable_logs() -> None:
73
74
  logging.getLogger('parso.python.diff').disabled = True
74
75
  logging.getLogger('humanfriendly.prompts').disabled = True
75
76
  logging.getLogger('blib2to3.pgen2.driver').disabled = True
76
- logging.getLogger('hilda.launch_lldb').disabled = True
77
+ logging.getLogger('hilda.launch_lldb').setLevel(logging.INFO)
77
78
 
78
79
 
79
80
  SerializableSymbol = namedtuple('SerializableSymbol', 'address type_ filename')
@@ -356,17 +357,19 @@ class HildaClient:
356
357
  if not self.process.Continue().Success():
357
358
  self.log_critical('failed to continue process')
358
359
 
359
- def detach(self):
360
+ def detach(self) -> None:
360
361
  """
361
362
  Detach from process.
362
363
 
363
364
  Useful in order to exit gracefully so process doesn't get killed
364
365
  while you exit
365
366
  """
367
+ if not self.process.is_alive:
368
+ return
366
369
  if not self.process.Detach().Success():
367
370
  self.log_critical('failed to detach')
368
- else:
369
- self.log_info('Process Detached')
371
+ return
372
+ self.log_info('Process Detached')
370
373
 
371
374
  @stop_is_needed
372
375
  def disass(self, address: int, buf: bytes, flavor: str = 'intel',
@@ -397,30 +400,33 @@ class HildaClient:
397
400
 
398
401
  return self.symbol(module.ResolveFileAddress(address).GetLoadAddress(self.target))
399
402
 
400
- def get_register(self, name) -> Symbol:
403
+ def get_register(self, name: str) -> Union[float, Symbol]:
401
404
  """
402
- Get value for register by its name
403
- :param name:
404
- :return:
405
+ Get value for register by its name. Value can either be an Symbol (int) or a float.
406
+
407
+ :param name: Register name
408
+ :return: Register value
405
409
  """
406
- register = self.frame.register[name.lower()]
407
- if register is None:
410
+ register_value = self.frame.register[name.lower()]
411
+ if register_value is None:
408
412
  raise AccessingRegisterError()
409
- return self.symbol(register.unsigned)
413
+ return self._get_symbol_or_float_from_sbvalue(register_value)
410
414
 
411
- def set_register(self, name, value):
415
+ def set_register(self, name: str, value: Union[float, int]) -> None:
412
416
  """
413
417
  Set value for register by its name
414
- :param name:
415
- :param value:
416
- :return:
418
+ :param name: Register name
419
+ :param value: Register value
417
420
  """
418
421
  register = self.frame.register[name.lower()]
419
422
  if register is None:
420
423
  raise AccessingRegisterError()
421
- register.value = hex(value)
424
+ if isinstance(value, int):
425
+ register.value = hex(value)
426
+ else:
427
+ register.value = str(value)
422
428
 
423
- def objc_call(self, obj, selector, *params):
429
+ def objc_call(self, obj: int, selector: str, *params):
424
430
  """
425
431
  Simulate a call to an objc selector
426
432
  :param obj: obj to pass into `objc_msgSend`
@@ -510,7 +516,7 @@ class HildaClient:
510
516
  if options.get('name', False):
511
517
  name = options['name']
512
518
 
513
- log_message = f'🚨 #{bp.id} 0x{symbol:x} {name}'
519
+ log_message = f'🚨 #{bp.id} 0x{symbol:x} {name} - Thread #{self.thread.idx}:{hex(self.thread.id)}'
514
520
 
515
521
  if 'regs' in options:
516
522
  log_message += '\nregs:'
@@ -524,27 +530,32 @@ class HildaClient:
524
530
  value = hilda.symbol(hilda.evaluate_expression(name))
525
531
  log_message += f'\n\t{name} = {hilda._monitor_format_value(fmt, value)}'
526
532
 
527
- if options.get('force_return', False):
528
- hilda.force_return(options['force_return'])
529
- log_message += f'\nforced return: {options["force_return"]}'
533
+ force_return = options.get('force_return')
534
+ if force_return is not None:
535
+ hilda.force_return(force_return)
536
+ log_message += f'\nforced return: {force_return}'
530
537
 
531
- if options.get('bt', False):
538
+ if options.get('bt'):
532
539
  # bugfix: for callstacks from xpc events
533
540
  hilda.finish()
534
- hilda.bt()
541
+ for frame in hilda.bt():
542
+ log_message += f'\n\t{frame[0]} {frame[1]}'
535
543
 
536
- if options.get('retval', False):
544
+ retval = options.get('retval')
545
+ if retval is not None:
537
546
  # return from function
538
547
  hilda.finish()
539
548
  value = hilda.evaluate_expression('$arg1')
540
- log_message += f'\nreturned: {hilda._monitor_format_value(options["retval"], value)}'
549
+ log_message += f'\nreturned: {hilda._monitor_format_value(retval, value)}'
541
550
 
542
551
  hilda.log_info(log_message)
543
552
 
544
553
  for cmd in options.get('cmd', []):
545
554
  hilda.lldb_handle_command(cmd)
546
555
 
547
- if not options.get('stop', False):
556
+ if options.get('stop', False):
557
+ hilda.log_info('Process remains stopped and focused on current thread')
558
+ else:
548
559
  hilda.cont()
549
560
 
550
561
  return self.bp(address, callback, condition=condition, **options)
@@ -834,7 +845,7 @@ class HildaClient:
834
845
  raise ConvertingFromNSObjectError from e
835
846
  return json.loads(json_dump, object_hook=self._from_ns_json_object_hook)['root']
836
847
 
837
- def evaluate_expression(self, expression) -> Symbol:
848
+ def evaluate_expression(self, expression: str) -> Union[float, Symbol]:
838
849
  """
839
850
  Wrapper for LLDB's EvaluateExpression.
840
851
  Used for quick code snippets.
@@ -844,8 +855,8 @@ class HildaClient:
844
855
  currentDevice = objc_get_class('UIDevice').currentDevice
845
856
  evaluate_expression(f'[[{currentDevice} systemName] hasPrefix:@"2"]')
846
857
 
847
- :param expression:
848
- :return: returned symbol
858
+ :param expression: Expression to evaluate
859
+ :return: Returned value (either float or a Symbol)
849
860
  """
850
861
  # prepending a prefix so LLDB knows to return an int type
851
862
  if isinstance(expression, int):
@@ -858,12 +869,12 @@ class HildaClient:
858
869
  options.SetTryAllThreads(True)
859
870
  options.SetUnwindOnError(self.configs.evaluation_unwind_on_error)
860
871
 
861
- e = self.frame.EvaluateExpression(formatted_expression, options)
872
+ sbvalue = self.frame.EvaluateExpression(formatted_expression, options)
862
873
 
863
- if not e.error.Success():
864
- raise EvaluatingExpressionError(str(e.error))
874
+ if not sbvalue.error.Success():
875
+ raise EvaluatingExpressionError(str(sbvalue.error))
865
876
 
866
- return self.symbol(e.unsigned)
877
+ return self._get_symbol_or_float_from_sbvalue(sbvalue)
867
878
 
868
879
  def import_module(self, filename: str, name: Optional[str] = None) -> Any:
869
880
  """
@@ -880,6 +891,16 @@ class HildaClient:
880
891
  spec.loader.exec_module(m)
881
892
  return m
882
893
 
894
+ def set_selected_thread(self, idx: Optional[int] = None) -> None:
895
+ if idx is None:
896
+ thread = selection_prompt(self.process.threads)
897
+ else:
898
+ try:
899
+ thread = [t for t in self.process.threads if t.idx == idx][0]
900
+ except IndexError:
901
+ raise InvalidThreadIndexError()
902
+ self.process.SetSelectedThread(thread)
903
+
883
904
  def unwind(self) -> bool:
884
905
  """ Unwind the stack (useful when get_evaluation_unwind() == False) """
885
906
  return self.thread.UnwindInnermostExpression().Success()
@@ -1033,7 +1054,7 @@ class HildaClient:
1033
1054
  ipython_config.InteractiveShellApp.extensions = ['hilda.ipython_extensions.magics',
1034
1055
  'hilda.ipython_extensions.events',
1035
1056
  'hilda.ipython_extensions.keybindings']
1036
- ipython_config.InteractiveShellApp.exec_lines = ["disable_logs()"]
1057
+ ipython_config.InteractiveShellApp.exec_lines = ['disable_logs()']
1037
1058
  if startup_files is not None:
1038
1059
  ipython_config.InteractiveShellApp.exec_files = startup_files
1039
1060
  self.log_debug(f'Startup files - {startup_files}')
@@ -1041,10 +1062,17 @@ class HildaClient:
1041
1062
  namespace = globals()
1042
1063
  namespace.update(locals())
1043
1064
  namespace['p'] = self
1065
+ namespace['ui'] = self.ui_manager
1066
+ namespace['cfg'] = self.configs
1044
1067
  if additional_namespace is not None:
1045
1068
  namespace.update(additional_namespace)
1046
1069
  sys.argv = ['a']
1047
1070
  IPython.start_ipython(config=ipython_config, user_ns=namespace)
1071
+
1072
+ def __enter__(self) -> 'HildaClient':
1073
+ return self
1074
+
1075
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
1048
1076
  self.detach()
1049
1077
 
1050
1078
  @staticmethod
@@ -1158,3 +1186,11 @@ class HildaClient:
1158
1186
  '__objc_class_list',
1159
1187
  f'{objc_classlist_addr}')
1160
1188
  return json.loads(self.po(obj_c_code))
1189
+
1190
+ def _get_symbol_or_float_from_sbvalue(self, value: lldb.SBValue) -> Union[float, Symbol]:
1191
+ # The `value` attribute of an SBValue stores a string representation of the actual value
1192
+ # in a python-compatible format, so we can eval it to get the native python value
1193
+ value = eval(value.value)
1194
+ if isinstance(value, float):
1195
+ return value
1196
+ return self.symbol(value)
hilda/launch_lldb.py CHANGED
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
4
4
  from threading import Thread
5
5
  from typing import List, Optional
6
6
 
7
- from hilda.exceptions import LLDBException
7
+ from hilda.exceptions import LLDBError
8
8
  from hilda.hilda_client import HildaClient
9
9
  from hilda.lldb_importer import lldb
10
10
 
@@ -14,14 +14,6 @@ lldb.hilda_client = None
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
16
 
17
- def hilda(debugger, startup_files: Optional[List[str]] = None):
18
- if lldb.hilda_client is None:
19
- lldb.hilda_client = HildaClient(debugger)
20
-
21
- additional_namespace = {'ui': lldb.hilda_client.ui_manager, 'cfg': lldb.hilda_client.configs}
22
- lldb.hilda_client.interact(additional_namespace=additional_namespace, startup_files=startup_files)
23
-
24
-
25
17
  def execute(cmd: str) -> int:
26
18
  logging.debug(f'executing: {cmd}')
27
19
  return os.system(cmd)
@@ -49,10 +41,10 @@ class LLDBListenerThread(Thread, ABC):
49
41
  def _create_process(self) -> lldb.SBProcess:
50
42
  pass
51
43
 
52
- def _check_success(self):
44
+ def _check_success(self) -> None:
53
45
  if self.error.Success():
54
46
  return
55
- raise LLDBException(self.error.description)
47
+ raise LLDBError(self.error.description)
56
48
 
57
49
  def run(self):
58
50
  event = lldb.SBEvent()
@@ -67,12 +59,25 @@ class LLDBListenerThread(Thread, ABC):
67
59
  logger.debug('Process Detached')
68
60
  self.should_quit = True
69
61
  elif state == lldb.eStateExited:
70
- logger.debug(f'Process Exited with status {self.process.GetExitStatus()}')
62
+ logger.info(f'Process Exited with status {self.process.GetExitStatus()}')
71
63
  self.should_quit = True
72
64
  elif state == lldb.eStateRunning and last_state == lldb.eStateStopped:
73
- logger.debug("Process Continued")
65
+ logger.debug('Process Continued')
74
66
  elif state == lldb.eStateStopped and last_state == lldb.eStateRunning:
75
67
  logger.debug('Process Stopped')
68
+ for thread in self.process:
69
+ frame = thread.GetFrameAtIndex(0)
70
+ stop_reason = thread.GetStopReason()
71
+ logger.debug(f'tid = {hex(thread.GetThreadID())} pc = {frame.GetPC()}')
72
+ if stop_reason not in [lldb.eStopReasonSignal, lldb.eStopReasonException,
73
+ lldb.eStopReasonBreakpoint,
74
+ lldb.eStopReasonWatchpoint, lldb.eStopReasonPlanComplete,
75
+ lldb.eStopReasonTrace,
76
+ lldb.eStopReasonSignal]:
77
+ continue
78
+ self.process.SetSelectedThread(thread)
79
+ break
80
+
76
81
  last_state = state
77
82
 
78
83
 
@@ -114,7 +119,7 @@ class LLDBAttachName(LLDBListenerThread):
114
119
  return self.debugger.CreateTargetWithFileAndArch(None, None)
115
120
 
116
121
  def _create_process(self) -> lldb.SBProcess:
117
- logger.debug(f'Attaching to {self.name}')
122
+ logger.debug(f'Attaching to {self.proc_name}')
118
123
  return self.target.AttachToProcessWithName(self.listener, self.proc_name, self.wait_for, self.error)
119
124
 
120
125
 
@@ -148,42 +153,36 @@ class LLDBLaunch(LLDBListenerThread):
148
153
  self.error)
149
154
 
150
155
 
151
- def remote(hostname: str, port: int, startup_files: Optional[List[str]] = None) -> None:
152
- """ Connect to remote process """
153
- try:
154
- lldb_t = LLDBRemote(hostname, port)
155
- lldb_t.start()
156
- hilda(lldb_t.debugger, startup_files)
157
- except LLDBException as e:
158
- logger.error(e.message)
159
-
160
-
161
- def attach(name: Optional[str] = None, pid: Optional[int] = None, wait_for: bool = False,
162
- startup_files: Optional[List[str]] = None) -> None:
163
- """ Attach to given process and start a lldb shell """
164
- if (name is not None and pid is not None) or (name is None and pid is None):
165
- raise ValueError('Provide either a process name or a PID, but not both.')
166
-
167
- try:
168
- if name is not None:
169
- lldb_t = LLDBAttachName(name, wait_for)
170
- else:
171
- lldb_t = LLDBAttachPid(pid)
172
- lldb_t.start()
173
- hilda(lldb_t.debugger, startup_files)
174
- except LLDBException as e:
175
- logger.error(e.message)
176
-
177
-
178
- def launch(exec_path: str, argv: Optional[List] = None, envp: Optional[List] = None,
179
- stdin: Optional[str] = None,
180
- stdout: Optional[str] = None, stderr: Optional[str] = None, wd: Optional[str] = None,
181
- flags: Optional[int] = 0, stop_at_entry: Optional[bool] = False,
182
- startup_files: Optional[List[str]] = None) -> None:
183
- """ Launch to given process and start a lldb shell """
184
- try:
185
- lldb_t = LLDBLaunch(exec_path, argv, envp, stdin, stdout, stderr, wd, flags, stop_at_entry)
186
- lldb_t.start()
187
- hilda(lldb_t.debugger, startup_files)
188
- except LLDBException as e:
189
- logger.error(e.message)
156
+ def _get_hilda_client_from_sbdebugger(debugger: lldb.SBDebugger) -> HildaClient:
157
+ hilda_client = HildaClient(debugger)
158
+ lldb.hilda_client = hilda_client
159
+ hilda_client.init_dynamic_environment()
160
+ return hilda_client
161
+
162
+
163
+ def create_hilda_client_using_remote_attach(
164
+ hostname: str, port: int) -> HildaClient:
165
+ lldb_t = LLDBRemote(hostname, port)
166
+ lldb_t.start()
167
+ return _get_hilda_client_from_sbdebugger(lldb_t.debugger)
168
+
169
+
170
+ def create_hilda_client_using_launch(
171
+ exec_path: str, argv: Optional[List] = None, envp: Optional[List] = None, stdin: Optional[str] = None,
172
+ stdout: Optional[str] = None, stderr: Optional[str] = None, wd: Optional[str] = None,
173
+ flags: Optional[int] = 0, stop_at_entry: Optional[bool] = False) -> HildaClient:
174
+ lldb_t = LLDBLaunch(exec_path, argv, envp, stdin, stdout, stderr, wd, flags, stop_at_entry)
175
+ lldb_t.start()
176
+ return _get_hilda_client_from_sbdebugger(lldb_t.debugger)
177
+
178
+
179
+ def create_hilda_client_using_attach_by_pid(pid: Optional[int] = None) -> HildaClient:
180
+ lldb_t = LLDBAttachPid(pid)
181
+ lldb_t.start()
182
+ return _get_hilda_client_from_sbdebugger(lldb_t.debugger)
183
+
184
+
185
+ def create_hilda_client_using_attach_by_name(name: Optional[str] = None, wait_for: bool = False) -> HildaClient:
186
+ lldb_t = LLDBAttachName(name, wait_for)
187
+ lldb_t.start()
188
+ return _get_hilda_client_from_sbdebugger(lldb_t.debugger)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hilda
3
- Version: 2.0.1
3
+ Version: 2.0.3
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>
@@ -51,37 +51,32 @@ Requires-Dist: construct
51
51
  Requires-Dist: pymobiledevice3
52
52
  Requires-Dist: keystone-engine
53
53
  Requires-Dist: tabulate
54
+ Requires-Dist: inquirer3
54
55
  Provides-Extra: test
55
56
  Requires-Dist: pytest ; extra == 'test'
56
57
 
57
- - [Description](#description)
58
- - [Installation](#installation)
59
- - [How to use](#how-to-use)
60
- - [Starting a Hilda shell](#starting-a-hilda-shell)
61
- - [Attach mode](#attach-mode)
62
- - [Launch mode](#launch-mode)
63
- - [Bare mode](#bare-mode)
64
- - [Remote mode](#remote-mode)
65
- - [The connected device is connected via network](#the-connected-device-is-connected-via-network)
66
- - [Startup Files](#startup-files)
67
- - [Usage](#usage)
68
- - [Magic functions](#magic-functions)
69
- - [Shortcuts](#shortcuts)
70
- - [Configurables](#configurables)
71
- - [Attributes](#attributes)
72
- - [Example Usage](#example-usage)
73
- - [UI Configuration](#ui-configuration)
74
- - [Symbol objects](#symbol-objects)
75
- - [Globalized symbols](#globalized-symbols)
76
- - [Searching for the right symbol](#searching-for-the-right-symbol)
77
- - [Objective-C Classes](#objective-c-classes)
78
- - [Objective-C Objects](#objective-c-objects)
79
- - [Using snippets](#using-snippets)
80
- - [Contributing](#contributing)
81
-
82
- Would you like any further adjustments?
83
-
84
- # Description
58
+ # Hilda
59
+
60
+ - [Hilda](#hilda)
61
+ - [Overview](#overview)
62
+ - [Installation](#installation)
63
+ - [How to use](#how-to-use)
64
+ - [Starting a Hilda interactive shell](#starting-a-hilda-interactive-shell)
65
+ - [Inside a Hilda shell](#inside-a-hilda-shell)
66
+ - [Magic functions](#magic-functions)
67
+ - [Key-bindings](#key-bindings)
68
+ - [Configurables](#configurables)
69
+ - [UI Configuration](#ui-configuration)
70
+ - [Python API](#python-api)
71
+ - [Symbol objects](#symbol-objects)
72
+ - [Globalized symbols](#globalized-symbols)
73
+ - [Searching for the right symbol](#searching-for-the-right-symbol)
74
+ - [Objective-C Classes](#objective-c-classes)
75
+ - [Objective-C Objects](#objective-c-objects)
76
+ - [Using snippets](#using-snippets)
77
+ - [Contributing](#contributing)
78
+
79
+ ## Overview
85
80
 
86
81
  Hilda is a debugger which combines both the power of LLDB and iPython for easier debugging.
87
82
 
@@ -93,8 +88,8 @@ debugger-y" approach (based on LLDB).
93
88
  Currently, the project is intended for iOS/OSX debugging, but in the future we will possibly add support for the
94
89
  following platforms as well:
95
90
 
96
- * Linux
97
- * Android
91
+ - Linux
92
+ - Android
98
93
 
99
94
  Since LLDB allows abstraction for both platform and architecture, it should be possible to make the necessary changes
100
95
  without too many modifications.
@@ -104,14 +99,14 @@ Pull requests are more than welcome 😊.
104
99
  If you need help or have an amazing idea you would like to suggest, feel free
105
100
  to [start a discussion 💬](https://github.com/doronz88/hilda/discussions).
106
101
 
107
- # Installation
102
+ ## Installation
108
103
 
109
104
  Requirements for remote iOS device (not required for debugging a local OSX process):
110
105
 
111
- * Jailbroken iOS device
112
- * `debugserver` in device's PATH
113
- * [You can use this tool in order to obtain the binary](https://github.com/doronz88/debugserver-deploy)
114
- * After re-signing with new entitlements, you can put the binary in the following path: `/usr/bin/debugserver`
106
+ - Jailbroken iOS device
107
+ - `debugserver` in device's PATH
108
+ - [You can use this tool in order to obtain the binary](https://github.com/doronz88/debugserver-deploy)
109
+ - After re-signing with new entitlements, you can put the binary in the following path: `/usr/bin/debugserver`
115
110
 
116
111
  In order to install please run:
117
112
 
@@ -121,104 +116,40 @@ xcrun python3 -m pip install --user -U hilda
121
116
 
122
117
  *⚠️ Please note that Hilda is installed on top of XCode's python so LLDB will be able to use its features.*
123
118
 
124
- # How to use
119
+ ## How to use
125
120
 
126
- ## Starting a Hilda shell
121
+ ### Starting a Hilda interactive shell
127
122
 
128
- ### Attach mode
123
+ You can may start a Hilda interactive shell by invoking any of the subcommand:
129
124
 
130
- Use the attach sub-command in order to start an LLDB shell attached to given process.
125
+ - `hilda launch /path/to/executable`
126
+ - Launch given executable on current host
127
+ - `hilda attach [-p pid] [-n process-name]`
128
+ - Attach to an already running process on current host (specified by either `pid` or `process-name`)
129
+ - `hilda remote HOSTNAME PORT`
130
+ - Attach to an already running process on a target host (sepcified by `HOSTNAME PORT`)
131
+ - `hilda bare`
132
+ - Only start an LLDB shell and load Hilda as a plugin.
133
+ - Please refer to the following help page if you require help on the command available to you within the lldb shell:
131
134
 
132
- ```shell
133
- hilda attach [-p pid] [-n process-name]
134
- ```
135
-
136
- ### Launch mode
137
-
138
- Use the attach sub-command in order to launch given process.
139
-
140
- ```shell
141
- hilda launch /path/to/executable \
142
- --argv arg1 --argv arg2 \
143
- --envp NAME=Alice --envp AGE=30 \
144
- --stdin /path/to/input.txt \
145
- --stdout /path/to/output.txt \
146
- --stderr /path/to/error.txt \
147
- --wd /path/to/working/directory \
148
- --flags 0x01 \
149
- --stop-at-entry
150
- ```
151
-
152
- ### Bare mode
153
-
154
- Use "Bare mode" to get a "bare-bones" lldb shell, whereas hilda plugin is already loaded and ready to start. This mode
155
- is useful when you need to have custom commands for attaching to the target process (for example when debugging OSX
156
- processes).
157
-
158
- To start this mode simply use:
159
-
160
- ```shell
161
- hilda bare
162
- ```
163
-
164
- Please refer to the following help page if you require help on the command available to you within the lldb shell:
165
-
166
- [lldb command map](https://lldb.llvm.org/use/map.html).
167
-
168
- As a cheatsheet, connecting to a remote platform like so:
169
-
170
- ```shell
171
- platform connect connect://ip:port
172
- ```
173
-
174
- ... and attaching to a local process:
175
-
176
- ```shell
177
- process attach -n proccess_name
178
- process attach -p proccess_pid
179
- ```
180
-
181
- When you are ready, just execute `hilda` to move to Hilda's iPython shell.
182
-
183
- ### Remote mode
184
-
185
- This mode will auto-connect to the remote device and attach to your target process assuming you are trying to debug a
186
- remote jailbroken iOS device.
187
-
188
- Please note the following:
189
-
190
- * script assumes the connected device already **has a running ssh server**, which doesn't require a password (you can
191
- use
192
- `ssh-copy-id` to achieve this).
135
+ [lldb command map](https://lldb.llvm.org/use/map.html).
193
136
 
194
- From this point the flow diverges into 2 flows:
137
+ As a cheatsheet, connecting to a remote platform like so:
195
138
 
196
- ### The connected device is connected via network
139
+ ```shell
140
+ platform connect connect://ip:port
141
+ ```
197
142
 
198
- Run the following command:
143
+ ... and attaching to a local process:
199
144
 
200
- ```shell
201
- hilda remote HOSTNAME PORT
202
- ```
203
-
204
- ## Startup Files
205
-
206
- Each command can accept startup files to execute on start. As opposed to snippets, the startup files can accept Hilda
207
- syntax.
208
-
209
- #### Startup File Example
210
-
211
- ```python
212
- cfg.objc_verbose_monitor = True
213
- p.bp(ADDRESS)
214
- p.cont()
215
- ```
145
+ ```shell
146
+ process attach -n proccess_name
147
+ process attach -p proccess_pid
148
+ ```
216
149
 
217
- ```shell
218
- hilda remote HOSTNAME PORT -f startupfile1 -f startupfile2
219
- ```
150
+ When you are ready, just execute `hilda` to move to Hilda's iPython shell.
220
151
 
221
- ## Usage
152
+ ### Inside a Hilda shell
222
153
 
223
154
  Upon starting Hilda shell, you are greeted with:
224
155
 
@@ -231,52 +162,53 @@ Have a nice flight ✈️! Starting an IPython shell...
231
162
  Here is a gist of methods you can access from `p`:
232
163
 
233
164
  - `hd`
234
- - Print an hexdump of given buffer
165
+ - Print an hexdump of given buffer
235
166
  - `lsof`
236
- - Get dictionary of all open FDs
167
+ - Get dictionary of all open FDs
237
168
  - `bt`
238
- - Print an improved backtrace.
169
+ - Print an improved backtrace.
239
170
  - `disable_jetsam_memory_checks`
240
- - Disable jetsam memory checks, prevent raising:
171
+ - Disable jetsam memory checks, prevent raising:
241
172
  `error: Execution was interrupted, reason: EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=15 MB, unused=0x0).`
242
173
  when evaluating expression.
243
174
  - `symbol`
244
- - Get symbol object for a given address
175
+ - Get symbol object for a given address
245
176
  - `objc_symbol`
246
- - Get objc symbol wrapper for given address
177
+ - Get objc symbol wrapper for given address
247
178
  - `inject`
248
- - Inject a single library into currently running process
179
+ - Inject a single library into currently running process
249
180
  - `rebind_symbols`
250
- - Reparse all loaded images symbols
181
+ - Reparse all loaded images symbols
251
182
  - `poke`
252
- - Write data at given address
183
+ - Write data at given address
253
184
  - `peek`
254
- - Read data at given address
185
+ - Read data at given address
255
186
  - `peek_str`
256
- - Peek a buffer till null termination
187
+ - Peek a buffer till null termination
257
188
  - `stop`
258
- - Stop process.
189
+ - Stop process.
259
190
  - `cont`
260
- - Continue process.
191
+ - Continue process.
261
192
  - `detach`
262
- - Detach from process.
193
+ - Detach from process.
263
194
  Useful in order to exit gracefully so process doesn't get killed
264
195
  while you exit
265
196
  - `disass`
266
- - Print disassembly from a given address
197
+ - Print disassembly from a given address
267
198
  - `file_symbol`
268
- - Calculate symbol address without ASLR
199
+ - Calculate symbol address without ASLR
269
200
  - `get_register`
270
- - Get value for register by its name
201
+ - Get value for register by its name
271
202
  - `set_register`
272
- - Set value for register by its name
203
+ - Set value for register by its name
273
204
  - `objc_call`
274
- - Simulate a call to an objc selector
205
+ - Simulate a call to an objc selector
275
206
  - `call`
276
- - Call function at given address with given parameters
207
+ - Call function at given address with given parameters
277
208
  - `monitor`
278
- - Monitor every time a given address is called
209
+ - Monitor every time a given address is called
279
210
  The following options are available:
211
+
280
212
  ```
281
213
  regs={reg1: format}
282
214
  will print register values
@@ -308,58 +240,57 @@ Here is a gist of methods you can access from `p`:
308
240
  override=True
309
241
  override previous break point at same location
310
242
  ```
243
+
311
244
  - `show_current_source`
312
- - print current source code if possible
245
+ - print current source code if possible
313
246
  - `finish`
314
- - Run current frame till its end.
247
+ - Run current frame till its end.
315
248
  - `step_into`
316
- - Step into current instruction.
249
+ - Step into current instruction.
317
250
  - `step_over`
318
- - Step over current instruction.
251
+ - Step over current instruction.
319
252
  - `remove_all_hilda_breakpoints`
320
- - Remove all breakpoints created by Hilda
253
+ - Remove all breakpoints created by Hilda
321
254
  - `remove_hilda_breakpoint`
322
- - Remove a single breakpoint placed by Hilda
255
+ - Remove a single breakpoint placed by Hilda
323
256
  - `force_return`
324
- - Prematurely return from a stack frame, short-circuiting exection of newer frames and optionally
257
+ - Prematurely return from a stack frame, short-circuiting exection of newer frames and optionally
325
258
  yielding a specified value.
326
259
  - `proc_info`
327
- - Print information about currently running mapped process.
260
+ - Print information about currently running mapped process.
328
261
  - `print_proc_entitlements`
329
- - Get the plist embedded inside the process' __LINKEDIT section.
262
+ - Get the plist embedded inside the process' __LINKEDIT section.
330
263
  - `bp`
331
- - Add a breakpoint
264
+ - Add a breakpoint
332
265
  - `show_hilda_breakpoints`
333
- - Show existing breakpoints created by Hilda.
334
- - `show_commands`
335
- - Show available commands.
266
+ - Show existing breakpoints created by Hilda.
336
267
  - `save`
337
- - Save loaded symbols map (for loading later using the load() command)
268
+ - Save loaded symbols map (for loading later using the load() command)
338
269
  - `load`
339
- - Load an existing symbols map (previously saved by the save() command)
270
+ - Load an existing symbols map (previously saved by the save() command)
340
271
  - `po`
341
- - Print given object using LLDB's po command
272
+ - Print given object using LLDB's po command
342
273
  Can also run big chunks of native code:
343
274
 
344
275
  po('NSMutableString *s = [NSMutableString string]; [s appendString:@"abc"]; [s description]')
345
276
  - `globalize_symbols`
346
- - Make all symbols in python's global scope
277
+ - Make all symbols in python's global scope
347
278
  - `jump`
348
- - jump to given symbol
279
+ - jump to given symbol
349
280
  - `lldb_handle_command`
350
- - Execute an LLDB command
281
+ - Execute an LLDB command
351
282
  For example:
352
283
  lldb_handle_command('register read')
353
284
  - `objc_get_class`
354
- - Get ObjC class object
285
+ - Get ObjC class object
355
286
  - `CFSTR`
356
- - Create CFStringRef object from given string
287
+ - Create CFStringRef object from given string
357
288
  - `ns`
358
- - Create NSObject from given data
289
+ - Create NSObject from given data
359
290
  - `from_ns`
360
- - Create python object from NS object.
291
+ - Create python object from NS object.
361
292
  - `evaluate_expression`
362
- - Wrapper for LLDB's EvaluateExpression.
293
+ - Wrapper for LLDB's EvaluateExpression.
363
294
  Used for quick code snippets.
364
295
 
365
296
  Feel free to use local variables inside the expression using format string.
@@ -367,31 +298,37 @@ Here is a gist of methods you can access from `p`:
367
298
  currentDevice = objc_get_class('UIDevice').currentDevice
368
299
  evaluate_expression(f'[[{currentDevice} systemName] hasPrefix:@"2"]')
369
300
  - `import_module`
370
- - Import & reload given python module (intended mainly for external snippets)
301
+ - Import & reload given python module (intended mainly for external snippets)
371
302
  - `unwind`
372
- - Unwind the stack (useful when get_evaluation_unwind() == False)
303
+ - Unwind the stack (useful when get_evaluation_unwind() == False)
304
+ - `set_selected_thread`
305
+ - sets the currently selected thread, which is used in other parts of the program, such as displaying disassembly or
306
+ checking registers.
307
+ This ensures the application focuses on the specified thread for these operations.
373
308
 
374
- ## Magic functions
309
+ All these methods are available from the global `p` within the newly created IPython shell. In addition, you may invoke any of the exported APIs described in the [Python API](#python-api)
375
310
 
376
- Sometimes accessing the python API can be tiring, so we added some magic functions to help you out!
311
+ #### Magic functions
312
+
313
+ Sometimes accessing the [Python API](#python-api) can be tiring, so we added some magic functions to help you out!
377
314
 
378
315
  - `%objc <className>`
379
- - Equivalent to: `className = p.objc_get_class(className)`
316
+ - Equivalent to: `className = p.objc_get_class(className)`
380
317
  - `%fbp <filename> <addressInHex>`
381
- - Equivalent to: `p.file_symbol(addressInHex, filename).bp()`
318
+ - Equivalent to: `p.file_symbol(addressInHex, filename).bp()`
382
319
 
383
- ## Shortcuts
320
+ #### Key-bindings
384
321
 
385
322
  - **F7**: Step Into
386
323
  - **F8**: Step Over
387
324
  - **F9**: Continue
388
325
  - **F10**: Stop
389
326
 
390
- ## Configurables
327
+ #### Configurables
391
328
 
392
329
  The global `cfg` used to configure various settings for evaluation and monitoring.
393
330
 
394
- ### Attributes
331
+ These settings include:
395
332
 
396
333
  - `evaluation_unwind_on_error`: Whether to unwind on error during evaluation. (Default: `False`)
397
334
  - `evaluation_ignore_breakpoints`: Whether to ignore breakpoints during evaluation. (Default: `False`)
@@ -400,15 +337,9 @@ The global `cfg` used to configure various settings for evaluation and monitorin
400
337
  - `objc_verbose_monitor`: When set to `True`, using `monitor()` will automatically print Objective-C method arguments. (
401
338
  Default: `False`)
402
339
 
403
- ### Example Usage
340
+ #### UI Configuration
404
341
 
405
- ```python
406
- cfg.objc_verbose_monitor = True
407
- ```
408
-
409
- ## UI Configuration
410
-
411
- Hilda contains minimal UI for examining the target state.
342
+ Hilda contains a minimal UI for examining the target state.
412
343
  The UI is divided into views:
413
344
 
414
345
  - Registers
@@ -465,7 +396,31 @@ ui.colors.address = 'red'
465
396
  ui.color.title = 'green'
466
397
  ```
467
398
 
468
- ## Symbol objects
399
+ ### Python API
400
+
401
+ Hilda provides a comprehensive API wrappers to access LLDB capabilities.
402
+ This API may be used to access process memory, trigger functions, place breakpoints and much more!
403
+
404
+ Also, in addition to access this API using the [Hilda shell](#inside-a-hilda-shell), you may also use pure-python script using any of the `create_hilda_client_using_*` APIs.
405
+
406
+ Consider the following snippet as an example of such usage:
407
+
408
+ ```python
409
+ from hilda.launch_lldb import create_hilda_client_using_attach_by_name
410
+
411
+ # attach to `sysmond`
412
+ p = create_hilda_client_using_attach_by_name('sysmond')
413
+
414
+ # allocate 10 bytes and print their address
415
+ print(p.symbols.malloc(10))
416
+
417
+ # detach
418
+ p.detach()
419
+ ```
420
+
421
+ Please note this script must be executed using `xcrun python3` in order for it to be able to access LLDB API.
422
+
423
+ #### Symbol objects
469
424
 
470
425
  In Hilda, almost everything is wrapped using the `Symbol` Object. Symbol is just a nicer way for referring to addresses
471
426
  encapsulated with an object allowing to deref the memory inside, or use these addresses as functions.
@@ -572,7 +527,7 @@ p.bp('symbol_name')
572
527
  p.bp('symbol_name', module_name='ModuleName')
573
528
  ```
574
529
 
575
- ## Globalized symbols
530
+ #### Globalized symbols
576
531
 
577
532
  Usually you would want/need to use the symbols already mapped into the currently running process. To do so, you can
578
533
  access them using `symbols.<symbol-name>`. The `symbols` global object is of type `SymbolsJar`, which is a wrapper
@@ -617,7 +572,7 @@ jar = jar.code()
617
572
  jar.monitor(regs={'x0': 'x'}, bt=True)
618
573
  ```
619
574
 
620
- ### Objective-C Classes
575
+ #### Objective-C Classes
621
576
 
622
577
  The same as symbols applies to Objective-C classes name resolution. You can either:
623
578
 
@@ -670,7 +625,7 @@ dictionary = NSDictionary.capture_self(True)
670
625
  dictionary.show()
671
626
  ```
672
627
 
673
- ## Objective-C Objects
628
+ #### Objective-C Objects
674
629
 
675
630
  In order to work with ObjC objects, each symbol contains a property called
676
631
  `objc_symbol`. After calling, you can work better with each object:
@@ -736,7 +691,7 @@ abc_string = p.evaluate_expression('[NSString stringWithFormat:@"abc"]')
736
691
  print(abc_string.po())
737
692
  ```
738
693
 
739
- ## Using snippets
694
+ #### Using snippets
740
695
 
741
696
  Snippets are extensions for normal functionality used as quick cookbooks for day-to-day tasks of a debugger.
742
697
 
@@ -3,13 +3,13 @@ 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=llBMh-GtSPemevJ46pFdqzJYvqrJ0mS-b_e99BsAPEQ,411
7
- hilda/cli.py,sha256=0keoM7FLQXiF-J65ftRUtLnYtyyRpGez6xNZ3tZIXZA,3329
8
- hilda/common.py,sha256=fxlVTyRP2AmKCnE6FdgnGJVoG-OBq7Tw6TrBQ_xgszI,194
9
- hilda/exceptions.py,sha256=spH9i27nLm71-SR5Nb028cBVD81qAS6qRfoC2XVoGls,2014
6
+ hilda/_version.py,sha256=nHByjT85Mzor0VestVUVI70fkRS763utSt6toCJI-NY,411
7
+ hilda/cli.py,sha256=jAM31J2aaXAyiEmMFRiRP3FjvQylt390SsFQJGhqfDo,3760
8
+ hilda/common.py,sha256=VFtpOH9IRqbu6lONM6Hz-PxcdJfktgS3akJv5UCHO0s,523
9
+ hilda/exceptions.py,sha256=8L1OvOqns4O4ieiH4YlrMbZkk_PvuyCq4UyqFAodkF8,2042
10
10
  hilda/hilda_ascii_art.html,sha256=-9YCjAKdGbjtdd6uoKrxkkcJq7j16r4dGka2bZ27b4o,120119
11
- hilda/hilda_client.py,sha256=TksJu9vdukY5cZQQh0qrY-siwXU3gVYkvEIaMBqQeAs,43486
12
- hilda/launch_lldb.py,sha256=SIBv-uGbp1mgJU96H9gBNU5ahiTwzRwpCiR5RGJ1xVE,7149
11
+ hilda/hilda_client.py,sha256=4wY1syGiVV_LGyXRNch2QZi7Zi1VEi6OrMjbLHzZ3eQ,45274
12
+ hilda/launch_lldb.py,sha256=tFSJK9dry1Z12lE5OSbDX53aJ23TO1XFElHo85qxeVo,7336
13
13
  hilda/lldb_entrypoint.py,sha256=vTiClzfiTtjorlxEfIsI-W657KEGobx74qDhaZ8nPhM,1007
14
14
  hilda/lldb_importer.py,sha256=LrIQnigDG3wgmIPXya67oBlWubkDgV-rEpzfWNEYCoc,553
15
15
  hilda/objective_c_class.py,sha256=Xyw7FucNVcu8NqhB0Gy-OjaN_2DmCywn6pjUEwyd1Hk,11760
@@ -46,9 +46,9 @@ hilda/snippets/macho/macho_load_commands.py,sha256=OsajG2xWuRwhYhj9f-lnUiNe43Yum
46
46
  hilda/ui/colors.json,sha256=f-ITquY3IInQreviTy23JfmxfJrGM1_MivACf1GKGqM,262
47
47
  hilda/ui/ui_manager.py,sha256=BmzI1sBx0PYCQDlB9Al7wsTEAMJxaJ7NW0DS4C7g5-0,2265
48
48
  hilda/ui/views.py,sha256=1u_eZzw7wAEP1bm_-9nkqgGhMSX__woiUuoBgnsAKVM,7843
49
- hilda-2.0.1.dist-info/LICENSE,sha256=M-LVJ0AFAYB82eueyl8brh-QLPe-iLNVgbCi79-3TDo,1078
50
- hilda-2.0.1.dist-info/METADATA,sha256=BExnYkqJD8IDK4klLR0g5GXN209FCxll3B-G6oMBl60,23606
51
- hilda-2.0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
52
- hilda-2.0.1.dist-info/entry_points.txt,sha256=9n3O3j6V3XnVR_GcFqCWNgRAbalfukTSW2WvghsLVmA,46
53
- hilda-2.0.1.dist-info/top_level.txt,sha256=TVD7l1WkE1noT866YqPFhiQnjYCYZM5Xz54v_3EYpnI,11
54
- hilda-2.0.1.dist-info/RECORD,,
49
+ hilda-2.0.3.dist-info/LICENSE,sha256=M-LVJ0AFAYB82eueyl8brh-QLPe-iLNVgbCi79-3TDo,1078
50
+ hilda-2.0.3.dist-info/METADATA,sha256=7eMn09PoasA7uQIPpQWsAbJtNUzuJqanUYlioQvWdgs,23306
51
+ hilda-2.0.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
52
+ hilda-2.0.3.dist-info/entry_points.txt,sha256=9n3O3j6V3XnVR_GcFqCWNgRAbalfukTSW2WvghsLVmA,46
53
+ hilda-2.0.3.dist-info/top_level.txt,sha256=TVD7l1WkE1noT866YqPFhiQnjYCYZM5Xz54v_3EYpnI,11
54
+ hilda-2.0.3.dist-info/RECORD,,
File without changes
File without changes