Commit | Line | Data |
---|---|---|
e088209c SM |
1 | #ifndef DISPLACED_STEPPING_H |
2 | #define DISPLACED_STEPPING_H | |
3 | ||
9635ae5d | 4 | #include "gdbsupport/array-view.h" |
e088209c SM |
5 | #include "gdbsupport/byte-vector.h" |
6 | ||
7 | struct gdbarch; | |
8 | struct thread_info; | |
348a832d | 9 | struct target_ops; |
e088209c SM |
10 | |
11 | enum displaced_step_prepare_status | |
12 | { | |
13 | /* A displaced stepping buffer was successfully allocated and prepared. */ | |
14 | DISPLACED_STEP_PREPARE_STATUS_OK, | |
15 | ||
16 | /* Something bad happened. */ | |
17 | DISPLACED_STEP_PREPARE_STATUS_ERROR, | |
18 | ||
19 | /* Not enough resources are available at this time, try again later. */ | |
20 | DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE, | |
21 | }; | |
22 | ||
23 | enum displaced_step_finish_status | |
24 | { | |
25 | /* The instruction was stepped and fixed up. */ | |
26 | DISPLACED_STEP_FINISH_STATUS_OK, | |
27 | ||
28 | /* The instruction was not stepped. */ | |
29 | DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED, | |
30 | }; | |
31 | ||
32 | /* Data returned by a gdbarch displaced_step_copy_insn method, to be passed to | |
33 | the matching displaced_step_fixup method. */ | |
34 | ||
35 | struct displaced_step_copy_insn_closure | |
36 | { | |
37 | virtual ~displaced_step_copy_insn_closure () = 0; | |
38 | }; | |
39 | ||
40 | typedef std::unique_ptr<displaced_step_copy_insn_closure> | |
41 | displaced_step_copy_insn_closure_up; | |
42 | ||
43 | /* A simple displaced step closure that contains only a byte buffer. */ | |
44 | ||
45 | struct buf_displaced_step_copy_insn_closure : displaced_step_copy_insn_closure | |
46 | { | |
47 | buf_displaced_step_copy_insn_closure (int buf_size) | |
48 | : buf (buf_size) | |
49 | {} | |
50 | ||
51 | gdb::byte_vector buf; | |
52 | }; | |
53 | ||
54 | /* Per-inferior displaced stepping state. */ | |
55 | ||
56 | struct displaced_step_inferior_state | |
57 | { | |
58 | displaced_step_inferior_state () | |
59 | { | |
60 | reset (); | |
61 | } | |
62 | ||
63 | /* Put this object back in its original state. */ | |
64 | void reset () | |
65 | { | |
66 | failed_before = false; | |
67 | } | |
68 | ||
69 | /* True if preparing a displaced step ever failed. If so, we won't | |
70 | try displaced stepping for this inferior again. */ | |
71 | bool failed_before; | |
d6864985 SM |
72 | |
73 | bool unavailable = false; | |
e088209c SM |
74 | }; |
75 | ||
76 | /* Per-thread displaced stepping state. */ | |
77 | ||
78 | struct displaced_step_thread_state | |
79 | { | |
80 | /* Return true if this thread is currently executing a displaced step. */ | |
81 | bool in_progress () const | |
82 | { return m_original_gdbarch != nullptr; } | |
83 | ||
84 | /* Return the gdbarch of the thread prior to the step. */ | |
85 | gdbarch *get_original_gdbarch () const | |
86 | { return m_original_gdbarch; } | |
87 | ||
88 | /* Mark this thread as currently executing a displaced step. | |
89 | ||
90 | ORIGINAL_GDBARCH is the current gdbarch of the thread (before the step | |
91 | is executed). */ | |
92 | void set (gdbarch *original_gdbarch) | |
93 | { m_original_gdbarch = original_gdbarch; } | |
94 | ||
95 | /* mark this thread as no longer executing a displaced step. */ | |
96 | void reset () | |
97 | { m_original_gdbarch = nullptr; } | |
98 | ||
99 | private: | |
100 | gdbarch *m_original_gdbarch = nullptr; | |
101 | }; | |
102 | ||
9635ae5d SM |
103 | struct displaced_step_buffer_state |
104 | { | |
105 | displaced_step_buffer_state (CORE_ADDR buffer_addr) | |
106 | : m_buffer_addr (buffer_addr) | |
107 | {} | |
108 | ||
109 | const CORE_ADDR m_buffer_addr; | |
110 | ||
111 | /* When a displaced step operation is using this buffer, this is the original | |
112 | PC of the instruction currently begin stepped. */ | |
113 | CORE_ADDR m_original_pc = 0; | |
114 | ||
115 | /* If set, the thread currently using the buffer. If unset, the buffer is not | |
116 | used. */ | |
117 | thread_info *m_current_thread = nullptr; | |
118 | ||
119 | /* Saved copy of the bytes in the displaced buffer, to be restored once the | |
120 | buffer is no longer used. */ | |
121 | gdb::byte_vector m_saved_copy; | |
122 | ||
123 | /* Closure obtained from gdbarch_displaced_step_copy_insn, to be passed to | |
124 | gdbarch_displaced_step_fixup_insn. */ | |
125 | displaced_step_copy_insn_closure_up m_copy_insn_closure; | |
126 | }; | |
127 | ||
e088209c SM |
128 | /* Manage access to a single displaced stepping buffer, without any |
129 | sharing. */ | |
130 | ||
9635ae5d | 131 | struct multiple_displaced_buffer_manager |
e088209c | 132 | { |
9635ae5d SM |
133 | multiple_displaced_buffer_manager (gdb::array_view<CORE_ADDR> buffer_addrs) |
134 | { | |
135 | gdb_assert (buffer_addrs.size () > 0); | |
136 | ||
137 | for (CORE_ADDR buffer_addr : buffer_addrs) | |
138 | m_buffers.emplace_back (buffer_addr); | |
139 | } | |
e088209c SM |
140 | |
141 | displaced_step_prepare_status prepare (thread_info *thread); | |
142 | ||
143 | displaced_step_finish_status finish (gdbarch *arch, thread_info *thread, | |
144 | gdb_signal sig); | |
145 | ||
c0fdb45e SM |
146 | CORE_ADDR first_buf_addr () const |
147 | { | |
148 | return m_buffers[0].m_buffer_addr; | |
149 | } | |
150 | ||
e088209c | 151 | private: |
9635ae5d | 152 | std::vector<displaced_step_buffer_state> m_buffers; |
e088209c SM |
153 | }; |
154 | ||
65a7e4d6 SM |
155 | bool default_supports_displaced_step (target_ops *target, thread_info *thread); |
156 | ||
348a832d SM |
157 | displaced_step_prepare_status |
158 | default_displaced_step_prepare (target_ops *target, thread_info *thread); | |
159 | ||
160 | displaced_step_finish_status | |
161 | default_displaced_step_finish (target_ops *target, thread_info *thread, | |
162 | gdb_signal sig); | |
e088209c SM |
163 | |
164 | #endif /* DISPLACED_STEPPING_H */ |