| 147 | } |
| 148 | |
| 149 | class breakpoint_recorder final { |
| 150 | struct breakpoint final { |
| 151 | std::size_t id = 0; |
| 152 | std::variant<std::size_t, std::string, cs::var> data; |
| 153 | |
| 154 | template <typename T> |
| 155 | breakpoint(std::size_t _id, T &&_data) : id(_id), data(std::forward<T>(_data)) |
| 156 | { |
| 157 | } |
| 158 | }; |
| 159 | |
| 160 | static std::size_t m_id; |
| 161 | std::forward_list<breakpoint> m_breakpoints; |
| 162 | cs::map_t<std::string, std::pair<std::size_t, bool>> m_pending; |
| 163 | |
| 164 | public: |
| 165 | breakpoint_recorder() = default; |
| 166 | |
| 167 | std::size_t add_line(std::size_t line_num) |
| 168 | { |
| 169 | m_breakpoints.emplace_front(++m_id, line_num); |
| 170 | return m_id; |
| 171 | } |
| 172 | |
| 173 | std::size_t add_func(cs::var function) |
| 174 | { |
| 175 | if (function.type() == typeid(cs::object_method)) |
| 176 | function = function.const_val<cs::object_method>().callable; |
| 177 | else if (function.type() != typeid(cs::callable)) |
| 178 | throw cs::runtime_error("Debugger just can break at specific line or function."); |
| 179 | const cs::callable::function_type &target = function.const_val<cs::callable>().get_raw_data(); |
| 180 | if (target.target_type() != typeid(cs::function_ptr)) |
| 181 | throw cs::runtime_error("Debugger can not break at CNI function."); |
| 182 | target.target<cs::function_ptr>()->fptr->set_debugger_state(true); |
| 183 | m_breakpoints.emplace_front(++m_id, function); |
| 184 | return m_id; |
| 185 | } |
| 186 | |
| 187 | std::size_t add_pending(const std::string &func) |
| 188 | { |
| 189 | m_breakpoints.emplace_front(++m_id, func); |
| 190 | m_pending.emplace(func, std::pair<std::size_t, bool>(m_id, true)); |
| 191 | return m_id; |
| 192 | } |
| 193 | |
| 194 | void replace_pending(const std::string &name, const cs::var &function) |
| 195 | { |
| 196 | if (m_pending.count(name) > 0) { |
| 197 | const cs::callable::function_type &target = function.const_val<cs::callable>().get_raw_data(); |
| 198 | target.target<cs::function_ptr>()->fptr->set_debugger_state(true); |
| 199 | auto key = m_pending.find(name); |
| 200 | if (key->second.second) { |
| 201 | for (auto &it : m_breakpoints) { |
| 202 | if (it.id == key->second.first) { |
| 203 | it.data.emplace<cs::var>(function); |
| 204 | key->second.second = false; |
| 205 | break; |
| 206 | } |
nothing calls this directly
no outgoing calls
no test coverage detected