docs: def hook(self, addr, hook=None, length=0, kwargs=None, replace=False):
          """
          Hook a section of code with a custom function. This is used internally to provide symbolic
          summaries of library functions, and can be used to instrument execution or to modify
          control flow.
  
          When hook is not specified, it returns a function decorator that allows easy hooking.
          Usage::
  
              # Assuming proj is an instance of angr.Project, we will add a custom hook at the entry
              # point of the project.
              @proj.hook(proj.entry)
              def my_hook(state):
                  print("Welcome to execution!")
  
          :param addr:        The address to hook.
          :param hook:        A :class:`angr.project.Hook` describing a procedure to run at the
                              given address. You may also pass in a SimProcedure class or a function
                              directly and it will be wrapped in a Hook object for you.
          :param length:      If you provide a function for the hook, this is the number of bytes
                              that will be skipped by executing the hook by default.
          :param kwargs:      If you provide a SimProcedure for the hook, these are the keyword
                              arguments that will be passed to the procedure's `run` method
                              eventually.
          :param replace:     Control the behavior on finding that the address is already hooked. If
                              true, silently replace the hook. If false (default), warn and do not
                              replace the hook. If none, warn and replace the hook.
          """
          if hook is None:
              # if we haven't been passed a thing to hook with, assume we're being used as a decorator
              return self._hook_decorator(addr, length=length, kwargs=kwargs)
  
          if kwargs is None: kwargs = {}
  
          l.debug('hooking %s with %s', self._addr_to_str(addr), str(hook))
  
          if self.is_hooked(addr):
              if replace is True:
                  pass
              elif replace is False:
                  l.warning("Address is already hooked, during hook(%s, %s). Not re-hooking.", self._addr_to_str(addr), hook)
                  return
              else:
                  l.warning("Address is already hooked, during hook(%s, %s). Re-hooking.", self._addr_to_str(addr), hook)
  
          if isinstance(hook, type):
              raise TypeError("Please instanciate your SimProcedure before hooking with it")
  
          if callable(hook):
              hook = SIM_PROCEDURES['stubs']['UserHook'](user_func=hook, length=length, **kwargs)
  
          self._sim_procedures[addr] = hook