gdb: make displaced stepping implementation capable of managing multiple buffers
[deliverable/binutils-gdb.git] / gdb / displaced-stepping.h
CommitLineData
bab37966
SM
1/* Displaced stepping related things.
2
3 Copyright (C) 2020 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#ifndef DISPLACED_STEPPING_H
21#define DISPLACED_STEPPING_H
22
480af54c 23#include "gdbsupport/array-view.h"
c7acb87b
SM
24#include "gdbsupport/byte-vector.h"
25
187b041e 26struct gdbarch;
c7acb87b
SM
27struct thread_info;
28
29/* True if we are debugging displaced stepping. */
30
31extern bool debug_displaced;
32
33/* Print a "displaced" debug statement. */
34
35#define displaced_debug_printf(fmt, ...) \
36 do \
37 { \
38 if (debug_displaced) \
39 debug_prefixed_printf ("displaced", __func__, fmt, ##__VA_ARGS__); \
40 } \
41 while (0)
42
bab37966
SM
43enum displaced_step_prepare_status
44{
45 /* A displaced stepping buffer was successfully allocated and prepared. */
46 DISPLACED_STEP_PREPARE_STATUS_OK,
47
48 /* This particular instruction can't be displaced stepped, GDB should fall
49 back on in-line stepping. */
50 DISPLACED_STEP_PREPARE_STATUS_CANT,
51
52 /* Not enough resources are available at this time, try again later. */
53 DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE,
54};
55
56enum displaced_step_finish_status
57{
58 /* Either the instruction was stepped and fixed up, or the specified thread
59 wasn't executing a displaced step (in which case there's nothing to
60 finish). */
61 DISPLACED_STEP_FINISH_STATUS_OK,
62
63 /* The thread started a displaced step, but didn't complete it. */
64 DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED,
65};
66
187b041e
SM
67/* Data returned by a gdbarch displaced_step_copy_insn method, to be passed to
68 the matching displaced_step_fixup method. */
c7acb87b
SM
69
70struct displaced_step_copy_insn_closure
71{
72 virtual ~displaced_step_copy_insn_closure () = 0;
73};
74
75using displaced_step_copy_insn_closure_up
76 = std::unique_ptr<displaced_step_copy_insn_closure>;
77
78/* A simple displaced step closure that contains only a byte buffer. */
79
80struct buf_displaced_step_copy_insn_closure : displaced_step_copy_insn_closure
81{
82 buf_displaced_step_copy_insn_closure (int buf_size)
83 : buf (buf_size)
84 {}
85
187b041e
SM
86 /* The content of this buffer is up to the user of the class, but typically
87 original instruction bytes, used during fixup to determine what needs to
88 be fixed up. */
c7acb87b
SM
89 gdb::byte_vector buf;
90};
91
92/* Per-inferior displaced stepping state. */
93
94struct displaced_step_inferior_state
95{
96 displaced_step_inferior_state ()
97 {
98 reset ();
99 }
100
101 /* Put this object back in its original state. */
102 void reset ()
103 {
187b041e
SM
104 failed_before = false;
105 in_progress_count = 0;
106 unavailable = false;
c7acb87b
SM
107 }
108
109 /* True if preparing a displaced step ever failed. If so, we won't
110 try displaced stepping for this inferior again. */
187b041e 111 bool failed_before;
c7acb87b 112
187b041e
SM
113 /* Number of displaced steps in progress for this inferior. */
114 unsigned int in_progress_count;
c7acb87b 115
187b041e
SM
116 /* If true, this tells GDB that it's not worth asking the gdbarch displaced
117 stepping implementation to prepare a displaced step, because it would
118 return UNAVAILABLE. This is set and reset by the gdbarch in the
119 displaced_step_prepare and displaced_step_finish methods. */
120 bool unavailable;
121};
c7acb87b 122
187b041e 123/* Per-thread displaced stepping state. */
c7acb87b 124
187b041e
SM
125struct displaced_step_thread_state
126{
127 /* Return true if this thread is currently executing a displaced step. */
128 bool in_progress () const
129 {
130 return m_original_gdbarch != nullptr;
131 }
132
133 /* Return the gdbarch of the thread prior to the step. */
134 gdbarch *get_original_gdbarch () const
135 {
136 return m_original_gdbarch;
137 }
138
139 /* Mark this thread as currently executing a displaced step.
140
141 ORIGINAL_GDBARCH is the current gdbarch of the thread (before the step
142 is executed). */
143 void set (gdbarch *original_gdbarch)
144 {
145 m_original_gdbarch = original_gdbarch;
146 }
147
148 /* Mark this thread as no longer executing a displaced step. */
149 void reset ()
150 {
151 m_original_gdbarch = nullptr;
152 }
153
154private:
155 gdbarch *m_original_gdbarch = nullptr;
156};
157
480af54c 158/* Control access to multiple displaced stepping buffers at fixed addresses. */
187b041e 159
480af54c 160struct displaced_step_buffers
187b041e 161{
480af54c
SM
162 explicit displaced_step_buffers (gdb::array_view<CORE_ADDR> buffer_addrs)
163 {
164 gdb_assert (buffer_addrs.size () > 0);
165
166 m_buffers.reserve (buffer_addrs.size ());
167
168 for (CORE_ADDR buffer_addr : buffer_addrs)
169 m_buffers.emplace_back (buffer_addr);
170 }
187b041e
SM
171
172 displaced_step_prepare_status prepare (thread_info *thread,
173 CORE_ADDR &displaced_pc);
174
175 displaced_step_finish_status finish (gdbarch *arch, thread_info *thread,
176 gdb_signal sig);
177
178 const displaced_step_copy_insn_closure *
179 copy_insn_closure_by_addr (CORE_ADDR addr);
180
181 void restore_in_ptid (ptid_t ptid);
182
183private:
187b041e 184
480af54c
SM
185 /* State of a single buffer. */
186
187 struct displaced_step_buffer
188 {
189 explicit displaced_step_buffer (CORE_ADDR addr)
190 : addr (addr)
191 {}
192
193 /* Address of the buffer. */
194 const CORE_ADDR addr;
195
196 /* The original PC of the instruction currently being stepped. */
197 CORE_ADDR original_pc = 0;
198
199 /* If set, the thread currently using the buffer. If unset, the buffer is not
200 used. */
201 thread_info *current_thread = nullptr;
187b041e 202
480af54c
SM
203 /* Saved copy of the bytes in the displaced buffer, to be restored once the
204 buffer is no longer used. */
205 gdb::byte_vector saved_copy;
c7acb87b 206
480af54c
SM
207 /* Closure obtained from gdbarch_displaced_step_copy_insn, to be passed to
208 gdbarch_displaced_step_fixup_insn. */
209 displaced_step_copy_insn_closure_up copy_insn_closure;
210 };
187b041e 211
480af54c 212 std::vector<displaced_step_buffer> m_buffers;
c7acb87b
SM
213};
214
bab37966 215#endif /* DISPLACED_STEPPING_H */
This page took 0.031271 seconds and 4 git commands to generate.