summaryrefslogtreecommitdiff
path: root/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h
blob: ed93fc194df111faf47bb1d0281d105d5b5eb446 (plain)
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
//===-- 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:
    typedef enum { eFixUpNone, eFixUpFixed, eFixUpToFix } FixUpState;

    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(NULL), 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_ap;
};

} // namespace lldb_private

#endif // lldb_AppleObjCTrampolineHandler_h_