gdb: move displaced stepping logic to gdbarch, allow starting concurrent displaced...
[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
14single_displaced_buffer_manager::prepare (thread_info *thread)
15{
16 /* Is a thread currently using the buffer? */
17 if (m_current_thread != nullptr)
18 {
19 /* If so, it better not be this thread. */
20 gdb_assert (thread != m_current_thread);
21 return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
22 }
23
24 gdbarch *arch = thread->arch ();
25 struct regcache *regcache = thread->regcache ();
26 ULONGEST len = gdbarch_max_insn_length (arch);
27 m_original_pc = regcache_read_pc (regcache);
28
29 /* Save the original contents of the displaced stepping buffer. */
30 m_saved_copy.resize (len);
31
32 int status = target_read_memory (m_buffer_addr, m_saved_copy.data (), len);
33 if (status != 0)
34 throw_error (MEMORY_ERROR,
35 _("Error accessing memory address %s (%s) for "
36 "displaced-stepping scratch space."),
37 paddress (arch, m_buffer_addr), safe_strerror (status));
38
39 if (debug_displaced)
40 {
41 fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ",
42 paddress (arch, m_buffer_addr));
43 displaced_step_dump_bytes (gdb_stdlog, m_saved_copy.data (), len);
44 };
45
46 m_copy_insn_closure = gdbarch_displaced_step_copy_insn (arch,
47 m_original_pc,
48 m_buffer_addr,
49 regcache);
50 if (m_copy_insn_closure == nullptr)
51 {
52 /* The architecture doesn't know how or want to displaced step
53 this instruction or instruction sequence. Fallback to
54 stepping over the breakpoint in-line. */
55 return DISPLACED_STEP_PREPARE_STATUS_ERROR;
56 }
57
58 try
59 {
60 /* Resume execution at the copy. */
61 regcache_write_pc (regcache, m_buffer_addr);
62 }
63 catch (...)
64 {
65 /* Failed to write the PC. Release the architecture's displaced
66 stepping resources and the thread's displaced stepping state. */
67 m_copy_insn_closure.reset ();
68
69 return DISPLACED_STEP_PREPARE_STATUS_ERROR;
70 }
71
72 /* This marks the buffer as being in use. */
73 m_current_thread = thread;
74
75 return DISPLACED_STEP_PREPARE_STATUS_OK;
76}
77
78static void
79write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr,
80 const gdb_byte *myaddr, int len)
81{
82 scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
83
84 inferior_ptid = ptid;
85 write_memory (memaddr, myaddr, len);
86}
87
88static bool
89displaced_step_instruction_executed_successfully (gdbarch *arch, gdb_signal signal)
90{
91 if (signal != GDB_SIGNAL_TRAP)
92 return false;
93
94 if (target_stopped_by_watchpoint ())
95 {
96 // FIXME: Not sure about this condition.
97 if (gdbarch_have_nonsteppable_watchpoint (arch)
98 || target_have_steppable_watchpoint)
99 return false;
100 }
101
102 return true;
103}
104
105displaced_step_finish_status
106single_displaced_buffer_manager::finish (gdbarch *arch, thread_info *thread,
107 gdb_signal sig)
108{
109 displaced_step_finish_status status;
110
111 gdb_assert (thread == m_current_thread);
112
113 ULONGEST len = gdbarch_max_insn_length (arch);
114
115 write_memory_ptid (thread->ptid, m_buffer_addr,
116 m_saved_copy.data (), len);
117 if (debug_displaced)
118 fprintf_unfiltered (gdb_stdlog, "displaced: restored %s %s\n",
119 target_pid_to_str (thread->ptid).c_str (),
120 paddress (arch, m_buffer_addr));
121
122 regcache *rc = get_thread_regcache (thread);
123
124 bool instruction_executed_successfully
125 = displaced_step_instruction_executed_successfully (arch, sig);
126
127
128 if (instruction_executed_successfully)
129 {
130 gdbarch_displaced_step_fixup (arch, m_copy_insn_closure.get (), m_original_pc,
131 m_buffer_addr, rc);
132 status = DISPLACED_STEP_FINISH_STATUS_OK;
133 }
134 else
135 {
136 /* Since the instruction didn't complete, all we can do is relocate the
137 PC. */
138 CORE_ADDR pc = regcache_read_pc (rc);
139 pc = m_original_pc + (pc - m_buffer_addr);
140 regcache_write_pc (rc, pc);
141 status = DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED;
142 }
143
144 m_copy_insn_closure.reset ();
145 m_current_thread = nullptr;
146
147 return status;
148}
This page took 0.028167 seconds and 4 git commands to generate.