reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
//===-- AppleObjCTrampolineHandler.h ----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef lldb_AppleObjCTrampolineHandler_h_
#define lldb_AppleObjCTrampolineHandler_h_

#include <map>
#include <mutex>
#include <vector>

#include "lldb/Expression/UtilityFunction.h"
#include "lldb/lldb-public.h"

namespace lldb_private {

class AppleObjCTrampolineHandler {
public:
  AppleObjCTrampolineHandler(const lldb::ProcessSP &process_sp,
                             const lldb::ModuleSP &objc_module_sp);

  ~AppleObjCTrampolineHandler();

  lldb::ThreadPlanSP GetStepThroughDispatchPlan(Thread &thread,
                                                bool stop_others);

  FunctionCaller *GetLookupImplementationFunctionCaller();

  bool AddrIsMsgForward(lldb::addr_t addr) const {
    return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr);
  }

  struct DispatchFunction {
  public:
    enum FixUpState { eFixUpNone, eFixUpFixed, eFixUpToFix };

    const char *name;
    bool stret_return;
    bool is_super;
    bool is_super2;
    FixUpState fixedup;
  };

  lldb::addr_t SetupDispatchFunction(Thread &thread,
                                     ValueList &dispatch_values);

private:
  static const char *g_lookup_implementation_function_name;
  static const char *g_lookup_implementation_with_stret_function_code;
  static const char *g_lookup_implementation_no_stret_function_code;

  class AppleObjCVTables {
  public:
    // These come from objc-gdb.h.
    enum VTableFlags {
      eOBJC_TRAMPOLINE_MESSAGE = (1 << 0), // trampoline acts like objc_msgSend
      eOBJC_TRAMPOLINE_STRET = (1 << 1),   // trampoline is struct-returning
      eOBJC_TRAMPOLINE_VTABLE = (1 << 2)   // trampoline is vtable dispatcher
    };

  private:
    struct VTableDescriptor {
      VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start)
          : flags(in_flags), code_start(in_code_start) {}

      uint32_t flags;
      lldb::addr_t code_start;
    };

    class VTableRegion {
    public:
      VTableRegion()
          : m_valid(false), m_owner(nullptr),
            m_header_addr(LLDB_INVALID_ADDRESS), m_code_start_addr(0),
            m_code_end_addr(0), m_next_region(0) {}

      VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr);

      void SetUpRegion();

      lldb::addr_t GetNextRegionAddr() { return m_next_region; }

      lldb::addr_t GetCodeStart() { return m_code_start_addr; }

      lldb::addr_t GetCodeEnd() { return m_code_end_addr; }

      uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; }

      bool IsValid() { return m_valid; }

      bool AddressInRegion(lldb::addr_t addr, uint32_t &flags);

      void Dump(Stream &s);

    public:
      bool m_valid;
      AppleObjCVTables *m_owner;
      lldb::addr_t m_header_addr;
      lldb::addr_t m_code_start_addr;
      lldb::addr_t m_code_end_addr;
      std::vector<VTableDescriptor> m_descriptors;
      lldb::addr_t m_next_region;
    };

  public:
    AppleObjCVTables(const lldb::ProcessSP &process_sp,
                     const lldb::ModuleSP &objc_module_sp);

    ~AppleObjCVTables();

    bool InitializeVTableSymbols();

    static bool RefreshTrampolines(void *baton,
                                   StoppointCallbackContext *context,
                                   lldb::user_id_t break_id,
                                   lldb::user_id_t break_loc_id);
    bool ReadRegions();

    bool ReadRegions(lldb::addr_t region_addr);

    bool IsAddressInVTables(lldb::addr_t addr, uint32_t &flags);

    lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); }

  private:
    lldb::ProcessWP m_process_wp;
    typedef std::vector<VTableRegion> region_collection;
    lldb::addr_t m_trampoline_header;
    lldb::break_id_t m_trampolines_changed_bp_id;
    region_collection m_regions;
    lldb::ModuleSP m_objc_module_sp;
  };

  static const DispatchFunction g_dispatch_functions[];

  typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch
                                                  // fn address to the index in
                                                  // g_dispatch_functions
  MsgsendMap m_msgSend_map;
  lldb::ProcessWP m_process_wp;
  lldb::ModuleSP m_objc_module_sp;
  const char *m_lookup_implementation_function_code;
  std::unique_ptr<UtilityFunction> m_impl_code;
  std::mutex m_impl_function_mutex;
  lldb::addr_t m_impl_fn_addr;
  lldb::addr_t m_impl_stret_fn_addr;
  lldb::addr_t m_msg_forward_addr;
  lldb::addr_t m_msg_forward_stret_addr;
  std::unique_ptr<AppleObjCVTables> m_vtables_up;
};

} // namespace lldb_private

#endif // lldb_AppleObjCTrampolineHandler_h_