gdb: add target_ops methods for displaced stepping
[deliverable/binutils-gdb.git] / gdb / displaced-stepping.c
CommitLineData
e088209c
SM
1#include "defs.h"
2
3#include "displaced-stepping.h"
4
5#include "gdbarch.h"
6#include "gdbthread.h"
7#include "target.h"
8#include "inferior.h"
9#include "gdbcore.h"
10
11displaced_step_copy_insn_closure::~displaced_step_copy_insn_closure() = default;
12
13displaced_step_prepare_status
9635ae5d 14multiple_displaced_buffer_manager::prepare (thread_info *thread)
e088209c 15{
9635ae5d
SM
16 gdb_assert (!thread->displaced_step_state.in_progress ());
17 displaced_step_buffer_state *buffer = nullptr;
18
19 /* Sanity check. */
20 for (displaced_step_buffer_state &buf : m_buffers)
21 gdb_assert (buf.m_current_thread != thread);
22
23 /* Search for an unused buffer. */
24 for (displaced_step_buffer_state &candidate : m_buffers)
e088209c 25 {
9635ae5d
SM
26 if (candidate.m_current_thread == nullptr)
27 {
28 buffer = &candidate;
29 break;
30 }
e088209c
SM
31 }
32
9635ae5d
SM
33 if (buffer == nullptr)
34 return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
35
e088209c 36 gdbarch *arch = thread->arch ();
9635ae5d
SM
37
38 if (debug_displaced)
39 fprintf_unfiltered (gdb_stdlog, "displaced: selected buffer at %s\n",
40 paddress (arch, buffer->m_buffer_addr));
41
e088209c
SM
42 struct regcache *regcache = thread->regcache ();
43 ULONGEST len = gdbarch_max_insn_length (arch);
9635ae5d 44 buffer->m_original_pc = regcache_read_pc (regcache);
e088209c
SM
45
46 /* Save the original contents of the displaced stepping buffer. */
9635ae5d 47 buffer->m_saved_copy.resize (len);
e088209c 48
9635ae5d 49 int status = target_read_memory (buffer->m_buffer_addr, buffer->m_saved_copy.data (), len);
e088209c
SM
50 if (status != 0)
51 throw_error (MEMORY_ERROR,
52 _("Error accessing memory address %s (%s) for "
53 "displaced-stepping scratch space."),
9635ae5d 54 paddress (arch, buffer->m_buffer_addr), safe_strerror (status));
e088209c
SM
55
56 if (debug_displaced)
57 {
58 fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ",
9635ae5d
SM
59 paddress (arch, buffer->m_buffer_addr));
60 displaced_step_dump_bytes (gdb_stdlog, buffer->m_saved_copy.data (), len);
e088209c
SM
61 };
62
9635ae5d
SM
63 buffer->m_copy_insn_closure
64 = gdbarch_displaced_step_copy_insn (arch, buffer->m_original_pc,
65 buffer->m_buffer_addr, regcache);
66 if (buffer->m_copy_insn_closure == nullptr)
e088209c
SM
67 {
68 /* The architecture doesn't know how or want to displaced step
69 this instruction or instruction sequence. Fallback to
70 stepping over the breakpoint in-line. */
71 return DISPLACED_STEP_PREPARE_STATUS_ERROR;
72 }
73
74 try
75 {
76 /* Resume execution at the copy. */
9635ae5d 77 regcache_write_pc (regcache, buffer->m_buffer_addr);
e088209c
SM
78 }
79 catch (...)
80 {
81 /* Failed to write the PC. Release the architecture's displaced
82 stepping resources and the thread's displaced stepping state. */
9635ae5d 83 buffer->m_copy_insn_closure.reset ();
e088209c
SM
84
85 return DISPLACED_STEP_PREPARE_STATUS_ERROR;
86 }
87
88 /* This marks the buffer as being in use. */
9635ae5d 89 buffer->m_current_thread = thread;
e088209c
SM
90
91 return DISPLACED_STEP_PREPARE_STATUS_OK;
92}
93
94static void
95write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr,
96 const gdb_byte *myaddr, int len)
97{
98 scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
99
100 inferior_ptid = ptid;
101 write_memory (memaddr, myaddr, len);
102}
103
104static bool
105displaced_step_instruction_executed_successfully (gdbarch *arch, gdb_signal signal)
106{
107 if (signal != GDB_SIGNAL_TRAP)
108 return false;
109
110 if (target_stopped_by_watchpoint ())
111 {
112 // FIXME: Not sure about this condition.
113 if (gdbarch_have_nonsteppable_watchpoint (arch)
114 || target_have_steppable_watchpoint)
115 return false;
116 }
117
118 return true;
119}
120
121displaced_step_finish_status
9635ae5d
SM
122multiple_displaced_buffer_manager::finish (gdbarch *arch, thread_info *thread,
123 gdb_signal sig)
e088209c
SM
124{
125 displaced_step_finish_status status;
9635ae5d 126 displaced_step_buffer_state *buffer = nullptr;
e088209c 127
9635ae5d
SM
128 gdb_assert (thread->displaced_step_state.in_progress ());
129
130 /* Find the buffer this thread was using. */
131 for (displaced_step_buffer_state &candidate : m_buffers)
132 {
133 if (thread == candidate.m_current_thread)
134 {
135 buffer = &candidate;
136 break;
137 }
138 }
139
140 gdb_assert (buffer != nullptr);
e088209c
SM
141
142 ULONGEST len = gdbarch_max_insn_length (arch);
143
9635ae5d
SM
144 /* Restore memory of the buffer. */
145 write_memory_ptid (thread->ptid, buffer->m_buffer_addr,
146 buffer->m_saved_copy.data (), len);
e088209c
SM
147 if (debug_displaced)
148 fprintf_unfiltered (gdb_stdlog, "displaced: restored %s %s\n",
149 target_pid_to_str (thread->ptid).c_str (),
9635ae5d 150 paddress (arch, buffer->m_buffer_addr));
e088209c
SM
151
152 regcache *rc = get_thread_regcache (thread);
153
154 bool instruction_executed_successfully
155 = displaced_step_instruction_executed_successfully (arch, sig);
156
e088209c
SM
157 if (instruction_executed_successfully)
158 {
9635ae5d
SM
159 gdbarch_displaced_step_fixup (arch, buffer->m_copy_insn_closure.get (),
160 buffer->m_original_pc,
161 buffer->m_buffer_addr, rc);
e088209c
SM
162 status = DISPLACED_STEP_FINISH_STATUS_OK;
163 }
164 else
165 {
166 /* Since the instruction didn't complete, all we can do is relocate the
167 PC. */
168 CORE_ADDR pc = regcache_read_pc (rc);
9635ae5d 169 pc = buffer->m_original_pc + (pc - buffer->m_buffer_addr);
e088209c
SM
170 regcache_write_pc (rc, pc);
171 status = DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED;
172 }
173
9635ae5d
SM
174 buffer->m_copy_insn_closure.reset ();
175 buffer->m_current_thread = nullptr;
e088209c
SM
176
177 return status;
178}
348a832d
SM
179
180displaced_step_prepare_status
181 default_displaced_step_prepare (target_ops *target, thread_info *thread)
182{
183 gdbarch *arch = thread->arch ();
184 return gdbarch_displaced_step_prepare (arch, thread);
185}
186
187displaced_step_finish_status
188default_displaced_step_finish (target_ops *target,
189 thread_info *thread,
190 gdb_signal sig)
191{
192 gdbarch *arch = thread->arch ();
193 return gdbarch_displaced_step_finish (arch, thread, sig);
194}
This page took 0.031894 seconds and 4 git commands to generate.